@planningcenter/chat-react-native 3.1.0-rc.1 → 3.1.0-rc.2

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.
Files changed (32) hide show
  1. package/build/components/conversation/message_form.js +2 -2
  2. package/build/components/conversation/message_form.js.map +1 -1
  3. package/build/components/conversation/message_reaction.d.ts +1 -1
  4. package/build/components/conversation/message_reaction.d.ts.map +1 -1
  5. package/build/components/conversation/message_reaction.js +4 -0
  6. package/build/components/conversation/message_reaction.js.map +1 -1
  7. package/build/hooks/use_conversation_jolt_events.js +2 -2
  8. package/build/hooks/use_conversation_jolt_events.js.map +1 -1
  9. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  10. package/build/hooks/use_conversation_messages.js +2 -2
  11. package/build/hooks/use_conversation_messages.js.map +1 -1
  12. package/build/hooks/use_conversation_messages_jolt_events.d.ts +1 -2
  13. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
  14. package/build/hooks/use_conversation_messages_jolt_events.js +63 -9
  15. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
  16. package/build/utils/cache/page_mutations.d.ts +21 -2
  17. package/build/utils/cache/page_mutations.d.ts.map +1 -1
  18. package/build/utils/cache/page_mutations.js +19 -2
  19. package/build/utils/cache/page_mutations.js.map +1 -1
  20. package/build/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.d.ts +12 -0
  21. package/build/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.d.ts.map +1 -0
  22. package/build/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.js +20 -0
  23. package/build/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.js.map +1 -0
  24. package/package.json +2 -2
  25. package/src/__tests__/utils/cache/page_mutations.ts +85 -3
  26. package/src/components/conversation/message_form.tsx +2 -2
  27. package/src/components/conversation/message_reaction.tsx +3 -0
  28. package/src/hooks/use_conversation_jolt_events.ts +2 -2
  29. package/src/hooks/use_conversation_messages.ts +5 -2
  30. package/src/hooks/use_conversation_messages_jolt_events.ts +75 -11
  31. package/src/utils/cache/page_mutations.ts +31 -3
  32. package/src/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.ts +36 -0
@@ -6,7 +6,7 @@ import { IconButton } from '../../components';
6
6
  import { useTheme } from '../../hooks';
7
7
  import { useApiClient } from '../../hooks/use_api_client';
8
8
  import { getMessagesQueryKey, getMessagesRequestArgs } from '../../hooks/use_conversation_messages';
9
- import { updateRecordInPagesData } from '../../utils';
9
+ import { updateOrCreateRecordInPagesData } from '../../utils';
10
10
  export const MessageForm = {
11
11
  Root: MessageFormRoot,
12
12
  TextInput: MessageFormInput,
@@ -45,7 +45,7 @@ function MessageFormRoot({ conversation, children }) {
45
45
  const updatedMessage = result.data;
46
46
  const queryKey = getMessagesQueryKey({ conversation_id: conversation.id });
47
47
  setText('');
48
- queryClient.setQueryData(queryKey, data => updateRecordInPagesData({
48
+ queryClient.setQueryData(queryKey, data => updateOrCreateRecordInPagesData({
49
49
  data,
50
50
  record: updatedMessage,
51
51
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"message_form.js","sourceRoot":"","sources":["../../../src/components/conversation/message_form.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useTheme as useNavigationTheme } from '@react-navigation/native'\nimport { InfiniteData, useMutation, useQueryClient } from '@tanstack/react-query'\nimport React from 'react'\nimport { StyleSheet, TextInput, View, ViewProps } from 'react-native'\nimport { IconButton } from '../../components'\nimport { useTheme } from '../../hooks'\nimport { useApiClient } from '../../hooks/use_api_client'\nimport { getMessagesQueryKey, getMessagesRequestArgs } from '../../hooks/use_conversation_messages'\nimport { ApiCollection, ApiResource, ConversationResource, MessageResource } from '../../types'\nimport { updateRecordInPagesData } from '../../utils'\n\nexport const MessageForm = {\n Root: MessageFormRoot,\n TextInput: MessageFormInput,\n SubmitButton: MessageFormSubmitBtn,\n AttachmentPicker: MessageFormAttachmentPicker,\n Commands: MessageFormCommands,\n}\n\ninterface MessagesFormRootProps extends ViewProps {\n conversation: ConversationResource\n}\n\nconst MessageFormContext = React.createContext({\n text: '',\n setText: (_text: string) => {},\n onSubmit: () => {},\n disabled: false,\n})\n\nfunction MessageFormRoot({ conversation, children }: MessagesFormRootProps) {\n const styles = useMessageFormStyles()\n const [text, setText] = React.useState('')\n const apiClient = useApiClient()\n const queryClient = useQueryClient()\n\n const { mutate, isPending } = useMutation({\n mutationFn: async () => {\n const requestParams = getMessagesRequestArgs({ conversation_id: conversation.id })\n const fieldsWithValueJoined = Object.fromEntries(\n Object.entries(requestParams.data.fields).map(([k, v]) => [k, v.join(',')])\n )\n\n return apiClient.chat.post({\n url: `/me/conversations/${conversation.id}/messages`,\n data: {\n ...requestParams.data,\n data: {\n type: 'Message',\n attributes: { text },\n },\n fields: fieldsWithValueJoined,\n },\n })\n },\n onSuccess: (result: ApiResource<MessageResource>) => {\n const updatedMessage = result.data\n type QueryData = InfiniteData<ApiCollection<MessageResource>>\n const queryKey = getMessagesQueryKey({ conversation_id: conversation.id })\n\n setText('')\n queryClient.setQueryData<QueryData>(queryKey, data =>\n updateRecordInPagesData({\n data,\n record: updatedMessage,\n })\n )\n },\n })\n\n return (\n <MessageFormContext.Provider\n value={{ text, setText, onSubmit: () => mutate(), disabled: isPending }}\n >\n <View style={styles.textInputContainer}>{children}</View>\n </MessageFormContext.Provider>\n )\n}\n\nfunction MessageFormInput() {\n const styles = useMessageFormStyles()\n const { text, setText, onSubmit } = React.useContext(MessageFormContext)\n\n return (\n <TextInput\n aria-disabled={true}\n placeholder=\"Send a message\"\n onChangeText={setText}\n value={text}\n style={styles.textInput}\n onSubmitEditing={onSubmit}\n />\n )\n}\n\nfunction MessageFormSubmitBtn() {\n const styles = useMessageFormStyles()\n const { onSubmit, disabled } = React.useContext(MessageFormContext)\n\n return (\n <IconButton\n disabled={disabled}\n accessibilityLabel=\"Send message\"\n size=\"md\"\n appearance=\"neutral\"\n style={styles.textInputSend}\n name={'general.upArrow'}\n onPress={onSubmit}\n />\n )\n}\n\nfunction MessageFormAttachmentPicker() {\n return (\n <IconButton\n accessibilityLabel=\"Shazam\"\n size=\"md\"\n appearance=\"neutral\"\n name={'general.paperclip'}\n />\n )\n}\n\nfunction MessageFormCommands() {\n return (\n <IconButton accessibilityLabel=\"Shazam\" size=\"md\" appearance=\"neutral\" name={'general.bolt'} />\n )\n}\n\nconst useMessageFormStyles = () => {\n const theme = useTheme()\n const navigationTheme = useNavigationTheme()\n\n return StyleSheet.create({\n textInputContainer: {\n borderColor: theme.colors.fillColorNeutral050Base,\n borderTopWidth: 1,\n padding: 12,\n backgroundColor: navigationTheme.colors.card,\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n },\n textInput: {\n borderRadius: 24,\n borderWidth: 1,\n padding: 12,\n paddingHorizontal: 20,\n borderColor: theme.colors.fillColorNeutral050Base,\n flex: 1,\n },\n textInputSend: {\n borderRadius: 24,\n height: 36,\n width: 36,\n backgroundColor: theme.colors.fillColorNeutral040,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"message_form.js","sourceRoot":"","sources":["../../../src/components/conversation/message_form.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useTheme as useNavigationTheme } from '@react-navigation/native'\nimport { InfiniteData, useMutation, useQueryClient } from '@tanstack/react-query'\nimport React from 'react'\nimport { StyleSheet, TextInput, View, ViewProps } from 'react-native'\nimport { IconButton } from '../../components'\nimport { useTheme } from '../../hooks'\nimport { useApiClient } from '../../hooks/use_api_client'\nimport { getMessagesQueryKey, getMessagesRequestArgs } from '../../hooks/use_conversation_messages'\nimport { ApiCollection, ApiResource, ConversationResource, MessageResource } from '../../types'\nimport { updateOrCreateRecordInPagesData } from '../../utils'\n\nexport const MessageForm = {\n Root: MessageFormRoot,\n TextInput: MessageFormInput,\n SubmitButton: MessageFormSubmitBtn,\n AttachmentPicker: MessageFormAttachmentPicker,\n Commands: MessageFormCommands,\n}\n\ninterface MessagesFormRootProps extends ViewProps {\n conversation: ConversationResource\n}\n\nconst MessageFormContext = React.createContext({\n text: '',\n setText: (_text: string) => {},\n onSubmit: () => {},\n disabled: false,\n})\n\nfunction MessageFormRoot({ conversation, children }: MessagesFormRootProps) {\n const styles = useMessageFormStyles()\n const [text, setText] = React.useState('')\n const apiClient = useApiClient()\n const queryClient = useQueryClient()\n\n const { mutate, isPending } = useMutation({\n mutationFn: async () => {\n const requestParams = getMessagesRequestArgs({ conversation_id: conversation.id })\n const fieldsWithValueJoined = Object.fromEntries(\n Object.entries(requestParams.data.fields).map(([k, v]) => [k, v.join(',')])\n )\n\n return apiClient.chat.post({\n url: `/me/conversations/${conversation.id}/messages`,\n data: {\n ...requestParams.data,\n data: {\n type: 'Message',\n attributes: { text },\n },\n fields: fieldsWithValueJoined,\n },\n })\n },\n onSuccess: (result: ApiResource<MessageResource>) => {\n const updatedMessage = result.data\n type QueryData = InfiniteData<ApiCollection<MessageResource>>\n const queryKey = getMessagesQueryKey({ conversation_id: conversation.id })\n\n setText('')\n queryClient.setQueryData<QueryData>(queryKey, data =>\n updateOrCreateRecordInPagesData({\n data,\n record: updatedMessage,\n })\n )\n },\n })\n\n return (\n <MessageFormContext.Provider\n value={{ text, setText, onSubmit: () => mutate(), disabled: isPending }}\n >\n <View style={styles.textInputContainer}>{children}</View>\n </MessageFormContext.Provider>\n )\n}\n\nfunction MessageFormInput() {\n const styles = useMessageFormStyles()\n const { text, setText, onSubmit } = React.useContext(MessageFormContext)\n\n return (\n <TextInput\n aria-disabled={true}\n placeholder=\"Send a message\"\n onChangeText={setText}\n value={text}\n style={styles.textInput}\n onSubmitEditing={onSubmit}\n />\n )\n}\n\nfunction MessageFormSubmitBtn() {\n const styles = useMessageFormStyles()\n const { onSubmit, disabled } = React.useContext(MessageFormContext)\n\n return (\n <IconButton\n disabled={disabled}\n accessibilityLabel=\"Send message\"\n size=\"md\"\n appearance=\"neutral\"\n style={styles.textInputSend}\n name={'general.upArrow'}\n onPress={onSubmit}\n />\n )\n}\n\nfunction MessageFormAttachmentPicker() {\n return (\n <IconButton\n accessibilityLabel=\"Shazam\"\n size=\"md\"\n appearance=\"neutral\"\n name={'general.paperclip'}\n />\n )\n}\n\nfunction MessageFormCommands() {\n return (\n <IconButton accessibilityLabel=\"Shazam\" size=\"md\" appearance=\"neutral\" name={'general.bolt'} />\n )\n}\n\nconst useMessageFormStyles = () => {\n const theme = useTheme()\n const navigationTheme = useNavigationTheme()\n\n return StyleSheet.create({\n textInputContainer: {\n borderColor: theme.colors.fillColorNeutral050Base,\n borderTopWidth: 1,\n padding: 12,\n backgroundColor: navigationTheme.colors.card,\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n },\n textInput: {\n borderRadius: 24,\n borderWidth: 1,\n padding: 12,\n paddingHorizontal: 20,\n borderColor: theme.colors.fillColorNeutral050Base,\n flex: 1,\n },\n textInputSend: {\n borderRadius: 24,\n height: 36,\n width: 36,\n backgroundColor: theme.colors.fillColorNeutral040,\n },\n })\n}\n"]}
@@ -4,7 +4,7 @@ export declare const REACTION_EMOJIS: Record<ReactionCountResource['value'], str
4
4
  export declare function MessageReaction({ reaction, onPress, }: {
5
5
  reaction: ReactionCountResource;
6
6
  onPress: (_reaction: ReactionCountResource) => void;
7
- }): React.JSX.Element;
7
+ }): React.JSX.Element | null;
8
8
  export declare const useReactionStyles: ({ mine }: {
9
9
  mine: number;
10
10
  }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"message_reaction.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/message_reaction.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AAEtE,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,CAM1E,CAAA;AAED,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,OAAO,EAAE,CAAC,SAAS,EAAE,qBAAqB,KAAK,IAAI,CAAA;CACpD,qBAaA;AAED,eAAO,MAAM,iBAAiB,aAAc;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;CAoB3D,CAAA"}
1
+ {"version":3,"file":"message_reaction.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/message_reaction.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AAEtE,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,CAM1E,CAAA;AAED,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,OAAO,EAAE,CAAC,SAAS,EAAE,qBAAqB,KAAK,IAAI,CAAA;CACpD,4BAgBA;AAED,eAAO,MAAM,iBAAiB,aAAc;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;CAoB3D,CAAA"}
@@ -13,6 +13,10 @@ export const REACTION_EMOJIS = {
13
13
  };
14
14
  export function MessageReaction({ reaction, onPress, }) {
15
15
  const styles = useReactionStyles(reaction);
16
+ if (!reaction.count)
17
+ return null;
18
+ if (!REACTION_EMOJIS[reaction.value])
19
+ return null;
16
20
  return (<PlatformPressable key={reaction.value} style={styles.reaction} onPress={() => onPress(reaction)}>
17
21
  <Text style={styles.reactionEmoji}>{REACTION_EMOJIS[reaction.value]}</Text>
18
22
  <Text style={styles.reactionText}>{reaction.count}</Text>
@@ -1 +1 @@
1
- {"version":3,"file":"message_reaction.js","sourceRoot":"","sources":["../../../src/components/conversation/message_reaction.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,aAAa,MAAM,OAAO,CAAA;AACjC,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGtC,MAAM,CAAC,MAAM,eAAe,GAAmD;IAC7E,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,IAAI;IACjB,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;CACZ,CAAA;AAED,MAAM,UAAU,eAAe,CAAC,EAC9B,QAAQ,EACR,OAAO,GAIR;IACC,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IAE1C,OAAO,CACL,CAAC,iBAAiB,CAChB,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CACpB,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CACvB,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAEjC;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAC1E;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAC1D;IAAA,EAAE,iBAAiB,CAAC,CACrB,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,EAAE,IAAI,EAAoB,EAAE,EAAE;IAC9D,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,MAAM,iBAAiB,GAAG,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAA;IAC/E,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAA;IAEzE,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,QAAQ,EAAE;YACR,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,mBAAmB;YAClE,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,uBAAuB;YACpE,YAAY,EAAE,EAAE;YAChB,eAAe,EAAE,CAAC;YAClB,iBAAiB,EAAE,EAAE;YACrB,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,CAAC;SACP;QACD,aAAa,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE;QAC9C,YAAY,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,uBAAuB,EAAE;KACtE,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { PlatformPressable } from '@react-navigation/elements'\nimport colorFunction from 'color'\nimport React from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Text } from '../../components/display'\nimport { useTheme } from '../../hooks'\nimport { ReactionCountResource } from '../../types/resources/reaction'\n\nexport const REACTION_EMOJIS: Record<ReactionCountResource['value'], string> = {\n thumbs_up: '👍',\n thumbs_down: '👎',\n pray: '🙏',\n laugh: '😂',\n heart: '❤️',\n}\n\nexport function MessageReaction({\n reaction,\n onPress,\n}: {\n reaction: ReactionCountResource\n onPress: (_reaction: ReactionCountResource) => void\n}) {\n const styles = useReactionStyles(reaction)\n\n return (\n <PlatformPressable\n key={reaction.value}\n style={styles.reaction}\n onPress={() => onPress(reaction)}\n >\n <Text style={styles.reactionEmoji}>{REACTION_EMOJIS[reaction.value]}</Text>\n <Text style={styles.reactionText}>{reaction.count}</Text>\n </PlatformPressable>\n )\n}\n\nexport const useReactionStyles = ({ mine }: { mine: number }) => {\n const { colors } = useTheme()\n const activeBorderColor = colorFunction(colors.interaction).alpha(0.8).string()\n const activeColor = colorFunction(colors.interaction).alpha(0.2).string()\n\n return StyleSheet.create({\n reaction: {\n borderWidth: 1,\n borderColor: mine ? activeBorderColor : colors.fillColorNeutral040,\n backgroundColor: mine ? activeColor : colors.fillColorNeutral050Base,\n borderRadius: 16,\n paddingVertical: 2,\n paddingHorizontal: 12,\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n },\n reactionEmoji: { fontSize: 12, paddingTop: 0 },\n reactionText: { fontSize: 12, color: colors.textColorDefaultPrimary },\n })\n}\n"]}
1
+ {"version":3,"file":"message_reaction.js","sourceRoot":"","sources":["../../../src/components/conversation/message_reaction.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,aAAa,MAAM,OAAO,CAAA;AACjC,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGtC,MAAM,CAAC,MAAM,eAAe,GAAmD;IAC7E,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,IAAI;IACjB,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;CACZ,CAAA;AAED,MAAM,UAAU,eAAe,CAAC,EAC9B,QAAQ,EACR,OAAO,GAIR;IACC,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IAE1C,IAAI,CAAC,QAAQ,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IAChC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAEjD,OAAO,CACL,CAAC,iBAAiB,CAChB,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CACpB,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CACvB,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAEjC;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAC1E;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAC1D;IAAA,EAAE,iBAAiB,CAAC,CACrB,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,EAAE,IAAI,EAAoB,EAAE,EAAE;IAC9D,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,MAAM,iBAAiB,GAAG,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAA;IAC/E,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAA;IAEzE,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,QAAQ,EAAE;YACR,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,mBAAmB;YAClE,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,uBAAuB;YACpE,YAAY,EAAE,EAAE;YAChB,eAAe,EAAE,CAAC;YAClB,iBAAiB,EAAE,EAAE;YACrB,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,CAAC;SACP;QACD,aAAa,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE;QAC9C,YAAY,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,uBAAuB,EAAE;KACtE,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { PlatformPressable } from '@react-navigation/elements'\nimport colorFunction from 'color'\nimport React from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Text } from '../../components/display'\nimport { useTheme } from '../../hooks'\nimport { ReactionCountResource } from '../../types/resources/reaction'\n\nexport const REACTION_EMOJIS: Record<ReactionCountResource['value'], string> = {\n thumbs_up: '👍',\n thumbs_down: '👎',\n pray: '🙏',\n laugh: '😂',\n heart: '❤️',\n}\n\nexport function MessageReaction({\n reaction,\n onPress,\n}: {\n reaction: ReactionCountResource\n onPress: (_reaction: ReactionCountResource) => void\n}) {\n const styles = useReactionStyles(reaction)\n\n if (!reaction.count) return null\n if (!REACTION_EMOJIS[reaction.value]) return null\n\n return (\n <PlatformPressable\n key={reaction.value}\n style={styles.reaction}\n onPress={() => onPress(reaction)}\n >\n <Text style={styles.reactionEmoji}>{REACTION_EMOJIS[reaction.value]}</Text>\n <Text style={styles.reactionText}>{reaction.count}</Text>\n </PlatformPressable>\n )\n}\n\nexport const useReactionStyles = ({ mine }: { mine: number }) => {\n const { colors } = useTheme()\n const activeBorderColor = colorFunction(colors.interaction).alpha(0.8).string()\n const activeColor = colorFunction(colors.interaction).alpha(0.2).string()\n\n return StyleSheet.create({\n reaction: {\n borderWidth: 1,\n borderColor: mine ? activeBorderColor : colors.fillColorNeutral040,\n backgroundColor: mine ? activeColor : colors.fillColorNeutral050Base,\n borderRadius: 16,\n paddingVertical: 2,\n paddingHorizontal: 12,\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n },\n reactionEmoji: { fontSize: 12, paddingTop: 0 },\n reactionText: { fontSize: 12, color: colors.textColorDefaultPrimary },\n })\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { useQueryClient } from '@tanstack/react-query';
2
- import { deleteRecordInPagesData, updateRecordInPagesData } from '../utils';
2
+ import { deleteRecordInPagesData, updateOrCreateRecordInPagesData } from '../utils';
3
3
  import { useApiClient } from './use_api_client';
4
4
  import { getConversationsRequestArgs } from './use_conversations';
5
5
  import { useCurrentPerson } from './use_current_person';
@@ -25,7 +25,7 @@ export function useConversationsJoltEvents() {
25
25
  };
26
26
  const handleConversationUpdateOrCreate = async (e) => {
27
27
  const conversation = await fetchConversation(e.data.data).catch(c => c);
28
- queryClient.setQueryData(conversationQueryKey, prev => updateRecordInPagesData({
28
+ queryClient.setQueryData(conversationQueryKey, prev => updateOrCreateRecordInPagesData({
29
29
  data: prev,
30
30
  record: conversation,
31
31
  processRecord: (record, current) => {
@@ -1 +1 @@
1
- {"version":3,"file":"use_conversation_jolt_events.js","sourceRoot":"","sources":["../../src/hooks/use_conversation_jolt_events.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEpE,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AASvD,MAAM,UAAU,0BAA0B;IACxC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IACpC,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAA;IACxC,MAAM,WAAW,GAAG,cAAc,CAAC,eAAe,aAAa,CAAC,EAAE,EAAE,CAAC,CAAA;IAErE,MAAM,wBAAwB,GAAG,2BAA2B,EAAE,CAAA;IAC9D,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,wBAAwB,CAAC,CAAA;IAEzE,MAAM,iBAAiB,GAAG,KAAK,EAAE,EAAE,EAAE,EAAwB,EAAE,EAAE;QAC/D,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,wBAAwB,CAAA;QACnD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,CAAoC;YAC3E,GAAG,EAAE,qBAAqB,EAAE,EAAE;YAC9B,IAAI,EAAE;gBACJ,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;aAC1B;SACF,CAAC,CAAA;QAEF,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;IAED,MAAM,gCAAgC,GAAG,KAAK,EAAE,CAAyB,EAAE,EAAE;QAC3E,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAEvE,WAAW,CAAC,YAAY,CAAY,oBAAoB,EAAE,IAAI,CAAC,EAAE,CAC/D,uBAAuB,CAAC;YACtB,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,YAAY;YACpB,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;gBACjC,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAA;YAClC,CAAC;SACF,CAAC,CACH,CAAA;IACH,CAAC,CAAA;IAED,MAAM,yBAAyB,GAAG,CAAC,CAAyB,EAAE,EAAE;QAC9D,WAAW,CAAC,YAAY,CAAY,oBAAoB,EAAE,IAAI,CAAC,EAAE,CAC/D,uBAAuB,CAAC;YACtB,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;SACpB,CAAC,CACH,CAAA;IACH,CAAC,CAAA;IAED,YAAY,CAAC,WAAW,EAAE,sBAAsB,EAAE,gCAAgC,CAAC,CAAA;IACnF,YAAY,CAAC,WAAW,EAAE,sBAAsB,EAAE,gCAAgC,CAAC,CAAA;IACnF,YAAY,CAAC,WAAW,EAAE,wBAAwB,EAAE,yBAAyB,CAAC,CAAA;AAChF,CAAC","sourcesContent":["import { CustomMessage } from '@planningcenter/jolt-client/dist/types/JoltConnection'\nimport { InfiniteData, useQueryClient } from '@tanstack/react-query'\nimport { ApiCollection, ApiResource, ConversationResource } from '../types'\nimport { deleteRecordInPagesData, updateRecordInPagesData } from '../utils'\nimport { useApiClient } from './use_api_client'\nimport { getConversationsRequestArgs } from './use_conversations'\nimport { useCurrentPerson } from './use_current_person'\nimport { useJoltChannel, useJoltEvent } from './use_jolt'\nimport { getRequestQueryKey } from './use_suspense_api'\n\ntype QueryData = InfiniteData<ApiCollection<ConversationResource>>\ninterface JoltConversationsEvent extends CustomMessage {\n data: {\n data: ConversationResource\n }\n}\n\nexport function useConversationsJoltEvents() {\n const apiClient = useApiClient()\n const queryClient = useQueryClient()\n const currentPerson = useCurrentPerson()\n const joltChannel = useJoltChannel(`chat.people.${currentPerson.id}`)\n\n const conversationsRequestArgs = getConversationsRequestArgs()\n const conversationQueryKey = getRequestQueryKey(conversationsRequestArgs)\n\n const fetchConversation = async ({ id }: ConversationResource) => {\n const { data: argsData } = conversationsRequestArgs\n const { data } = await apiClient.chat.get<ApiResource<ConversationResource>>({\n url: `/me/conversations/${id}`,\n data: {\n fields: argsData.fields,\n include: argsData.include,\n },\n })\n\n return data\n }\n\n const handleConversationUpdateOrCreate = async (e: JoltConversationsEvent) => {\n const conversation = await fetchConversation(e.data.data).catch(c => c)\n\n queryClient.setQueryData<QueryData>(conversationQueryKey, prev =>\n updateRecordInPagesData({\n data: prev,\n record: conversation,\n processRecord: (record, current) => {\n return { ...current, ...record }\n },\n })\n )\n }\n\n const handleConversationDestroy = (e: JoltConversationsEvent) => {\n queryClient.setQueryData<QueryData>(conversationQueryKey, prev =>\n deleteRecordInPagesData({\n data: prev,\n record: e.data.data,\n })\n )\n }\n\n useJoltEvent(joltChannel, 'conversation.updated', handleConversationUpdateOrCreate)\n useJoltEvent(joltChannel, 'conversation.created', handleConversationUpdateOrCreate)\n useJoltEvent(joltChannel, 'conversation.destroyed', handleConversationDestroy)\n}\n"]}
1
+ {"version":3,"file":"use_conversation_jolt_events.js","sourceRoot":"","sources":["../../src/hooks/use_conversation_jolt_events.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEpE,OAAO,EAAE,uBAAuB,EAAE,+BAA+B,EAAE,MAAM,UAAU,CAAA;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AASvD,MAAM,UAAU,0BAA0B;IACxC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IACpC,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAA;IACxC,MAAM,WAAW,GAAG,cAAc,CAAC,eAAe,aAAa,CAAC,EAAE,EAAE,CAAC,CAAA;IAErE,MAAM,wBAAwB,GAAG,2BAA2B,EAAE,CAAA;IAC9D,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,wBAAwB,CAAC,CAAA;IAEzE,MAAM,iBAAiB,GAAG,KAAK,EAAE,EAAE,EAAE,EAAwB,EAAE,EAAE;QAC/D,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,wBAAwB,CAAA;QACnD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,CAAoC;YAC3E,GAAG,EAAE,qBAAqB,EAAE,EAAE;YAC9B,IAAI,EAAE;gBACJ,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;aAC1B;SACF,CAAC,CAAA;QAEF,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;IAED,MAAM,gCAAgC,GAAG,KAAK,EAAE,CAAyB,EAAE,EAAE;QAC3E,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAEvE,WAAW,CAAC,YAAY,CAAY,oBAAoB,EAAE,IAAI,CAAC,EAAE,CAC/D,+BAA+B,CAAC;YAC9B,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,YAAY;YACpB,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;gBACjC,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAA;YAClC,CAAC;SACF,CAAC,CACH,CAAA;IACH,CAAC,CAAA;IAED,MAAM,yBAAyB,GAAG,CAAC,CAAyB,EAAE,EAAE;QAC9D,WAAW,CAAC,YAAY,CAAY,oBAAoB,EAAE,IAAI,CAAC,EAAE,CAC/D,uBAAuB,CAAC;YACtB,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;SACpB,CAAC,CACH,CAAA;IACH,CAAC,CAAA;IAED,YAAY,CAAC,WAAW,EAAE,sBAAsB,EAAE,gCAAgC,CAAC,CAAA;IACnF,YAAY,CAAC,WAAW,EAAE,sBAAsB,EAAE,gCAAgC,CAAC,CAAA;IACnF,YAAY,CAAC,WAAW,EAAE,wBAAwB,EAAE,yBAAyB,CAAC,CAAA;AAChF,CAAC","sourcesContent":["import { CustomMessage } from '@planningcenter/jolt-client/dist/types/JoltConnection'\nimport { InfiniteData, useQueryClient } from '@tanstack/react-query'\nimport { ApiCollection, ApiResource, ConversationResource } from '../types'\nimport { deleteRecordInPagesData, updateOrCreateRecordInPagesData } from '../utils'\nimport { useApiClient } from './use_api_client'\nimport { getConversationsRequestArgs } from './use_conversations'\nimport { useCurrentPerson } from './use_current_person'\nimport { useJoltChannel, useJoltEvent } from './use_jolt'\nimport { getRequestQueryKey } from './use_suspense_api'\n\ntype QueryData = InfiniteData<ApiCollection<ConversationResource>>\ninterface JoltConversationsEvent extends CustomMessage {\n data: {\n data: ConversationResource\n }\n}\n\nexport function useConversationsJoltEvents() {\n const apiClient = useApiClient()\n const queryClient = useQueryClient()\n const currentPerson = useCurrentPerson()\n const joltChannel = useJoltChannel(`chat.people.${currentPerson.id}`)\n\n const conversationsRequestArgs = getConversationsRequestArgs()\n const conversationQueryKey = getRequestQueryKey(conversationsRequestArgs)\n\n const fetchConversation = async ({ id }: ConversationResource) => {\n const { data: argsData } = conversationsRequestArgs\n const { data } = await apiClient.chat.get<ApiResource<ConversationResource>>({\n url: `/me/conversations/${id}`,\n data: {\n fields: argsData.fields,\n include: argsData.include,\n },\n })\n\n return data\n }\n\n const handleConversationUpdateOrCreate = async (e: JoltConversationsEvent) => {\n const conversation = await fetchConversation(e.data.data).catch(c => c)\n\n queryClient.setQueryData<QueryData>(conversationQueryKey, prev =>\n updateOrCreateRecordInPagesData({\n data: prev,\n record: conversation,\n processRecord: (record, current) => {\n return { ...current, ...record }\n },\n })\n )\n }\n\n const handleConversationDestroy = (e: JoltConversationsEvent) => {\n queryClient.setQueryData<QueryData>(conversationQueryKey, prev =>\n deleteRecordInPagesData({\n data: prev,\n record: e.data.data,\n })\n )\n }\n\n useJoltEvent(joltChannel, 'conversation.updated', handleConversationUpdateOrCreate)\n useJoltEvent(joltChannel, 'conversation.created', handleConversationUpdateOrCreate)\n useJoltEvent(joltChannel, 'conversation.destroyed', handleConversationDestroy)\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"use_conversation_messages.d.ts","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,OAAO,EAEL,wBAAwB,EAEzB,MAAM,oBAAoB,CAAA;AAE3B,eAAO,MAAM,uBAAuB,wBACb;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,SACzC,wBAAwB;;;;;;CAehC,CAAA;AAED,eAAO,MAAM,sBAAsB,wBAAyB;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;CAoBrF,CAAA;AAEF,eAAO,MAAM,mBAAmB,wBAAyB;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,iDAGnF,CAAA"}
1
+ {"version":3,"file":"use_conversation_messages.d.ts","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,OAAO,EAEL,wBAAwB,EAEzB,MAAM,oBAAoB,CAAA;AAE3B,eAAO,MAAM,uBAAuB,wBACb;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,SACzC,wBAAwB;;;;;;CAiBhC,CAAA;AAED,eAAO,MAAM,sBAAsB,wBAAyB;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;CAoBrF,CAAA;AAEF,eAAO,MAAM,mBAAmB,wBAAyB;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,iDAGnF,CAAA"}
@@ -1,12 +1,12 @@
1
+ import { useMemo } from 'react';
1
2
  import { useConversationMessagesJoltEvents } from './use_conversation_messages_jolt_events';
2
3
  import { getRequestQueryKey, useSuspensePaginator, } from './use_suspense_api';
3
4
  export const useConversationMessages = ({ conversation_id }, opts) => {
4
5
  const { data, refetch, isRefetching, fetchNextPage } = useSuspensePaginator(getMessagesRequestArgs({ conversation_id }), opts);
5
6
  const queryKey = getMessagesQueryKey({ conversation_id });
6
- const messages = data.sort((a, b) => -a.id.localeCompare(b.id));
7
+ const messages = useMemo(() => data.filter(message => !message.deletedAt).sort((a, b) => -a.id.localeCompare(b.id)), [data]);
7
8
  useConversationMessagesJoltEvents({
8
9
  conversationId: conversation_id,
9
- refetchMessages: refetch,
10
10
  });
11
11
  return { messages, refetch, isRefetching, fetchNextPage, queryKey };
12
12
  };
@@ -1 +1 @@
1
- {"version":3,"file":"use_conversation_messages.js","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iCAAiC,EAAE,MAAM,yCAAyC,CAAA;AAC3F,OAAO,EACL,kBAAkB,EAElB,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAE3B,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,EAAE,eAAe,EAA+B,EAChD,IAA+B,EAC/B,EAAE;IACF,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,oBAAoB,CACzE,sBAAsB,CAAC,EAAE,eAAe,EAAE,CAAC,EAC3C,IAAI,CACL,CAAA;IACD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;IACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAE/D,iCAAiC,CAAC;QAChC,cAAc,EAAE,eAAe;QAC/B,eAAe,EAAE,OAAO;KACzB,CAAC,CAAA;IAEF,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAA;AACrE,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,EAAE,eAAe,EAA+B,EAAE,EAAE,CAAC,CAAC;IAC3F,GAAG,EAAE,qBAAqB,eAAe,WAAW;IACpD,IAAI,EAAE;QACJ,OAAO,EAAE,EAAE;QACX,MAAM,EAAE;YACN,OAAO,EAAE;gBACP,MAAM;gBACN,gBAAgB;gBAChB,MAAM;gBACN,aAAa;gBACb,YAAY;gBACZ,YAAY;gBACZ,QAAQ;gBACR,iBAAiB;aAClB;YACD,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;YAC1B,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,CAAC;SACtE;QACD,OAAO,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC;KACvC;CACF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAAE,eAAe,EAA+B,EAAE,EAAE;IACtF,MAAM,WAAW,GAAG,sBAAsB,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;IAC/D,OAAO,kBAAkB,CAAC,WAAW,CAAC,CAAA;AACxC,CAAC,CAAA","sourcesContent":["import { MessageResource } from '../types'\nimport { useConversationMessagesJoltEvents } from './use_conversation_messages_jolt_events'\nimport {\n getRequestQueryKey,\n SuspensePaginatorOptions,\n useSuspensePaginator,\n} from './use_suspense_api'\n\nexport const useConversationMessages = (\n { conversation_id }: { conversation_id: string },\n opts?: SuspensePaginatorOptions\n) => {\n const { data, refetch, isRefetching, fetchNextPage } = useSuspensePaginator<MessageResource>(\n getMessagesRequestArgs({ conversation_id }),\n opts\n )\n const queryKey = getMessagesQueryKey({ conversation_id })\n const messages = data.sort((a, b) => -a.id.localeCompare(b.id))\n\n useConversationMessagesJoltEvents({\n conversationId: conversation_id,\n refetchMessages: refetch,\n })\n\n return { messages, refetch, isRefetching, fetchNextPage, queryKey }\n}\n\nexport const getMessagesRequestArgs = ({ conversation_id }: { conversation_id: string }) => ({\n url: `/me/conversations/${conversation_id}/messages`,\n data: {\n perPage: 25,\n fields: {\n Message: [\n 'text',\n 'text_edited_at',\n 'mine',\n 'attachments',\n 'created_at',\n 'deleted_at',\n 'author',\n 'reaction_counts',\n ],\n Person: ['name', 'avatar'],\n ReactionCount: ['value', 'count', 'mine', 'message_id', 'author_ids'],\n },\n include: ['author', 'reaction_counts'],\n },\n})\n\nexport const getMessagesQueryKey = ({ conversation_id }: { conversation_id: string }) => {\n const requestArgs = getMessagesRequestArgs({ conversation_id })\n return getRequestQueryKey(requestArgs)\n}\n"]}
1
+ {"version":3,"file":"use_conversation_messages.js","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B,OAAO,EAAE,iCAAiC,EAAE,MAAM,yCAAyC,CAAA;AAC3F,OAAO,EACL,kBAAkB,EAElB,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAE3B,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,EAAE,eAAe,EAA+B,EAChD,IAA+B,EAC/B,EAAE;IACF,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,oBAAoB,CACzE,sBAAsB,CAAC,EAAE,eAAe,EAAE,CAAC,EAC3C,IAAI,CACL,CAAA;IACD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;IACzD,MAAM,QAAQ,GAAG,OAAO,CACtB,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1F,CAAC,IAAI,CAAC,CACP,CAAA;IAED,iCAAiC,CAAC;QAChC,cAAc,EAAE,eAAe;KAChC,CAAC,CAAA;IAEF,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAA;AACrE,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,EAAE,eAAe,EAA+B,EAAE,EAAE,CAAC,CAAC;IAC3F,GAAG,EAAE,qBAAqB,eAAe,WAAW;IACpD,IAAI,EAAE;QACJ,OAAO,EAAE,EAAE;QACX,MAAM,EAAE;YACN,OAAO,EAAE;gBACP,MAAM;gBACN,gBAAgB;gBAChB,MAAM;gBACN,aAAa;gBACb,YAAY;gBACZ,YAAY;gBACZ,QAAQ;gBACR,iBAAiB;aAClB;YACD,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;YAC1B,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,CAAC;SACtE;QACD,OAAO,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC;KACvC;CACF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAAE,eAAe,EAA+B,EAAE,EAAE;IACtF,MAAM,WAAW,GAAG,sBAAsB,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;IAC/D,OAAO,kBAAkB,CAAC,WAAW,CAAC,CAAA;AACxC,CAAC,CAAA","sourcesContent":["import { useMemo } from 'react'\nimport { MessageResource } from '../types'\nimport { useConversationMessagesJoltEvents } from './use_conversation_messages_jolt_events'\nimport {\n getRequestQueryKey,\n SuspensePaginatorOptions,\n useSuspensePaginator,\n} from './use_suspense_api'\n\nexport const useConversationMessages = (\n { conversation_id }: { conversation_id: string },\n opts?: SuspensePaginatorOptions\n) => {\n const { data, refetch, isRefetching, fetchNextPage } = useSuspensePaginator<MessageResource>(\n getMessagesRequestArgs({ conversation_id }),\n opts\n )\n const queryKey = getMessagesQueryKey({ conversation_id })\n const messages = useMemo(\n () => data.filter(message => !message.deletedAt).sort((a, b) => -a.id.localeCompare(b.id)),\n [data]\n )\n\n useConversationMessagesJoltEvents({\n conversationId: conversation_id,\n })\n\n return { messages, refetch, isRefetching, fetchNextPage, queryKey }\n}\n\nexport const getMessagesRequestArgs = ({ conversation_id }: { conversation_id: string }) => ({\n url: `/me/conversations/${conversation_id}/messages`,\n data: {\n perPage: 25,\n fields: {\n Message: [\n 'text',\n 'text_edited_at',\n 'mine',\n 'attachments',\n 'created_at',\n 'deleted_at',\n 'author',\n 'reaction_counts',\n ],\n Person: ['name', 'avatar'],\n ReactionCount: ['value', 'count', 'mine', 'message_id', 'author_ids'],\n },\n include: ['author', 'reaction_counts'],\n },\n})\n\nexport const getMessagesQueryKey = ({ conversation_id }: { conversation_id: string }) => {\n const requestArgs = getMessagesRequestArgs({ conversation_id })\n return getRequestQueryKey(requestArgs)\n}\n"]}
@@ -1,7 +1,6 @@
1
1
  interface Props {
2
2
  conversationId: string;
3
- refetchMessages?: () => void;
4
3
  }
5
- export declare function useConversationMessagesJoltEvents({ conversationId, refetchMessages }: Props): void;
4
+ export declare function useConversationMessagesJoltEvents({ conversationId }: Props): void;
6
5
  export {};
7
6
  //# sourceMappingURL=use_conversation_messages_jolt_events.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_conversation_messages_jolt_events.d.ts","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages_jolt_events.ts"],"names":[],"mappings":"AAUA,UAAU,KAAK;IACb,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;CAC7B;AAED,wBAAgB,iCAAiC,CAAC,EAAE,cAAc,EAAE,eAAe,EAAE,EAAE,KAAK,QAiC3F"}
1
+ {"version":3,"file":"use_conversation_messages_jolt_events.d.ts","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages_jolt_events.ts"],"names":[],"mappings":"AAgBA,UAAU,KAAK;IACb,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,wBAAgB,iCAAiC,CAAC,EAAE,cAAc,EAAE,EAAE,KAAK,QA4F1E"}
@@ -1,36 +1,90 @@
1
1
  import { useJoltChannel, useJoltEvent } from './use_jolt';
2
- import { updateRecordInPagesData } from '../utils';
2
+ import { deleteRecordInPagesData, updateOrCreateRecordInPagesData, updateRecordInPagesData, } from '../utils';
3
3
  import { useQueryClient } from '@tanstack/react-query';
4
4
  import { useCurrentPerson } from './use_current_person';
5
5
  import { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource';
6
6
  import { getMessagesRequestArgs } from './use_conversation_messages';
7
7
  import { getRequestQueryKey } from './use_suspense_api';
8
- export function useConversationMessagesJoltEvents({ conversationId, refetchMessages }) {
8
+ import { transformReactionEventDataToReactionCountResource } from '../utils/jolt/transform_reaction_event_data_to_reaction_count_resource';
9
+ export function useConversationMessagesJoltEvents({ conversationId }) {
9
10
  const queryClient = useQueryClient();
10
11
  const currentPerson = useCurrentPerson();
11
12
  const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`);
12
13
  const messagesRequestArgs = getMessagesRequestArgs({ conversation_id: conversationId });
13
14
  const messagesQueryKey = getRequestQueryKey(messagesRequestArgs);
14
- const handleMessageJoltEvent = async () => {
15
- refetchMessages?.();
16
- };
17
15
  const handleMessageUpdateOrCreate = async (e) => {
18
16
  const { data } = e.data;
19
17
  const message = transformMessageEventDataToMessageResource({
20
18
  data,
21
19
  currentPersonId: currentPerson.id,
22
20
  });
21
+ queryClient.setQueryData(messagesQueryKey, prev => {
22
+ if (e.event === 'message.created') {
23
+ return updateOrCreateRecordInPagesData({
24
+ data: prev,
25
+ record: message,
26
+ processRecord: (record, current) => {
27
+ return { ...current, ...record };
28
+ },
29
+ });
30
+ }
31
+ else {
32
+ return updateRecordInPagesData({
33
+ data: prev,
34
+ record: message,
35
+ processRecord: (record, current) => {
36
+ return { ...current, ...record };
37
+ },
38
+ });
39
+ }
40
+ });
41
+ };
42
+ const handleMessageDeleted = async (e) => {
43
+ const { data } = e.data;
44
+ const message = transformMessageEventDataToMessageResource({
45
+ data,
46
+ currentPersonId: currentPerson.id,
47
+ });
48
+ queryClient.setQueryData(messagesQueryKey, prev => deleteRecordInPagesData({ data: prev, record: message }));
49
+ };
50
+ const handleReactionJoltEvent = async (e) => {
51
+ const { data } = e.data;
52
+ const message = { id: data.message_sort_key };
23
53
  queryClient.setQueryData(messagesQueryKey, prev => updateRecordInPagesData({
24
54
  data: prev,
25
55
  record: message,
26
- processRecord: (record, current) => {
27
- return { ...current, ...record };
56
+ processRecord: (record, oldMessage) => {
57
+ const reactionCounts = oldMessage.reactionCounts || [];
58
+ let foundMatch = false;
59
+ let newReactionCounts = reactionCounts.map(reactionCount => {
60
+ if (reactionCount.value === data.value) {
61
+ foundMatch = true;
62
+ return transformReactionEventDataToReactionCountResource({
63
+ data,
64
+ oldData: reactionCount,
65
+ event: e.event,
66
+ currentPersonId: currentPerson.id,
67
+ });
68
+ }
69
+ return reactionCount;
70
+ });
71
+ if (!foundMatch) {
72
+ const newReactionCount = transformReactionEventDataToReactionCountResource({
73
+ data,
74
+ event: e.event,
75
+ currentPersonId: currentPerson.id,
76
+ });
77
+ if (newReactionCount?.count) {
78
+ newReactionCounts = [...newReactionCounts, newReactionCount];
79
+ }
80
+ }
81
+ return { ...oldMessage, reactionCounts: newReactionCounts };
28
82
  },
29
83
  }));
30
84
  };
31
85
  useJoltEvent(joltChannel, 'message.created', handleMessageUpdateOrCreate);
32
86
  useJoltEvent(joltChannel, 'message.updated', handleMessageUpdateOrCreate);
33
- useJoltEvent(joltChannel, 'message.deleted', handleMessageJoltEvent);
34
- useJoltEvent(joltChannel, 'reaction.*', handleMessageJoltEvent);
87
+ useJoltEvent(joltChannel, 'message.destroyed', handleMessageDeleted);
88
+ useJoltEvent(joltChannel, 'reaction.*', handleReactionJoltEvent);
35
89
  }
36
90
  //# sourceMappingURL=use_conversation_messages_jolt_events.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_conversation_messages_jolt_events.js","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages_jolt_events.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAElD,OAAO,EAAgB,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,0CAA0C,EAAE,MAAM,gEAAgE,CAAA;AAC3H,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAOvD,MAAM,UAAU,iCAAiC,CAAC,EAAE,cAAc,EAAE,eAAe,EAAS;IAC1F,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IACpC,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAA;IACxC,MAAM,WAAW,GAAG,cAAc,CAAC,sBAAsB,cAAc,EAAE,CAAC,CAAA;IAC1E,MAAM,mBAAmB,GAAG,sBAAsB,CAAC,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC,CAAA;IACvF,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAEhE,MAAM,sBAAsB,GAAG,KAAK,IAAI,EAAE;QACxC,eAAe,EAAE,EAAE,CAAA;IACrB,CAAC,CAAA;IAED,MAAM,2BAA2B,GAAG,KAAK,EAAE,CAAsB,EAAE,EAAE;QACnE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAA;QACvB,MAAM,OAAO,GAAG,0CAA0C,CAAC;YACzD,IAAI;YACJ,eAAe,EAAE,aAAa,CAAC,EAAE;SAClC,CAAC,CAAA;QAEF,WAAW,CAAC,YAAY,CAAY,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAC3D,uBAAuB,CAAC;YACtB,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,OAAO;YACf,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;gBACjC,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAA;YAClC,CAAC;SACF,CAAC,CACH,CAAA;IACH,CAAC,CAAA;IAED,YAAY,CAAC,WAAW,EAAE,iBAAiB,EAAE,2BAA2B,CAAC,CAAA;IACzE,YAAY,CAAC,WAAW,EAAE,iBAAiB,EAAE,2BAA2B,CAAC,CAAA;IACzE,YAAY,CAAC,WAAW,EAAE,iBAAiB,EAAE,sBAAsB,CAAC,CAAA;IACpE,YAAY,CAAC,WAAW,EAAE,YAAY,EAAE,sBAAsB,CAAC,CAAA;AACjE,CAAC","sourcesContent":["import { ApiCollection, MessageResource } from '../types'\nimport { useJoltChannel, useJoltEvent } from './use_jolt'\nimport { updateRecordInPagesData } from '../utils'\nimport { MessageCreatedEvent } from '../types/jolt_events/message_events'\nimport { InfiniteData, useQueryClient } from '@tanstack/react-query'\nimport { useCurrentPerson } from './use_current_person'\nimport { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'\nimport { getMessagesRequestArgs } from './use_conversation_messages'\nimport { getRequestQueryKey } from './use_suspense_api'\n\ninterface Props {\n conversationId: string\n refetchMessages?: () => void\n}\n\nexport function useConversationMessagesJoltEvents({ conversationId, refetchMessages }: Props) {\n const queryClient = useQueryClient()\n const currentPerson = useCurrentPerson()\n const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)\n const messagesRequestArgs = getMessagesRequestArgs({ conversation_id: conversationId })\n const messagesQueryKey = getRequestQueryKey(messagesRequestArgs)\n\n const handleMessageJoltEvent = async () => {\n refetchMessages?.()\n }\n\n const handleMessageUpdateOrCreate = async (e: MessageCreatedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n\n queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>\n updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, current) => {\n return { ...current, ...record }\n },\n })\n )\n }\n\n useJoltEvent(joltChannel, 'message.created', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.updated', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.deleted', handleMessageJoltEvent)\n useJoltEvent(joltChannel, 'reaction.*', handleMessageJoltEvent)\n}\n\ntype QueryData = InfiniteData<ApiCollection<MessageResource>>\n"]}
1
+ {"version":3,"file":"use_conversation_messages_jolt_events.js","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages_jolt_events.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApiCollection, MessageResource } from '../types'\nimport { useJoltChannel, useJoltEvent } from './use_jolt'\nimport {\n deleteRecordInPagesData,\n updateOrCreateRecordInPagesData,\n updateRecordInPagesData,\n} from '../utils'\nimport { MessageCreatedEvent, MessageDeletedEvent } from '../types/jolt_events/message_events'\nimport { InfiniteData, useQueryClient } from '@tanstack/react-query'\nimport { useCurrentPerson } from './use_current_person'\nimport { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'\nimport { getMessagesRequestArgs } from './use_conversation_messages'\nimport { getRequestQueryKey } from './use_suspense_api'\nimport { JoltReactionEvent } from '../types/jolt_events'\nimport { transformReactionEventDataToReactionCountResource } from '../utils/jolt/transform_reaction_event_data_to_reaction_count_resource'\n\ninterface Props {\n conversationId: string\n}\n\nexport function useConversationMessagesJoltEvents({ conversationId }: Props) {\n const queryClient = useQueryClient()\n const currentPerson = useCurrentPerson()\n const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)\n const messagesRequestArgs = getMessagesRequestArgs({ conversation_id: conversationId })\n const messagesQueryKey = getRequestQueryKey(messagesRequestArgs)\n\n const handleMessageUpdateOrCreate = async (e: MessageCreatedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n\n queryClient.setQueryData<QueryData>(messagesQueryKey, prev => {\n if (e.event === 'message.created') {\n return updateOrCreateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, current) => {\n return { ...current, ...record }\n },\n })\n } else {\n return updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, current) => {\n return { ...current, ...record }\n },\n })\n }\n })\n }\n\n const handleMessageDeleted = async (e: MessageDeletedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n\n queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>\n deleteRecordInPagesData({ data: prev, record: message })\n )\n }\n\n const handleReactionJoltEvent = async (e: JoltReactionEvent) => {\n const { data } = e.data\n const message = { id: data.message_sort_key } as MessageResource\n queryClient.setQueryData<QueryData>(messagesQueryKey, 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 === data.value) {\n foundMatch = true\n return transformReactionEventDataToReactionCountResource({\n data,\n oldData: reactionCount,\n event: e.event,\n currentPersonId: currentPerson.id,\n })\n }\n return reactionCount\n })\n\n if (!foundMatch) {\n const newReactionCount = transformReactionEventDataToReactionCountResource({\n data,\n event: e.event,\n currentPersonId: currentPerson.id,\n })\n\n if (newReactionCount?.count) {\n newReactionCounts = [...newReactionCounts, newReactionCount]\n }\n }\n\n return { ...oldMessage, reactionCounts: newReactionCounts }\n },\n })\n )\n }\n\n useJoltEvent(joltChannel, 'message.created', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.updated', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.destroyed', handleMessageDeleted)\n useJoltEvent(joltChannel, 'reaction.*', handleReactionJoltEvent)\n}\n\ntype QueryData = InfiniteData<ApiCollection<MessageResource>>\n"]}
@@ -6,9 +6,28 @@
6
6
  import { ApiCollection, ResourceObject } from '../../types';
7
7
  /**
8
8
  * updateRecordInPagesData
9
- * Can be used to add as well but it's not at all efficient. It's better to use addRecordInPagesData.
9
+ * Updates record if found in the cache, otherwise noops.
10
10
  */
11
11
  export declare function updateRecordInPagesData<T extends ResourceObject>({ data, record, processRecord, }: {
12
+ data?: {
13
+ pages: ApiCollection<T>[];
14
+ pageParams: any;
15
+ };
16
+ record: T;
17
+ processRecord?: (_next: T, _prev: T) => T;
18
+ }): {
19
+ pages: {
20
+ data: T[];
21
+ links: Record<string, string>;
22
+ meta: import("../../types").CollectionMeta;
23
+ }[];
24
+ pageParams: any;
25
+ } | undefined;
26
+ /**
27
+ * updateOrCreateRecordInPagesData
28
+ * Updates record if found in the cache, otherwise inserts.
29
+ */
30
+ export declare function updateOrCreateRecordInPagesData<T extends ResourceObject>({ data, record, processRecord, }: {
12
31
  data?: {
13
32
  pages: ApiCollection<T>[];
14
33
  pageParams: any;
@@ -29,7 +48,7 @@ export declare function addRecordInPagesData<T extends ResourceObject>({ data, r
29
48
  pageParams: any;
30
49
  };
31
50
  record: T;
32
- processRecord?: (_next: T, _prev?: T) => T;
51
+ processRecord?: (_next: T) => T;
33
52
  }): {
34
53
  pages: ApiCollection<T>[];
35
54
  pageParams: any;
@@ -1 +1 @@
1
- {"version":3,"file":"page_mutations.d.ts","sourceRoot":"","sources":["../../../src/utils/cache/page_mutations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE3D;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,cAAc,EAAE,EAChE,IAAI,EACJ,MAAM,EACN,aAAsB,GACvB,EAAE;IACD,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,UAAU,EAAE,GAAG,CAAA;KAAE,CAAA;IACrD,MAAM,EAAE,CAAC,CAAA;IACT,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;CAC3C;;;;;;gBAHiD,GAAG;cA4BpD;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,cAAc,EAAE,EAC7D,IAAI,EACJ,MAAM,EACN,aAAsB,GACvB,EAAE;IACD,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,UAAU,EAAE,GAAG,CAAA;KAAE,CAAA;IACrD,MAAM,EAAE,CAAC,CAAA;IACT,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;CAC3C;;gBAHiD,GAAG;cAapD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,cAAc,EAAE,EAChE,IAAI,EACJ,MAAM,GACP,EAAE;IACD,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,UAAU,EAAE,GAAG,CAAA;KAAE,CAAA;IACrD,MAAM,EAAE,CAAC,CAAA;CACV;;;;;;gBAFiD,GAAG;cAcpD"}
1
+ {"version":3,"file":"page_mutations.d.ts","sourceRoot":"","sources":["../../../src/utils/cache/page_mutations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE3D;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,cAAc,EAAE,EAChE,IAAI,EACJ,MAAM,EACN,aAAsB,GACvB,EAAE;IACD,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,UAAU,EAAE,GAAG,CAAA;KAAE,CAAA;IACrD,MAAM,EAAE,CAAC,CAAA;IACT,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAA;CAC1C;;;;;;gBAHiD,GAAG;cAkBpD;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,CAAC,SAAS,cAAc,EAAE,EACxE,IAAI,EACJ,MAAM,EACN,aAAsB,GACvB,EAAE;IACD,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,UAAU,EAAE,GAAG,CAAA;KAAE,CAAA;IACrD,MAAM,EAAE,CAAC,CAAA;IACT,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;CAC3C;;;;;;gBAHiD,GAAG;cA2BpD;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,cAAc,EAAE,EAC7D,IAAI,EACJ,MAAM,EACN,aAAsB,GACvB,EAAE;IACD,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,UAAU,EAAE,GAAG,CAAA;KAAE,CAAA;IACrD,MAAM,EAAE,CAAC,CAAA;IACT,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAA;CAChC;;gBAHiD,GAAG;cAapD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,cAAc,EAAE,EAChE,IAAI,EACJ,MAAM,GACP,EAAE;IACD,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,UAAU,EAAE,GAAG,CAAA;KAAE,CAAA;IACrD,MAAM,EAAE,CAAC,CAAA;CACV;;;;;;gBAFiD,GAAG;cAcpD"}
@@ -5,9 +5,27 @@
5
5
  */
6
6
  /**
7
7
  * updateRecordInPagesData
8
- * Can be used to add as well but it's not at all efficient. It's better to use addRecordInPagesData.
8
+ * Updates record if found in the cache, otherwise noops.
9
9
  */
10
10
  export function updateRecordInPagesData({ data, record, processRecord = r => r, }) {
11
+ if (!data)
12
+ return data;
13
+ const newPages = data.pages.map(page => {
14
+ const newData = page.data.map(message => {
15
+ if (message.id === record.id) {
16
+ return processRecord(record, message);
17
+ }
18
+ return message;
19
+ });
20
+ return { ...page, data: newData };
21
+ });
22
+ return { ...data, pages: newPages };
23
+ }
24
+ /**
25
+ * updateOrCreateRecordInPagesData
26
+ * Updates record if found in the cache, otherwise inserts.
27
+ */
28
+ export function updateOrCreateRecordInPagesData({ data, record, processRecord = r => r, }) {
11
29
  if (!data)
12
30
  return data;
13
31
  let foundRecord = false;
@@ -22,7 +40,6 @@ export function updateRecordInPagesData({ data, record, processRecord = r => r,
22
40
  return { ...page, data: newData };
23
41
  });
24
42
  if (!foundRecord) {
25
- // Can be used to add as well but it's not at all efficient. It's better to use addRecordInPagesData.
26
43
  // This is a fallback for when the record is not found in the cache.
27
44
  const firstPage = { ...newPages[0] };
28
45
  firstPage.data = [processRecord(record), ...firstPage.data];
@@ -1 +1 @@
1
- {"version":3,"file":"page_mutations.js","sourceRoot":"","sources":["../../../src/utils/cache/page_mutations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAA2B,EAChE,IAAI,EACJ,MAAM,EACN,aAAa,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAKvB;IACC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IAEtB,IAAI,WAAW,GAAG,KAAK,CAAA;IACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;YACtC,IAAI,OAAO,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC;gBAC7B,WAAW,GAAG,IAAI,CAAA;gBAClB,OAAO,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;YACvC,CAAC;YACD,OAAO,OAAO,CAAA;QAChB,CAAC,CAAC,CAAA;QAEF,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,qGAAqG;QACrG,oEAAoE;QACpE,MAAM,SAAS,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;QACpC,SAAS,CAAC,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;QAC3D,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;IACzB,CAAC;IAED,OAAO,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;AACrC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAA2B,EAC7D,IAAI,EACJ,MAAM,EACN,aAAa,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAKvB;IACC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IAEtB,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;IAChC,MAAM,SAAS,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;IACpC,SAAS,CAAC,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAE3D,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;IAEvB,OAAO,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAA2B,EAChE,IAAI,EACJ,MAAM,GAIP;IACC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IAEtB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;YACzC,OAAO,OAAO,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAA;QACjC,CAAC,CAAC,CAAA;QAEF,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,OAAO,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;AACrC,CAAC","sourcesContent":["/**\n * Helpers to handle updating messages in the cache\n * Messages are ordered by ULID on the client so we may\n * have diverging logic from other kinds of api data\n */\n\nimport { ApiCollection, ResourceObject } from '../../types'\n\n/**\n * updateRecordInPagesData\n * Can be used to add as well but it's not at all efficient. It's better to use addRecordInPagesData.\n */\nexport function updateRecordInPagesData<T extends ResourceObject>({\n data,\n record,\n processRecord = r => r,\n}: {\n data?: { pages: ApiCollection<T>[]; pageParams: any }\n record: T\n processRecord?: (_next: T, _prev?: T) => T\n}) {\n if (!data) return data\n\n let foundRecord = false\n const newPages = data.pages.map(page => {\n const newData = page.data.map(message => {\n if (message.id === record.id) {\n foundRecord = true\n return processRecord(record, message)\n }\n return message\n })\n\n return { ...page, data: newData }\n })\n\n if (!foundRecord) {\n // Can be used to add as well but it's not at all efficient. It's better to use addRecordInPagesData.\n // This is a fallback for when the record is not found in the cache.\n const firstPage = { ...newPages[0] }\n firstPage.data = [processRecord(record), ...firstPage.data]\n newPages[0] = firstPage\n }\n\n return { ...data, pages: newPages }\n}\n\nexport function addRecordInPagesData<T extends ResourceObject>({\n data,\n record,\n processRecord = r => r,\n}: {\n data?: { pages: ApiCollection<T>[]; pageParams: any }\n record: T\n processRecord?: (_next: T, _prev?: T) => T\n}) {\n if (!data) return data\n\n const newPages = [...data.pages]\n const firstPage = { ...newPages[0] }\n firstPage.data = [processRecord(record), ...firstPage.data]\n\n newPages[0] = firstPage\n\n return { ...data, pages: newPages }\n}\n\n/**\n * deleteRecordInPagesData\n */\nexport function deleteRecordInPagesData<T extends ResourceObject>({\n data,\n record,\n}: {\n data?: { pages: ApiCollection<T>[]; pageParams: any }\n record: T\n}) {\n if (!data) return data\n\n const newPages = data.pages.map(page => {\n const newData = page.data.filter(message => {\n return message.id !== record.id\n })\n\n return { ...page, data: newData }\n })\n\n return { ...data, pages: newPages }\n}\n"]}
1
+ {"version":3,"file":"page_mutations.js","sourceRoot":"","sources":["../../../src/utils/cache/page_mutations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Helpers to handle updating messages in the cache\n * Messages are ordered by ULID on the client so we may\n * have diverging logic from other kinds of api data\n */\n\nimport { ApiCollection, ResourceObject } from '../../types'\n\n/**\n * updateRecordInPagesData\n * Updates record if found in the cache, otherwise noops.\n */\nexport function updateRecordInPagesData<T extends ResourceObject>({\n data,\n record,\n processRecord = r => r,\n}: {\n data?: { pages: ApiCollection<T>[]; pageParams: any }\n record: T\n processRecord?: (_next: T, _prev: T) => T\n}) {\n if (!data) return data\n\n const newPages = data.pages.map(page => {\n const newData = page.data.map(message => {\n if (message.id === record.id) {\n return processRecord(record, message)\n }\n return message\n })\n\n return { ...page, data: newData }\n })\n\n return { ...data, pages: newPages }\n}\n\n/**\n * updateOrCreateRecordInPagesData\n * Updates record if found in the cache, otherwise inserts.\n */\nexport function updateOrCreateRecordInPagesData<T extends ResourceObject>({\n data,\n record,\n processRecord = r => r,\n}: {\n data?: { pages: ApiCollection<T>[]; pageParams: any }\n record: T\n processRecord?: (_next: T, _prev?: T) => T\n}) {\n if (!data) return data\n\n let foundRecord = false\n const newPages = data.pages.map(page => {\n const newData = page.data.map(message => {\n if (message.id === record.id) {\n foundRecord = true\n return processRecord(record, message)\n }\n return message\n })\n\n return { ...page, data: newData }\n })\n\n if (!foundRecord) {\n // This is a fallback for when the record is not found in the cache.\n const firstPage = { ...newPages[0] }\n firstPage.data = [processRecord(record), ...firstPage.data]\n newPages[0] = firstPage\n }\n\n return { ...data, pages: newPages }\n}\n\nexport function addRecordInPagesData<T extends ResourceObject>({\n data,\n record,\n processRecord = r => r,\n}: {\n data?: { pages: ApiCollection<T>[]; pageParams: any }\n record: T\n processRecord?: (_next: T) => T\n}) {\n if (!data) return data\n\n const newPages = [...data.pages]\n const firstPage = { ...newPages[0] }\n firstPage.data = [processRecord(record), ...firstPage.data]\n\n newPages[0] = firstPage\n\n return { ...data, pages: newPages }\n}\n\n/**\n * deleteRecordInPagesData\n */\nexport function deleteRecordInPagesData<T extends ResourceObject>({\n data,\n record,\n}: {\n data?: { pages: ApiCollection<T>[]; pageParams: any }\n record: T\n}) {\n if (!data) return data\n\n const newPages = data.pages.map(page => {\n const newData = page.data.filter(message => {\n return message.id !== record.id\n })\n\n return { ...page, data: newData }\n })\n\n return { ...data, pages: newPages }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { JoltReactionEvent } from '../../types/jolt_events';
2
+ import { ReactionCreatedEvent } from '../../types/jolt_events/reaction_events';
3
+ import { ReactionCountResource } from '../../types/resources/reaction';
4
+ interface Props {
5
+ data: ReactionCreatedEvent['data']['data'];
6
+ oldData?: ReactionCountResource;
7
+ event: JoltReactionEvent['event'];
8
+ currentPersonId: string;
9
+ }
10
+ export declare function transformReactionEventDataToReactionCountResource({ data, oldData, event, currentPersonId, }: Props): ReactionCountResource;
11
+ export {};
12
+ //# sourceMappingURL=transform_reaction_event_data_to_reaction_count_resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform_reaction_event_data_to_reaction_count_resource.d.ts","sourceRoot":"","sources":["../../../src/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAA;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AAEtE,UAAU,KAAK;IACb,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;IAC1C,OAAO,CAAC,EAAE,qBAAqB,CAAA;IAC/B,KAAK,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAA;IACjC,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,wBAAgB,iDAAiD,CAAC,EAChE,IAAI,EACJ,OAAO,EACP,KAAK,EACL,eAAe,GAChB,EAAE,KAAK,GAAG,qBAAqB,CAmB/B"}
@@ -0,0 +1,20 @@
1
+ export function transformReactionEventDataToReactionCountResource({ data, oldData, event, currentPersonId, }) {
2
+ let authorIds = new Set(oldData?.authorIds || []);
3
+ if (event === 'reaction.created') {
4
+ authorIds.add(data.author_id.toString());
5
+ }
6
+ else if (event === 'reaction.destroyed') {
7
+ authorIds.delete(data.author_id.toString());
8
+ }
9
+ const mine = authorIds.has(currentPersonId.toString());
10
+ return {
11
+ type: 'ReactionCount',
12
+ id: `${data.message_sort_key}/${data.value}`,
13
+ value: data.value,
14
+ count: data.count,
15
+ mine: mine ? 1 : 0,
16
+ messageId: data.message_sort_key,
17
+ authorIds: Array.from(authorIds),
18
+ };
19
+ }
20
+ //# sourceMappingURL=transform_reaction_event_data_to_reaction_count_resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform_reaction_event_data_to_reaction_count_resource.js","sourceRoot":"","sources":["../../../src/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,iDAAiD,CAAC,EAChE,IAAI,EACJ,OAAO,EACP,KAAK,EACL,eAAe,GACT;IACN,IAAI,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC,CAAA;IACjD,IAAI,KAAK,KAAK,kBAAkB,EAAE,CAAC;QACjC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC1C,CAAC;SAAM,IAAI,KAAK,KAAK,oBAAoB,EAAE,CAAC;QAC1C,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC7C,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,eAAe,CAAC,QAAQ,EAAE,CAAC,CAAA;IAEtD,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,EAAE,EAAE,GAAG,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,KAAK,EAAE;QAC5C,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClB,SAAS,EAAE,IAAI,CAAC,gBAAgB;QAChC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;KACjC,CAAA;AACH,CAAC","sourcesContent":["import { JoltReactionEvent } from '../../types/jolt_events'\nimport { ReactionCreatedEvent } from '../../types/jolt_events/reaction_events'\nimport { ReactionCountResource } from '../../types/resources/reaction'\n\ninterface Props {\n data: ReactionCreatedEvent['data']['data']\n oldData?: ReactionCountResource\n event: JoltReactionEvent['event']\n currentPersonId: string\n}\n\nexport function transformReactionEventDataToReactionCountResource({\n data,\n oldData,\n event,\n currentPersonId,\n}: Props): ReactionCountResource {\n let authorIds = new Set(oldData?.authorIds || [])\n if (event === 'reaction.created') {\n authorIds.add(data.author_id.toString())\n } else if (event === 'reaction.destroyed') {\n authorIds.delete(data.author_id.toString())\n }\n\n const mine = authorIds.has(currentPersonId.toString())\n\n return {\n type: 'ReactionCount',\n id: `${data.message_sort_key}/${data.value}`,\n value: data.value,\n count: data.count,\n mine: mine ? 1 : 0,\n messageId: data.message_sort_key,\n authorIds: Array.from(authorIds),\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.1.0-rc.1",
3
+ "version": "3.1.0-rc.2",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -52,5 +52,5 @@
52
52
  "prettier": "^3.4.2",
53
53
  "typescript": "<5.6.0"
54
54
  },
55
- "gitHead": "a653776f157e5b79468f1221233ea8a082dc009e"
55
+ "gitHead": "c63ab69895844b3623090178214fad9f22eded1a"
56
56
  }
@@ -1,4 +1,8 @@
1
- import { deleteRecordInPagesData, updateRecordInPagesData } from '../../../utils/'
1
+ import {
2
+ deleteRecordInPagesData,
3
+ updateOrCreateRecordInPagesData,
4
+ updateRecordInPagesData,
5
+ } from '../../../utils/'
2
6
 
3
7
  const data = {
4
8
  pageParams: {},
@@ -90,15 +94,93 @@ describe('updateRecordInPagesData', () => {
90
94
  })
91
95
  })
92
96
 
93
- it('should add records that do not yet exist', () => {
97
+ it('should skip the record if it does not exist', () => {
94
98
  const id = '5'
95
99
  const record = createRecord({ id })
96
-
97
100
  const result = updateRecordInPagesData<typeof record>({
98
101
  data,
99
102
  record,
100
103
  processRecord: r => ({ ...r, text: 'updated ' + r.text }),
101
104
  })
105
+ expect(result).toEqual(data)
106
+ })
107
+ })
108
+
109
+ describe('updateOrCreateRecordInPagesData', () => {
110
+ it('should update the record in the pages data', () => {
111
+ const id = '3'
112
+ const record = createRecord({ id })
113
+ const result = updateOrCreateRecordInPagesData({ data, record })
114
+
115
+ expect(result).toEqual({
116
+ pageParams: {},
117
+ pages: [
118
+ {
119
+ data: [
120
+ { id: '1', type: 'Message', text: 'message 1' },
121
+ { id: '2', type: 'Message', text: 'message 2' },
122
+ ],
123
+ included: [],
124
+ links: {},
125
+ meta: { count: 2, totalCount: 2 },
126
+ },
127
+ {
128
+ data: [
129
+ { id: '3', type: 'Message', text: 'example 3' },
130
+ { id: '4', type: 'Message', text: 'message 4' },
131
+ ],
132
+ included: [],
133
+ links: {},
134
+ meta: { count: 2, totalCount: 2 },
135
+ },
136
+ ],
137
+ })
138
+ })
139
+
140
+ it('should update the record in the pages data with a custom processRecord function', () => {
141
+ const id = '2'
142
+ const record = createRecord({ id })
143
+
144
+ const result = updateOrCreateRecordInPagesData<typeof record>({
145
+ data,
146
+ record,
147
+ processRecord: r => ({ ...r, text: 'updated ' + r.text }),
148
+ })
149
+
150
+ expect(result).toEqual({
151
+ pageParams: {},
152
+ pages: [
153
+ {
154
+ data: [
155
+ { id: '1', type: 'Message', text: 'message 1' },
156
+ { id, type: 'Message', text: `updated example ${id}` },
157
+ ],
158
+ included: [],
159
+ links: {},
160
+ meta: { count: 2, totalCount: 2 },
161
+ },
162
+ {
163
+ data: [
164
+ { id: '3', type: 'Message', text: 'message 3' },
165
+ { id: '4', type: 'Message', text: 'message 4' },
166
+ ],
167
+ included: [],
168
+ links: {},
169
+ meta: { count: 2, totalCount: 2 },
170
+ },
171
+ ],
172
+ })
173
+ })
174
+
175
+ it('should add records that do not yet exist, but does not run processRecord', () => {
176
+ const id = '5'
177
+ const record = createRecord({ id })
178
+
179
+ const result = updateOrCreateRecordInPagesData<typeof record>({
180
+ data,
181
+ record,
182
+ processRecord: r => ({ ...r, text: 'updated ' + r.text }),
183
+ })
102
184
 
103
185
  expect(result).toEqual({
104
186
  pageParams: {},
@@ -7,7 +7,7 @@ import { useTheme } from '../../hooks'
7
7
  import { useApiClient } from '../../hooks/use_api_client'
8
8
  import { getMessagesQueryKey, getMessagesRequestArgs } from '../../hooks/use_conversation_messages'
9
9
  import { ApiCollection, ApiResource, ConversationResource, MessageResource } from '../../types'
10
- import { updateRecordInPagesData } from '../../utils'
10
+ import { updateOrCreateRecordInPagesData } from '../../utils'
11
11
 
12
12
  export const MessageForm = {
13
13
  Root: MessageFormRoot,
@@ -60,7 +60,7 @@ function MessageFormRoot({ conversation, children }: MessagesFormRootProps) {
60
60
 
61
61
  setText('')
62
62
  queryClient.setQueryData<QueryData>(queryKey, data =>
63
- updateRecordInPagesData({
63
+ updateOrCreateRecordInPagesData({
64
64
  data,
65
65
  record: updatedMessage,
66
66
  })
@@ -23,6 +23,9 @@ export function MessageReaction({
23
23
  }) {
24
24
  const styles = useReactionStyles(reaction)
25
25
 
26
+ if (!reaction.count) return null
27
+ if (!REACTION_EMOJIS[reaction.value]) return null
28
+
26
29
  return (
27
30
  <PlatformPressable
28
31
  key={reaction.value}
@@ -1,7 +1,7 @@
1
1
  import { CustomMessage } from '@planningcenter/jolt-client/dist/types/JoltConnection'
2
2
  import { InfiniteData, useQueryClient } from '@tanstack/react-query'
3
3
  import { ApiCollection, ApiResource, ConversationResource } from '../types'
4
- import { deleteRecordInPagesData, updateRecordInPagesData } from '../utils'
4
+ import { deleteRecordInPagesData, updateOrCreateRecordInPagesData } from '../utils'
5
5
  import { useApiClient } from './use_api_client'
6
6
  import { getConversationsRequestArgs } from './use_conversations'
7
7
  import { useCurrentPerson } from './use_current_person'
@@ -41,7 +41,7 @@ export function useConversationsJoltEvents() {
41
41
  const conversation = await fetchConversation(e.data.data).catch(c => c)
42
42
 
43
43
  queryClient.setQueryData<QueryData>(conversationQueryKey, prev =>
44
- updateRecordInPagesData({
44
+ updateOrCreateRecordInPagesData({
45
45
  data: prev,
46
46
  record: conversation,
47
47
  processRecord: (record, current) => {
@@ -1,3 +1,4 @@
1
+ import { useMemo } from 'react'
1
2
  import { MessageResource } from '../types'
2
3
  import { useConversationMessagesJoltEvents } from './use_conversation_messages_jolt_events'
3
4
  import {
@@ -15,11 +16,13 @@ export const useConversationMessages = (
15
16
  opts
16
17
  )
17
18
  const queryKey = getMessagesQueryKey({ conversation_id })
18
- const messages = data.sort((a, b) => -a.id.localeCompare(b.id))
19
+ const messages = useMemo(
20
+ () => data.filter(message => !message.deletedAt).sort((a, b) => -a.id.localeCompare(b.id)),
21
+ [data]
22
+ )
19
23
 
20
24
  useConversationMessagesJoltEvents({
21
25
  conversationId: conversation_id,
22
- refetchMessages: refetch,
23
26
  })
24
27
 
25
28
  return { messages, refetch, isRefetching, fetchNextPage, queryKey }
@@ -1,42 +1,106 @@
1
1
  import { ApiCollection, MessageResource } from '../types'
2
2
  import { useJoltChannel, useJoltEvent } from './use_jolt'
3
- import { updateRecordInPagesData } from '../utils'
4
- import { MessageCreatedEvent } from '../types/jolt_events/message_events'
3
+ import {
4
+ deleteRecordInPagesData,
5
+ updateOrCreateRecordInPagesData,
6
+ updateRecordInPagesData,
7
+ } from '../utils'
8
+ import { MessageCreatedEvent, MessageDeletedEvent } from '../types/jolt_events/message_events'
5
9
  import { InfiniteData, useQueryClient } from '@tanstack/react-query'
6
10
  import { useCurrentPerson } from './use_current_person'
7
11
  import { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'
8
12
  import { getMessagesRequestArgs } from './use_conversation_messages'
9
13
  import { getRequestQueryKey } from './use_suspense_api'
14
+ import { JoltReactionEvent } from '../types/jolt_events'
15
+ import { transformReactionEventDataToReactionCountResource } from '../utils/jolt/transform_reaction_event_data_to_reaction_count_resource'
10
16
 
11
17
  interface Props {
12
18
  conversationId: string
13
- refetchMessages?: () => void
14
19
  }
15
20
 
16
- export function useConversationMessagesJoltEvents({ conversationId, refetchMessages }: Props) {
21
+ export function useConversationMessagesJoltEvents({ conversationId }: Props) {
17
22
  const queryClient = useQueryClient()
18
23
  const currentPerson = useCurrentPerson()
19
24
  const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)
20
25
  const messagesRequestArgs = getMessagesRequestArgs({ conversation_id: conversationId })
21
26
  const messagesQueryKey = getRequestQueryKey(messagesRequestArgs)
22
27
 
23
- const handleMessageJoltEvent = async () => {
24
- refetchMessages?.()
28
+ const handleMessageUpdateOrCreate = async (e: MessageCreatedEvent) => {
29
+ const { data } = e.data
30
+ const message = transformMessageEventDataToMessageResource({
31
+ data,
32
+ currentPersonId: currentPerson.id,
33
+ })
34
+
35
+ queryClient.setQueryData<QueryData>(messagesQueryKey, prev => {
36
+ if (e.event === 'message.created') {
37
+ return updateOrCreateRecordInPagesData({
38
+ data: prev,
39
+ record: message,
40
+ processRecord: (record, current) => {
41
+ return { ...current, ...record }
42
+ },
43
+ })
44
+ } else {
45
+ return updateRecordInPagesData({
46
+ data: prev,
47
+ record: message,
48
+ processRecord: (record, current) => {
49
+ return { ...current, ...record }
50
+ },
51
+ })
52
+ }
53
+ })
25
54
  }
26
55
 
27
- const handleMessageUpdateOrCreate = async (e: MessageCreatedEvent) => {
56
+ const handleMessageDeleted = async (e: MessageDeletedEvent) => {
28
57
  const { data } = e.data
29
58
  const message = transformMessageEventDataToMessageResource({
30
59
  data,
31
60
  currentPersonId: currentPerson.id,
32
61
  })
33
62
 
63
+ queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>
64
+ deleteRecordInPagesData({ data: prev, record: message })
65
+ )
66
+ }
67
+
68
+ const handleReactionJoltEvent = async (e: JoltReactionEvent) => {
69
+ const { data } = e.data
70
+ const message = { id: data.message_sort_key } as MessageResource
34
71
  queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>
35
72
  updateRecordInPagesData({
36
73
  data: prev,
37
74
  record: message,
38
- processRecord: (record, current) => {
39
- return { ...current, ...record }
75
+ processRecord: (record, oldMessage) => {
76
+ const reactionCounts = oldMessage.reactionCounts || []
77
+ let foundMatch = false
78
+ let newReactionCounts = reactionCounts.map(reactionCount => {
79
+ if (reactionCount.value === data.value) {
80
+ foundMatch = true
81
+ return transformReactionEventDataToReactionCountResource({
82
+ data,
83
+ oldData: reactionCount,
84
+ event: e.event,
85
+ currentPersonId: currentPerson.id,
86
+ })
87
+ }
88
+ return reactionCount
89
+ })
90
+
91
+ if (!foundMatch) {
92
+ const newReactionCount = transformReactionEventDataToReactionCountResource({
93
+ data,
94
+ event: e.event,
95
+ currentPersonId: currentPerson.id,
96
+ })
97
+
98
+ if (newReactionCount?.count) {
99
+ newReactionCounts = [...newReactionCounts, newReactionCount]
100
+ }
101
+ }
102
+
103
+ return { ...oldMessage, reactionCounts: newReactionCounts }
40
104
  },
41
105
  })
42
106
  )
@@ -44,8 +108,8 @@ export function useConversationMessagesJoltEvents({ conversationId, refetchMessa
44
108
 
45
109
  useJoltEvent(joltChannel, 'message.created', handleMessageUpdateOrCreate)
46
110
  useJoltEvent(joltChannel, 'message.updated', handleMessageUpdateOrCreate)
47
- useJoltEvent(joltChannel, 'message.deleted', handleMessageJoltEvent)
48
- useJoltEvent(joltChannel, 'reaction.*', handleMessageJoltEvent)
111
+ useJoltEvent(joltChannel, 'message.destroyed', handleMessageDeleted)
112
+ useJoltEvent(joltChannel, 'reaction.*', handleReactionJoltEvent)
49
113
  }
50
114
 
51
115
  type QueryData = InfiniteData<ApiCollection<MessageResource>>
@@ -8,12 +8,41 @@ import { ApiCollection, ResourceObject } from '../../types'
8
8
 
9
9
  /**
10
10
  * updateRecordInPagesData
11
- * Can be used to add as well but it's not at all efficient. It's better to use addRecordInPagesData.
11
+ * Updates record if found in the cache, otherwise noops.
12
12
  */
13
13
  export function updateRecordInPagesData<T extends ResourceObject>({
14
14
  data,
15
15
  record,
16
16
  processRecord = r => r,
17
+ }: {
18
+ data?: { pages: ApiCollection<T>[]; pageParams: any }
19
+ record: T
20
+ processRecord?: (_next: T, _prev: T) => T
21
+ }) {
22
+ if (!data) return data
23
+
24
+ const newPages = data.pages.map(page => {
25
+ const newData = page.data.map(message => {
26
+ if (message.id === record.id) {
27
+ return processRecord(record, message)
28
+ }
29
+ return message
30
+ })
31
+
32
+ return { ...page, data: newData }
33
+ })
34
+
35
+ return { ...data, pages: newPages }
36
+ }
37
+
38
+ /**
39
+ * updateOrCreateRecordInPagesData
40
+ * Updates record if found in the cache, otherwise inserts.
41
+ */
42
+ export function updateOrCreateRecordInPagesData<T extends ResourceObject>({
43
+ data,
44
+ record,
45
+ processRecord = r => r,
17
46
  }: {
18
47
  data?: { pages: ApiCollection<T>[]; pageParams: any }
19
48
  record: T
@@ -35,7 +64,6 @@ export function updateRecordInPagesData<T extends ResourceObject>({
35
64
  })
36
65
 
37
66
  if (!foundRecord) {
38
- // Can be used to add as well but it's not at all efficient. It's better to use addRecordInPagesData.
39
67
  // This is a fallback for when the record is not found in the cache.
40
68
  const firstPage = { ...newPages[0] }
41
69
  firstPage.data = [processRecord(record), ...firstPage.data]
@@ -52,7 +80,7 @@ export function addRecordInPagesData<T extends ResourceObject>({
52
80
  }: {
53
81
  data?: { pages: ApiCollection<T>[]; pageParams: any }
54
82
  record: T
55
- processRecord?: (_next: T, _prev?: T) => T
83
+ processRecord?: (_next: T) => T
56
84
  }) {
57
85
  if (!data) return data
58
86
 
@@ -0,0 +1,36 @@
1
+ import { JoltReactionEvent } from '../../types/jolt_events'
2
+ import { ReactionCreatedEvent } from '../../types/jolt_events/reaction_events'
3
+ import { ReactionCountResource } from '../../types/resources/reaction'
4
+
5
+ interface Props {
6
+ data: ReactionCreatedEvent['data']['data']
7
+ oldData?: ReactionCountResource
8
+ event: JoltReactionEvent['event']
9
+ currentPersonId: string
10
+ }
11
+
12
+ export function transformReactionEventDataToReactionCountResource({
13
+ data,
14
+ oldData,
15
+ event,
16
+ currentPersonId,
17
+ }: Props): ReactionCountResource {
18
+ let authorIds = new Set(oldData?.authorIds || [])
19
+ if (event === 'reaction.created') {
20
+ authorIds.add(data.author_id.toString())
21
+ } else if (event === 'reaction.destroyed') {
22
+ authorIds.delete(data.author_id.toString())
23
+ }
24
+
25
+ const mine = authorIds.has(currentPersonId.toString())
26
+
27
+ return {
28
+ type: 'ReactionCount',
29
+ id: `${data.message_sort_key}/${data.value}`,
30
+ value: data.value,
31
+ count: data.count,
32
+ mine: mine ? 1 : 0,
33
+ messageId: data.message_sort_key,
34
+ authorIds: Array.from(authorIds),
35
+ }
36
+ }