@planningcenter/chat-react-native 3.35.0-rc.3 → 3.35.0-rc.5
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/README.md +1 -1
- package/build/components/conversation/jump_to_bottom_button.d.ts +2 -1
- package/build/components/conversation/jump_to_bottom_button.d.ts.map +1 -1
- package/build/components/conversation/jump_to_bottom_button.js +39 -7
- package/build/components/conversation/jump_to_bottom_button.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.map +1 -1
- package/build/components/conversation/unread_divider.d.ts +6 -0
- package/build/components/conversation/unread_divider.d.ts.map +1 -0
- package/build/components/conversation/unread_divider.js +59 -0
- package/build/components/conversation/unread_divider.js.map +1 -0
- package/build/contexts/conversation_context.d.ts +2 -0
- package/build/contexts/conversation_context.d.ts.map +1 -1
- package/build/contexts/conversation_context.js +13 -5
- package/build/contexts/conversation_context.js.map +1 -1
- package/build/hooks/use_conversation_messages.d.ts +2 -0
- package/build/hooks/use_conversation_messages.d.ts.map +1 -1
- package/build/hooks/use_conversation_messages.js +9 -5
- 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 +5 -0
- package/build/hooks/use_conversations_actions.d.ts.map +1 -1
- package/build/hooks/use_conversations_actions.js +12 -0
- package/build/hooks/use_conversations_actions.js.map +1 -1
- package/build/hooks/use_flat_list_viewability.d.ts +20 -0
- package/build/hooks/use_flat_list_viewability.d.ts.map +1 -0
- package/build/hooks/use_flat_list_viewability.js +30 -0
- package/build/hooks/use_flat_list_viewability.js.map +1 -0
- package/build/hooks/use_jump_to_bottom_action.d.ts +9 -0
- package/build/hooks/use_jump_to_bottom_action.d.ts.map +1 -0
- package/build/hooks/use_jump_to_bottom_action.js +62 -0
- package/build/hooks/use_jump_to_bottom_action.js.map +1 -0
- package/build/hooks/use_jump_to_unread_anchor.d.ts +20 -0
- package/build/hooks/use_jump_to_unread_anchor.d.ts.map +1 -0
- package/build/hooks/use_jump_to_unread_anchor.js +53 -0
- package/build/hooks/use_jump_to_unread_anchor.js.map +1 -0
- package/build/hooks/use_jump_to_unread_gates.d.ts +5 -0
- package/build/hooks/use_jump_to_unread_gates.d.ts.map +1 -0
- package/build/hooks/use_jump_to_unread_gates.js +10 -0
- package/build/hooks/use_jump_to_unread_gates.js.map +1 -0
- 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 +17 -1
- package/build/hooks/use_mark_latest_message_read.js.map +1 -1
- package/build/hooks/use_scroll_tracking.d.ts +13 -0
- package/build/hooks/use_scroll_tracking.d.ts.map +1 -0
- package/build/hooks/use_scroll_tracking.js +45 -0
- package/build/hooks/use_scroll_tracking.js.map +1 -0
- package/build/hooks/use_track_highest_seen_message.d.ts +4 -0
- package/build/hooks/use_track_highest_seen_message.d.ts.map +1 -0
- package/build/hooks/use_track_highest_seen_message.js +35 -0
- package/build/hooks/use_track_highest_seen_message.js.map +1 -0
- package/build/navigation/index.d.ts.map +1 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +87 -44
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/group_notification_settings_screen.d.ts.map +1 -1
- package/build/screens/group_notification_settings_screen.js +6 -3
- package/build/screens/group_notification_settings_screen.js.map +1 -1
- package/build/screens/notification_settings_screen.js +2 -2
- package/build/screens/notification_settings_screen.js.map +1 -1
- package/build/screens/preferred_app_selection_screen.js +3 -3
- package/build/screens/preferred_app_selection_screen.js.map +1 -1
- package/build/utils/cache/messages_cache.d.ts +1 -0
- package/build/utils/cache/messages_cache.d.ts.map +1 -1
- package/build/utils/cache/messages_cache.js +4 -0
- package/build/utils/cache/messages_cache.js.map +1 -1
- package/build/utils/group_messages.d.ts +9 -2
- package/build/utils/group_messages.d.ts.map +1 -1
- package/build/utils/group_messages.js +20 -1
- package/build/utils/group_messages.js.map +1 -1
- package/build/utils/highest_seen_tracker.d.ts +12 -0
- package/build/utils/highest_seen_tracker.d.ts.map +1 -0
- package/build/utils/highest_seen_tracker.js +37 -0
- package/build/utils/highest_seen_tracker.js.map +1 -0
- package/build/utils/message_viewability.d.ts +24 -0
- package/build/utils/message_viewability.d.ts.map +1 -0
- package/build/utils/message_viewability.js +29 -0
- package/build/utils/message_viewability.js.map +1 -0
- package/build/utils/unread_divider_helpers.d.ts +18 -0
- package/build/utils/unread_divider_helpers.d.ts.map +1 -0
- package/build/utils/unread_divider_helpers.js +13 -0
- package/build/utils/unread_divider_helpers.js.map +1 -0
- package/package.json +10 -4
- package/src/__tests__/contexts/session_context.tsx +1 -1
- package/src/__tests__/hooks/use_async_storage.test.tsx +1 -1
- package/src/__tests__/hooks/use_attachment_uploader.test.tsx +1 -1
- package/src/__tests__/hooks/use_chat_configuration.test.tsx +1 -1
- package/src/__tests__/hooks/use_conversation_messages.test.tsx +1 -1
- package/src/__tests__/hooks/use_mark_latest_message_read.test.tsx +154 -0
- package/src/__tests__/utils/cache/messages_cache.test.ts +54 -0
- package/src/components/conversation/jump_to_bottom_button.tsx +57 -8
- package/src/components/conversation/reply_shadow_message.tsx +4 -2
- package/src/components/conversation/unread_divider.tsx +90 -0
- package/src/contexts/conversation_context.tsx +15 -13
- package/src/hooks/use_conversation_messages.ts +19 -3
- package/src/hooks/use_conversation_messages_jolt_events.ts +4 -3
- package/src/hooks/use_conversations_actions.ts +15 -0
- package/src/hooks/use_flat_list_viewability.ts +50 -0
- package/src/hooks/use_jump_to_bottom_action.ts +75 -0
- package/src/hooks/use_jump_to_unread_anchor.ts +68 -0
- package/src/hooks/use_jump_to_unread_gates.ts +10 -0
- package/src/hooks/use_mark_latest_message_read.ts +16 -2
- package/src/hooks/use_scroll_tracking.ts +64 -0
- package/src/hooks/use_track_highest_seen_message.ts +43 -0
- package/src/screens/conversation_screen.tsx +173 -70
- package/src/screens/group_notification_settings_screen.tsx +6 -3
- package/src/screens/notification_settings_screen.tsx +2 -2
- package/src/screens/preferred_app_selection_screen.tsx +3 -3
- package/src/utils/__tests__/group_messages.test.ts +71 -0
- package/src/utils/__tests__/highest_seen_tracker.test.ts +82 -0
- package/src/utils/__tests__/message_viewability.test.ts +168 -0
- package/src/utils/__tests__/unread_divider_helpers.test.ts +85 -0
- package/src/utils/cache/messages_cache.ts +5 -0
- package/src/utils/group_messages.ts +42 -2
- package/src/utils/highest_seen_tracker.ts +42 -0
- package/src/utils/message_viewability.ts +49 -0
- package/src/utils/unread_divider_helpers.ts +25 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preferred_app_selection_screen.js","sourceRoot":"","sources":["../../src/screens/preferred_app_selection_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { PlatformPressable } from '@react-navigation/elements'\nimport { StaticScreenProps } from '@react-navigation/native'\nimport { useMutation } from '@tanstack/react-query'\nimport React, { type PropsWithChildren } from 'react'\nimport { Image, StyleSheet, View, type ViewStyle } from 'react-native'\nimport { Heading, Icon, Text } from '../components'\nimport { useApiClient, useTheme } from '../hooks'\nimport { useAppName } from '../hooks/use_app_name'\nimport { throwResponseError } from '../utils/response_error'\nimport { PreferredApp, useChatTypes } from './preferred_app/hooks/use_chat_types'\n\nexport type PreferredAppSelectionScreenProps = StaticScreenProps<{\n chatTypeId: number | string\n conversationType?: 'group' | 'team'\n currentSelection?: PreferredApp\n}>\n\nexport function PreferredAppSelectionScreen({ route }: PreferredAppSelectionScreenProps) {\n const { chatTypeId } = route.params\n const { data: chatTypes, refetch: refetchChatTypes } = useChatTypes()\n const appName = useAppName()\n\n const apiClient = useApiClient()\n\n const { mutate: updateChatType } = useMutation({\n throwOnError: true,\n onSuccess: () => refetchChatTypes(),\n mutationFn: (app: PreferredApp) => {\n return apiClient.chat\n .post({\n url: `/me/chat_types/${chatTypeId}/set_preferred_app`,\n data: { data: { type: 'ChatType', attributes: { app } } },\n })\n .catch(throwResponseError)\n },\n })\n const chatType = chatTypes.find(t => t.id === chatTypeId)\n const { preferredAppOptions } = chatType || {}\n\n const handleSelection = (app: PreferredApp) => {\n updateChatType(app)\n }\n\n const sectionTitle = `${chatType?.title}
|
|
1
|
+
{"version":3,"file":"preferred_app_selection_screen.js","sourceRoot":"","sources":["../../src/screens/preferred_app_selection_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAE9D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,KAAiC,MAAM,OAAO,CAAA;AACrD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAkB,MAAM,cAAc,CAAA;AACtE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAgB,YAAY,EAAE,MAAM,sCAAsC,CAAA;AAQjF,MAAM,UAAU,2BAA2B,CAAC,EAAE,KAAK,EAAoC;IACrF,MAAM,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC,MAAM,CAAA;IACnC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAA;IACrE,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAE5B,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAEhC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,WAAW,CAAC;QAC7C,YAAY,EAAE,IAAI;QAClB,SAAS,EAAE,GAAG,EAAE,CAAC,gBAAgB,EAAE;QACnC,UAAU,EAAE,CAAC,GAAiB,EAAE,EAAE;YAChC,OAAO,SAAS,CAAC,IAAI;iBAClB,IAAI,CAAC;gBACJ,GAAG,EAAE,kBAAkB,UAAU,oBAAoB;gBACrD,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;aAC1D,CAAC;iBACD,KAAK,CAAC,kBAAkB,CAAC,CAAA;QAC9B,CAAC;KACF,CAAC,CAAA;IACF,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,UAAU,CAAC,CAAA;IACzD,MAAM,EAAE,mBAAmB,EAAE,GAAG,QAAQ,IAAI,EAAE,CAAA;IAE9C,MAAM,eAAe,GAAG,CAAC,GAAiB,EAAE,EAAE;QAC5C,cAAc,CAAC,GAAG,CAAC,CAAA;IACrB,CAAC,CAAA;IAED,MAAM,YAAY,GAAG,GAAG,QAAQ,EAAE,KAAK,gBAAgB,CAAA;IAEvD,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAC1B;QAAA,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CACjD;UAAA,CAAC,YAAY,CACf;QAAA,EAAE,OAAO,CACT;QAAA,CAAC,mBAAmB,EAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CACvE,CAAC,YAAY,CACX,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,MAAM,EAAE,CAAC,CACxB,QAAQ,CAAC,CAAC,QAAQ,EAAE,YAAY,KAAK,MAAM,CAAC,CAC5C,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAEvC;YAAA,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EACvD;YAAA,CAAC,IAAI,CACH;cAAA,CAAC,MAAM,CACP;cAAA,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CACjF;YAAA,EAAE,IAAI,CACR;UAAA,EAAE,YAAY,CAAC,CAChB,CAAC,CACJ;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,MAAM,gBAAgB,GAAG,CAAC,GAAoB,EAAE,EAAE,CAAC,CAAC,CAAe,EAAE,CAAe,EAAE,EAAE;IACtF,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,CAAC,CAAA;IAC1B,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACxC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAExC,OAAO,CAAC,CAAA;AACV,CAAC,CAAA;AAED,MAAM,WAAW,GAAG,CAAC,MAAoB,EAAE,EAAE;IAC3C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,eAAe;YAClB,OAAO,OAAO,CAAC,+BAA+B,CAAC,CAAA;QACjD,KAAK,UAAU;YACb,OAAO,OAAO,CAAC,8BAA8B,CAAC,CAAA;QAChD,KAAK,MAAM;YACT,OAAO,OAAO,CAAC,2BAA2B,CAAC,CAAA;QAC7C;YACE,OAAO,SAAS,CAAA;IACpB,CAAC;AACH,CAAC,CAAA;AAED,MAAM,YAAY,GAAG,CAAC,EACpB,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,GAC4E,EAAE,EAAE;IACrF,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;IACzC,OAAO,CACL,CAAC,iBAAiB,CAChB,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CACxB,OAAO,CAAC,CAAC,OAAO,CAAC,CACjB,iBAAiB,CAAC,OAAO,CACzB,kBAAkB,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAE3C;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CACtB;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CACvD;QAAA,CAAC,IAAI,CACH,IAAI,CAAC,eAAe,CACpB,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAC3B,2BAA2B,CAC3B,qBAAqB,CAAC,CAAC,GAAG,CAAC,EAE/B;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,iBAAiB,CAAC,CACrB,CAAA;AACH,CAAC,CAAA;AAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,SAAS,EAAE;QACT,IAAI,EAAE,CAAC;KACR;IACD,OAAO,EAAE;QACP,UAAU,EAAE,EAAE;KACf;IACD,cAAc,EAAE;QACd,iBAAiB,EAAE,EAAE;QACrB,aAAa,EAAE,CAAC;KACjB;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;QACV,YAAY,EAAE,CAAC;KAChB;CACF,CAAC,CAAA;AAEF,MAAM,YAAY,GAAG,CAAC,EAAE,QAAQ,GAAG,KAAK,KAA6B,EAAE,EAAE,EAAE;IACzE,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;IAExB,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE;YACT,WAAW,EAAE,EAAE;YACf,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,eAAe;SAC9C;QACD,GAAG,EAAE;YACH,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,eAAe;YAC/B,GAAG,EAAE,EAAE;YACP,iBAAiB,EAAE,CAAC;YACpB,iBAAiB,EAAE,KAAK,CAAC,MAAM,CAAC,sBAAsB;YACtD,eAAe,EAAE,EAAE;YACnB,YAAY,EAAE,EAAE;SACjB;QACD,QAAQ,EAAE;YACR,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,EAAE;YACP,UAAU,EAAE,CAAC;SACd;QACD,YAAY,EAAE;YACZ,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,iBAAiB;YACrC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAC1B;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { PlatformPressable } from '@react-navigation/elements'\nimport { StaticScreenProps } from '@react-navigation/native'\nimport { useMutation } from '@tanstack/react-query'\nimport React, { type PropsWithChildren } from 'react'\nimport { Image, StyleSheet, View, type ViewStyle } from 'react-native'\nimport { Heading, Icon, Text } from '../components'\nimport { useApiClient, useTheme } from '../hooks'\nimport { useAppName } from '../hooks/use_app_name'\nimport { throwResponseError } from '../utils/response_error'\nimport { PreferredApp, useChatTypes } from './preferred_app/hooks/use_chat_types'\n\nexport type PreferredAppSelectionScreenProps = StaticScreenProps<{\n chatTypeId: number | string\n conversationType?: 'group' | 'team'\n currentSelection?: PreferredApp\n}>\n\nexport function PreferredAppSelectionScreen({ route }: PreferredAppSelectionScreenProps) {\n const { chatTypeId } = route.params\n const { data: chatTypes, refetch: refetchChatTypes } = useChatTypes()\n const appName = useAppName()\n\n const apiClient = useApiClient()\n\n const { mutate: updateChatType } = useMutation({\n throwOnError: true,\n onSuccess: () => refetchChatTypes(),\n mutationFn: (app: PreferredApp) => {\n return apiClient.chat\n .post({\n url: `/me/chat_types/${chatTypeId}/set_preferred_app`,\n data: { data: { type: 'ChatType', attributes: { app } } },\n })\n .catch(throwResponseError)\n },\n })\n const chatType = chatTypes.find(t => t.id === chatTypeId)\n const { preferredAppOptions } = chatType || {}\n\n const handleSelection = (app: PreferredApp) => {\n updateChatType(app)\n }\n\n const sectionTitle = `${chatType?.title} conversations`\n\n return (\n <View style={styles.container}>\n <View style={styles.section}>\n <Heading variant=\"h2\" style={styles.sectionHeading}>\n {sectionTitle}\n </Heading>\n {preferredAppOptions?.sort(sortPreferredApp('asc')).map((option, key) => (\n <PressableRow\n key={`${key}-${option}`}\n isActive={chatType?.preferredApp === option}\n onPress={() => handleSelection(option)}\n >\n <Image source={getAppImage(option)} style={styles.logo} />\n <Text>\n {option}\n {appName.includes(option.replace(/\\s/, '').toLowerCase()) ? ' ( current )' : ''}\n </Text>\n </PressableRow>\n ))}\n </View>\n </View>\n )\n}\n\nconst sortPreferredApp = (dir?: 'asc' | 'desc') => (a: PreferredApp, b: PreferredApp) => {\n if (a === 'None') return 1\n if (a > b) return dir === 'asc' ? 1 : -1\n if (b > a) return dir === 'asc' ? -1 : 1\n\n return 0\n}\n\nconst getAppImage = (option: PreferredApp) => {\n switch (option) {\n case 'Church Center':\n return require('../../assets/churchCenter.png')\n case 'Services':\n return require('../../assets/servicesApp.png')\n case 'Chat':\n return require('../../assets/chatLogo.png')\n default:\n return undefined\n }\n}\n\nconst PressableRow = ({\n children,\n isActive,\n onPress,\n style,\n}: PropsWithChildren<{ isActive: boolean; onPress: () => void; style?: ViewStyle }>) => {\n const styles = useRowStyles({ isActive })\n return (\n <PlatformPressable\n style={styles.pressable}\n onPress={onPress}\n accessibilityRole=\"radio\"\n accessibilityState={{ selected: isActive }}\n >\n <View style={styles.row}>\n <View style={[styles.rowInner, style]}>{children}</View>\n <Icon\n name=\"general.check\"\n style={styles.rowIconRight}\n accessibilityElementsHidden\n maxFontSizeMultiplier={2.5}\n />\n </View>\n </PlatformPressable>\n )\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n },\n section: {\n paddingTop: 24,\n },\n sectionHeading: {\n paddingHorizontal: 16,\n paddingBottom: 4,\n },\n logo: {\n width: 32,\n height: 32,\n borderRadius: 8,\n },\n})\n\nconst useRowStyles = ({ isActive = false }: { isActive?: boolean } = {}) => {\n const theme = useTheme()\n\n return StyleSheet.create({\n pressable: {\n paddingLeft: 16,\n backgroundColor: theme.colors.surfaceColor100,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 12,\n borderBottomWidth: 1,\n borderBottomColor: theme.colors.borderColorDefaultBase,\n paddingVertical: 12,\n paddingRight: 16,\n },\n rowInner: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n flexShrink: 1,\n },\n rowIconRight: {\n fontSize: 16,\n color: theme.colors.statusSuccessIcon,\n opacity: isActive ? 1 : 0,\n },\n })\n}\n"]}
|
|
@@ -7,5 +7,6 @@ export declare function updateCacheWithReaction(queryClient: QueryClient, queryK
|
|
|
7
7
|
export declare function isTemporaryMessageId(messageId?: string | null): boolean;
|
|
8
8
|
export declare function isNewMessage(message?: MessageResource): boolean;
|
|
9
9
|
export declare function getThreadedMessagesQueryKey(conversationId: number, replyRootId: string): import("../../hooks").RequestQueryKey;
|
|
10
|
+
export declare function hasUnloadedNewerPages(queryClient: QueryClient, queryKey: unknown[]): boolean;
|
|
10
11
|
export declare function mergeMessageUpdate(record: MessageResource, current?: MessageResource): MessageResource;
|
|
11
12
|
//# sourceMappingURL=messages_cache.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages_cache.d.ts","sourceRoot":"","sources":["../../../src/utils/cache/messages_cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEjE,OAAO,EAA8B,eAAe,EAAE,MAAM,aAAa,CAAA;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAM3D,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,QAkC7C;AAID,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,eAAe,QAgBzB;AAED,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,iBAAiB,EACxB,eAAe,EAAE,MAAM,QAuCxB;AAGD,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEvE;AACD,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAE/D;AAED,wBAAgB,2BAA2B,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,yCAMtF;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,eAAe,GACxB,eAAe,CAWjB"}
|
|
1
|
+
{"version":3,"file":"messages_cache.d.ts","sourceRoot":"","sources":["../../../src/utils/cache/messages_cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEjE,OAAO,EAA8B,eAAe,EAAE,MAAM,aAAa,CAAA;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAM3D,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,QAkC7C;AAID,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,eAAe,QAgBzB;AAED,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,iBAAiB,EACxB,eAAe,EAAE,MAAM,QAuCxB;AAGD,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEvE;AACD,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAE/D;AAED,wBAAgB,2BAA2B,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,yCAMtF;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAG5F;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,eAAe,GACxB,eAAe,CAWjB"}
|
|
@@ -97,6 +97,10 @@ export function getThreadedMessagesQueryKey(conversationId, replyRootId) {
|
|
|
97
97
|
});
|
|
98
98
|
return getRequestQueryKey(requestArgs);
|
|
99
99
|
}
|
|
100
|
+
export function hasUnloadedNewerPages(queryClient, queryKey) {
|
|
101
|
+
const data = queryClient.getQueryData(queryKey);
|
|
102
|
+
return !!data?.pages?.[0]?.meta?.next?.idGt;
|
|
103
|
+
}
|
|
100
104
|
export function mergeMessageUpdate(record, current) {
|
|
101
105
|
if (!current) {
|
|
102
106
|
return record;
|
|
@@ -1 +1 @@
|
|
|
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
|
+
{"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 hasUnloadedNewerPages(queryClient: QueryClient, queryKey: unknown[]): boolean {\n const data = queryClient.getQueryData<MessagesQueryData>(queryKey)\n return !!data?.pages?.[0]?.meta?.next?.idGt\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,9 +1,14 @@
|
|
|
1
1
|
import type { MessageResource } from '../types/resources/message';
|
|
2
|
+
export declare const UNREAD_DIVIDER_KEY = "unread-divider";
|
|
2
3
|
export type DateSeparator = {
|
|
3
4
|
type: 'DateSeparator';
|
|
4
5
|
id: string;
|
|
5
6
|
date: string;
|
|
6
7
|
};
|
|
8
|
+
export type UnreadDividerItem = {
|
|
9
|
+
type: 'UnreadDivider';
|
|
10
|
+
id: typeof UNREAD_DIVIDER_KEY;
|
|
11
|
+
};
|
|
7
12
|
export type ReplyShadowMessage = {
|
|
8
13
|
type: 'ReplyShadowMessage';
|
|
9
14
|
id: string;
|
|
@@ -11,11 +16,13 @@ export type ReplyShadowMessage = {
|
|
|
11
16
|
isReplyShadowMessage: boolean;
|
|
12
17
|
nextRendersAuthor: boolean;
|
|
13
18
|
};
|
|
14
|
-
export type EnrichedMessage = MessageResource | DateSeparator | ReplyShadowMessage;
|
|
19
|
+
export type EnrichedMessage = MessageResource | DateSeparator | UnreadDividerItem | ReplyShadowMessage;
|
|
15
20
|
interface GroupMessagesProps {
|
|
16
21
|
ms: MessageResource[];
|
|
17
22
|
inReplyScreen?: boolean;
|
|
23
|
+
jumpToUnreadActive?: boolean;
|
|
24
|
+
initialMessageId?: string | null;
|
|
18
25
|
}
|
|
19
|
-
export declare function groupMessages({ ms, inReplyScreen }: GroupMessagesProps): EnrichedMessage[];
|
|
26
|
+
export declare function groupMessages({ ms, inReplyScreen, jumpToUnreadActive, initialMessageId, }: GroupMessagesProps): EnrichedMessage[];
|
|
20
27
|
export {};
|
|
21
28
|
//# 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,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,
|
|
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,eAAO,MAAM,kBAAkB,mBAAmB,CAAA;AAElD,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,iBAAiB,GAAG;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,EAAE,EAAE,OAAO,kBAAkB,CAAA;CAAE,CAAA;AAExF,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,GACvB,eAAe,GACf,aAAa,GACb,iBAAiB,GACjB,kBAAkB,CAAA;AAEtB,UAAU,kBAAkB;IAC1B,EAAE,EAAE,eAAe,EAAE,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAED,wBAAgB,aAAa,CAAC,EAC5B,EAAE,EACF,aAAa,EACb,kBAAkB,EAClB,gBAAgB,GACjB,EAAE,kBAAkB,GAAG,eAAe,EAAE,CAyCxC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import dayjs from './dayjs';
|
|
2
2
|
import { isSystemMessage } from './system_messages';
|
|
3
3
|
const FIVE_MINUTES_MS = 5 * 60 * 1000;
|
|
4
|
-
export
|
|
4
|
+
export const UNREAD_DIVIDER_KEY = 'unread-divider';
|
|
5
|
+
export function groupMessages({ ms, inReplyScreen, jumpToUnreadActive, initialMessageId, }) {
|
|
5
6
|
const items = [];
|
|
6
7
|
let myLatestSeen = false;
|
|
7
8
|
let nextNeighborEnriched;
|
|
@@ -11,6 +12,9 @@ export function groupMessages({ ms, inReplyScreen }) {
|
|
|
11
12
|
if (isSystemMessage(message)) {
|
|
12
13
|
const enriched = enrichSystemMessage(message, next);
|
|
13
14
|
items.push(enriched);
|
|
15
|
+
if (crossesUnreadBoundary(message, prev, jumpToUnreadActive, initialMessageId)) {
|
|
16
|
+
items.push(unreadDivider());
|
|
17
|
+
}
|
|
14
18
|
if (datesDifferBetween(message, prev))
|
|
15
19
|
items.push(dateSeparator(message));
|
|
16
20
|
nextNeighborEnriched = enriched;
|
|
@@ -21,6 +25,9 @@ export function groupMessages({ ms, inReplyScreen }) {
|
|
|
21
25
|
myLatestSeen = true;
|
|
22
26
|
const enriched = enrichRegularMessage(message, prev, next, isMyLatest, !!inReplyScreen);
|
|
23
27
|
items.push(enriched);
|
|
28
|
+
if (crossesUnreadBoundary(message, prev, jumpToUnreadActive, initialMessageId)) {
|
|
29
|
+
items.push(unreadDivider());
|
|
30
|
+
}
|
|
24
31
|
const shadow = replyShadowFor(enriched, prev);
|
|
25
32
|
if (shadow)
|
|
26
33
|
items.push(shadow);
|
|
@@ -31,6 +38,18 @@ export function groupMessages({ ms, inReplyScreen }) {
|
|
|
31
38
|
});
|
|
32
39
|
return items;
|
|
33
40
|
}
|
|
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
|
+
}
|
|
34
53
|
function neighborsOf(arr, i) {
|
|
35
54
|
return { prev: arr[i + 1], next: arr[i - 1] };
|
|
36
55
|
}
|
|
@@ -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 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"]}
|
|
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"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const FLUSH_DELAY_MS = 2000;
|
|
2
|
+
type SendFn = (args: {
|
|
3
|
+
conversationId: number;
|
|
4
|
+
sortKey: string;
|
|
5
|
+
}) => void;
|
|
6
|
+
export declare function makeHighestSeenTracker(conversationId: number, send: SendFn, flushDelayMs?: number): {
|
|
7
|
+
onSeen(sortKey: string): void;
|
|
8
|
+
flushNow(): void;
|
|
9
|
+
cancel(): void;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=highest_seen_tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highest_seen_tracker.d.ts","sourceRoot":"","sources":["../../src/utils/highest_seen_tracker.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,OAAO,CAAA;AAElC,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAAA;AAEzE,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,YAAY,GAAE,MAAuB;oBAcnB,MAAM;;;EAoBzB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const FLUSH_DELAY_MS = 2000;
|
|
2
|
+
export function makeHighestSeenTracker(conversationId, send, flushDelayMs = FLUSH_DELAY_MS) {
|
|
3
|
+
let highest = null;
|
|
4
|
+
let lastSent = null;
|
|
5
|
+
let timer = null;
|
|
6
|
+
const fire = () => {
|
|
7
|
+
timer = null;
|
|
8
|
+
if (!highest || highest === lastSent)
|
|
9
|
+
return;
|
|
10
|
+
lastSent = highest;
|
|
11
|
+
send({ conversationId, sortKey: highest });
|
|
12
|
+
};
|
|
13
|
+
return {
|
|
14
|
+
onSeen(sortKey) {
|
|
15
|
+
if (highest && sortKey.localeCompare(highest) <= 0)
|
|
16
|
+
return;
|
|
17
|
+
highest = sortKey;
|
|
18
|
+
if (timer)
|
|
19
|
+
clearTimeout(timer);
|
|
20
|
+
timer = setTimeout(fire, flushDelayMs);
|
|
21
|
+
},
|
|
22
|
+
flushNow() {
|
|
23
|
+
if (timer) {
|
|
24
|
+
clearTimeout(timer);
|
|
25
|
+
timer = null;
|
|
26
|
+
}
|
|
27
|
+
fire();
|
|
28
|
+
},
|
|
29
|
+
cancel() {
|
|
30
|
+
if (timer) {
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
timer = null;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=highest_seen_tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highest_seen_tracker.js","sourceRoot":"","sources":["../../src/utils/highest_seen_tracker.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAA;AAIlC,MAAM,UAAU,sBAAsB,CACpC,cAAsB,EACtB,IAAY,EACZ,eAAuB,cAAc;IAErC,IAAI,OAAO,GAAkB,IAAI,CAAA;IACjC,IAAI,QAAQ,GAAkB,IAAI,CAAA;IAClC,IAAI,KAAK,GAAyC,IAAI,CAAA;IAEtD,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,KAAK,GAAG,IAAI,CAAA;QACZ,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,QAAQ;YAAE,OAAM;QAC5C,QAAQ,GAAG,OAAO,CAAA;QAClB,IAAI,CAAC,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;IAC5C,CAAC,CAAA;IAED,OAAO;QACL,MAAM,CAAC,OAAe;YACpB,IAAI,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,OAAM;YAC1D,OAAO,GAAG,OAAO,CAAA;YACjB,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAA;YAC9B,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;QACxC,CAAC;QACD,QAAQ;YACN,IAAI,KAAK,EAAE,CAAC;gBACV,YAAY,CAAC,KAAK,CAAC,CAAA;gBACnB,KAAK,GAAG,IAAI,CAAA;YACd,CAAC;YACD,IAAI,EAAE,CAAA;QACR,CAAC;QACD,MAAM;YACJ,IAAI,KAAK,EAAE,CAAC;gBACV,YAAY,CAAC,KAAK,CAAC,CAAA;gBACnB,KAAK,GAAG,IAAI,CAAA;YACd,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["export const FLUSH_DELAY_MS = 2000\n\ntype SendFn = (args: { conversationId: number; sortKey: string }) => void\n\nexport function makeHighestSeenTracker(\n conversationId: number,\n send: SendFn,\n flushDelayMs: number = FLUSH_DELAY_MS\n) {\n let highest: string | null = null\n let lastSent: string | null = null\n let timer: ReturnType<typeof setTimeout> | null = null\n\n const fire = () => {\n timer = null\n if (!highest || highest === lastSent) return\n lastSent = highest\n send({ conversationId, sortKey: highest })\n }\n\n return {\n onSeen(sortKey: string) {\n if (highest && sortKey.localeCompare(highest) <= 0) return\n highest = sortKey\n if (timer) clearTimeout(timer)\n timer = setTimeout(fire, flushDelayMs)\n },\n flushNow() {\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n fire()\n },\n cancel() {\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ViewableEntry<Item> {
|
|
2
|
+
key: string;
|
|
3
|
+
isViewable: boolean;
|
|
4
|
+
item: Item;
|
|
5
|
+
}
|
|
6
|
+
export interface ViewabilityEvent<Item> {
|
|
7
|
+
viewableItems: ViewableEntry<Item>[];
|
|
8
|
+
changed: ViewableEntry<Item>[];
|
|
9
|
+
userHasScrolled: boolean;
|
|
10
|
+
}
|
|
11
|
+
export type ViewabilityObserver<Item> = (event: ViewabilityEvent<Item>) => void;
|
|
12
|
+
export declare function reportViewableMessages<Item extends {
|
|
13
|
+
id?: string;
|
|
14
|
+
type?: string;
|
|
15
|
+
}>(onMessageSeen: (id: string) => void): ViewabilityObserver<Item>;
|
|
16
|
+
export declare function detectDividerExitTowardNewer<Item extends {
|
|
17
|
+
id?: string;
|
|
18
|
+
type?: string;
|
|
19
|
+
}>({ dividerKey, initialMessageId, onExited, }: {
|
|
20
|
+
dividerKey: string;
|
|
21
|
+
initialMessageId: string | null;
|
|
22
|
+
onExited: () => void;
|
|
23
|
+
}): ViewabilityObserver<Item>;
|
|
24
|
+
//# sourceMappingURL=message_viewability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message_viewability.d.ts","sourceRoot":"","sources":["../../src/utils/message_viewability.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa,CAAC,IAAI;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,OAAO,CAAA;IACnB,IAAI,EAAE,IAAI,CAAA;CACX;AAED,MAAM,WAAW,gBAAgB,CAAC,IAAI;IACpC,aAAa,EAAE,aAAa,CAAC,IAAI,CAAC,EAAE,CAAA;IACpC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,EAAE,CAAA;IAC9B,eAAe,EAAE,OAAO,CAAA;CACzB;AAED,MAAM,MAAM,mBAAmB,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,gBAAgB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;AAE/E,wBAAgB,sBAAsB,CAAC,IAAI,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAChF,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,GAClC,mBAAmB,CAAC,IAAI,CAAC,CAS3B;AAED,wBAAgB,4BAA4B,CAAC,IAAI,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EACxF,UAAU,EACV,gBAAgB,EAChB,QAAQ,GACT,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAW5B"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { dividerExitedTowardNewer } from './unread_divider_helpers';
|
|
2
|
+
export function reportViewableMessages(onMessageSeen) {
|
|
3
|
+
return ({ viewableItems, userHasScrolled }) => {
|
|
4
|
+
if (!userHasScrolled)
|
|
5
|
+
return;
|
|
6
|
+
for (const entry of viewableItems) {
|
|
7
|
+
if (entry.item?.type !== 'Message')
|
|
8
|
+
continue;
|
|
9
|
+
const id = entry.item?.id;
|
|
10
|
+
if (typeof id === 'string')
|
|
11
|
+
onMessageSeen(id);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function detectDividerExitTowardNewer({ dividerKey, initialMessageId, onExited, }) {
|
|
16
|
+
return ({ viewableItems, changed, userHasScrolled }) => {
|
|
17
|
+
if (!userHasScrolled || !initialMessageId)
|
|
18
|
+
return;
|
|
19
|
+
const exited = dividerExitedTowardNewer({
|
|
20
|
+
changed,
|
|
21
|
+
viewableItems,
|
|
22
|
+
dividerKey,
|
|
23
|
+
initialMessageId,
|
|
24
|
+
});
|
|
25
|
+
if (exited)
|
|
26
|
+
onExited();
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=message_viewability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message_viewability.js","sourceRoot":"","sources":["../../src/utils/message_viewability.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAA;AAgBnE,MAAM,UAAU,sBAAsB,CACpC,aAAmC;IAEnC,OAAO,CAAC,EAAE,aAAa,EAAE,eAAe,EAAE,EAAE,EAAE;QAC5C,IAAI,CAAC,eAAe;YAAE,OAAM;QAC5B,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;YAClC,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,SAAS;gBAAE,SAAQ;YAC5C,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,CAAA;YACzB,IAAI,OAAO,EAAE,KAAK,QAAQ;gBAAE,aAAa,CAAC,EAAE,CAAC,CAAA;QAC/C,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,4BAA4B,CAA8C,EACxF,UAAU,EACV,gBAAgB,EAChB,QAAQ,GAKT;IACC,OAAO,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE;QACrD,IAAI,CAAC,eAAe,IAAI,CAAC,gBAAgB;YAAE,OAAM;QACjD,MAAM,MAAM,GAAG,wBAAwB,CAAC;YACtC,OAAO;YACP,aAAa;YACb,UAAU;YACV,gBAAgB;SACjB,CAAC,CAAA;QACF,IAAI,MAAM;YAAE,QAAQ,EAAE,CAAA;IACxB,CAAC,CAAA;AACH,CAAC","sourcesContent":["import { dividerExitedTowardNewer } from './unread_divider_helpers'\n\nexport interface ViewableEntry<Item> {\n key: string\n isViewable: boolean\n item: Item\n}\n\nexport interface ViewabilityEvent<Item> {\n viewableItems: ViewableEntry<Item>[]\n changed: ViewableEntry<Item>[]\n userHasScrolled: boolean\n}\n\nexport type ViewabilityObserver<Item> = (event: ViewabilityEvent<Item>) => void\n\nexport function reportViewableMessages<Item extends { id?: string; type?: string }>(\n onMessageSeen: (id: string) => void\n): ViewabilityObserver<Item> {\n return ({ viewableItems, userHasScrolled }) => {\n if (!userHasScrolled) return\n for (const entry of viewableItems) {\n if (entry.item?.type !== 'Message') continue\n const id = entry.item?.id\n if (typeof id === 'string') onMessageSeen(id)\n }\n }\n}\n\nexport function detectDividerExitTowardNewer<Item extends { id?: string; type?: string }>({\n dividerKey,\n initialMessageId,\n onExited,\n}: {\n dividerKey: string\n initialMessageId: string | null\n onExited: () => void\n}): ViewabilityObserver<Item> {\n return ({ viewableItems, changed, userHasScrolled }) => {\n if (!userHasScrolled || !initialMessageId) return\n const exited = dividerExitedTowardNewer({\n changed,\n viewableItems,\n dividerKey,\n initialMessageId,\n })\n if (exited) onExited()\n }\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type ViewableChangeEntry = {
|
|
2
|
+
key: string;
|
|
3
|
+
isViewable: boolean;
|
|
4
|
+
};
|
|
5
|
+
type ViewableItem = {
|
|
6
|
+
item: {
|
|
7
|
+
id?: string;
|
|
8
|
+
type?: string;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export declare function dividerExitedTowardNewer({ changed, viewableItems, dividerKey, initialMessageId, }: {
|
|
12
|
+
changed: ViewableChangeEntry[];
|
|
13
|
+
viewableItems: ViewableItem[];
|
|
14
|
+
dividerKey: string;
|
|
15
|
+
initialMessageId: string;
|
|
16
|
+
}): boolean;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=unread_divider_helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unread_divider_helpers.d.ts","sourceRoot":"","sources":["../../src/utils/unread_divider_helpers.ts"],"names":[],"mappings":"AAAA,KAAK,mBAAmB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAA;AAC/D,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAA;AAE5D,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,aAAa,EACb,UAAU,EACV,gBAAgB,GACjB,EAAE;IACD,OAAO,EAAE,mBAAmB,EAAE,CAAA;IAC9B,aAAa,EAAE,YAAY,EAAE,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,gBAAgB,EAAE,MAAM,CAAA;CACzB,GAAG,OAAO,CAWV"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function dividerExitedTowardNewer({ changed, viewableItems, dividerKey, initialMessageId, }) {
|
|
2
|
+
const dividerExited = changed.some(c => c.key === dividerKey && !c.isViewable);
|
|
3
|
+
if (!dividerExited)
|
|
4
|
+
return false;
|
|
5
|
+
const visibleMessageIds = viewableItems
|
|
6
|
+
.filter(v => v.item?.type === 'Message')
|
|
7
|
+
.map(v => v.item?.id)
|
|
8
|
+
.filter((id) => !!id);
|
|
9
|
+
if (visibleMessageIds.length === 0)
|
|
10
|
+
return false;
|
|
11
|
+
return visibleMessageIds.every(id => id.localeCompare(initialMessageId) > 0);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=unread_divider_helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unread_divider_helpers.js","sourceRoot":"","sources":["../../src/utils/unread_divider_helpers.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,wBAAwB,CAAC,EACvC,OAAO,EACP,aAAa,EACb,UAAU,EACV,gBAAgB,GAMjB;IACC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,UAAU,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;IAC9E,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAA;IAEhC,MAAM,iBAAiB,GAAG,aAAa;SACpC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC;SACvC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IACrC,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAEhD,OAAO,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAA;AAC9E,CAAC","sourcesContent":["type ViewableChangeEntry = { key: string; isViewable: boolean }\ntype ViewableItem = { item: { id?: string; type?: string } }\n\nexport function dividerExitedTowardNewer({\n changed,\n viewableItems,\n dividerKey,\n initialMessageId,\n}: {\n changed: ViewableChangeEntry[]\n viewableItems: ViewableItem[]\n dividerKey: string\n initialMessageId: string\n}): boolean {\n const dividerExited = changed.some(c => c.key === dividerKey && !c.isViewable)\n if (!dividerExited) return false\n\n const visibleMessageIds = viewableItems\n .filter(v => v.item?.type === 'Message')\n .map(v => v.item?.id)\n .filter((id): id is string => !!id)\n if (visibleMessageIds.length === 0) return false\n\n return visibleMessageIds.every(id => id.localeCompare(initialMessageId) > 0)\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "3.35.0-rc.
|
|
3
|
+
"version": "3.35.0-rc.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -52,9 +52,12 @@
|
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@react-native/eslint-config": "~0.83.0",
|
|
55
|
-
"@testing-library/react-
|
|
55
|
+
"@testing-library/react-native": "^13.2.0",
|
|
56
|
+
"@types/color": "^3.0.0",
|
|
56
57
|
"@types/jest": "^29.5.14",
|
|
57
|
-
"@typescript-eslint/parser": "^8.
|
|
58
|
+
"@typescript-eslint/parser": "^8.36.0",
|
|
59
|
+
"color": "^3.1.2",
|
|
60
|
+
"eslint": "8.57.1",
|
|
58
61
|
"eslint-plugin-react-compiler": "^19.1.0-rc.2",
|
|
59
62
|
"expo-module-scripts": "^55.0.0",
|
|
60
63
|
"fast-text-encoding": "^1.0.6",
|
|
@@ -62,8 +65,11 @@
|
|
|
62
65
|
"jest-fetch-mock": "^3.0.3",
|
|
63
66
|
"msw": "^2.7.3",
|
|
64
67
|
"prettier": "^3.4.2",
|
|
68
|
+
"react": "19.2.0",
|
|
69
|
+
"react-native": "0.83.6",
|
|
70
|
+
"react-native-svg": "15.15.3",
|
|
65
71
|
"react-native-url-polyfill": "^2.0.0",
|
|
66
72
|
"typescript": "~5.9.2"
|
|
67
73
|
},
|
|
68
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "944a6cf0bdfa1ada82ec68c9e79c8fd3ae522e15"
|
|
69
75
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import AsyncStorage from '@react-native-async-storage/async-storage'
|
|
2
2
|
import { QueryClientProvider } from '@tanstack/react-query'
|
|
3
|
-
import { renderHook, act } from '@testing-library/react-
|
|
3
|
+
import { renderHook, act } from '@testing-library/react-native'
|
|
4
4
|
import React, { useContext, Suspense } from 'react'
|
|
5
5
|
import { buildTestQueryClient } from '../../__utils__/query_client'
|
|
6
6
|
import {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import AsyncStorage from '@react-native-async-storage/async-storage'
|
|
2
2
|
import { QueryClientProvider } from '@tanstack/react-query'
|
|
3
|
-
import { renderHook, act } from '@testing-library/react-
|
|
3
|
+
import { renderHook, act } from '@testing-library/react-native'
|
|
4
4
|
import React, { Suspense } from 'react'
|
|
5
5
|
import { buildTestQueryClient } from '../../__utils__/query_client'
|
|
6
6
|
import { useAsyncStorage } from '../../hooks/use_async_storage'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { QueryClientProvider } from '@tanstack/react-query'
|
|
2
|
-
import { renderHook, act } from '@testing-library/react-
|
|
2
|
+
import { renderHook, act } from '@testing-library/react-native'
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import { buildTestQueryClient } from '../../__utils__/query_client'
|
|
5
5
|
import { useApiClient } from '../../hooks/use_api_client'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { QueryClientProvider } from '@tanstack/react-query'
|
|
2
|
-
import { renderHook, act } from '@testing-library/react-
|
|
2
|
+
import { renderHook, act } from '@testing-library/react-native'
|
|
3
3
|
import React, { Suspense } from 'react'
|
|
4
4
|
import { buildTestQueryClient } from '../../__utils__/query_client'
|
|
5
5
|
import {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { QueryClientProvider } from '@tanstack/react-query'
|
|
2
|
-
import { act, renderHook } from '@testing-library/react-
|
|
2
|
+
import { act, renderHook } from '@testing-library/react-native'
|
|
3
3
|
import React, { Suspense } from 'react'
|
|
4
4
|
import { buildTestQueryClient } from '../../__utils__/query_client'
|
|
5
5
|
import { ConversationContextProvider } from '../../contexts/conversation_context'
|