@planningcenter/chat-react-native 4.0.1-qa-staging.2 → 4.0.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/conversation/message.d.ts +2 -3
- package/build/components/conversation/message.d.ts.map +1 -1
- package/build/components/conversation/message.js +22 -23
- package/build/components/conversation/message.js.map +1 -1
- package/build/components/conversation/message_read_receipts.d.ts +4 -2
- package/build/components/conversation/message_read_receipts.d.ts.map +1 -1
- package/build/components/conversation/message_read_receipts.js +3 -2
- package/build/components/conversation/message_read_receipts.js.map +1 -1
- package/build/components/conversation/reply_shadow_message.d.ts +1 -2
- package/build/components/conversation/reply_shadow_message.d.ts.map +1 -1
- package/build/components/conversation/reply_shadow_message.js +46 -47
- package/build/components/conversation/reply_shadow_message.js.map +1 -1
- package/build/hooks/use_conversation_messages.d.ts.map +1 -1
- package/build/hooks/use_conversation_messages.js +28 -40
- package/build/hooks/use_conversation_messages.js.map +1 -1
- package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
- package/build/hooks/use_conversation_messages_jolt_events.js +1 -6
- package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
- package/build/hooks/use_message_create_or_update.d.ts +4 -99
- package/build/hooks/use_message_create_or_update.d.ts.map +1 -1
- package/build/hooks/use_message_create_or_update.js +6 -47
- package/build/hooks/use_message_create_or_update.js.map +1 -1
- package/build/screens/conversation_new/components/groups_form.js +80 -71
- package/build/screens/conversation_new/components/groups_form.js.map +1 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +365 -184
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/types/resources/message.d.ts +0 -2
- package/build/types/resources/message.d.ts.map +1 -1
- package/build/types/resources/message.js.map +1 -1
- package/build/utils/cache/messages_cache.d.ts +0 -1
- package/build/utils/cache/messages_cache.d.ts.map +1 -1
- package/build/utils/cache/messages_cache.js +7 -14
- package/build/utils/cache/messages_cache.js.map +1 -1
- package/build/utils/cache/optimistically_create_message.d.ts +1 -2
- package/build/utils/cache/optimistically_create_message.d.ts.map +1 -1
- package/build/utils/cache/optimistically_create_message.js +2 -4
- package/build/utils/cache/optimistically_create_message.js.map +1 -1
- package/build/utils/client/transform_response.d.ts.map +1 -1
- package/build/utils/client/transform_response.js +5 -9
- package/build/utils/client/transform_response.js.map +1 -1
- package/build/utils/group_messages.d.ts +0 -1
- package/build/utils/group_messages.d.ts.map +1 -1
- package/build/utils/group_messages.js +1 -10
- package/build/utils/group_messages.js.map +1 -1
- package/build/utils/jolt/transform_message_event_data_to_message_resource.d.ts.map +1 -1
- package/build/utils/jolt/transform_message_event_data_to_message_resource.js +0 -1
- package/build/utils/jolt/transform_message_event_data_to_message_resource.js.map +1 -1
- package/build/utils/request/messages_data_options.d.ts.map +1 -1
- package/build/utils/request/messages_data_options.js +2 -2
- package/build/utils/request/messages_data_options.js.map +1 -1
- package/package.json +3 -3
- package/src/components/conversation/message.tsx +18 -15
- package/src/components/conversation/message_read_receipts.tsx +5 -3
- package/src/components/conversation/reply_shadow_message.tsx +7 -9
- package/src/hooks/use_conversation_messages.ts +1 -5
- package/src/hooks/use_conversation_messages_jolt_events.ts +0 -7
- package/src/hooks/use_message_create_or_update.ts +16 -29
- package/src/screens/conversation_new/components/groups_form.tsx +7 -2
- package/src/screens/conversation_screen.tsx +104 -11
- package/src/types/resources/message.ts +0 -2
- package/src/utils/__tests__/group_messages.test.ts +0 -48
- package/src/utils/cache/messages_cache.ts +11 -27
- package/src/utils/cache/optimistically_create_message.ts +0 -3
- package/src/utils/client/transform_response.ts +5 -7
- package/src/utils/group_messages.ts +1 -18
- package/src/utils/jolt/transform_message_event_data_to_message_resource.ts +0 -1
- package/src/utils/request/messages_data_options.ts +1 -2
- package/build/components/conversation/message_list.d.ts +0 -21
- package/build/components/conversation/message_list.d.ts.map +0 -1
- package/build/components/conversation/message_list.js +0 -273
- package/build/components/conversation/message_list.js.map +0 -1
- package/build/utils/replace_equal_by_id.d.ts +0 -6
- package/build/utils/replace_equal_by_id.d.ts.map +0 -1
- package/build/utils/replace_equal_by_id.js +0 -41
- package/build/utils/replace_equal_by_id.js.map +0 -1
- package/src/components/conversation/__tests__/message_list.test.tsx +0 -271
- package/src/components/conversation/__tests__/reply_shadow_message.test.tsx +0 -119
- package/src/components/conversation/message_list.tsx +0 -157
- package/src/hooks/__tests__/use_message_create_or_update.test.tsx +0 -110
- package/src/utils/__tests__/replace_equal_by_id.test.ts +0 -73
- package/src/utils/cache/__tests__/messages_cache.test.ts +0 -89
- package/src/utils/cache/__tests__/messages_cache_reply_roots.test.ts +0 -70
- package/src/utils/client/__tests__/transform_response.test.ts +0 -62
- package/src/utils/replace_equal_by_id.ts +0 -42
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group_messages.js","names":["dayjs","isSystemMessage","FIVE_MINUTES_MS","groupMessages","ms","inReplyScreen","items","messagesById","Map","map","message","id","myLatestSeen","nextNeighborEnriched","forEach","i","prev","neighborsOf","next","enriched","enrichSystemMessage","push","datesDifferBetween","dateSeparator","isMyLatest","mine","enrichRegularMessage","replyRoot","resolveReplyRoot","shadow","replyShadowFor","arr","replyRootId","get","myLatestInConversation","lastInGroup","renderAuthor","nextRendersAuthor","isReplyShadowMessage","nextIsReplyShadowMessage","threadPosition","inThread","showThreadDetails","startsNewGroup","nextIntroducesReplyShadow","threadPositionFor","prevIsMyReply","undefined","nextIsMyReply","a","b","author","differsByMoreThan5Min","Math","abs","toMillis","createdAt","iso","Date","getTime","dateKey","format","type","date","isThreadRoot","isLast","current","nextInThread","nextIsThreadRoot","differentThread","enteringNewThread","messageId"],"sources":["../../src/utils/group_messages.ts"],"sourcesContent":["import type { MessageResource } from '../types/resources/message'\nimport dayjs from './dayjs'\nimport { isSystemMessage } from './system_messages'\n\nconst FIVE_MINUTES_MS = 5 * 60 * 1000\n\nexport type DateSeparator = { type: 'DateSeparator'; id: string; date: string }\n\nexport type ReplyShadowMessage = {\n type: 'ReplyShadowMessage'\n id: string\n messageId: string\n replyRoot: MessageResource | null\n isReplyShadowMessage: boolean\n nextRendersAuthor: boolean\n}\n\nexport type EnrichedMessage = MessageResource | DateSeparator | ReplyShadowMessage\n\ninterface GroupMessagesProps {\n ms: MessageResource[]\n inReplyScreen?: boolean\n}\n\nexport function groupMessages({ ms, inReplyScreen }: GroupMessagesProps): EnrichedMessage[] {\n const items: EnrichedMessage[] = []\n const messagesById = new Map(ms.map(message => [message.id, message]))\n let myLatestSeen = false\n let nextNeighborEnriched: MessageResource | undefined\n\n ms.forEach((message, i) => {\n const { prev } = neighborsOf(ms, i)\n const next = nextNeighborEnriched\n\n if (isSystemMessage(message)) {\n const enriched = enrichSystemMessage(message, next)\n items.push(enriched)\n if (datesDifferBetween(message, prev)) items.push(dateSeparator(message))\n nextNeighborEnriched = enriched\n return\n }\n\n const isMyLatest = !myLatestSeen && message.mine\n if (isMyLatest) myLatestSeen = true\n\n const enriched = enrichRegularMessage(\n { ...message, replyRoot: resolveReplyRoot(message, messagesById) },\n prev,\n next,\n isMyLatest,\n !!inReplyScreen\n )\n items.push(enriched)\n\n const shadow = replyShadowFor(enriched, prev)\n if (shadow) items.push(shadow)\n\n if (!prev || datesDifferBetween(message, prev)) {\n items.push(dateSeparator(message))\n }\n\n nextNeighborEnriched = enriched\n })\n\n return items\n}\n\nfunction neighborsOf<T>(arr: T[], i: number): { prev: T | undefined; next: T | undefined } {\n return { prev: arr[i + 1], next: arr[i - 1] }\n}\n\nfunction resolveReplyRoot(\n message: MessageResource,\n messagesById: Map<string, MessageResource>\n): MessageResource | null {\n if (!message.replyRootId || message.replyRootId === message.id) return null\n return messagesById.get(message.replyRootId) ?? message.replyRoot ?? null\n}\n\nfunction enrichSystemMessage(\n message: MessageResource,\n next: MessageResource | undefined\n): MessageResource {\n return {\n ...message,\n myLatestInConversation: false,\n lastInGroup: true,\n renderAuthor: false,\n nextRendersAuthor: next?.renderAuthor,\n isReplyShadowMessage: false,\n nextIsReplyShadowMessage: false,\n threadPosition: null,\n }\n}\n\nfunction enrichRegularMessage(\n message: MessageResource,\n prev: MessageResource | undefined,\n next: MessageResource | undefined,\n isMyLatest: boolean,\n inReplyScreen: boolean\n): MessageResource {\n const inThread = message.replyRootId !== null\n const showThreadDetails = !inReplyScreen && inThread\n\n return {\n ...message,\n myLatestInConversation: isMyLatest,\n lastInGroup: !next || startsNewGroup(next, message),\n renderAuthor: !message.mine && (!prev || startsNewGroup(message, prev)),\n nextRendersAuthor: next?.renderAuthor,\n isReplyShadowMessage: false,\n nextIsReplyShadowMessage: nextIntroducesReplyShadow(next, message),\n threadPosition: showThreadDetails ? threadPositionFor(message, next) : null,\n prevIsMyReply: showThreadDetails ? prev?.mine : undefined,\n nextIsMyReply: showThreadDetails ? next?.mine : undefined,\n }\n}\n\nfunction startsNewGroup(a: MessageResource, b: MessageResource): boolean {\n return (\n a.author?.id !== b.author?.id ||\n differsByMoreThan5Min(a, b) ||\n a.replyRootId !== b.replyRootId ||\n datesDifferBetween(a, b)\n )\n}\n\nfunction differsByMoreThan5Min(a: MessageResource, b: MessageResource): boolean {\n return Math.abs(toMillis(a.createdAt) - toMillis(b.createdAt)) > FIVE_MINUTES_MS\n}\n\nfunction toMillis(iso: string): number {\n return new Date(iso).getTime()\n}\n\nfunction datesDifferBetween(a: MessageResource, b: MessageResource | undefined): boolean {\n if (!b) return false\n return dateKey(a) !== dateKey(b)\n}\n\nfunction dateKey(message: MessageResource): string {\n return dayjs(message.createdAt).format('YYYY-MM-DD')\n}\n\nfunction dateSeparator(message: MessageResource): DateSeparator {\n return { type: 'DateSeparator', id: `day-divider-${message.id}`, date: dateKey(message) }\n}\n\nfunction threadPositionFor(\n message: MessageResource,\n next: MessageResource | undefined\n): 'first' | 'center' | 'last' | null {\n const isThreadRoot = message.replyRootId === message.id\n const isLast =\n !next || next.replyRootId !== message.replyRootId || datesDifferBetween(next, message)\n\n if (isThreadRoot && isLast) return null\n if (isThreadRoot) return 'first'\n if (isLast) return 'last'\n return 'center'\n}\n\nfunction nextIntroducesReplyShadow(\n next: MessageResource | undefined,\n current: MessageResource\n): boolean {\n if (!next) return false\n const nextInThread = next.replyRootId !== null\n const nextIsThreadRoot = next.replyRootId === next.id\n const differentThread = next.replyRootId !== current.replyRootId\n return nextInThread && !nextIsThreadRoot && (differentThread || datesDifferBetween(next, current))\n}\n\nfunction replyShadowFor(\n message: MessageResource,\n prev: MessageResource | undefined\n): ReplyShadowMessage | undefined {\n if (!message.replyRootId) return undefined\n if (message.replyRootId === message.id) return undefined\n\n const enteringNewThread =\n !prev || prev.replyRootId !== message.replyRootId || datesDifferBetween(prev, message)\n if (!enteringNewThread) return undefined\n\n return {\n type: 'ReplyShadowMessage',\n id: `${message.id}-${message.replyRootId}`,\n messageId: message.replyRootId,\n replyRoot: message.replyRoot ?? null,\n isReplyShadowMessage: true,\n nextRendersAuthor: message.renderAuthor ?? false,\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"group_messages.js","names":["dayjs","isSystemMessage","FIVE_MINUTES_MS","groupMessages","ms","inReplyScreen","items","myLatestSeen","nextNeighborEnriched","forEach","message","i","prev","neighborsOf","next","enriched","enrichSystemMessage","push","datesDifferBetween","dateSeparator","isMyLatest","mine","enrichRegularMessage","shadow","replyShadowFor","arr","myLatestInConversation","lastInGroup","renderAuthor","nextRendersAuthor","isReplyShadowMessage","nextIsReplyShadowMessage","threadPosition","inThread","replyRootId","showThreadDetails","startsNewGroup","nextIntroducesReplyShadow","threadPositionFor","prevIsMyReply","undefined","nextIsMyReply","a","b","author","id","differsByMoreThan5Min","Math","abs","toMillis","createdAt","iso","Date","getTime","dateKey","format","type","date","isThreadRoot","isLast","current","nextInThread","nextIsThreadRoot","differentThread","enteringNewThread","messageId"],"sources":["../../src/utils/group_messages.ts"],"sourcesContent":["import type { MessageResource } from '../types/resources/message'\nimport dayjs from './dayjs'\nimport { isSystemMessage } from './system_messages'\n\nconst FIVE_MINUTES_MS = 5 * 60 * 1000\n\nexport type DateSeparator = { type: 'DateSeparator'; id: string; date: string }\n\nexport type ReplyShadowMessage = {\n type: 'ReplyShadowMessage'\n id: string\n messageId: string\n isReplyShadowMessage: boolean\n nextRendersAuthor: boolean\n}\n\nexport type EnrichedMessage = MessageResource | DateSeparator | ReplyShadowMessage\n\ninterface GroupMessagesProps {\n ms: MessageResource[]\n inReplyScreen?: boolean\n}\n\nexport function groupMessages({ ms, inReplyScreen }: GroupMessagesProps): EnrichedMessage[] {\n const items: EnrichedMessage[] = []\n let myLatestSeen = false\n let nextNeighborEnriched: MessageResource | undefined\n\n ms.forEach((message, i) => {\n const { prev } = neighborsOf(ms, i)\n const next = nextNeighborEnriched\n\n if (isSystemMessage(message)) {\n const enriched = enrichSystemMessage(message, next)\n items.push(enriched)\n if (datesDifferBetween(message, prev)) items.push(dateSeparator(message))\n nextNeighborEnriched = enriched\n return\n }\n\n const isMyLatest = !myLatestSeen && message.mine\n if (isMyLatest) myLatestSeen = true\n\n const enriched = enrichRegularMessage(message, prev, next, isMyLatest, !!inReplyScreen)\n items.push(enriched)\n\n const shadow = replyShadowFor(enriched, prev)\n if (shadow) items.push(shadow)\n\n if (!prev || datesDifferBetween(message, prev)) {\n items.push(dateSeparator(message))\n }\n\n nextNeighborEnriched = enriched\n })\n\n return items\n}\n\nfunction neighborsOf<T>(arr: T[], i: number): { prev: T | undefined; next: T | undefined } {\n return { prev: arr[i + 1], next: arr[i - 1] }\n}\n\nfunction enrichSystemMessage(\n message: MessageResource,\n next: MessageResource | undefined\n): MessageResource {\n return {\n ...message,\n myLatestInConversation: false,\n lastInGroup: true,\n renderAuthor: false,\n nextRendersAuthor: next?.renderAuthor,\n isReplyShadowMessage: false,\n nextIsReplyShadowMessage: false,\n threadPosition: null,\n }\n}\n\nfunction enrichRegularMessage(\n message: MessageResource,\n prev: MessageResource | undefined,\n next: MessageResource | undefined,\n isMyLatest: boolean,\n inReplyScreen: boolean\n): MessageResource {\n const inThread = message.replyRootId !== null\n const showThreadDetails = !inReplyScreen && inThread\n\n return {\n ...message,\n myLatestInConversation: isMyLatest,\n lastInGroup: !next || startsNewGroup(next, message),\n renderAuthor: !message.mine && (!prev || startsNewGroup(message, prev)),\n nextRendersAuthor: next?.renderAuthor,\n isReplyShadowMessage: false,\n nextIsReplyShadowMessage: nextIntroducesReplyShadow(next, message),\n threadPosition: showThreadDetails ? threadPositionFor(message, next) : null,\n prevIsMyReply: showThreadDetails ? prev?.mine : undefined,\n nextIsMyReply: showThreadDetails ? next?.mine : undefined,\n }\n}\n\nfunction startsNewGroup(a: MessageResource, b: MessageResource): boolean {\n return (\n a.author?.id !== b.author?.id ||\n differsByMoreThan5Min(a, b) ||\n a.replyRootId !== b.replyRootId ||\n datesDifferBetween(a, b)\n )\n}\n\nfunction differsByMoreThan5Min(a: MessageResource, b: MessageResource): boolean {\n return Math.abs(toMillis(a.createdAt) - toMillis(b.createdAt)) > FIVE_MINUTES_MS\n}\n\nfunction toMillis(iso: string): number {\n return new Date(iso).getTime()\n}\n\nfunction datesDifferBetween(a: MessageResource, b: MessageResource | undefined): boolean {\n if (!b) return false\n return dateKey(a) !== dateKey(b)\n}\n\nfunction dateKey(message: MessageResource): string {\n return dayjs(message.createdAt).format('YYYY-MM-DD')\n}\n\nfunction dateSeparator(message: MessageResource): DateSeparator {\n return { type: 'DateSeparator', id: `day-divider-${message.id}`, date: dateKey(message) }\n}\n\nfunction threadPositionFor(\n message: MessageResource,\n next: MessageResource | undefined\n): 'first' | 'center' | 'last' | null {\n const isThreadRoot = message.replyRootId === message.id\n const isLast =\n !next || next.replyRootId !== message.replyRootId || datesDifferBetween(next, message)\n\n if (isThreadRoot && isLast) return null\n if (isThreadRoot) return 'first'\n if (isLast) return 'last'\n return 'center'\n}\n\nfunction nextIntroducesReplyShadow(\n next: MessageResource | undefined,\n current: MessageResource\n): boolean {\n if (!next) return false\n const nextInThread = next.replyRootId !== null\n const nextIsThreadRoot = next.replyRootId === next.id\n const differentThread = next.replyRootId !== current.replyRootId\n return nextInThread && !nextIsThreadRoot && (differentThread || datesDifferBetween(next, current))\n}\n\nfunction replyShadowFor(\n message: MessageResource,\n prev: MessageResource | undefined\n): ReplyShadowMessage | undefined {\n if (!message.replyRootId) return undefined\n if (message.replyRootId === message.id) return undefined\n\n const enteringNewThread =\n !prev || prev.replyRootId !== message.replyRootId || datesDifferBetween(prev, message)\n if (!enteringNewThread) return undefined\n\n return {\n type: 'ReplyShadowMessage',\n id: `${message.id}-${message.replyRootId}`,\n messageId: message.replyRootId,\n isReplyShadowMessage: true,\n nextRendersAuthor: message.renderAuthor ?? false,\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform_message_event_data_to_message_resource.d.ts","sourceRoot":"","sources":["../../../src/utils/jolt/transform_message_event_data_to_message_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAA;AAI5E,wBAAgB,0CAA0C,CAAC,EACzD,IAAI,EACJ,eAAe,GAChB,EAAE;IACD,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;IACzC,eAAe,EAAE,MAAM,CAAA;CACxB,GAAG,eAAe,
|
|
1
|
+
{"version":3,"file":"transform_message_event_data_to_message_resource.d.ts","sourceRoot":"","sources":["../../../src/utils/jolt/transform_message_event_data_to_message_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAA;AAI5E,wBAAgB,0CAA0C,CAAC,EACzD,IAAI,EACJ,eAAe,GAChB,EAAE;IACD,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;IACzC,eAAe,EAAE,MAAM,CAAA;CACxB,GAAG,eAAe,CA8BlB"}
|
|
@@ -22,7 +22,6 @@ export function transformMessageEventDataToMessageResource({
|
|
|
22
22
|
reactionCounts: [],
|
|
23
23
|
replyCount: data.reply_count || 0,
|
|
24
24
|
replyRootId: data.reply_root_id || null,
|
|
25
|
-
idempotentKey: data.idempotent_key ?? null,
|
|
26
25
|
messageType: data.message_type,
|
|
27
26
|
personIdsForSystemEvent: data.system_event_person_ids,
|
|
28
27
|
systemTextParts: data.system_text_parts ? {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform_message_event_data_to_message_resource.js","names":["deepCamelCaseKeys","transformMessageEventDataToMessageResource","data","currentPersonId","type","id","sort_key","text","html","createdAt","created_at","deletedAt","deleted_at","textEditedAt","text_edited_at","mine","author_id","attachments","author","name","author_name","avatar","author_avatar","reactionCounts","replyCount","reply_count","replyRootId","reply_root_id","
|
|
1
|
+
{"version":3,"file":"transform_message_event_data_to_message_resource.js","names":["deepCamelCaseKeys","transformMessageEventDataToMessageResource","data","currentPersonId","type","id","sort_key","text","html","createdAt","created_at","deletedAt","deleted_at","textEditedAt","text_edited_at","mine","author_id","attachments","author","name","author_name","avatar","author_avatar","reactionCounts","replyCount","reply_count","replyRootId","reply_root_id","messageType","message_type","personIdsForSystemEvent","system_event_person_ids","systemTextParts","system_text_parts","names","overflowCount","overflow_count","action"],"sources":["../../../src/utils/jolt/transform_message_event_data_to_message_resource.ts"],"sourcesContent":["import { MessageResource } from '../../types'\nimport { MessageCreatedEvent } from '../../types/jolt_events/message_events'\nimport { DenormalizedAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport { deepCamelCaseKeys } from '../deepCamelCaseKeys'\n\nexport function transformMessageEventDataToMessageResource({\n data,\n currentPersonId,\n}: {\n data: MessageCreatedEvent['data']['data']\n currentPersonId: number\n}): MessageResource {\n return {\n type: 'Message',\n id: data.sort_key,\n text: data.text,\n html: data.html,\n createdAt: data.created_at,\n deletedAt: data.deleted_at,\n textEditedAt: data.text_edited_at,\n mine: data.author_id === currentPersonId,\n attachments: deepCamelCaseKeys<DenormalizedAttachmentResource[]>(data.attachments) || [],\n author: {\n type: 'Person',\n id: data.author_id,\n name: data.author_name,\n avatar: data.author_avatar,\n },\n reactionCounts: [],\n replyCount: data.reply_count || 0,\n replyRootId: data.reply_root_id || null,\n messageType: data.message_type,\n personIdsForSystemEvent: data.system_event_person_ids,\n systemTextParts: data.system_text_parts\n ? {\n names: data.system_text_parts.names,\n overflowCount: data.system_text_parts.overflow_count,\n action: data.system_text_parts.action,\n }\n : null,\n }\n}\n"],"mappings":"AAGA,SAASA,iBAAiB,QAAQ,sBAAsB;AAExD,OAAO,SAASC,0CAA0CA,CAAC;EACzDC,IAAI;EACJC;AAIF,CAAC,EAAmB;EAClB,OAAO;IACLC,IAAI,EAAE,SAAS;IACfC,EAAE,EAAEH,IAAI,CAACI,QAAQ;IACjBC,IAAI,EAAEL,IAAI,CAACK,IAAI;IACfC,IAAI,EAAEN,IAAI,CAACM,IAAI;IACfC,SAAS,EAAEP,IAAI,CAACQ,UAAU;IAC1BC,SAAS,EAAET,IAAI,CAACU,UAAU;IAC1BC,YAAY,EAAEX,IAAI,CAACY,cAAc;IACjCC,IAAI,EAAEb,IAAI,CAACc,SAAS,KAAKb,eAAe;IACxCc,WAAW,EAAEjB,iBAAiB,CAAmCE,IAAI,CAACe,WAAW,CAAC,IAAI,EAAE;IACxFC,MAAM,EAAE;MACNd,IAAI,EAAE,QAAQ;MACdC,EAAE,EAAEH,IAAI,CAACc,SAAS;MAClBG,IAAI,EAAEjB,IAAI,CAACkB,WAAW;MACtBC,MAAM,EAAEnB,IAAI,CAACoB;IACf,CAAC;IACDC,cAAc,EAAE,EAAE;IAClBC,UAAU,EAAEtB,IAAI,CAACuB,WAAW,IAAI,CAAC;IACjCC,WAAW,EAAExB,IAAI,CAACyB,aAAa,IAAI,IAAI;IACvCC,WAAW,EAAE1B,IAAI,CAAC2B,YAAY;IAC9BC,uBAAuB,EAAE5B,IAAI,CAAC6B,uBAAuB;IACrDC,eAAe,EAAE9B,IAAI,CAAC+B,iBAAiB,GACnC;MACEC,KAAK,EAAEhC,IAAI,CAAC+B,iBAAiB,CAACC,KAAK;MACnCC,aAAa,EAAEjC,IAAI,CAAC+B,iBAAiB,CAACG,cAAc;MACpDC,MAAM,EAAEnC,IAAI,CAAC+B,iBAAiB,CAACI;IACjC,CAAC,GACD;EACN,CAAC;AACH","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages_data_options.d.ts","sourceRoot":"","sources":["../../../src/utils/request/messages_data_options.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB;;;;
|
|
1
|
+
{"version":3,"file":"messages_data_options.d.ts","sourceRoot":"","sources":["../../../src/utils/request/messages_data_options.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB;;;;CAkB5B,CAAA;AAED,eAAO,MAAM,kBAAkB,UAAgC,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const getMessageFields = {
|
|
2
|
-
Message: ['text', 'text_edited_at', 'mine', 'attachments', 'created_at', 'deleted_at', 'author', 'reaction_counts', 'reply_count', 'reply_root', '
|
|
2
|
+
Message: ['text', 'text_edited_at', 'mine', 'attachments', 'created_at', 'deleted_at', 'author', 'reaction_counts', 'reply_count', 'reply_root', 'message_type', 'person_ids_for_system_event', 'system_text_parts'],
|
|
3
3
|
Person: ['name', 'avatar'],
|
|
4
4
|
ReactionCount: ['value', 'count', 'mine', 'message_id', 'author_ids']
|
|
5
5
|
};
|
|
6
|
-
export const getMessagesInclude = ['author', 'reaction_counts'
|
|
6
|
+
export const getMessagesInclude = ['author', 'reaction_counts'];
|
|
7
7
|
//# sourceMappingURL=messages_data_options.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages_data_options.js","names":["getMessageFields","Message","Person","ReactionCount","getMessagesInclude"],"sources":["../../../src/utils/request/messages_data_options.ts"],"sourcesContent":["export const getMessageFields = {\n Message: [\n 'text',\n 'text_edited_at',\n 'mine',\n 'attachments',\n 'created_at',\n 'deleted_at',\n 'author',\n 'reaction_counts',\n 'reply_count',\n 'reply_root',\n '
|
|
1
|
+
{"version":3,"file":"messages_data_options.js","names":["getMessageFields","Message","Person","ReactionCount","getMessagesInclude"],"sources":["../../../src/utils/request/messages_data_options.ts"],"sourcesContent":["export const getMessageFields = {\n Message: [\n 'text',\n 'text_edited_at',\n 'mine',\n 'attachments',\n 'created_at',\n 'deleted_at',\n 'author',\n 'reaction_counts',\n 'reply_count',\n 'reply_root',\n 'message_type',\n 'person_ids_for_system_event',\n 'system_text_parts',\n ],\n Person: ['name', 'avatar'],\n ReactionCount: ['value', 'count', 'mine', 'message_id', 'author_ids'],\n}\n\nexport const getMessagesInclude = ['author', 'reaction_counts']\n"],"mappings":"AAAA,OAAO,MAAMA,gBAAgB,GAAG;EAC9BC,OAAO,EAAE,CACP,MAAM,EACN,gBAAgB,EAChB,MAAM,EACN,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,cAAc,EACd,6BAA6B,EAC7B,mBAAmB,CACpB;EACDC,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;EAC1BC,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY;AACtE,CAAC;AAED,OAAO,MAAMC,kBAAkB,GAAG,CAAC,QAAQ,EAAE,iBAAiB,CAAC","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "4.0.1-
|
|
3
|
+
"version": "4.0.1-rc.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@fortawesome/fontawesome-svg-core": "^7.2.0",
|
|
35
35
|
"@fortawesome/react-native-fontawesome": "^0.3.2",
|
|
36
|
-
"@planningcenter/emoji-keyboard": "4.0.
|
|
36
|
+
"@planningcenter/emoji-keyboard": "4.0.0",
|
|
37
37
|
"lodash-inflection": "^1.5.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"sf-symbols-typescript": "^2.2.0",
|
|
85
85
|
"typescript": "~6.0.3"
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "fa30b4ca64df403ad4e1f307404547528b3b8014"
|
|
88
88
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useNavigation } from '@react-navigation/native'
|
|
2
2
|
import { some } from 'lodash'
|
|
3
|
-
import React, {
|
|
3
|
+
import React, { useEffect } from 'react'
|
|
4
4
|
import {
|
|
5
5
|
AccessibilityActionEvent,
|
|
6
6
|
Pressable,
|
|
@@ -44,14 +44,14 @@ import { TheirReplyConnector, MyReplyConnector, AVATAR_CONNECTOR_SPACING } from
|
|
|
44
44
|
interface MessageProps extends MessageResource {
|
|
45
45
|
canDeleteNonAuthoredMessages: boolean
|
|
46
46
|
conversation_id: number
|
|
47
|
-
|
|
47
|
+
latestReadMessageSortKey?: string
|
|
48
48
|
inReplyScreen?: boolean
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
export
|
|
51
|
+
export function Message({
|
|
52
52
|
canDeleteNonAuthoredMessages,
|
|
53
53
|
conversation_id,
|
|
54
|
-
|
|
54
|
+
latestReadMessageSortKey,
|
|
55
55
|
inReplyScreen,
|
|
56
56
|
...message
|
|
57
57
|
}: MessageProps) {
|
|
@@ -73,16 +73,11 @@ export const Message = memo(function MessageRow({
|
|
|
73
73
|
const [messageBubbleHeight, setMessageBubbleHeight] = React.useState(0)
|
|
74
74
|
const { animatedBackgroundColor, handleMessagePressIn, handleMessagePressOut } =
|
|
75
75
|
useAnimatedMessageBackgroundColor()
|
|
76
|
-
const
|
|
77
|
-
const isDeletedReplyRootMessage = isReplyRootMessage && !!message.deletedAt
|
|
78
|
-
const showReadReceipts = message.mine && !pending && !error
|
|
79
|
-
const replyToReplyRootMessage = !isReplyRootMessage && !!message.replyRootId
|
|
80
|
-
const { message: fetchedReplyRoot } = useConversationMessage({
|
|
76
|
+
const { message: replyRootMessage } = useConversationMessage({
|
|
81
77
|
conversation_id,
|
|
82
78
|
messageId: message.replyRootId || '',
|
|
83
|
-
enabled:
|
|
79
|
+
enabled: !!message.replyRootId,
|
|
84
80
|
})
|
|
85
|
-
const replyRoot = message.replyRoot ?? fetchedReplyRoot
|
|
86
81
|
|
|
87
82
|
const metaProps = {
|
|
88
83
|
authorName: author.name,
|
|
@@ -90,11 +85,14 @@ export const Message = memo(function MessageRow({
|
|
|
90
85
|
}
|
|
91
86
|
|
|
92
87
|
const renderAuthor = (!message.mine && message.renderAuthor) || false
|
|
93
|
-
const showReplyCountButton = !inReplyScreen &&
|
|
88
|
+
const showReplyCountButton = !inReplyScreen && message.replyRootId === message.id
|
|
89
|
+
const isReplyRootMessage = message.replyRootId === message.id
|
|
90
|
+
const isDeletedReplyRootMessage = isReplyRootMessage && !!message.deletedAt
|
|
91
|
+
const replyToReplyRootMessage = !isReplyRootMessage && !!message.replyRootId
|
|
94
92
|
|
|
95
93
|
const replyCountText = pluralize(message.replyCount, 'reply')
|
|
96
94
|
const messagePendingLabel = isPersisted ? 'Saving' : 'Sending'
|
|
97
|
-
const replyRootAuthorName =
|
|
95
|
+
const replyRootAuthorName = message.replyRootId ? replyRootMessage?.author.name : author.name
|
|
98
96
|
const messageText = isDeletedReplyRootMessage ? 'Message deleted' : text
|
|
99
97
|
|
|
100
98
|
const messageBottomMargin =
|
|
@@ -286,7 +284,12 @@ export const Message = memo(function MessageRow({
|
|
|
286
284
|
)}
|
|
287
285
|
{showMessageMeta && !isDeletedReplyRootMessage && (
|
|
288
286
|
<View style={styles.messageMeta}>
|
|
289
|
-
{
|
|
287
|
+
{message.mine && !pending && !error && (
|
|
288
|
+
<MessageReadReceipts
|
|
289
|
+
message={message}
|
|
290
|
+
latestReadMessageSortKey={latestReadMessageSortKey}
|
|
291
|
+
/>
|
|
292
|
+
)}
|
|
290
293
|
{error ? (
|
|
291
294
|
<View style={styles.errorContainer}>
|
|
292
295
|
{retryFailedSaveMutation.isPending ? (
|
|
@@ -335,7 +338,7 @@ export const Message = memo(function MessageRow({
|
|
|
335
338
|
</Animated.View>
|
|
336
339
|
</Pressable>
|
|
337
340
|
)
|
|
338
|
-
}
|
|
341
|
+
}
|
|
339
342
|
|
|
340
343
|
const useMessageStyles = (mine: boolean, isDeleting: boolean) => {
|
|
341
344
|
const { colors } = useTheme()
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { StyleSheet, View } from 'react-native'
|
|
3
3
|
import { useTheme } from '../../hooks'
|
|
4
|
+
import { MessageResource } from '../../types'
|
|
4
5
|
import { Icon, Text } from '../display'
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
|
-
|
|
8
|
+
message: MessageResource
|
|
9
|
+
latestReadMessageSortKey?: string
|
|
8
10
|
}
|
|
9
11
|
|
|
10
|
-
export function MessageReadReceipts({
|
|
12
|
+
export function MessageReadReceipts({ message, latestReadMessageSortKey }: Props) {
|
|
11
13
|
const styles = useStyles()
|
|
12
|
-
if (!
|
|
14
|
+
if (!latestReadMessageSortKey || message.id > latestReadMessageSortKey) {
|
|
13
15
|
return (
|
|
14
16
|
<View style={styles.badgeContainer}>
|
|
15
17
|
<Icon name="general.check" style={styles.icon} />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useNavigation } from '@react-navigation/native'
|
|
2
2
|
import { some } from 'lodash'
|
|
3
|
-
import React
|
|
3
|
+
import React from 'react'
|
|
4
4
|
import { Pressable, StyleSheet, useWindowDimensions, View } from 'react-native'
|
|
5
5
|
import Animated from 'react-native-reanimated'
|
|
6
6
|
import {
|
|
@@ -37,20 +37,18 @@ interface ReplyShadowMessageProps extends MessageResource {
|
|
|
37
37
|
nextRendersAuthor: boolean
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
export
|
|
40
|
+
export function ReplyShadowMessage({
|
|
41
41
|
conversation_id,
|
|
42
42
|
inReplyScreen,
|
|
43
43
|
messageId,
|
|
44
|
-
replyRoot,
|
|
45
44
|
isReplyShadowMessage,
|
|
46
45
|
nextRendersAuthor,
|
|
47
46
|
}: ReplyShadowMessageProps) {
|
|
48
|
-
const
|
|
49
|
-
const message = replyRoot ?? fetched.message
|
|
47
|
+
const { message, isError, isLoading } = useConversationMessage({ conversation_id, messageId })
|
|
50
48
|
|
|
51
49
|
if (inReplyScreen) return null
|
|
52
|
-
if (
|
|
53
|
-
if (!message) return <ShadowMessageFallback text="Message deleted" />
|
|
50
|
+
if (isLoading) return <ShadowMessageFallback text="Loading..." />
|
|
51
|
+
if (isError || !message) return <ShadowMessageFallback text="Message deleted" />
|
|
54
52
|
|
|
55
53
|
const enrichedMessage = {
|
|
56
54
|
...message,
|
|
@@ -59,7 +57,7 @@ export const ReplyShadowMessage = memo(function ReplyShadowMessageRow({
|
|
|
59
57
|
}
|
|
60
58
|
|
|
61
59
|
return <ShadowMessageContent conversation_id={conversation_id} {...enrichedMessage} />
|
|
62
|
-
}
|
|
60
|
+
}
|
|
63
61
|
|
|
64
62
|
interface ShadowMessageContentProps extends MessageResource {
|
|
65
63
|
conversation_id: number
|
|
@@ -84,7 +82,7 @@ function ShadowMessageContent({ conversation_id, ...message }: ShadowMessageCont
|
|
|
84
82
|
const handleNavigateToReplies = () => {
|
|
85
83
|
navigation.navigate('ConversationReply', {
|
|
86
84
|
conversation_id,
|
|
87
|
-
reply_root_id: message.replyRootId
|
|
85
|
+
reply_root_id: message.replyRootId,
|
|
88
86
|
reply_root_author_name: message.author.name,
|
|
89
87
|
})
|
|
90
88
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useMemo } from 'react'
|
|
2
2
|
import { MessageResource } from '../types'
|
|
3
|
-
import { replaceEqualById } from '../utils/replace_equal_by_id'
|
|
4
3
|
import { getMessagesQueryKey, getMessagesRequestArgs } from '../utils/request/get_messages'
|
|
5
4
|
import { SuspensePaginatorOptions, useSuspensePaginator } from './use_suspense_api'
|
|
6
5
|
|
|
@@ -11,10 +10,7 @@ export const useConversationMessages = (
|
|
|
11
10
|
const { data, refetch, isRefetching, fetchNextPage, hasNextPage } =
|
|
12
11
|
useSuspensePaginator<MessageResource>(
|
|
13
12
|
getMessagesRequestArgs({ conversation_id, reply_root_id }),
|
|
14
|
-
|
|
15
|
-
structuralSharing: replaceEqualById,
|
|
16
|
-
...opts,
|
|
17
|
-
}
|
|
13
|
+
opts
|
|
18
14
|
)
|
|
19
15
|
const queryKey = getMessagesQueryKey({ conversation_id, reply_root_id })
|
|
20
16
|
const messages = useMemo(
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
updateCacheWithMessage,
|
|
12
12
|
updateCacheWithIndividualMessage,
|
|
13
13
|
updateCacheWithReaction,
|
|
14
|
-
updateCacheReplyRoots,
|
|
15
14
|
getThreadedMessagesQueryKey,
|
|
16
15
|
} from '../utils/cache/messages_cache'
|
|
17
16
|
import { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'
|
|
@@ -45,7 +44,6 @@ export function useConversationMessagesJoltEvents({ conversationId }: Props) {
|
|
|
45
44
|
data,
|
|
46
45
|
currentPersonId: currentPerson.id,
|
|
47
46
|
})
|
|
48
|
-
const isReplyRootUpdate = e.event === 'message.updated' && data.reply_root_id === data.sort_key
|
|
49
47
|
|
|
50
48
|
if (e.event === 'message.created' && data.author_id) {
|
|
51
49
|
removeAllTypingEventsByAuthorId(data.author_id)
|
|
@@ -64,11 +62,6 @@ export function useConversationMessagesJoltEvents({ conversationId }: Props) {
|
|
|
64
62
|
data.reply_root_id
|
|
65
63
|
)
|
|
66
64
|
updateCacheWithMessage(queryClient, threadedMessagesQueryKey, message, e.event)
|
|
67
|
-
|
|
68
|
-
if (isReplyRootUpdate) {
|
|
69
|
-
updateCacheReplyRoots(queryClient, messagesQueryKey, message)
|
|
70
|
-
updateCacheReplyRoots(queryClient, threadedMessagesQueryKey, message)
|
|
71
|
-
}
|
|
72
65
|
}
|
|
73
66
|
|
|
74
67
|
// Update individual message query cache so reply shadow messages update immediately
|
|
@@ -22,14 +22,6 @@ interface Props {
|
|
|
22
22
|
replyRootId?: string | null
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
interface MessageMutationVariables {
|
|
26
|
-
text: string
|
|
27
|
-
attachments?: DenormalizedAttachmentResourceForCreate[]
|
|
28
|
-
idempotentKey?: string
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
type ResolvedMessageMutationVariables = MessageMutationVariables & { idempotentKey: string }
|
|
32
|
-
|
|
33
25
|
export function useMessageCreateOrUpdate({ conversationId, message, replyRootId }: Props) {
|
|
34
26
|
const messageId = message?.id || null
|
|
35
27
|
const isEditing = !isNewMessage(message)
|
|
@@ -37,7 +29,13 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
|
|
|
37
29
|
const currentPerson = useCurrentPerson()
|
|
38
30
|
|
|
39
31
|
const mutation = useMutation({
|
|
40
|
-
mutationFn: ({
|
|
32
|
+
mutationFn: ({
|
|
33
|
+
text,
|
|
34
|
+
attachments,
|
|
35
|
+
}: {
|
|
36
|
+
text: string
|
|
37
|
+
attachments?: DenormalizedAttachmentResourceForCreate[]
|
|
38
|
+
}) => {
|
|
41
39
|
const requestParams = getMessagesRequestArgs({ conversation_id: conversationId })
|
|
42
40
|
const fieldsWithValueJoined = Object.fromEntries(
|
|
43
41
|
Object.entries(requestParams.data.fields).map(([k, v]) => [k, v.join(',')])
|
|
@@ -48,6 +46,7 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
|
|
|
48
46
|
...(!isEditing && replyRootId ? { reply_root: { id: replyRootId } } : {}),
|
|
49
47
|
}
|
|
50
48
|
if (!isEditing) {
|
|
49
|
+
const idempotentKey = insecureUUID()
|
|
51
50
|
attributes.idempotent_key = idempotentKey
|
|
52
51
|
startMessageCreationTracking(idempotentKey)
|
|
53
52
|
}
|
|
@@ -72,7 +71,13 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
|
|
|
72
71
|
})
|
|
73
72
|
}
|
|
74
73
|
},
|
|
75
|
-
onMutate: async ({
|
|
74
|
+
onMutate: async ({
|
|
75
|
+
text,
|
|
76
|
+
attachments,
|
|
77
|
+
}: {
|
|
78
|
+
text: string
|
|
79
|
+
attachments?: DenormalizedAttachmentResourceForCreate[]
|
|
80
|
+
}) => {
|
|
76
81
|
if (message && isEditing) {
|
|
77
82
|
const optimisticMessage = optimisticallyUpdateMessage({
|
|
78
83
|
conversationId,
|
|
@@ -91,7 +96,6 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
|
|
|
91
96
|
attachments,
|
|
92
97
|
currentPerson,
|
|
93
98
|
replyRootId,
|
|
94
|
-
idempotentKey,
|
|
95
99
|
})
|
|
96
100
|
|
|
97
101
|
return { message: optimisticMessage }
|
|
@@ -151,24 +155,7 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
|
|
|
151
155
|
},
|
|
152
156
|
})
|
|
153
157
|
|
|
154
|
-
|
|
155
|
-
variables: MessageMutationVariables
|
|
156
|
-
): ResolvedMessageMutationVariables => ({
|
|
157
|
-
...variables,
|
|
158
|
-
idempotentKey: variables.idempotentKey ?? message?.idempotentKey ?? insecureUUID(),
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
const mutate = (
|
|
162
|
-
variables: MessageMutationVariables,
|
|
163
|
-
options?: Parameters<typeof mutation.mutate>[1]
|
|
164
|
-
) => mutation.mutate(resolveVariables(variables), options)
|
|
165
|
-
|
|
166
|
-
const mutateAsync = (
|
|
167
|
-
variables: MessageMutationVariables,
|
|
168
|
-
options?: Parameters<typeof mutation.mutateAsync>[1]
|
|
169
|
-
) => mutation.mutateAsync(resolveVariables(variables), options)
|
|
170
|
-
|
|
171
|
-
return { ...mutation, mutate, mutateAsync }
|
|
158
|
+
return mutation
|
|
172
159
|
}
|
|
173
160
|
|
|
174
161
|
/**
|
|
@@ -212,9 +212,11 @@ function FormContent({
|
|
|
212
212
|
</View>
|
|
213
213
|
<Divider />
|
|
214
214
|
<Pressable style={styles.titleSection} onPress={handleTitleSectionPress}>
|
|
215
|
-
<Heading variant="h3">
|
|
215
|
+
<Heading variant="h3">
|
|
216
|
+
Title <Text style={styles.required}>*</Text>
|
|
217
|
+
</Heading>
|
|
216
218
|
<AutoFocusAwareTextInput
|
|
217
|
-
placeholder="Topic of conversation
|
|
219
|
+
placeholder="Topic of conversation"
|
|
218
220
|
value={title}
|
|
219
221
|
onChangeText={setTitle}
|
|
220
222
|
style={styles.titleInput}
|
|
@@ -291,6 +293,9 @@ const useStyles = () => {
|
|
|
291
293
|
fontSize: 18,
|
|
292
294
|
color: colors.textColorDefaultPrimary,
|
|
293
295
|
},
|
|
296
|
+
required: {
|
|
297
|
+
color: colors.statusErrorText,
|
|
298
|
+
},
|
|
294
299
|
memberSection: {
|
|
295
300
|
padding: sectionPadding,
|
|
296
301
|
paddingBottom: 0,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { date as formatDate } from '@planningcenter/datetime-fmt'
|
|
1
2
|
import { HeaderTitle, HeaderTitleProps, PlatformPressable } from '@react-navigation/elements'
|
|
2
3
|
import {
|
|
3
4
|
CommonActions,
|
|
@@ -10,21 +11,24 @@ import {
|
|
|
10
11
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
11
12
|
import { FlatList, Platform, StyleSheet, useWindowDimensions, View } from 'react-native'
|
|
12
13
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
13
|
-
import { Badge, Icon } from '../components'
|
|
14
|
+
import { Badge, Icon, Text } from '../components'
|
|
14
15
|
import { ConversationStartBanner } from '../components/conversation/conversation_start_banner'
|
|
15
16
|
import { JumpToBottomButton } from '../components/conversation/jump_to_bottom_button'
|
|
17
|
+
import { Message } from '../components/conversation/message'
|
|
16
18
|
import { MessageForm } from '../components/conversation/message_form'
|
|
17
|
-
import { MessageList } from '../components/conversation/message_list'
|
|
18
19
|
import {
|
|
19
20
|
ConversationDisabledBanner,
|
|
20
21
|
LeaderMessagesDisabledBanner,
|
|
21
22
|
MemberMessagesDisabledBanner,
|
|
22
23
|
} from '../components/conversation/messages_disabled_banners'
|
|
24
|
+
import { ReplyShadowMessage } from '../components/conversation/reply_shadow_message'
|
|
25
|
+
import { SystemMessage } from '../components/conversation/system_message'
|
|
23
26
|
import { TypingIndicator } from '../components/conversation/typing_indicator'
|
|
24
27
|
import { KeyboardView } from '../components/display/keyboard_view'
|
|
25
28
|
import { useHeaderSlotReserve } from '../components/display/platform_modal_header_buttons'
|
|
26
29
|
import BlankState from '../components/primitive/blank_state_primitive'
|
|
27
30
|
import { ConversationContextProvider } from '../contexts/conversation_context'
|
|
31
|
+
import { useTheme } from '../hooks'
|
|
28
32
|
import { useMessageAvailableMembersAction } from '../hooks/direct_messages/use_message_available_members_action'
|
|
29
33
|
import { useConversation } from '../hooks/use_conversation'
|
|
30
34
|
import { useConversationJoltEvents } from '../hooks/use_conversation_jolt_events'
|
|
@@ -41,6 +45,10 @@ import { useVideoModerationJoltEvents } from '../hooks/use_video_moderation_jolt
|
|
|
41
45
|
import { ConversationResource } from '../types/resources/conversation'
|
|
42
46
|
import { ConversationBadgeResource } from '../types/resources/conversation_badge'
|
|
43
47
|
import { MessageResource } from '../types/resources/message'
|
|
48
|
+
import { getRelativeDateStatus } from '../utils/date'
|
|
49
|
+
import { groupMessages, type DateSeparator } from '../utils/group_messages'
|
|
50
|
+
import { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL } from '../utils/styles'
|
|
51
|
+
import { isSystemMessage } from '../utils/system_messages'
|
|
44
52
|
|
|
45
53
|
export type ConversationRouteProps = {
|
|
46
54
|
conversation_id: number
|
|
@@ -93,11 +101,16 @@ function ConversationScreenContent({ route }: ConversationScreenProps) {
|
|
|
93
101
|
const { markHandledByMessageForm } = useVideoModerationJoltEvents()
|
|
94
102
|
useEnsureConversationsRouteExists()
|
|
95
103
|
useMarkLatestMessageRead({ conversation, messages })
|
|
96
|
-
const
|
|
104
|
+
const messagesWithSeparators = groupMessages({
|
|
105
|
+
ms: messages,
|
|
106
|
+
inReplyScreen: !!reply_root_id,
|
|
107
|
+
})
|
|
108
|
+
const noMessages = messagesWithSeparators.length === 0
|
|
97
109
|
|
|
98
110
|
const { repliesDisabled, memberAbility, badges, title } = conversation
|
|
99
111
|
const canReply = memberAbility?.canReply
|
|
100
112
|
const showLeaderDisabledReplyBanner = canReply && repliesDisabled
|
|
113
|
+
const canDeleteNonAuthoredMessages = memberAbility?.canDeleteNonAuthoredMessages ?? false
|
|
101
114
|
const currentlyEditingMessage = messages.find(m => String(m.id) === String(editing_message_id))
|
|
102
115
|
const replyRootAuthorFirstName = reply_root_author_name?.split(' ')[0]
|
|
103
116
|
const replyHeaderTitle = replyRootAuthorFirstName
|
|
@@ -168,19 +181,54 @@ function ConversationScreenContent({ route }: ConversationScreenProps) {
|
|
|
168
181
|
<ConversationStartBanner conversation={conversation} hasMessages={false} />
|
|
169
182
|
</View>
|
|
170
183
|
) : (
|
|
171
|
-
<
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
hasNextPage={hasNextPage}
|
|
178
|
-
onEndReached={() => fetchNextPage()}
|
|
184
|
+
<FlatList
|
|
185
|
+
inverted
|
|
186
|
+
ref={listRef}
|
|
187
|
+
contentContainerStyle={styles.listContainer}
|
|
188
|
+
data={messagesWithSeparators}
|
|
189
|
+
keyExtractor={item => item.id}
|
|
179
190
|
onScroll={trackScroll}
|
|
180
191
|
onLayout={onLayout}
|
|
181
192
|
onContentSizeChange={onContentSizeChange}
|
|
182
193
|
onScrollEndDrag={onScrollEndDrag}
|
|
183
194
|
onMomentumScrollEnd={onMomentumScrollEnd}
|
|
195
|
+
scrollEventThrottle={10}
|
|
196
|
+
ListFooterComponent={
|
|
197
|
+
hasNextPage ? null : (
|
|
198
|
+
<ConversationStartBanner conversation={conversation} hasMessages={true} />
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
renderItem={({ item }) => {
|
|
202
|
+
if (item.type === 'DateSeparator') {
|
|
203
|
+
return <InlineDateSeparator {...item} />
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (item.type === 'ReplyShadowMessage') {
|
|
207
|
+
return (
|
|
208
|
+
<ReplyShadowMessage
|
|
209
|
+
{...(item as any)}
|
|
210
|
+
conversation_id={conversation_id}
|
|
211
|
+
inReplyScreen={!!reply_root_id}
|
|
212
|
+
/>
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (isSystemMessage(item)) {
|
|
217
|
+
return <SystemMessage message={item} conversationId={conversation_id} />
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return (
|
|
221
|
+
<Message
|
|
222
|
+
{...item}
|
|
223
|
+
canDeleteNonAuthoredMessages={canDeleteNonAuthoredMessages}
|
|
224
|
+
conversation_id={conversation_id}
|
|
225
|
+
latestReadMessageSortKey={conversation?.latestReadMessageSortKey}
|
|
226
|
+
inReplyScreen={!!reply_root_id}
|
|
227
|
+
/>
|
|
228
|
+
)
|
|
229
|
+
}}
|
|
230
|
+
onEndReached={() => fetchNextPage()}
|
|
231
|
+
ListHeaderComponent={<View style={styles.listHeader} />}
|
|
184
232
|
/>
|
|
185
233
|
)}
|
|
186
234
|
<JumpToBottomButton onPress={handleReturnToBottom} visible={showJumpToBottomButton} />
|
|
@@ -247,6 +295,44 @@ function ConversationBottomBar({
|
|
|
247
295
|
)
|
|
248
296
|
}
|
|
249
297
|
|
|
298
|
+
function InlineDateSeparator({ date }: DateSeparator) {
|
|
299
|
+
const styles = useDateSeparatorStyles()
|
|
300
|
+
const { isThisYear } = getRelativeDateStatus(date)
|
|
301
|
+
const showYear = !isThisYear
|
|
302
|
+
const dateStamp = formatDate(date, { style: 'long', year: showYear })
|
|
303
|
+
|
|
304
|
+
return (
|
|
305
|
+
<View style={styles.container}>
|
|
306
|
+
<View style={styles.separator} />
|
|
307
|
+
<Text variant="footnote" style={styles.dateText}>
|
|
308
|
+
{dateStamp}
|
|
309
|
+
</Text>
|
|
310
|
+
<View style={styles.separator} />
|
|
311
|
+
</View>
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const useDateSeparatorStyles = () => {
|
|
316
|
+
const theme = useTheme()
|
|
317
|
+
return StyleSheet.create({
|
|
318
|
+
container: {
|
|
319
|
+
alignItems: 'center',
|
|
320
|
+
flexDirection: 'row',
|
|
321
|
+
paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,
|
|
322
|
+
paddingVertical: 16,
|
|
323
|
+
},
|
|
324
|
+
separator: {
|
|
325
|
+
flex: 1,
|
|
326
|
+
height: 1,
|
|
327
|
+
borderTopWidth: 1,
|
|
328
|
+
borderTopColor: theme.colors.borderColorDefaultBase,
|
|
329
|
+
},
|
|
330
|
+
dateText: {
|
|
331
|
+
paddingHorizontal: 8,
|
|
332
|
+
},
|
|
333
|
+
})
|
|
334
|
+
}
|
|
335
|
+
|
|
250
336
|
interface ConversationScreenTitleProps extends HeaderTitleProps {
|
|
251
337
|
conversation_id: number
|
|
252
338
|
badge?: ConversationBadgeResource
|
|
@@ -343,6 +429,13 @@ const useStyles = () => {
|
|
|
343
429
|
flex: 1,
|
|
344
430
|
justifyContent: 'center',
|
|
345
431
|
},
|
|
432
|
+
listContainer: {
|
|
433
|
+
paddingVertical: 12,
|
|
434
|
+
},
|
|
435
|
+
listHeader: {
|
|
436
|
+
// Just whitespace to provide space where the typing indicator can be
|
|
437
|
+
height: 16,
|
|
438
|
+
},
|
|
346
439
|
})
|
|
347
440
|
}
|
|
348
441
|
|