diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index d0678ec5..cdefb9c4 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,5 +1,11 @@ # @baseapp-frontend/components +## 0.0.53 + +### Patch Changes + +- Implement system messages + ## 0.0.52 ### Patch Changes diff --git a/packages/components/__generated__/ChatRoomMessagesListPaginationQuery.graphql.ts b/packages/components/__generated__/ChatRoomMessagesListPaginationQuery.graphql.ts index e46f1a0c..77db960b 100644 --- a/packages/components/__generated__/ChatRoomMessagesListPaginationQuery.graphql.ts +++ b/packages/components/__generated__/ChatRoomMessagesListPaginationQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<39f8d49d41c823e22d2be2830169f552>> * @lightSyntaxTransform * @nogrep */ @@ -260,6 +260,13 @@ return { "name": "isRead", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "messageType", + "storageKey": null + }, { "alias": null, "args": null, @@ -361,16 +368,16 @@ return { ] }, "params": { - "cacheID": "f296a259a1d80db1209eb995234dcfed", + "cacheID": "9ddf1824c13a8a7892f2f6d07274bc3b", "id": null, "metadata": {}, "name": "ChatRoomMessagesListPaginationQuery", "operationKind": "query", - "text": "query ChatRoomMessagesListPaginationQuery(\n $count: Int = 20\n $cursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...MessagesListFragment_1G22uz\n id\n }\n}\n\nfragment MessageItemFragment on Message {\n id\n content\n created\n extraData\n inReplyTo {\n id\n }\n isRead\n pk\n profile {\n id\n }\n verb\n}\n\nfragment MessagesListFragment_1G22uz on ChatRoom {\n id\n isGroup\n unreadMessages {\n count\n markedUnread\n id\n }\n allMessages(first: $count, after: $cursor) {\n totalCount\n edges {\n node {\n id\n created\n profile {\n id\n name\n image(height: 32, width: 32) {\n url\n }\n }\n isRead\n ...MessageItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + "text": "query ChatRoomMessagesListPaginationQuery(\n $count: Int = 20\n $cursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...MessagesListFragment_1G22uz\n id\n }\n}\n\nfragment MessageItemFragment on Message {\n id\n content\n created\n extraData\n inReplyTo {\n id\n }\n isRead\n pk\n profile {\n id\n }\n verb\n}\n\nfragment MessagesListFragment_1G22uz on ChatRoom {\n id\n isGroup\n unreadMessages {\n count\n markedUnread\n id\n }\n allMessages(first: $count, after: $cursor) {\n totalCount\n edges {\n node {\n id\n created\n profile {\n id\n name\n image(height: 32, width: 32) {\n url\n }\n }\n isRead\n messageType\n ...MessageItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "2101646ad6b90d900738f9b290616d98"; +(node as any).hash = "9a3c1fd2e9507a24075ab2654972c7cf"; export default node; diff --git a/packages/components/__generated__/ChatRoomQuery.graphql.ts b/packages/components/__generated__/ChatRoomQuery.graphql.ts index 10d44d5b..eb94e7a9 100644 --- a/packages/components/__generated__/ChatRoomQuery.graphql.ts +++ b/packages/components/__generated__/ChatRoomQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<117c133e1e86b1597b3571fe2492c791>> * @lightSyntaxTransform * @nogrep */ @@ -342,6 +342,13 @@ return { "name": "isRead", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "messageType", + "storageKey": null + }, { "alias": null, "args": null, @@ -445,12 +452,12 @@ return { ] }, "params": { - "cacheID": "418e1900e952253a01398308df1c9875", + "cacheID": "afc29c79eba4d84f8cb3363107dee423", "id": null, "metadata": {}, "name": "ChatRoomQuery", "operationKind": "query", - "text": "query ChatRoomQuery(\n $roomId: ID!\n) {\n chatRoom(id: $roomId) {\n id\n participantsCount\n ...TitleFragment\n ...MessagesListFragment\n }\n}\n\nfragment GroupTitleFragment on ChatRoom {\n id\n image(width: 144, height: 144) {\n url\n }\n title\n}\n\nfragment MessageItemFragment on Message {\n id\n content\n created\n extraData\n inReplyTo {\n id\n }\n isRead\n pk\n profile {\n id\n }\n verb\n}\n\nfragment MessagesListFragment on ChatRoom {\n id\n isGroup\n unreadMessages {\n count\n markedUnread\n id\n }\n allMessages(first: 20) {\n totalCount\n edges {\n node {\n id\n created\n profile {\n id\n name\n image(height: 32, width: 32) {\n url\n }\n }\n isRead\n ...MessageItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment RoomTitleFragment on ChatRoom {\n id\n participants(first: 2) {\n edges {\n node {\n profile {\n id\n name\n image(width: 100, height: 100) {\n url\n }\n }\n id\n }\n }\n }\n}\n\nfragment TitleFragment on ChatRoom {\n id\n isGroup\n ...RoomTitleFragment\n ...GroupTitleFragment\n}\n" + "text": "query ChatRoomQuery(\n $roomId: ID!\n) {\n chatRoom(id: $roomId) {\n id\n participantsCount\n ...TitleFragment\n ...MessagesListFragment\n }\n}\n\nfragment GroupTitleFragment on ChatRoom {\n id\n image(width: 144, height: 144) {\n url\n }\n title\n}\n\nfragment MessageItemFragment on Message {\n id\n content\n created\n extraData\n inReplyTo {\n id\n }\n isRead\n pk\n profile {\n id\n }\n verb\n}\n\nfragment MessagesListFragment on ChatRoom {\n id\n isGroup\n unreadMessages {\n count\n markedUnread\n id\n }\n allMessages(first: 20) {\n totalCount\n edges {\n node {\n id\n created\n profile {\n id\n name\n image(height: 32, width: 32) {\n url\n }\n }\n isRead\n messageType\n ...MessageItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment RoomTitleFragment on ChatRoom {\n id\n participants(first: 2) {\n edges {\n node {\n profile {\n id\n name\n image(width: 100, height: 100) {\n url\n }\n }\n id\n }\n }\n }\n}\n\nfragment TitleFragment on ChatRoom {\n id\n isGroup\n ...RoomTitleFragment\n ...GroupTitleFragment\n}\n" } }; })(); diff --git a/packages/components/__generated__/MessageUpdateMutation.graphql.ts b/packages/components/__generated__/MessageUpdateMutation.graphql.ts index 228e669f..a05c670c 100644 --- a/packages/components/__generated__/MessageUpdateMutation.graphql.ts +++ b/packages/components/__generated__/MessageUpdateMutation.graphql.ts @@ -5,273 +5,258 @@ */ /* tslint:disable */ - /* eslint-disable */ // @ts-nocheck -import { ConcreteRequest, Mutation } from 'relay-runtime' -import { FragmentRefs } from 'relay-runtime' +import { ConcreteRequest, Mutation } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; export type ChatRoomEditMessageInput = { - clientMutationId?: string | null | undefined - content: string - id: string -} + clientMutationId?: string | null | undefined; + content: string; + id: string; +}; export type MessageUpdateMutation$variables = { - input: ChatRoomEditMessageInput -} + input: ChatRoomEditMessageInput; +}; export type MessageUpdateMutation$data = { - readonly chatRoomEditMessage: - | { - readonly errors: - | ReadonlyArray< - | { - readonly field: string - readonly messages: ReadonlyArray - } - | null - | undefined - > - | null - | undefined - readonly message: - | { - readonly node: - | { - readonly content: string | null | undefined - readonly id: string - readonly ' $fragmentSpreads': FragmentRefs<'MessageItemFragment'> - } - | null - | undefined - } - | null - | undefined - } - | null - | undefined -} + readonly chatRoomEditMessage: { + readonly errors: ReadonlyArray<{ + readonly field: string; + readonly messages: ReadonlyArray; + } | null | undefined> | null | undefined; + readonly message: { + readonly node: { + readonly content: string | null | undefined; + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"MessageItemFragment">; + } | null | undefined; + } | null | undefined; + } | null | undefined; +}; export type MessageUpdateMutation = { - response: MessageUpdateMutation$data - variables: MessageUpdateMutation$variables -} + response: MessageUpdateMutation$data; + variables: MessageUpdateMutation$variables; +}; -const node: ConcreteRequest = (function () { - var v0 = [ +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "content", + "storageKey": null +}, +v4 = { + "alias": null, + "args": null, + "concreteType": "ErrorType", + "kind": "LinkedField", + "name": "errors", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "field", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "messages", + "storageKey": null + } + ], + "storageKey": null +}, +v5 = [ + (v2/*: any*/) +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "MessageUpdateMutation", + "selections": [ { - defaultValue: null, - kind: 'LocalArgument', - name: 'input', - }, + "alias": null, + "args": (v1/*: any*/), + "concreteType": "ChatRoomEditMessagePayload", + "kind": "LinkedField", + "name": "chatRoomEditMessage", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "MessageEdge", + "kind": "LinkedField", + "name": "message", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Message", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "MessageItemFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + }, + (v4/*: any*/) + ], + "storageKey": null + } ], - v1 = [ + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "MessageUpdateMutation", + "selections": [ { - kind: 'Variable', - name: 'input', - variableName: 'input', - }, - ], - v2 = { - alias: null, - args: null, - kind: 'ScalarField', - name: 'id', - storageKey: null, - }, - v3 = { - alias: null, - args: null, - kind: 'ScalarField', - name: 'content', - storageKey: null, - }, - v4 = { - alias: null, - args: null, - concreteType: 'ErrorType', - kind: 'LinkedField', - name: 'errors', - plural: true, - selections: [ - { - alias: null, - args: null, - kind: 'ScalarField', - name: 'field', - storageKey: null, - }, - { - alias: null, - args: null, - kind: 'ScalarField', - name: 'messages', - storageKey: null, - }, - ], - storageKey: null, - }, - v5 = [v2 /*: any*/] - return { - fragment: { - argumentDefinitions: v0 /*: any*/, - kind: 'Fragment', - metadata: null, - name: 'MessageUpdateMutation', - selections: [ - { - alias: null, - args: v1 /*: any*/, - concreteType: 'ChatRoomEditMessagePayload', - kind: 'LinkedField', - name: 'chatRoomEditMessage', - plural: false, - selections: [ - { - alias: null, - args: null, - concreteType: 'MessageEdge', - kind: 'LinkedField', - name: 'message', - plural: false, - selections: [ - { - alias: null, - args: null, - concreteType: 'Message', - kind: 'LinkedField', - name: 'node', - plural: false, - selections: [ - v2 /*: any*/, - v3 /*: any*/, - { - args: null, - kind: 'FragmentSpread', - name: 'MessageItemFragment', - }, - ], - storageKey: null, - }, - ], - storageKey: null, - }, - v4 /*: any*/, - ], - storageKey: null, - }, - ], - type: 'Mutation', - abstractKey: null, - }, - kind: 'Request', - operation: { - argumentDefinitions: v0 /*: any*/, - kind: 'Operation', - name: 'MessageUpdateMutation', - selections: [ - { - alias: null, - args: v1 /*: any*/, - concreteType: 'ChatRoomEditMessagePayload', - kind: 'LinkedField', - name: 'chatRoomEditMessage', - plural: false, - selections: [ - { - alias: null, - args: null, - concreteType: 'MessageEdge', - kind: 'LinkedField', - name: 'message', - plural: false, - selections: [ - { - alias: null, - args: null, - concreteType: 'Message', - kind: 'LinkedField', - name: 'node', - plural: false, - selections: [ - v2 /*: any*/, - v3 /*: any*/, - { - alias: null, - args: null, - kind: 'ScalarField', - name: 'created', - storageKey: null, - }, - { - alias: null, - args: null, - kind: 'ScalarField', - name: 'extraData', - storageKey: null, - }, - { - alias: null, - args: null, - concreteType: 'Message', - kind: 'LinkedField', - name: 'inReplyTo', - plural: false, - selections: v5 /*: any*/, - storageKey: null, - }, - { - alias: null, - args: null, - kind: 'ScalarField', - name: 'isRead', - storageKey: null, - }, - { - alias: null, - args: null, - kind: 'ScalarField', - name: 'pk', - storageKey: null, - }, - { - alias: null, - args: null, - concreteType: 'Profile', - kind: 'LinkedField', - name: 'profile', - plural: false, - selections: v5 /*: any*/, - storageKey: null, - }, - { - alias: null, - args: null, - kind: 'ScalarField', - name: 'verb', - storageKey: null, - }, - ], - storageKey: null, - }, - ], - storageKey: null, - }, - v4 /*: any*/, - ], - storageKey: null, - }, - ], - }, - params: { - cacheID: 'f9b41a8750ea7be70eae5f1bccf57cbd', - id: null, - metadata: {}, - name: 'MessageUpdateMutation', - operationKind: 'mutation', - text: 'mutation MessageUpdateMutation(\n $input: ChatRoomEditMessageInput!\n) {\n chatRoomEditMessage(input: $input) {\n message {\n node {\n id\n content\n ...MessageItemFragment\n }\n }\n errors {\n field\n messages\n }\n }\n}\n\nfragment MessageItemFragment on Message {\n id\n content\n created\n extraData\n inReplyTo {\n id\n }\n isRead\n pk\n profile {\n id\n }\n verb\n}\n', - }, + "alias": null, + "args": (v1/*: any*/), + "concreteType": "ChatRoomEditMessagePayload", + "kind": "LinkedField", + "name": "chatRoomEditMessage", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "MessageEdge", + "kind": "LinkedField", + "name": "message", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Message", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "extraData", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "Message", + "kind": "LinkedField", + "name": "inReplyTo", + "plural": false, + "selections": (v5/*: any*/), + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "isRead", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "pk", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "Profile", + "kind": "LinkedField", + "name": "profile", + "plural": false, + "selections": (v5/*: any*/), + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "verb", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + }, + (v4/*: any*/) + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "f9b41a8750ea7be70eae5f1bccf57cbd", + "id": null, + "metadata": {}, + "name": "MessageUpdateMutation", + "operationKind": "mutation", + "text": "mutation MessageUpdateMutation(\n $input: ChatRoomEditMessageInput!\n) {\n chatRoomEditMessage(input: $input) {\n message {\n node {\n id\n content\n ...MessageItemFragment\n }\n }\n errors {\n field\n messages\n }\n }\n}\n\nfragment MessageItemFragment on Message {\n id\n content\n created\n extraData\n inReplyTo {\n id\n }\n isRead\n pk\n profile {\n id\n }\n verb\n}\n" } -})() +}; +})(); -;(node as any).hash = 'b118f4853919251adbfb8bcdbf909ca5' +(node as any).hash = "b118f4853919251adbfb8bcdbf909ca5"; -export default node +export default node; diff --git a/packages/components/__generated__/MessagesListFragment.graphql.ts b/packages/components/__generated__/MessagesListFragment.graphql.ts index 1c5f80a5..93a0869f 100644 --- a/packages/components/__generated__/MessagesListFragment.graphql.ts +++ b/packages/components/__generated__/MessagesListFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<132c9b893bebbdd1686a37cce9ee0d0f>> + * @generated SignedSource<<89d17b7a6ecad5b65bc1bfa05cf71913>> * @lightSyntaxTransform * @nogrep */ @@ -9,6 +9,7 @@ // @ts-nocheck import { ReaderFragment, RefetchableFragment } from 'relay-runtime'; +export type MessageType = "SYSTEM_GENERATED" | "USER_MESSAGE" | "%future added value"; import { FragmentRefs } from "relay-runtime"; export type MessagesListFragment$data = { readonly allMessages: { @@ -17,6 +18,7 @@ export type MessagesListFragment$data = { readonly created: any; readonly id: string; readonly isRead: boolean | null | undefined; + readonly messageType: MessageType | null | undefined; readonly profile: { readonly id: string; readonly image: { @@ -228,6 +230,13 @@ return { "name": "isRead", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "messageType", + "storageKey": null + }, { "args": null, "kind": "FragmentSpread", @@ -287,6 +296,6 @@ return { }; })(); -(node as any).hash = "2101646ad6b90d900738f9b290616d98"; +(node as any).hash = "9a3c1fd2e9507a24075ab2654972c7cf"; export default node; diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/SystemMessage/index.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/SystemMessage/index.tsx new file mode 100644 index 00000000..f2009d10 --- /dev/null +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/SystemMessage/index.tsx @@ -0,0 +1,19 @@ +import { FC } from 'react' + +import { useFragment } from 'react-relay' + +import { MessageItemFragment } from '../../../graphql/fragments/MessageItem' +import { SystemMessageTypography } from './styled' +import { SystemMessageProps } from './types' + +const SystemMessage: FC = ({ messageRef }) => { + const message = useFragment(MessageItemFragment, messageRef) + + return ( + + {message.content} + + ) +} + +export default SystemMessage diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/SystemMessage/styled.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/SystemMessage/styled.tsx new file mode 100644 index 00000000..27165e4e --- /dev/null +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/SystemMessage/styled.tsx @@ -0,0 +1,12 @@ +import { Typography, styled } from '@mui/material' + +export const SystemMessageTypography = styled(Typography)(({ theme }) => ({ + alignSelf: 'center', + backgroundColor: theme.palette.grey[300], + borderRadius: theme.spacing(1), + marginBottom: theme.spacing(1), + marginTop: theme.spacing(2), + padding: theme.spacing(0.5, 1), + textAlign: 'center', + width: 'fit-content', +})) diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/SystemMessage/types.ts b/packages/components/modules/messages/MessagesList/MessagesGroup/SystemMessage/types.ts new file mode 100644 index 00000000..67770e46 --- /dev/null +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/SystemMessage/types.ts @@ -0,0 +1,5 @@ +import { MessageItemFragment$key } from '../../../../../__generated__/MessageItemFragment.graphql' + +export interface SystemMessageProps { + messageRef: MessageItemFragment$key +} diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/index.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx similarity index 89% rename from packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/index.tsx rename to packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx index 83d081ee..c8475f1f 100644 --- a/packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/index.tsx +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx @@ -6,10 +6,10 @@ import { CopyIcon, DownloadIcon, PenEditIcon } from '@baseapp-frontend/design-sy import { Typography } from '@mui/material' import { useFragment } from 'react-relay' -import ActionsOverlay from '../../../../__shared__/ActionsOverlay' -import { HOVER_OVERLAY_MODES } from '../../../../__shared__/ActionsOverlay/constants' -import MessageUpdate from '../../../MessageUpdate' -import { MessageItemFragment } from '../../../graphql/fragments/MessageItem' +import ActionsOverlay from '../../../../../__shared__/ActionsOverlay' +import { HOVER_OVERLAY_MODES } from '../../../../../__shared__/ActionsOverlay/constants' +import MessageUpdate from '../../../../MessageUpdate' +import { MessageItemFragment } from '../../../../graphql/fragments/MessageItem' import { MessageItemContainer } from './styled' import { MessageItemProps } from './types' diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/styled.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/MessageItem/styled.tsx similarity index 100% rename from packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/styled.tsx rename to packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/MessageItem/styled.tsx diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/types.ts b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/MessageItem/types.ts similarity index 73% rename from packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/types.ts rename to packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/MessageItem/types.ts index 3dee4d0f..ade93782 100644 --- a/packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/types.ts +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/MessageItem/types.ts @@ -1,6 +1,6 @@ import { BoxProps } from '@mui/material' -import { MessageItemFragment$key } from '../../../../../__generated__/MessageItemFragment.graphql' +import { MessageItemFragment$key } from '../../../../../../__generated__/MessageItemFragment.graphql' export interface MessageItemProps { messageRef: MessageItemFragment$key diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/Timestamp/index.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/Timestamp/index.tsx similarity index 100% rename from packages/components/modules/messages/MessagesList/MessagesGroup/Timestamp/index.tsx rename to packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/Timestamp/index.tsx diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/Timestamp/types.ts b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/Timestamp/types.ts similarity index 100% rename from packages/components/modules/messages/MessagesList/MessagesGroup/Timestamp/types.ts rename to packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/Timestamp/types.ts diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/index.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/index.tsx new file mode 100644 index 00000000..023a498c --- /dev/null +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/index.tsx @@ -0,0 +1,109 @@ +import { FC, useCallback, useMemo } from 'react' + +import { useCurrentProfile } from '@baseapp-frontend/authentication' +import { AvatarWithPlaceholder } from '@baseapp-frontend/design-system' + +import { Box, Typography } from '@mui/material' +import { DateTime } from 'luxon' + +import { MAXIMUM_DIFF_TO_GROUP_MESSAGES_CREATED_TIME } from '../../../constants' +import DefaultMessageItem from './MessageItem' +import Timestamp from './Timestamp' +import { UserMessageProps } from './types' + +const UserMessage: FC = ({ + allMessages, + allMessagesLastIndex, + message, + messageIndex, + isGroup = false, + MessageItem = DefaultMessageItem, + MessageItemProps = {}, +}) => { + const { currentProfile } = useCurrentProfile() + + const renderLastMessageTime = useCallback( + (index: number) => { + const currentMessage = allMessages?.[index] + const nextMessage = allMessages?.[index - 1] + + const isNextMessageFromOtherParticipant = + nextMessage?.profile?.id !== currentMessage?.profile?.id + + const { minutes: dateDiff } = DateTime.fromISO(nextMessage?.created).diff( + DateTime.fromISO(currentMessage?.created), + 'minutes', + ) + const isDateDiffAboveMaximumInterval = dateDiff > MAXIMUM_DIFF_TO_GROUP_MESSAGES_CREATED_TIME + + if (isNextMessageFromOtherParticipant || !nextMessage || isDateDiffAboveMaximumInterval) { + return + } + + return null + }, + [allMessages], + ) + + const isFirstGroupedMessage = useMemo(() => { + const currentMessage = allMessages?.[messageIndex] + const previousMessage = allMessages?.[messageIndex + 1] + + const isPreviousMessageFromOtherParticipant = + previousMessage?.profile?.id !== currentMessage?.profile?.id + const roomHasOnlyOneMessage = allMessagesLastIndex === 0 + + if (isPreviousMessageFromOtherParticipant || roomHasOnlyOneMessage) return true + + return false + }, [allMessages, allMessagesLastIndex, messageIndex]) + + const isOwnMessage = currentProfile?.id === message?.profile?.id + + const flexAlignments = isOwnMessage ? 'flex-end' : 'flex-start' + const canShowAvatar = isFirstGroupedMessage && !isOwnMessage + + const canShowName = canShowAvatar && isGroup + + if (!message) return null + + return ( + + {canShowAvatar && ( + + + + )} + + {canShowName && ( + + {message?.profile?.name} + + )} + + {renderLastMessageTime(messageIndex)} + + + ) +} + +export default UserMessage diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/types.ts b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/types.ts new file mode 100644 index 00000000..8dcd33d7 --- /dev/null +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/UserMessage/types.ts @@ -0,0 +1,14 @@ +import { FC } from 'react' + +import { MessageNode } from '../../../types' +import { MessageItemProps } from './MessageItem/types' + +export interface UserMessageProps { + allMessages: MessageNode[] + message: MessageNode + messageIndex: number + isGroup?: boolean + allMessagesLastIndex: number + MessageItem?: FC + MessageItemProps?: Partial +} diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx index 9b972d8c..f38e2398 100644 --- a/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx @@ -1,15 +1,12 @@ -import { FC, useCallback, useMemo } from 'react' +import { FC, useCallback } from 'react' -import { useCurrentProfile } from '@baseapp-frontend/authentication' -import { AvatarWithPlaceholder } from '@baseapp-frontend/design-system' import { datesDontHaveSameDay } from '@baseapp-frontend/utils' import { Box, Divider, Typography, useTheme } from '@mui/material' -import { DateTime } from 'luxon' -import { MAXIMUM_DIFF_TO_GROUP_MESSAGES_CREATED_TIME } from '../../constants' -import DefaultMessageItem from './MessageItem' -import Timestamp from './Timestamp' +import { MESSAGE_TYPE } from '../../constants' +import DefaultSystemMessage from './SystemMessage' +import DefaultUserMessage from './UserMessage' import { DateGroupTypography } from './styled' import { MessagesGroupProps } from './types' import { displayFormattedDate } from './utils' @@ -22,10 +19,11 @@ const MessagesGroup: FC = ({ messageIndex, isGroup = false, firstUnreadMessageId, - MessageItem = DefaultMessageItem, - MessageItemProps = {}, + SystemMessage = DefaultSystemMessage, + SystemMessageProps = {}, + UserMessage = DefaultUserMessage, + UserMessageProps = {}, }) => { - const { currentProfile } = useCurrentProfile() const theme = useTheme() const renderDateOnTopOfMessagesGroup = useCallback( @@ -76,90 +74,24 @@ const MessagesGroup: FC = ({ [allMessages, firstUnreadMessageId, theme.palette.error.light], ) - const renderLastMessageTime = useCallback( - (index: number) => { - const currentMessage = allMessages?.[index] - const nextMessage = allMessages?.[index - 1] - - const isNextMessageFromOtherParticipant = - nextMessage?.profile?.id !== currentMessage?.profile?.id - - const { minutes: dateDiff } = DateTime.fromISO(nextMessage?.created).diff( - DateTime.fromISO(currentMessage?.created), - 'minutes', - ) - const isDateDiffAboveMaximumInterval = dateDiff > MAXIMUM_DIFF_TO_GROUP_MESSAGES_CREATED_TIME - - if (isNextMessageFromOtherParticipant || !nextMessage || isDateDiffAboveMaximumInterval) { - return - } - - return null - }, - [allMessages], - ) - - const isFirstGroupedMessage = useMemo(() => { - const currentMessage = allMessages?.[messageIndex] - const previousMessage = allMessages?.[messageIndex + 1] - - const isPreviousMessageFromOtherParticipant = - previousMessage?.profile?.id !== currentMessage?.profile?.id - const roomHasOnlyOneMessage = allMessagesLastIndex === 0 - - if (isPreviousMessageFromOtherParticipant || roomHasOnlyOneMessage) return true - - return false - }, [allMessages, allMessagesLastIndex, messageIndex]) - - const isOwnMessage = currentProfile?.id === message?.profile?.id - - const flexAlignments = isOwnMessage ? 'flex-end' : 'flex-start' - const canShowAvatar = isFirstGroupedMessage && !isOwnMessage - - const canShowName = canShowAvatar && isGroup - if (!message) return null return ( {renderUnreadMessagesDivider(messageIndex)} {renderDateOnTopOfMessagesGroup(messageIndex)} - - {canShowAvatar && ( - - - - )} - - {canShowName && ( - - {message?.profile?.name} - - )} - - {renderLastMessageTime(messageIndex)} - - + {message.messageType === MESSAGE_TYPE.system ? ( + + ) : ( + + )} ) } diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/types.ts b/packages/components/modules/messages/MessagesList/MessagesGroup/types.ts index d5d4746d..1b470397 100644 --- a/packages/components/modules/messages/MessagesList/MessagesGroup/types.ts +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/types.ts @@ -1,7 +1,8 @@ import { FC } from 'react' import { MessageNode } from '../../types' -import { MessageItemProps } from './MessageItem/types' +import { SystemMessageProps } from './SystemMessage/types' +import { UserMessageProps } from './UserMessage/types' export interface MessagesGroupProps { allMessages: MessageNode[] @@ -11,6 +12,8 @@ export interface MessagesGroupProps { allMessagesLastIndex: number firstUnreadMessageId?: string | null hasNext: boolean - MessageItem?: FC - MessageItemProps?: Partial + SystemMessage?: FC + SystemMessageProps?: Partial + UserMessage?: FC + UserMessageProps?: Partial } diff --git a/packages/components/modules/messages/MessagesList/index.tsx b/packages/components/modules/messages/MessagesList/index.tsx index 9157a8c7..4918b773 100644 --- a/packages/components/modules/messages/MessagesList/index.tsx +++ b/packages/components/modules/messages/MessagesList/index.tsx @@ -9,6 +9,7 @@ import { Virtuoso, VirtuosoHandle } from 'react-virtuoso' import { ChatRoomMessagesListPaginationQuery } from '../../../__generated__/ChatRoomMessagesListPaginationQuery.graphql' import { MessagesListFragment$key } from '../../../__generated__/MessagesListFragment.graphql' +import { MESSAGE_TYPE } from '../constants' import { useChatRoom } from '../context' import { MessagesListFragment } from '../graphql/fragments/MessagesList' import { useReadMessageMutation } from '../graphql/mutations/ReadMessages' @@ -48,9 +49,10 @@ const MessagesList: FC = ({ const [commitMutation] = useReadMessageMutation() const getFirstUnreadMessageId = () => { - if (room?.unreadMessages?.count === 0) return null - return allMessages.find((message, index) => { - const previousMessage = allMessages?.[index + 1] + if (!room?.unreadMessages?.count) return null + const userMessages = allMessages.filter((message) => message?.messageType === MESSAGE_TYPE.user) + return userMessages.find((message, index) => { + const previousMessage = userMessages?.[index + 1] const hasPreviousMessage = !!previousMessage return ( message?.profile?.id !== currentProfile?.id && diff --git a/packages/components/modules/messages/constants.ts b/packages/components/modules/messages/constants.ts index 51ad883b..629cc96f 100644 --- a/packages/components/modules/messages/constants.ts +++ b/packages/components/modules/messages/constants.ts @@ -1 +1,10 @@ +import { ValueOf } from '@baseapp-frontend/utils' + export const MAXIMUM_DIFF_TO_GROUP_MESSAGES_CREATED_TIME = 3 // in minutes + +export const MESSAGE_TYPE = { + user: 'USER_MESSAGE', + system: 'SYSTEM_GENERATED', +} as const + +export type MessageTypeOptions = ValueOf diff --git a/packages/components/modules/messages/graphql/fragments/MessagesList.ts b/packages/components/modules/messages/graphql/fragments/MessagesList.ts index 12ae8ab2..7991a404 100644 --- a/packages/components/modules/messages/graphql/fragments/MessagesList.ts +++ b/packages/components/modules/messages/graphql/fragments/MessagesList.ts @@ -24,6 +24,7 @@ export const MessagesListFragment = graphql` } } isRead + messageType ...MessageItemFragment } } diff --git a/packages/components/package.json b/packages/components/package.json index afbb9fa6..33257553 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,7 +1,7 @@ { "name": "@baseapp-frontend/components", "description": "BaseApp components modules such as comments, notifications, messages, and more.", - "version": "0.0.52", + "version": "0.0.53", "main": "./index.ts", "types": "dist/index.d.ts", "sideEffects": false, diff --git a/packages/components/schema.graphql b/packages/components/schema.graphql index 31ed127f..c71e66f4 100644 --- a/packages/components/schema.graphql +++ b/packages/components/schema.graphql @@ -642,9 +642,10 @@ type Message implements Node { """The ID of the object""" id: ID! created: DateTime! - content: String + content(profileId: ID): String user: User profile: Profile + messageType: MessageType verb: Verbs room: ChatRoom inReplyTo: Message @@ -673,6 +674,12 @@ type MessageEdge { cursor: String! } +"""An enumeration.""" +enum MessageType { + USER_MESSAGE + SYSTEM_GENERATED +} + type Metadata { created: DateTime! modified: DateTime! @@ -1149,6 +1156,8 @@ type Profile implements Node & PermissionsInterface & PageInterface & FollowsInt ): ProfileUserRoleConnection chatroomparticipantSet(offset: Int, before: String, after: String, first: Int, last: Int, profile_TargetContentType: ID): ChatRoomParticipantConnection! unreadmessagecountSet(offset: Int, before: String, after: String, first: Int, last: Int): UnreadMessageCountConnection! + linkedOnContentCapitalSet(offset: Int, before: String, after: String, first: Int, last: Int, verb: Verbs): MessageConnection! + linkedOnContentSmallSet(offset: Int, before: String, after: String, first: Int, last: Int, verb: Verbs): MessageConnection! messageSet(offset: Int, before: String, after: String, first: Int, last: Int, verb: Verbs): MessageConnection! following(offset: Int, before: String, after: String, first: Int, last: Int, targetIsFollowingBack: Boolean): FollowConnection followers(offset: Int, before: String, after: String, first: Int, last: Int, targetIsFollowingBack: Boolean): FollowConnection