# Customer chats

Let members and staff start conversations on any subject, outside of a reservation.

Source: https://docs.champagne.dev-ukab.fr/fr/graphql/customer-chats

A customer chat is a conversation between one person of the club (a member or an applicant) and
the club team about a subject of their choice. Either side can start it, and a person can keep
several chats open at once. Reservation conversations stay attached to their reservation (see [Reservations](/fr/graphql/reservations)).

Staff need the `customer_chats` permission in the club; club administrators always have it.
Members can only reach their own chats in the club of their session.

## Staff inbox [#staff-inbox]

```graphql
query CustomerChats($clubId: ID!, $archived: Boolean!) {
  customerChats(clubId: $clubId, archived: $archived) {
    id
    personId
    personName
    subject
    createdAt
    archivedAt
    unread
    lastMessage {
      author
      senderName
      body
      createdAt
    }
  }
}
```

| Argument   | Type       | Description                                                     |
| ---------- | ---------- | --------------------------------------------------------------- |
| `clubId`   | `ID!`      | Club whose chats are listed.                                    |
| `archived` | `Boolean!` | `false` (default) lists active chats, `true` the archived ones. |

Every staff member with access sees every chat of the club, sorted by latest message first.
`unread` and `archivedAt` belong to the caller: a chat is unread while a customer message is newer
than the caller's last read, and archiving it never affects another staff member. Any new message,
from either side, restores the chat to every staff member's active list.

```graphql
query CustomerChat($clubId: ID!, $chatId: ID!) {
  customerChat(clubId: $clubId, chatId: $chatId) {
    id
    personId
    personName
    subject
    messages {
      id
      author
      senderName
      body
      createdAt
    }
  }
}

mutation ReadCustomerChat($clubId: ID!, $chatId: ID!) {
  markCustomerChatRead(clubId: $clubId, chatId: $chatId)
}

mutation ArchiveCustomerChat($clubId: ID!, $chatId: ID!) {
  setCustomerChatArchived(clubId: $clubId, chatId: $chatId, archived: true)
}
```

`customerChat` returns `null` for a chat of another club. Messages are ordered oldest first;
`author` is `customer` or `professional`. `markCustomerChatRead` and `setCustomerChatArchived`
return `false` when the chat does not exist in the club.

## Start and answer as staff [#start-and-answer-as-staff]

```graphql
mutation StartCustomerChat($clubId: ID!, $personId: ID!, $subject: String!, $body: String!) {
  startCustomerChat(clubId: $clubId, personId: $personId, subject: $subject, body: $body) {
    id
    subject
  }
}

mutation PostCustomerChatMessage($clubId: ID!, $chatId: ID!, $body: String!) {
  postCustomerChatMessage(clubId: $clubId, chatId: $chatId, body: $body) {
    id
    messages {
      id
      body
    }
  }
}
```

The person must belong to `clubId`. Messages are signed with the staff member's name, or
`Club team` when it is empty, and are immediately read for the sender. Each staff message sends
the member a `chat` notification in the app and by email (according to their preferences)
linking to `/account/chats/{chatId}`, and emits the `chat.message` webhook. Starting a chat is
recorded as `customer_chat.started` and later replies as `customer_chat.message_posted` in the
staff activity log.

## Member operations [#member-operations]

```graphql
query MyCustomerChats($clubId: ID!) {
  myCustomerChats(clubId: $clubId) {
    id
    subject
    unread
    lastMessage {
      author
      senderName
      body
      createdAt
    }
  }
}

mutation StartMyCustomerChat($clubId: ID!, $subject: String!, $body: String!) {
  startMyCustomerChat(clubId: $clubId, subject: $subject, body: $body) {
    id
  }
}
```

`myCustomerChat(clubId, chatId)`, `postMyCustomerChatMessage(clubId, chatId, body)` and
`markMyCustomerChatRead(clubId, chatId)` complete the member API. A member chat is unread while
a professional message is newer than the member's last read; the member's own messages count as
read. Chats of another member return `null` (or `false` for `markMyCustomerChatRead`). Members of
another club and staff accounts receive `UNAUTHENTICATED`. Customer messages are signed with the
member's name and do not notify staff beyond the unread state of their inbox.

## Validation [#validation]

Subjects are trimmed and must contain 1 to 120 characters; message bodies are trimmed and must
contain 1 to 4000 characters. Invalid IDs and out-of-range values return `BAD_USER_INPUT`.
