@planningcenter/chat-react-native 3.38.0-rc.9 → 3.38.1-rc.0
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/jump_to_bottom_button.d.ts +1 -2
- package/build/components/conversation/jump_to_bottom_button.d.ts.map +1 -1
- package/build/components/conversation/jump_to_bottom_button.js +7 -39
- package/build/components/conversation/jump_to_bottom_button.js.map +1 -1
- package/build/components/conversation/reply_shadow_message.d.ts +2 -1
- package/build/components/conversation/reply_shadow_message.d.ts.map +1 -1
- package/build/components/conversation/reply_shadow_message.js.map +1 -1
- package/build/contexts/conversation_context.d.ts +1 -8
- package/build/contexts/conversation_context.d.ts.map +1 -1
- package/build/contexts/conversation_context.js +3 -21
- package/build/contexts/conversation_context.js.map +1 -1
- package/build/hooks/use_api.d.ts.map +1 -1
- package/build/hooks/use_api.js +8 -2
- package/build/hooks/use_api.js.map +1 -1
- package/build/hooks/use_conversation_messages.d.ts +6 -15
- package/build/hooks/use_conversation_messages.d.ts.map +1 -1
- package/build/hooks/use_conversation_messages.js +9 -62
- 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 +4 -4
- package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
- package/build/hooks/use_conversations_actions.d.ts +0 -5
- package/build/hooks/use_conversations_actions.d.ts.map +1 -1
- package/build/hooks/use_conversations_actions.js +0 -12
- package/build/hooks/use_conversations_actions.js.map +1 -1
- package/build/hooks/use_features.d.ts +0 -1
- package/build/hooks/use_features.d.ts.map +1 -1
- package/build/hooks/use_features.js +0 -1
- package/build/hooks/use_features.js.map +1 -1
- package/build/hooks/use_mark_latest_message_read.d.ts +1 -1
- package/build/hooks/use_mark_latest_message_read.d.ts.map +1 -1
- package/build/hooks/use_mark_latest_message_read.js +1 -17
- package/build/hooks/use_mark_latest_message_read.js.map +1 -1
- package/build/hooks/use_suspense_api.d.ts +0 -1
- package/build/hooks/use_suspense_api.d.ts.map +1 -1
- package/build/hooks/use_suspense_api.js +1 -1
- package/build/hooks/use_suspense_api.js.map +1 -1
- package/build/screens/conversation_filter_recipients/components/header_row.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/components/header_row.js +3 -2
- package/build/screens/conversation_filter_recipients/components/header_row.js.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js +47 -18
- package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts +2 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js +23 -26
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js.map +1 -1
- package/build/screens/conversation_filter_recipients/types.d.ts +1 -1
- package/build/screens/conversation_filter_recipients/types.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/types.js.map +1 -1
- package/build/screens/conversation_screen.d.ts +0 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +48 -95
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts +1 -1
- package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/components/recipient_link_row.js +3 -3
- package/build/screens/conversation_select_recipients/components/recipient_link_row.js.map +1 -1
- package/build/screens/conversation_select_recipients/components/team_recipient_row.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/components/team_recipient_row.js +1 -1
- package/build/screens/conversation_select_recipients/components/team_recipient_row.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 +0 -4
- package/build/utils/cache/messages_cache.js.map +1 -1
- package/build/utils/group_messages.d.ts +2 -9
- package/build/utils/group_messages.d.ts.map +1 -1
- package/build/utils/group_messages.js +1 -20
- package/build/utils/group_messages.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/hooks/use_api.test.tsx +53 -0
- package/src/components/conversation/jump_to_bottom_button.tsx +8 -57
- package/src/components/conversation/reply_shadow_message.tsx +1 -1
- package/src/contexts/conversation_context.tsx +2 -30
- package/src/hooks/use_api.ts +9 -2
- package/src/hooks/use_conversation_messages.ts +20 -120
- package/src/hooks/use_conversation_messages_jolt_events.ts +3 -4
- package/src/hooks/use_conversations_actions.ts +0 -15
- package/src/hooks/use_features.ts +0 -1
- package/src/hooks/use_mark_latest_message_read.ts +2 -16
- package/src/hooks/use_suspense_api.ts +1 -1
- package/src/screens/conversation_filter_recipients/components/header_row.tsx +3 -2
- package/src/screens/conversation_filter_recipients/hooks/__tests__/use_service_types_with_teams.test.ts +108 -0
- package/src/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.tsx +46 -19
- package/src/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.ts +31 -29
- package/src/screens/conversation_filter_recipients/types.tsx +1 -1
- package/src/screens/conversation_screen.tsx +76 -184
- package/src/screens/conversation_select_recipients/components/recipient_link_row.tsx +6 -4
- package/src/screens/conversation_select_recipients/components/team_recipient_row.tsx +2 -1
- package/src/utils/__tests__/group_messages.test.ts +0 -71
- package/src/utils/cache/messages_cache.ts +0 -5
- package/src/utils/group_messages.ts +2 -42
- package/build/components/conversation/unread_divider.d.ts +0 -6
- package/build/components/conversation/unread_divider.d.ts.map +0 -1
- package/build/components/conversation/unread_divider.js +0 -59
- package/build/components/conversation/unread_divider.js.map +0 -1
- package/build/hooks/use_flat_list_viewability.d.ts +0 -20
- package/build/hooks/use_flat_list_viewability.d.ts.map +0 -1
- package/build/hooks/use_flat_list_viewability.js +0 -30
- package/build/hooks/use_flat_list_viewability.js.map +0 -1
- package/build/hooks/use_jump_to_bottom_action.d.ts +0 -9
- package/build/hooks/use_jump_to_bottom_action.d.ts.map +0 -1
- package/build/hooks/use_jump_to_bottom_action.js +0 -62
- package/build/hooks/use_jump_to_bottom_action.js.map +0 -1
- package/build/hooks/use_jump_to_unread_anchor.d.ts +0 -20
- package/build/hooks/use_jump_to_unread_anchor.d.ts.map +0 -1
- package/build/hooks/use_jump_to_unread_anchor.js +0 -53
- package/build/hooks/use_jump_to_unread_anchor.js.map +0 -1
- package/build/hooks/use_jump_to_unread_gates.d.ts +0 -5
- package/build/hooks/use_jump_to_unread_gates.d.ts.map +0 -1
- package/build/hooks/use_jump_to_unread_gates.js +0 -10
- package/build/hooks/use_jump_to_unread_gates.js.map +0 -1
- package/build/hooks/use_scroll_tracking.d.ts +0 -13
- package/build/hooks/use_scroll_tracking.d.ts.map +0 -1
- package/build/hooks/use_scroll_tracking.js +0 -45
- package/build/hooks/use_scroll_tracking.js.map +0 -1
- package/build/hooks/use_track_highest_seen_message.d.ts +0 -4
- package/build/hooks/use_track_highest_seen_message.d.ts.map +0 -1
- package/build/hooks/use_track_highest_seen_message.js +0 -35
- package/build/hooks/use_track_highest_seen_message.js.map +0 -1
- package/build/utils/conversation_messages.d.ts +0 -10
- package/build/utils/conversation_messages.d.ts.map +0 -1
- package/build/utils/conversation_messages.js +0 -22
- package/build/utils/conversation_messages.js.map +0 -1
- package/build/utils/highest_seen_tracker.d.ts +0 -12
- package/build/utils/highest_seen_tracker.d.ts.map +0 -1
- package/build/utils/highest_seen_tracker.js +0 -37
- package/build/utils/highest_seen_tracker.js.map +0 -1
- package/build/utils/message_viewability.d.ts +0 -24
- package/build/utils/message_viewability.d.ts.map +0 -1
- package/build/utils/message_viewability.js +0 -29
- package/build/utils/message_viewability.js.map +0 -1
- package/build/utils/unread_divider_helpers.d.ts +0 -18
- package/build/utils/unread_divider_helpers.d.ts.map +0 -1
- package/build/utils/unread_divider_helpers.js +0 -13
- package/build/utils/unread_divider_helpers.js.map +0 -1
- package/src/__tests__/hooks/use_conversation_messages.test.tsx +0 -109
- package/src/__tests__/hooks/use_mark_latest_message_read.test.tsx +0 -154
- package/src/__tests__/utils/cache/messages_cache.test.ts +0 -54
- package/src/components/conversation/unread_divider.tsx +0 -90
- package/src/hooks/use_flat_list_viewability.ts +0 -50
- package/src/hooks/use_jump_to_bottom_action.ts +0 -75
- package/src/hooks/use_jump_to_unread_anchor.ts +0 -68
- package/src/hooks/use_jump_to_unread_gates.ts +0 -10
- package/src/hooks/use_scroll_tracking.ts +0 -64
- package/src/hooks/use_track_highest_seen_message.ts +0 -43
- package/src/utils/__tests__/conversation_messages.test.ts +0 -105
- package/src/utils/__tests__/highest_seen_tracker.test.ts +0 -82
- package/src/utils/__tests__/message_viewability.test.ts +0 -168
- package/src/utils/__tests__/unread_divider_helpers.test.ts +0 -85
- package/src/utils/conversation_messages.ts +0 -37
- package/src/utils/highest_seen_tracker.ts +0 -42
- package/src/utils/message_viewability.ts +0 -49
- package/src/utils/unread_divider_helpers.ts +0 -25
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages_cache.js","sourceRoot":"","sources":["../../../src/utils/cache/messages_cache.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"messages_cache.js","sourceRoot":"","sources":["../../../src/utils/cache/messages_cache.ts"],"names":[],"mappings":"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","sourcesContent":["import { InfiniteData, QueryClient } from '@tanstack/react-query'\nimport { getRequestQueryKey } from '../../hooks/use_suspense_api'\nimport { ApiCollection, ApiResource, MessageResource } from '../../types'\nimport { JoltReactionEvent } from '../../types/jolt_events'\nimport { transformReactionEventDataToReactionCountResource } from '../jolt/transform_reaction_event_data_to_reaction_count_resource'\nimport { getMessagesRequestArgs } from '../request/get_messages'\nimport { updateOrCreateRecordInPagesData, updateRecordInPagesData } from './page_mutations'\nimport { deleteRecordInPagesData } from './page_mutations'\n\nexport function updateCacheWithMessage(\n queryClient: QueryClient,\n queryKey: unknown[],\n message: MessageResource,\n event: 'message.created' | 'message.updated'\n) {\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev => {\n if (event === 'message.created') {\n // Before adding the new message, remove any pending temporary messages\n // with matching text to prevent duplicates from race conditions\n let dataAfterTempRemoval = prev\n if (prev && message.text && message.mine) {\n dataAfterTempRemoval = deleteRecordInPagesData({\n data: prev,\n record: message,\n matchFn: (existingMessage, _record) => {\n return (\n isTemporaryMessageId(existingMessage.id) &&\n existingMessage.text === message.text &&\n existingMessage.mine\n )\n },\n })\n }\n\n return updateOrCreateRecordInPagesData({\n data: dataAfterTempRemoval,\n record: message,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n } else {\n return updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n }\n })\n}\n\ntype IndividualMessageQueryData = ApiResource<MessageResource>\n\nexport function updateCacheWithIndividualMessage(\n queryClient: QueryClient,\n queryKey: unknown[],\n message: MessageResource\n) {\n queryClient.setQueryData<IndividualMessageQueryData>(queryKey, prev => {\n if (!prev) {\n return {\n data: message,\n links: {},\n meta: {},\n }\n }\n\n return {\n ...prev,\n data: mergeMessageUpdate(message, prev.data),\n }\n })\n}\n\nexport function updateCacheWithReaction(\n queryClient: QueryClient,\n queryKey: unknown[],\n event: JoltReactionEvent,\n currentPersonId: number\n) {\n const message = { id: event.data.data.message_sort_key } as MessageResource\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev =>\n updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, oldMessage) => {\n const reactionCounts = oldMessage.reactionCounts || []\n let foundMatch = false\n let newReactionCounts = reactionCounts.map(reactionCount => {\n if (reactionCount.value === event.data.data.value) {\n foundMatch = true\n return transformReactionEventDataToReactionCountResource({\n data: event.data.data,\n oldData: reactionCount,\n event: event.event,\n currentPersonId,\n })\n }\n return reactionCount\n })\n\n if (!foundMatch) {\n const newReactionCount = transformReactionEventDataToReactionCountResource({\n data: event.data.data,\n event: event.event,\n currentPersonId,\n })\n\n if (newReactionCount?.count) {\n newReactionCounts = [...newReactionCounts, newReactionCount]\n }\n }\n\n return { ...oldMessage, reactionCounts: newReactionCounts }\n },\n })\n )\n}\n\ntype MessagesQueryData = InfiniteData<ApiCollection<MessageResource>>\nexport function isTemporaryMessageId(messageId?: string | null): boolean {\n return !!messageId && messageId.endsWith('-temp')\n}\nexport function isNewMessage(message?: MessageResource): boolean {\n return !message?.id || isTemporaryMessageId(message.id)\n}\n\nexport function getThreadedMessagesQueryKey(conversationId: number, replyRootId: string) {\n const requestArgs = getMessagesRequestArgs({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n return getRequestQueryKey(requestArgs)\n}\n\nexport function mergeMessageUpdate(\n record: MessageResource,\n current?: MessageResource\n): MessageResource {\n if (!current) {\n return record\n }\n\n return {\n ...current,\n ...record,\n // Preserve reactions from cache - they're managed via separate reaction events\n reactionCounts: current.reactionCounts || [],\n }\n}\n"]}
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import type { MessageResource } from '../types/resources/message';
|
|
2
|
-
export declare const UNREAD_DIVIDER_KEY = "unread-divider";
|
|
3
2
|
export type DateSeparator = {
|
|
4
3
|
type: 'DateSeparator';
|
|
5
4
|
id: string;
|
|
6
5
|
date: string;
|
|
7
6
|
};
|
|
8
|
-
export type UnreadDividerItem = {
|
|
9
|
-
type: 'UnreadDivider';
|
|
10
|
-
id: typeof UNREAD_DIVIDER_KEY;
|
|
11
|
-
};
|
|
12
7
|
export type ReplyShadowMessage = {
|
|
13
8
|
type: 'ReplyShadowMessage';
|
|
14
9
|
id: string;
|
|
@@ -16,13 +11,11 @@ export type ReplyShadowMessage = {
|
|
|
16
11
|
isReplyShadowMessage: boolean;
|
|
17
12
|
nextRendersAuthor: boolean;
|
|
18
13
|
};
|
|
19
|
-
export type EnrichedMessage = MessageResource | DateSeparator |
|
|
14
|
+
export type EnrichedMessage = MessageResource | DateSeparator | ReplyShadowMessage;
|
|
20
15
|
interface GroupMessagesProps {
|
|
21
16
|
ms: MessageResource[];
|
|
22
17
|
inReplyScreen?: boolean;
|
|
23
|
-
jumpToUnreadActive?: boolean;
|
|
24
|
-
initialMessageId?: string | null;
|
|
25
18
|
}
|
|
26
|
-
export declare function groupMessages({ ms, inReplyScreen
|
|
19
|
+
export declare function groupMessages({ ms, inReplyScreen }: GroupMessagesProps): EnrichedMessage[];
|
|
27
20
|
export {};
|
|
28
21
|
//# sourceMappingURL=group_messages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group_messages.d.ts","sourceRoot":"","sources":["../../src/utils/group_messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAMjE,
|
|
1
|
+
{"version":3,"file":"group_messages.d.ts","sourceRoot":"","sources":["../../src/utils/group_messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAMjE,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,oBAAoB,CAAA;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,oBAAoB,EAAE,OAAO,CAAA;IAC7B,iBAAiB,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,aAAa,GAAG,kBAAkB,CAAA;AAElF,UAAU,kBAAkB;IAC1B,EAAE,EAAE,eAAe,EAAE,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,kBAAkB,GAAG,eAAe,EAAE,CAkC1F"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import dayjs from './dayjs';
|
|
2
2
|
import { isSystemMessage } from './system_messages';
|
|
3
3
|
const FIVE_MINUTES_MS = 5 * 60 * 1000;
|
|
4
|
-
export
|
|
5
|
-
export function groupMessages({ ms, inReplyScreen, jumpToUnreadActive, initialMessageId, }) {
|
|
4
|
+
export function groupMessages({ ms, inReplyScreen }) {
|
|
6
5
|
const items = [];
|
|
7
6
|
let myLatestSeen = false;
|
|
8
7
|
let nextNeighborEnriched;
|
|
@@ -12,9 +11,6 @@ export function groupMessages({ ms, inReplyScreen, jumpToUnreadActive, initialMe
|
|
|
12
11
|
if (isSystemMessage(message)) {
|
|
13
12
|
const enriched = enrichSystemMessage(message, next);
|
|
14
13
|
items.push(enriched);
|
|
15
|
-
if (crossesUnreadBoundary(message, prev, jumpToUnreadActive, initialMessageId)) {
|
|
16
|
-
items.push(unreadDivider());
|
|
17
|
-
}
|
|
18
14
|
if (datesDifferBetween(message, prev))
|
|
19
15
|
items.push(dateSeparator(message));
|
|
20
16
|
nextNeighborEnriched = enriched;
|
|
@@ -25,9 +21,6 @@ export function groupMessages({ ms, inReplyScreen, jumpToUnreadActive, initialMe
|
|
|
25
21
|
myLatestSeen = true;
|
|
26
22
|
const enriched = enrichRegularMessage(message, prev, next, isMyLatest, !!inReplyScreen);
|
|
27
23
|
items.push(enriched);
|
|
28
|
-
if (crossesUnreadBoundary(message, prev, jumpToUnreadActive, initialMessageId)) {
|
|
29
|
-
items.push(unreadDivider());
|
|
30
|
-
}
|
|
31
24
|
const shadow = replyShadowFor(enriched, prev);
|
|
32
25
|
if (shadow)
|
|
33
26
|
items.push(shadow);
|
|
@@ -38,18 +31,6 @@ export function groupMessages({ ms, inReplyScreen, jumpToUnreadActive, initialMe
|
|
|
38
31
|
});
|
|
39
32
|
return items;
|
|
40
33
|
}
|
|
41
|
-
function crossesUnreadBoundary(message, prev, jumpToUnreadActive, initialMessageId) {
|
|
42
|
-
if (!jumpToUnreadActive)
|
|
43
|
-
return false;
|
|
44
|
-
if (!initialMessageId)
|
|
45
|
-
return false;
|
|
46
|
-
if (!prev)
|
|
47
|
-
return false;
|
|
48
|
-
return (prev.id.localeCompare(initialMessageId) <= 0 && message.id.localeCompare(initialMessageId) > 0);
|
|
49
|
-
}
|
|
50
|
-
function unreadDivider() {
|
|
51
|
-
return { type: 'UnreadDivider', id: UNREAD_DIVIDER_KEY };
|
|
52
|
-
}
|
|
53
34
|
function neighborsOf(arr, i) {
|
|
54
35
|
return { prev: arr[i + 1], next: arr[i - 1] };
|
|
55
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group_messages.js","sourceRoot":"","sources":["../../src/utils/group_messages.ts"],"names":[],"mappings":"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","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 const UNREAD_DIVIDER_KEY = 'unread-divider'\n\nexport type DateSeparator = { type: 'DateSeparator'; id: string; date: string }\n\nexport type UnreadDividerItem = { type: 'UnreadDivider'; id: typeof UNREAD_DIVIDER_KEY }\n\nexport type ReplyShadowMessage = {\n type: 'ReplyShadowMessage'\n id: string\n messageId: string\n isReplyShadowMessage: boolean\n nextRendersAuthor: boolean\n}\n\nexport type EnrichedMessage =\n | MessageResource\n | DateSeparator\n | UnreadDividerItem\n | ReplyShadowMessage\n\ninterface GroupMessagesProps {\n ms: MessageResource[]\n inReplyScreen?: boolean\n jumpToUnreadActive?: boolean\n initialMessageId?: string | null\n}\n\nexport function groupMessages({\n ms,\n inReplyScreen,\n jumpToUnreadActive,\n initialMessageId,\n}: 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 (crossesUnreadBoundary(message, prev, jumpToUnreadActive, initialMessageId)) {\n items.push(unreadDivider())\n }\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 if (crossesUnreadBoundary(message, prev, jumpToUnreadActive, initialMessageId)) {\n items.push(unreadDivider())\n }\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 crossesUnreadBoundary(\n message: MessageResource,\n prev: MessageResource | undefined,\n jumpToUnreadActive: boolean | undefined,\n initialMessageId: string | null | undefined\n): boolean {\n if (!jumpToUnreadActive) return false\n if (!initialMessageId) return false\n if (!prev) return false\n return (\n prev.id.localeCompare(initialMessageId) <= 0 && message.id.localeCompare(initialMessageId) > 0\n )\n}\n\nfunction unreadDivider(): UnreadDividerItem {\n return { type: 'UnreadDivider', id: UNREAD_DIVIDER_KEY }\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"]}
|
|
1
|
+
{"version":3,"file":"group_messages.js","sourceRoot":"","sources":["../../src/utils/group_messages.ts"],"names":[],"mappings":"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","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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "3.38.
|
|
3
|
+
"version": "3.38.1-rc.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "./src/index.tsx",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@fortawesome/fontawesome-svg-core": "^7.2.0",
|
|
28
28
|
"@fortawesome/react-native-fontawesome": "^0.3.2",
|
|
29
|
-
"@planningcenter/emoji-keyboard": "3.38.0
|
|
29
|
+
"@planningcenter/emoji-keyboard": "3.38.0",
|
|
30
30
|
"lodash-inflection": "^1.5.0",
|
|
31
31
|
"react-compiler-runtime": "^1.0.0"
|
|
32
32
|
},
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"react-native-url-polyfill": "^2.0.0",
|
|
73
73
|
"typescript": "~5.9.2"
|
|
74
74
|
},
|
|
75
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "3268ac630db7e7d7c9d1af4ce152ffc08fa1679c"
|
|
76
76
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { QueryClientProvider } from '@tanstack/react-query'
|
|
2
|
+
import { renderHook, waitFor } from '@testing-library/react-native'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { buildTestQueryClient } from '../../__utils__/query_client'
|
|
5
|
+
import { ChatContext, ChatContextValue } from '../../contexts/chat_context'
|
|
6
|
+
import { useApiGet } from '../../hooks/use_api'
|
|
7
|
+
import { ApiClient, useApiClient } from '../../hooks/use_api_client'
|
|
8
|
+
import { Session } from '../../utils'
|
|
9
|
+
|
|
10
|
+
jest.mock('../../hooks/use_api_client')
|
|
11
|
+
|
|
12
|
+
const mockedUseApiClient = useApiClient as jest.MockedFunction<typeof useApiClient>
|
|
13
|
+
|
|
14
|
+
let get: jest.Mock
|
|
15
|
+
|
|
16
|
+
const renderUseApiGet = (session: Session) => {
|
|
17
|
+
const queryClient = buildTestQueryClient()
|
|
18
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
19
|
+
<QueryClientProvider client={queryClient}>
|
|
20
|
+
<ChatContext.Provider value={{ session } as unknown as ChatContextValue}>
|
|
21
|
+
{children}
|
|
22
|
+
</ChatContext.Provider>
|
|
23
|
+
</QueryClientProvider>
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
return renderHook(() => useApiGet({ url: '/me', data: { fields: { Person: ['id'] } } }), {
|
|
27
|
+
wrapper,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
get = jest.fn().mockResolvedValue({ data: { id: 1 } })
|
|
33
|
+
mockedUseApiClient.mockReturnValue({ chat: { get } } as unknown as ApiClient)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
jest.clearAllMocks()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('useApiGet', () => {
|
|
41
|
+
it('does not fetch while the session has no access token', () => {
|
|
42
|
+
const { result } = renderUseApiGet(new Session())
|
|
43
|
+
|
|
44
|
+
expect(result.current.fetchStatus).toBe('idle')
|
|
45
|
+
expect(get).not.toHaveBeenCalled()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('fetches once the session carries an access token', async () => {
|
|
49
|
+
renderUseApiGet(new Session({ token: { access_token: 'a-real-token' } }))
|
|
50
|
+
|
|
51
|
+
await waitFor(() => expect(get).toHaveBeenCalledTimes(1))
|
|
52
|
+
})
|
|
53
|
+
})
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { useEffect } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { View, Pressable, StyleSheet } from 'react-native'
|
|
3
3
|
import Animated, {
|
|
4
|
-
|
|
4
|
+
useSharedValue,
|
|
5
|
+
useAnimatedStyle,
|
|
5
6
|
interpolate,
|
|
7
|
+
Extrapolation,
|
|
6
8
|
ReduceMotion,
|
|
7
|
-
useAnimatedStyle,
|
|
8
|
-
useSharedValue,
|
|
9
9
|
withSpring,
|
|
10
|
-
withTiming,
|
|
11
10
|
} from 'react-native-reanimated'
|
|
12
11
|
import { useTheme } from '../../hooks'
|
|
13
12
|
import { platformFontWeightMedium } from '../../utils'
|
|
@@ -16,17 +15,11 @@ import { Icon, Text } from '../display'
|
|
|
16
15
|
interface JumpToBottomButtonProps {
|
|
17
16
|
onPress: () => void
|
|
18
17
|
visible: boolean
|
|
19
|
-
loading?: boolean
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
export const JumpToBottomButton = ({
|
|
23
|
-
onPress,
|
|
24
|
-
visible,
|
|
25
|
-
loading = false,
|
|
26
|
-
}: JumpToBottomButtonProps) => {
|
|
20
|
+
export const JumpToBottomButton = ({ onPress, visible }: JumpToBottomButtonProps) => {
|
|
27
21
|
const styles = useStyles()
|
|
28
22
|
const progress = useSharedValue(0)
|
|
29
|
-
const loadingProgress = useSharedValue(0)
|
|
30
23
|
|
|
31
24
|
useEffect(() => {
|
|
32
25
|
progress.value = withSpring(visible ? 1 : 0, {
|
|
@@ -38,13 +31,6 @@ export const JumpToBottomButton = ({
|
|
|
38
31
|
})
|
|
39
32
|
}, [visible, progress])
|
|
40
33
|
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
loadingProgress.value = withTiming(loading ? 1 : 0, {
|
|
43
|
-
duration: 750,
|
|
44
|
-
reduceMotion: ReduceMotion.System,
|
|
45
|
-
})
|
|
46
|
-
}, [loading, loadingProgress])
|
|
47
|
-
|
|
48
34
|
const animatedStyle = useAnimatedStyle(() => {
|
|
49
35
|
return {
|
|
50
36
|
opacity: progress.value,
|
|
@@ -59,34 +45,16 @@ export const JumpToBottomButton = ({
|
|
|
59
45
|
}
|
|
60
46
|
})
|
|
61
47
|
|
|
62
|
-
const iconStyle = useAnimatedStyle(() => ({ opacity: 1 - loadingProgress.value }))
|
|
63
|
-
const spinnerStyle = useAnimatedStyle(() => ({ opacity: loadingProgress.value }))
|
|
64
|
-
|
|
65
48
|
return (
|
|
66
49
|
<View>
|
|
67
|
-
<Animated.View
|
|
68
|
-
style={[styles.container, animatedStyle]}
|
|
69
|
-
pointerEvents={visible ? 'auto' : 'none'}
|
|
70
|
-
>
|
|
50
|
+
<Animated.View style={[styles.container, animatedStyle]}>
|
|
71
51
|
<Pressable
|
|
72
52
|
onPress={onPress}
|
|
73
|
-
disabled={loading}
|
|
74
|
-
accessibilityRole="button"
|
|
75
|
-
accessibilityLabel="Jump to most recent message"
|
|
76
|
-
accessibilityState={{ busy: loading }}
|
|
77
|
-
hitSlop={hitSlop}
|
|
78
53
|
style={({ pressed }) => [styles.button, pressed && styles.pressed]}
|
|
79
54
|
>
|
|
80
|
-
<
|
|
81
|
-
<Animated.View style={[styles.glyphLayer, iconStyle]}>
|
|
82
|
-
<Icon name="general.downArrow" style={styles.icon} />
|
|
83
|
-
</Animated.View>
|
|
84
|
-
<Animated.View style={[styles.glyphLayer, spinnerStyle]}>
|
|
85
|
-
<ActivityIndicator size="small" color={styles.icon.color} style={styles.spinner} />
|
|
86
|
-
</Animated.View>
|
|
87
|
-
</View>
|
|
55
|
+
<Icon name="general.downArrow" style={styles.icon} />
|
|
88
56
|
<Text variant="tertiary" style={styles.text}>
|
|
89
|
-
|
|
57
|
+
Jump to bottom
|
|
90
58
|
</Text>
|
|
91
59
|
</Pressable>
|
|
92
60
|
</Animated.View>
|
|
@@ -94,8 +62,6 @@ export const JumpToBottomButton = ({
|
|
|
94
62
|
)
|
|
95
63
|
}
|
|
96
64
|
|
|
97
|
-
const hitSlop = { top: 12, bottom: 12, left: 12, right: 12 }
|
|
98
|
-
|
|
99
65
|
const useStyles = () => {
|
|
100
66
|
const { colors } = useTheme()
|
|
101
67
|
|
|
@@ -127,25 +93,10 @@ const useStyles = () => {
|
|
|
127
93
|
color: colors.fillColorNeutral100Inverted,
|
|
128
94
|
fontWeight: platformFontWeightMedium,
|
|
129
95
|
},
|
|
130
|
-
glyph: {
|
|
131
|
-
width: 14,
|
|
132
|
-
height: 14,
|
|
133
|
-
alignItems: 'center',
|
|
134
|
-
justifyContent: 'center',
|
|
135
|
-
},
|
|
136
|
-
glyphLayer: {
|
|
137
|
-
position: 'absolute',
|
|
138
|
-
alignItems: 'center',
|
|
139
|
-
justifyContent: 'center',
|
|
140
|
-
},
|
|
141
96
|
icon: {
|
|
142
97
|
color: colors.fillColorNeutral100Inverted,
|
|
143
98
|
fontSize: 14,
|
|
144
99
|
},
|
|
145
|
-
spinner: {
|
|
146
|
-
width: 14,
|
|
147
|
-
height: 14,
|
|
148
|
-
},
|
|
149
100
|
pressed: {
|
|
150
101
|
transform: [{ scale: 0.95 }],
|
|
151
102
|
},
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
import { Avatar, Icon, IconProps, Image, Text } from '../display'
|
|
29
29
|
import { TheirReplyConnector, MyReplyConnector } from './reply_connectors'
|
|
30
30
|
|
|
31
|
-
interface ReplyShadowMessageProps {
|
|
31
|
+
interface ReplyShadowMessageProps extends MessageResource {
|
|
32
32
|
messageId: string
|
|
33
33
|
conversation_id: number
|
|
34
34
|
inReplyScreen?: boolean
|
|
@@ -1,59 +1,31 @@
|
|
|
1
|
-
import React, { createContext, PropsWithChildren, useContext, useMemo
|
|
1
|
+
import React, { createContext, PropsWithChildren, useContext, useMemo } from 'react'
|
|
2
2
|
|
|
3
3
|
interface ConversationContextValue {
|
|
4
4
|
conversationId: number
|
|
5
5
|
currentPageReplyRootId: string | null
|
|
6
|
-
initialMessageId: string | null
|
|
7
|
-
setInitialMessageId: (id: string | null) => void
|
|
8
|
-
initialMessageIdIsAnchor: boolean
|
|
9
|
-
atEndOfMessageHistory: boolean
|
|
10
|
-
setAtEndOfMessageHistory: (atEnd: boolean) => void
|
|
11
6
|
}
|
|
12
7
|
|
|
13
8
|
interface ConversationContextProviderProps extends PropsWithChildren {
|
|
14
9
|
conversationId: number
|
|
15
10
|
currentPageReplyRootId: string | null
|
|
16
|
-
initialMessageId?: string | null
|
|
17
|
-
initialMessageIdIsAnchor?: boolean
|
|
18
11
|
}
|
|
19
12
|
|
|
20
13
|
const ConversationContext = createContext<ConversationContextValue>({
|
|
21
14
|
conversationId: 0,
|
|
22
15
|
currentPageReplyRootId: null,
|
|
23
|
-
initialMessageId: null,
|
|
24
|
-
setInitialMessageId: () => {},
|
|
25
|
-
initialMessageIdIsAnchor: false,
|
|
26
|
-
atEndOfMessageHistory: false,
|
|
27
|
-
setAtEndOfMessageHistory: () => {},
|
|
28
16
|
})
|
|
29
17
|
|
|
30
18
|
export const ConversationContextProvider = ({
|
|
31
19
|
children,
|
|
32
20
|
conversationId,
|
|
33
21
|
currentPageReplyRootId,
|
|
34
|
-
initialMessageId: initialMessageIdProp = null,
|
|
35
|
-
initialMessageIdIsAnchor = false,
|
|
36
22
|
}: ConversationContextProviderProps) => {
|
|
37
|
-
const [initialMessageId, setInitialMessageId] = useState(initialMessageIdProp)
|
|
38
|
-
const [atEndOfMessageHistory, setAtEndOfMessageHistory] = useState(false)
|
|
39
|
-
|
|
40
23
|
const value = useMemo(
|
|
41
24
|
() => ({
|
|
42
25
|
conversationId,
|
|
43
26
|
currentPageReplyRootId,
|
|
44
|
-
initialMessageId,
|
|
45
|
-
setInitialMessageId,
|
|
46
|
-
initialMessageIdIsAnchor,
|
|
47
|
-
atEndOfMessageHistory,
|
|
48
|
-
setAtEndOfMessageHistory,
|
|
49
27
|
}),
|
|
50
|
-
[
|
|
51
|
-
conversationId,
|
|
52
|
-
currentPageReplyRootId,
|
|
53
|
-
initialMessageId,
|
|
54
|
-
initialMessageIdIsAnchor,
|
|
55
|
-
atEndOfMessageHistory,
|
|
56
|
-
]
|
|
28
|
+
[conversationId, currentPageReplyRootId]
|
|
57
29
|
)
|
|
58
30
|
|
|
59
31
|
return <ConversationContext.Provider value={value}>{children}</ConversationContext.Provider>
|
package/src/hooks/use_api.ts
CHANGED
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
useInfiniteQuery,
|
|
5
5
|
useQuery,
|
|
6
6
|
} from '@tanstack/react-query'
|
|
7
|
+
import { useContext } from 'react'
|
|
8
|
+
import { ChatContext } from '../contexts/chat_context'
|
|
7
9
|
import { ApiCollection, ApiResource, FailedResponse, ResourceObject } from '../types'
|
|
8
10
|
import { GetRequest, RequestData } from '../utils/client'
|
|
9
11
|
import { getNextPageParamFromMeta } from './paginator_meta'
|
|
@@ -17,8 +19,11 @@ interface ApiGetOptions extends GetRequest {
|
|
|
17
19
|
|
|
18
20
|
export const useApiGet = <T extends ResourceObject | ResourceObject[]>(args: ApiGetOptions) => {
|
|
19
21
|
type Resource = ApiResource<T>
|
|
22
|
+
const { session } = useContext(ChatContext)
|
|
20
23
|
const apiClient = useApiClient()
|
|
21
24
|
|
|
25
|
+
const enabled = !!session.token?.access_token && (args.enabled ?? true)
|
|
26
|
+
|
|
22
27
|
const { data, ...query } = useQuery<Resource, FailedResponse>({
|
|
23
28
|
queryKey: getRequestQueryKey(args),
|
|
24
29
|
queryFn: ({ queryKey }) => {
|
|
@@ -26,7 +31,7 @@ export const useApiGet = <T extends ResourceObject | ResourceObject[]>(args: Api
|
|
|
26
31
|
|
|
27
32
|
return apiClient[app].get({ url, data: d, headers }) as Promise<Resource>
|
|
28
33
|
},
|
|
29
|
-
enabled
|
|
34
|
+
enabled,
|
|
30
35
|
})
|
|
31
36
|
|
|
32
37
|
return { ...data, ...query }
|
|
@@ -41,7 +46,9 @@ export const useApiPaginator = <T extends ResourceObject>(
|
|
|
41
46
|
args: ApiGetOptions,
|
|
42
47
|
opts?: PaginatorOptions
|
|
43
48
|
) => {
|
|
49
|
+
const { session } = useContext(ChatContext)
|
|
44
50
|
const apiClient = useApiClient()
|
|
51
|
+
const enabled = !!session.token?.access_token && (args.enabled ?? true)
|
|
45
52
|
const query = useInfiniteQuery<
|
|
46
53
|
ApiCollection<T>,
|
|
47
54
|
FailedResponse,
|
|
@@ -65,7 +72,7 @@ export const useApiPaginator = <T extends ResourceObject>(
|
|
|
65
72
|
},
|
|
66
73
|
initialPageParam: {} as Partial<RequestData>,
|
|
67
74
|
getNextPageParam: lastPage => getNextPageParamFromMeta(lastPage.meta?.next),
|
|
68
|
-
enabled
|
|
75
|
+
enabled,
|
|
69
76
|
...(opts || {}),
|
|
70
77
|
})
|
|
71
78
|
|
|
@@ -1,128 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
InfiniteData,
|
|
4
|
-
useQueryClient,
|
|
5
|
-
useSuspenseInfiniteQuery,
|
|
6
|
-
useSuspenseQueries,
|
|
7
|
-
} from '@tanstack/react-query'
|
|
8
|
-
import { useCallback, useMemo } from 'react'
|
|
9
|
-
import { useConversationContext } from '../contexts/conversation_context'
|
|
10
|
-
import { ApiCollection, MessageResource } from '../types'
|
|
11
|
-
import {
|
|
12
|
-
anchoredSeedPageParams,
|
|
13
|
-
MessagesPageParam,
|
|
14
|
-
newerPageParam,
|
|
15
|
-
olderPageParam,
|
|
16
|
-
sortAndFilterMessages,
|
|
17
|
-
} from '../utils/conversation_messages'
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import { MessageResource } from '../types'
|
|
18
3
|
import { getMessagesQueryKey, getMessagesRequestArgs } from '../utils/request/get_messages'
|
|
19
|
-
import {
|
|
20
|
-
import { throwResponseError } from './use_suspense_api'
|
|
21
|
-
|
|
22
|
-
type Args = { conversation_id: number; reply_root_id?: string | null }
|
|
23
|
-
|
|
24
|
-
export type ConversationMessagesOptions = Omit<
|
|
25
|
-
AnyUseSuspenseInfiniteQueryOptions,
|
|
26
|
-
| 'getNextPageParam'
|
|
27
|
-
| 'getPreviousPageParam'
|
|
28
|
-
| 'initialData'
|
|
29
|
-
| 'initialPageParam'
|
|
30
|
-
| 'queryFn'
|
|
31
|
-
| 'queryKey'
|
|
32
|
-
>
|
|
4
|
+
import { SuspensePaginatorOptions, useSuspensePaginator } from './use_suspense_api'
|
|
33
5
|
|
|
34
6
|
export const useConversationMessages = (
|
|
35
|
-
{ conversation_id, reply_root_id }:
|
|
36
|
-
opts?:
|
|
7
|
+
{ conversation_id, reply_root_id }: { conversation_id: number; reply_root_id?: string | null },
|
|
8
|
+
opts?: SuspensePaginatorOptions
|
|
37
9
|
) => {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const requestArgs = useMemo(
|
|
43
|
-
() => getMessagesRequestArgs({ conversation_id, reply_root_id }),
|
|
44
|
-
[conversation_id, reply_root_id]
|
|
10
|
+
const { data, refetch, isRefetching, fetchNextPage } = useSuspensePaginator<MessageResource>(
|
|
11
|
+
getMessagesRequestArgs({ conversation_id, reply_root_id }),
|
|
12
|
+
opts
|
|
45
13
|
)
|
|
46
|
-
const queryKey =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return apiClient.chat
|
|
58
|
-
.get<ApiCollection<MessageResource>>({ url: requestArgs.url, data })
|
|
59
|
-
.catch(throwResponseError)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const seedPageParams = anchored ? anchoredSeedPageParams(initialMessageId) : []
|
|
63
|
-
const seedQueries = useSuspenseQueries({
|
|
64
|
-
queries: seedPageParams.map((pageParam, index) => ({
|
|
65
|
-
queryKey: [...queryKey, 'seed', index],
|
|
66
|
-
queryFn: () => fetchPage(pageParam),
|
|
67
|
-
staleTime: Infinity,
|
|
68
|
-
gcTime: 0,
|
|
69
|
-
})),
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
const initialData: InfiniteData<ApiCollection<MessageResource>, MessagesPageParam> | undefined =
|
|
73
|
-
anchored
|
|
74
|
-
? {
|
|
75
|
-
pages: seedQueries.map(q => q.data),
|
|
76
|
-
pageParams: seedPageParams,
|
|
77
|
-
}
|
|
78
|
-
: undefined
|
|
79
|
-
|
|
80
|
-
const initialPageParam: MessagesPageParam = anchored ? seedPageParams[0] : {}
|
|
81
|
-
|
|
82
|
-
const {
|
|
83
|
-
data,
|
|
84
|
-
refetch,
|
|
85
|
-
isRefetching,
|
|
86
|
-
fetchNextPage,
|
|
87
|
-
hasNextPage,
|
|
88
|
-
fetchPreviousPage,
|
|
89
|
-
hasPreviousPage,
|
|
90
|
-
isFetchingPreviousPage,
|
|
91
|
-
} = useSuspenseInfiniteQuery<
|
|
92
|
-
ApiCollection<MessageResource>,
|
|
93
|
-
Response,
|
|
94
|
-
InfiniteData<ApiCollection<MessageResource>, MessagesPageParam>,
|
|
95
|
-
typeof queryKey,
|
|
96
|
-
MessagesPageParam
|
|
97
|
-
>({
|
|
98
|
-
queryKey,
|
|
99
|
-
queryFn: ({ pageParam }) => fetchPage(pageParam),
|
|
100
|
-
initialPageParam,
|
|
101
|
-
initialData,
|
|
102
|
-
getNextPageParam: olderPageParam,
|
|
103
|
-
getPreviousPageParam: anchored ? newerPageParam : () => undefined,
|
|
104
|
-
...(opts || {}),
|
|
105
|
-
...(anchored ? { staleTime: Infinity, refetchOnMount: false } : {}),
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
const messages = useMemo(() => sortAndFilterMessages(data.pages), [data.pages])
|
|
109
|
-
|
|
110
|
-
const queryClient = useQueryClient()
|
|
111
|
-
const cancelFetchNewerMessages = useCallback(
|
|
112
|
-
() => queryClient.cancelQueries({ queryKey }),
|
|
113
|
-
[queryClient, queryKey]
|
|
14
|
+
const queryKey = getMessagesQueryKey({ conversation_id, reply_root_id })
|
|
15
|
+
const messages = useMemo(
|
|
16
|
+
() =>
|
|
17
|
+
data
|
|
18
|
+
.filter(
|
|
19
|
+
message =>
|
|
20
|
+
(!message.deletedAt || message.replyRootId) &&
|
|
21
|
+
(message.attachments?.length || message.text?.length)
|
|
22
|
+
)
|
|
23
|
+
.sort((a, b) => -a.id.localeCompare(b.id)),
|
|
24
|
+
[data]
|
|
114
25
|
)
|
|
115
26
|
|
|
116
|
-
return {
|
|
117
|
-
messages,
|
|
118
|
-
refetch,
|
|
119
|
-
isRefetching,
|
|
120
|
-
fetchOlderMessages: fetchNextPage,
|
|
121
|
-
hasMoreOlderMessages: hasNextPage,
|
|
122
|
-
fetchNewerMessages: fetchPreviousPage,
|
|
123
|
-
hasMoreNewerMessages: hasPreviousPage,
|
|
124
|
-
isFetchingNewerMessages: isFetchingPreviousPage,
|
|
125
|
-
cancelFetchNewerMessages,
|
|
126
|
-
queryKey,
|
|
127
|
-
}
|
|
27
|
+
return { messages, refetch, isRefetching, fetchNextPage, queryKey }
|
|
128
28
|
}
|