@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.
- package/build/components/conversation/message_form.js +2 -2
- package/build/components/conversation/message_form.js.map +1 -1
- package/build/components/conversation/message_reaction.d.ts +1 -1
- package/build/components/conversation/message_reaction.d.ts.map +1 -1
- package/build/components/conversation/message_reaction.js +4 -0
- package/build/components/conversation/message_reaction.js.map +1 -1
- package/build/hooks/use_conversation_jolt_events.js +2 -2
- package/build/hooks/use_conversation_jolt_events.js.map +1 -1
- package/build/hooks/use_conversation_messages.d.ts.map +1 -1
- package/build/hooks/use_conversation_messages.js +2 -2
- package/build/hooks/use_conversation_messages.js.map +1 -1
- package/build/hooks/use_conversation_messages_jolt_events.d.ts +1 -2
- package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
- package/build/hooks/use_conversation_messages_jolt_events.js +63 -9
- package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
- package/build/utils/cache/page_mutations.d.ts +21 -2
- package/build/utils/cache/page_mutations.d.ts.map +1 -1
- package/build/utils/cache/page_mutations.js +19 -2
- package/build/utils/cache/page_mutations.js.map +1 -1
- package/build/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.d.ts +12 -0
- package/build/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.d.ts.map +1 -0
- package/build/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.js +20 -0
- package/build/utils/jolt/transform_reaction_event_data_to_reaction_count_resource.js.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/utils/cache/page_mutations.ts +85 -3
- package/src/components/conversation/message_form.tsx +2 -2
- package/src/components/conversation/message_reaction.tsx +3 -0
- package/src/hooks/use_conversation_jolt_events.ts +2 -2
- package/src/hooks/use_conversation_messages.ts +5 -2
- package/src/hooks/use_conversation_messages_jolt_events.ts +75 -11
- package/src/utils/cache/page_mutations.ts +31 -3
- 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 {
|
|
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 =>
|
|
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":"AAAA,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,EAAgB,WAAW,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACjF,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAa,MAAM,cAAc,CAAA;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAEnG,OAAO,EAAE,
|
|
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,
|
|
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,
|
|
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 =>
|
|
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,
|
|
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":"
|
|
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":"
|
|
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
|
|
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":"
|
|
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
|
-
|
|
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,
|
|
27
|
-
|
|
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.
|
|
34
|
-
useJoltEvent(joltChannel, 'reaction.*',
|
|
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,
|
|
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,EACL,uBAAuB,EACvB,+BAA+B,EAC/B,uBAAuB,GACxB,MAAM,UAAU,CAAA;AAEjB,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;AAEvD,OAAO,EAAE,iDAAiD,EAAE,MAAM,wEAAwE,CAAA;AAM1I,MAAM,UAAU,iCAAiC,CAAC,EAAE,cAAc,EAAS;IACzE,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,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;YAC3D,IAAI,CAAC,CAAC,KAAK,KAAK,iBAAiB,EAAE,CAAC;gBAClC,OAAO,+BAA+B,CAAC;oBACrC,IAAI,EAAE,IAAI;oBACV,MAAM,EAAE,OAAO;oBACf,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;wBACjC,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAA;oBAClC,CAAC;iBACF,CAAC,CAAA;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,uBAAuB,CAAC;oBAC7B,IAAI,EAAE,IAAI;oBACV,MAAM,EAAE,OAAO;oBACf,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;wBACjC,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAA;oBAClC,CAAC;iBACF,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM,oBAAoB,GAAG,KAAK,EAAE,CAAsB,EAAE,EAAE;QAC5D,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,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CACzD,CAAA;IACH,CAAC,CAAA;IAED,MAAM,uBAAuB,GAAG,KAAK,EAAE,CAAoB,EAAE,EAAE;QAC7D,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAA;QACvB,MAAM,OAAO,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,gBAAgB,EAAqB,CAAA;QAChE,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,UAAU,EAAE,EAAE;gBACpC,MAAM,cAAc,GAAG,UAAU,CAAC,cAAc,IAAI,EAAE,CAAA;gBACtD,IAAI,UAAU,GAAG,KAAK,CAAA;gBACtB,IAAI,iBAAiB,GAAG,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE;oBACzD,IAAI,aAAa,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;wBACvC,UAAU,GAAG,IAAI,CAAA;wBACjB,OAAO,iDAAiD,CAAC;4BACvD,IAAI;4BACJ,OAAO,EAAE,aAAa;4BACtB,KAAK,EAAE,CAAC,CAAC,KAAK;4BACd,eAAe,EAAE,aAAa,CAAC,EAAE;yBAClC,CAAC,CAAA;oBACJ,CAAC;oBACD,OAAO,aAAa,CAAA;gBACtB,CAAC,CAAC,CAAA;gBAEF,IAAI,CAAC,UAAU,EAAE,CAAC;oBAChB,MAAM,gBAAgB,GAAG,iDAAiD,CAAC;wBACzE,IAAI;wBACJ,KAAK,EAAE,CAAC,CAAC,KAAK;wBACd,eAAe,EAAE,aAAa,CAAC,EAAE;qBAClC,CAAC,CAAA;oBAEF,IAAI,gBAAgB,EAAE,KAAK,EAAE,CAAC;wBAC5B,iBAAiB,GAAG,CAAC,GAAG,iBAAiB,EAAE,gBAAgB,CAAC,CAAA;oBAC9D,CAAC;gBACH,CAAC;gBAED,OAAO,EAAE,GAAG,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAA;YAC7D,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,mBAAmB,EAAE,oBAAoB,CAAC,CAAA;IACpE,YAAY,CAAC,WAAW,EAAE,YAAY,EAAE,uBAAuB,CAAC,CAAA;AAClE,CAAC","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
|
-
*
|
|
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
|
|
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,
|
|
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
|
-
*
|
|
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,
|
|
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.
|
|
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": "
|
|
55
|
+
"gitHead": "c63ab69895844b3623090178214fad9f22eded1a"
|
|
56
56
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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 {
|
|
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
|
-
|
|
63
|
+
updateOrCreateRecordInPagesData({
|
|
64
64
|
data,
|
|
65
65
|
record: updatedMessage,
|
|
66
66
|
})
|
|
@@ -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,
|
|
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
|
-
|
|
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 =
|
|
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 {
|
|
4
|
-
|
|
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
|
|
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
|
|
24
|
-
|
|
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
|
|
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,
|
|
39
|
-
|
|
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.
|
|
48
|
-
useJoltEvent(joltChannel, 'reaction.*',
|
|
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
|
-
*
|
|
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
|
|
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
|
+
}
|