@planningcenter/chat-react-native 3.2.0-rc.2 → 3.2.0-rc.4

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 (28) hide show
  1. package/build/components/conversations/action_toggle_button.d.ts +1 -1
  2. package/build/components/conversations/action_toggle_button.d.ts.map +1 -1
  3. package/build/components/conversations/action_toggle_button.js +2 -1
  4. package/build/components/conversations/action_toggle_button.js.map +1 -1
  5. package/build/components/conversations/conversation_actions.js +20 -5
  6. package/build/components/conversations/conversation_actions.js.map +1 -1
  7. package/build/components/conversations/conversations.d.ts +3 -6
  8. package/build/components/conversations/conversations.d.ts.map +1 -1
  9. package/build/components/conversations/conversations.js +3 -10
  10. package/build/components/conversations/conversations.js.map +1 -1
  11. package/build/contexts/conversations_context.d.ts +14 -0
  12. package/build/contexts/conversations_context.d.ts.map +1 -0
  13. package/build/contexts/conversations_context.js +47 -0
  14. package/build/contexts/conversations_context.js.map +1 -0
  15. package/build/hooks/use_conversations.d.ts +6 -32
  16. package/build/hooks/use_conversations.d.ts.map +1 -1
  17. package/build/hooks/use_conversations.js +15 -14
  18. package/build/hooks/use_conversations.js.map +1 -1
  19. package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
  20. package/build/screens/conversations/conversations_screen.js +5 -12
  21. package/build/screens/conversations/conversations_screen.js.map +1 -1
  22. package/package.json +2 -2
  23. package/src/components/conversations/action_toggle_button.tsx +2 -1
  24. package/src/components/conversations/conversation_actions.tsx +29 -6
  25. package/src/components/conversations/conversations.tsx +16 -26
  26. package/src/contexts/conversations_context.tsx +79 -0
  27. package/src/hooks/use_conversations.ts +34 -16
  28. package/src/screens/conversations/conversations_screen.tsx +5 -18
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { type PressableProps } from 'react-native';
2
+ import { type PressableProps } from 'react-native-gesture-handler';
3
3
  import { IconString } from '../display';
4
4
  interface ActionToggleButtonProps extends PressableProps {
5
5
  backgroundColor: string;
@@ -1 +1 @@
1
- {"version":3,"file":"action_toggle_button.d.ts","sourceRoot":"","sources":["../../../src/components/conversations/action_toggle_button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAyB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AACzE,OAAO,EAAQ,UAAU,EAAiB,MAAM,YAAY,CAAA;AAI5D,UAAU,uBAAwB,SAAQ,cAAc;IACtD,eAAe,EAAE,MAAM,CAAA;IACvB,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE;QACb,IAAI,EAAE;YAAE,QAAQ,EAAE,UAAU,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;QAC7C,KAAK,EAAE;YAAE,QAAQ,EAAE,UAAU,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAC/C,CAAA;IACD,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,eAAe,EACf,OAAO,EACP,aAAa,EACb,QAAgB,EAChB,OAAO,EACP,OAAe,EACf,GAAG,KAAK,EACT,EAAE,uBAAuB,qBA8BzB"}
1
+ {"version":3,"file":"action_toggle_button.d.ts","sourceRoot":"","sources":["../../../src/components/conversations/action_toggle_button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7E,OAAO,EAAQ,UAAU,EAAiB,MAAM,YAAY,CAAA;AAI5D,UAAU,uBAAwB,SAAQ,cAAc;IACtD,eAAe,EAAE,MAAM,CAAA;IACvB,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE;QACb,IAAI,EAAE;YAAE,QAAQ,EAAE,UAAU,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;QAC7C,KAAK,EAAE;YAAE,QAAQ,EAAE,UAAU,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAC/C,CAAA;IACD,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,eAAe,EACf,OAAO,EACP,aAAa,EACb,QAAgB,EAChB,OAAO,EACP,OAAe,EACf,GAAG,KAAK,EACT,EAAE,uBAAuB,qBA8BzB"}
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import { Pressable, StyleSheet } from 'react-native';
2
+ import { StyleSheet } from 'react-native';
3
+ import { Pressable } from 'react-native-gesture-handler';
3
4
  import { Icon, Spinner, Text } from '../display';
4
5
  import { useCreateAndroidRippleColor, useTheme } from '../../hooks';
5
6
  import { platformFontWeightMedium, platformPressedOpacityStyle } from '../../utils/styles';
@@ -1 +1 @@
1
- {"version":3,"file":"action_toggle_button.js","sourceRoot":"","sources":["../../../src/components/conversations/action_toggle_button.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react'\nimport { Pressable, StyleSheet, type PressableProps } from 'react-native'\nimport { Icon, IconString, Spinner, Text } from '../display'\nimport { useCreateAndroidRippleColor, useTheme } from '../../hooks'\nimport { platformFontWeightMedium, platformPressedOpacityStyle } from '../../utils/styles'\n\ninterface ActionToggleButtonProps extends PressableProps {\n backgroundColor: string\n toggled: boolean\n toggleContent: {\n true: { iconName: IconString; label: string }\n false: { iconName: IconString; label: string }\n }\n loading?: boolean\n}\n\nexport function ActionToggleButton({\n backgroundColor,\n onPress,\n toggleContent,\n disabled = false,\n toggled,\n loading = false,\n ...props\n}: ActionToggleButtonProps) {\n const styles = useStyles({ backgroundColor, disabled })\n const androidRippleColor = useCreateAndroidRippleColor({\n color: backgroundColor,\n })\n\n const { iconName, label } = toggleContent[toggled ? 'true' : 'false']\n\n return (\n <Pressable\n onPress={onPress}\n style={({ pressed }) => [styles.button, pressed && platformPressedOpacityStyle]}\n android_ripple={{ color: androidRippleColor, borderless: false, foreground: true }}\n disabled={disabled || loading}\n accessibilityRole=\"togglebutton\"\n accessibilityState={{ checked: toggled }}\n {...props}\n >\n {loading ? (\n <Spinner size={20} />\n ) : (\n <>\n <Icon name={iconName} style={styles.icon} size={20} />\n <Text variant=\"footnote\" style={styles.text}>\n {label}\n </Text>\n </>\n )}\n </Pressable>\n )\n}\n\nconst useStyles = ({ backgroundColor, disabled }: Partial<ActionToggleButtonProps>) => {\n const { colors } = useTheme()\n const fillColor = disabled ? colors.textColorDefaultDisabled : colors.fillColorNeutral100Inverted\n const buttonBackgroundColor = disabled\n ? colors.fillColorButtonNeutralSolidDisabled\n : backgroundColor\n\n return StyleSheet.create({\n button: {\n flex: 1,\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n height: '100%',\n backgroundColor: buttonBackgroundColor,\n },\n icon: {\n color: fillColor,\n marginTop: 4,\n },\n text: {\n color: fillColor,\n fontWeight: platformFontWeightMedium,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"action_toggle_button.js","sourceRoot":"","sources":["../../../src/components/conversations/action_toggle_button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,SAAS,EAAuB,MAAM,8BAA8B,CAAA;AAC7E,OAAO,EAAE,IAAI,EAAc,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAC5D,OAAO,EAAE,2BAA2B,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAA;AAY1F,MAAM,UAAU,kBAAkB,CAAC,EACjC,eAAe,EACf,OAAO,EACP,aAAa,EACb,QAAQ,GAAG,KAAK,EAChB,OAAO,EACP,OAAO,GAAG,KAAK,EACf,GAAG,KAAK,EACgB;IACxB,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC,CAAA;IACvD,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;QACrD,KAAK,EAAE,eAAe;KACvB,CAAC,CAAA;IAEF,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;IAErE,OAAO,CACL,CAAC,SAAS,CACR,OAAO,CAAC,CAAC,OAAO,CAAC,CACjB,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,IAAI,2BAA2B,CAAC,CAAC,CAChF,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CACnF,QAAQ,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,CAC9B,iBAAiB,CAAC,cAAc,CAChC,kBAAkB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CACzC,IAAI,KAAK,CAAC,CAEV;MAAA,CAAC,OAAO,CAAC,CAAC,CAAC,CACT,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAG,CACtB,CAAC,CAAC,CAAC,CACF,EACE;UAAA,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EACnD;UAAA,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAC1C;YAAA,CAAC,KAAK,CACR;UAAA,EAAE,IAAI,CACR;QAAA,GAAG,CACJ,CACH;IAAA,EAAE,SAAS,CAAC,CACb,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,CAAC,EAAE,eAAe,EAAE,QAAQ,EAAoC,EAAE,EAAE;IACpF,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,MAAM,CAAC,2BAA2B,CAAA;IACjG,MAAM,qBAAqB,GAAG,QAAQ;QACpC,CAAC,CAAC,MAAM,CAAC,mCAAmC;QAC5C,CAAC,CAAC,eAAe,CAAA;IAEnB,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,MAAM,EAAE;YACN,IAAI,EAAE,CAAC;YACP,aAAa,EAAE,QAAQ;YACvB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,GAAG,EAAE,CAAC;YACN,MAAM,EAAE,MAAM;YACd,eAAe,EAAE,qBAAqB;SACvC;QACD,IAAI,EAAE;YACJ,KAAK,EAAE,SAAS;YAChB,SAAS,EAAE,CAAC;SACb;QACD,IAAI,EAAE;YACJ,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,wBAAwB;SACrC;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import React from 'react'\nimport { StyleSheet } from 'react-native'\nimport { Pressable, type PressableProps } from 'react-native-gesture-handler'\nimport { Icon, IconString, Spinner, Text } from '../display'\nimport { useCreateAndroidRippleColor, useTheme } from '../../hooks'\nimport { platformFontWeightMedium, platformPressedOpacityStyle } from '../../utils/styles'\n\ninterface ActionToggleButtonProps extends PressableProps {\n backgroundColor: string\n toggled: boolean\n toggleContent: {\n true: { iconName: IconString; label: string }\n false: { iconName: IconString; label: string }\n }\n loading?: boolean\n}\n\nexport function ActionToggleButton({\n backgroundColor,\n onPress,\n toggleContent,\n disabled = false,\n toggled,\n loading = false,\n ...props\n}: ActionToggleButtonProps) {\n const styles = useStyles({ backgroundColor, disabled })\n const androidRippleColor = useCreateAndroidRippleColor({\n color: backgroundColor,\n })\n\n const { iconName, label } = toggleContent[toggled ? 'true' : 'false']\n\n return (\n <Pressable\n onPress={onPress}\n style={({ pressed }) => [styles.button, pressed && platformPressedOpacityStyle]}\n android_ripple={{ color: androidRippleColor, borderless: false, foreground: true }}\n disabled={disabled || loading}\n accessibilityRole=\"togglebutton\"\n accessibilityState={{ checked: toggled }}\n {...props}\n >\n {loading ? (\n <Spinner size={20} />\n ) : (\n <>\n <Icon name={iconName} style={styles.icon} size={20} />\n <Text variant=\"footnote\" style={styles.text}>\n {label}\n </Text>\n </>\n )}\n </Pressable>\n )\n}\n\nconst useStyles = ({ backgroundColor, disabled }: Partial<ActionToggleButtonProps>) => {\n const { colors } = useTheme()\n const fillColor = disabled ? colors.textColorDefaultDisabled : colors.fillColorNeutral100Inverted\n const buttonBackgroundColor = disabled\n ? colors.fillColorButtonNeutralSolidDisabled\n : backgroundColor\n\n return StyleSheet.create({\n button: {\n flex: 1,\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n height: '100%',\n backgroundColor: buttonBackgroundColor,\n },\n icon: {\n color: fillColor,\n marginTop: 4,\n },\n text: {\n color: fillColor,\n fontWeight: platformFontWeightMedium,\n },\n })\n}\n"]}
@@ -38,18 +38,33 @@ export function ConversationActions({ children, conversation, style, onPress, })
38
38
  function LeftActions({ conversation, onClose }) {
39
39
  const styles = useStyles();
40
40
  const [muted, setMuted] = useState(conversation.muted);
41
+ const [latestMessageUnread, setLatestMessageUnread] = useState(conversation.unreadCount > 0);
42
+ const emptyConversation = conversation.lastMessageCreatedAt === null;
43
+ const muteToggleContent = {
44
+ true: { iconName: 'general.bellMuted', label: 'Mute' },
45
+ false: { iconName: 'general.bell', label: 'Unmute' },
46
+ };
47
+ const latestMessageUnreadToggleContent = {
48
+ true: { iconName: 'general.outlinedTextMessage', label: 'Mark read' },
49
+ false: { iconName: 'general.textMessageNotifications', label: 'Mark unread' },
50
+ };
41
51
  const handleMute = useCallback(() => {
42
52
  setMuted(!muted);
43
53
  onClose();
44
54
  }, [muted, onClose]);
55
+ const handleLatestMessageUnread = useCallback(() => {
56
+ setLatestMessageUnread(!latestMessageUnread);
57
+ onClose();
58
+ }, [latestMessageUnread, onClose]);
45
59
  return (<View style={styles.actionButtonContainer}>
46
- <ActionToggleButton loading={false} toggled={muted} toggleContent={{
47
- true: { iconName: 'general.bellMuted', label: 'Mute' },
48
- false: { iconName: 'general.bell', label: 'Unmute' },
49
- }} onPress={() => handleMute()} backgroundColor={tokens.fillColorInteractionSwipeSecondary}/>
60
+ <ActionToggleButton loading={false} // TODO: Might need this when there is data fetching
61
+ disabled={emptyConversation} toggled={latestMessageUnread} onPress={() => handleLatestMessageUnread()} toggleContent={latestMessageUnreadToggleContent} backgroundColor={tokens.fillColorInteractionSwipeDefault}/>
62
+ <ActionToggleButton loading={false} // TODO: Might need this when there is data fetching
63
+ toggled={muted} onPress={() => handleMute()} toggleContent={muteToggleContent} backgroundColor={tokens.fillColorInteractionSwipeSecondary}/>
50
64
  </View>);
51
65
  }
52
66
  const ACTION_BUTTON_WIDTH = 120;
67
+ const ACTION_BUTTON_COUNT = 2;
53
68
  const useStyles = () => {
54
69
  const { colors } = useTheme();
55
70
  return StyleSheet.create({
@@ -59,7 +74,7 @@ const useStyles = () => {
59
74
  actionButtonContainer: {
60
75
  flexDirection: 'row',
61
76
  alignItems: 'center',
62
- width: ACTION_BUTTON_WIDTH,
77
+ width: ACTION_BUTTON_WIDTH * ACTION_BUTTON_COUNT,
63
78
  alignContent: 'stretch',
64
79
  },
65
80
  swipeableContainer: {
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_actions.js","sourceRoot":"","sources":["../../../src/components/conversations/conversation_actions.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react'\nimport { Platform, View, StyleSheet, ViewStyle, Pressable } from 'react-native'\nimport ReanimatedSwipeable, {\n SwipeableMethods,\n} from 'react-native-gesture-handler/ReanimatedSwipeable'\nimport { useTheme } from '../../hooks'\nimport { ActionToggleButton } from './action_toggle_button'\nimport { tokens } from '../../vendor/tapestry/tokens'\nimport { ConversationResource } from '../../types'\nimport { useConversationActionsContext } from '../../contexts/swipeable_active_conversation'\n\nexport function ConversationActions({\n children,\n conversation,\n style,\n onPress,\n}: {\n children: ReactNode\n conversation: ConversationResource\n onPress: () => void\n style?: ViewStyle\n}) {\n const swipeableRef = useRef<SwipeableMethods>(null)\n const styles = useStyles()\n const { activeConversationId, setActiveConversationId } = useConversationActionsContext()\n const [disabled, setDisabled] = useState(false)\n const overshootLeft = Platform.OS === 'ios'\n\n const handleSwipeableClose = () => {\n setDisabled(false)\n swipeableRef.current?.close()\n }\n\n const handleSwipeableOpen = () => {\n setDisabled(true)\n setActiveConversationId(conversation.id)\n }\n\n const handlePress = useCallback(() => {\n if (disabled || !onPress) return\n onPress()\n }, [disabled, onPress])\n\n useEffect(() => {\n if (activeConversationId === conversation.id) return\n\n handleSwipeableClose()\n }, [activeConversationId, conversation.id])\n\n return (\n <ReanimatedSwipeable\n ref={swipeableRef}\n childrenContainerStyle={styles.swipeableChildContainer}\n containerStyle={styles.swipeableContainer}\n overshootFriction={8}\n overshootLeft={overshootLeft}\n overshootRight={false}\n onSwipeableOpenStartDrag={handleSwipeableOpen}\n onSwipeableClose={() => setDisabled(false)}\n renderLeftActions={() => (\n <LeftActions conversation={conversation} onClose={handleSwipeableClose} />\n )}\n >\n <Pressable onPress={handlePress} style={style}>\n {children}\n </Pressable>\n </ReanimatedSwipeable>\n )\n}\n\ninterface LeftActionsProps {\n conversation: ConversationResource\n onClose: () => void\n}\n\nfunction LeftActions({ conversation, onClose }: LeftActionsProps) {\n const styles = useStyles()\n const [muted, setMuted] = useState(conversation.muted)\n\n const handleMute = useCallback(() => {\n setMuted(!muted)\n onClose()\n }, [muted, onClose])\n\n return (\n <View style={styles.actionButtonContainer}>\n <ActionToggleButton\n loading={false}\n toggled={muted}\n toggleContent={{\n true: { iconName: 'general.bellMuted', label: 'Mute' },\n false: { iconName: 'general.bell', label: 'Unmute' },\n }}\n onPress={() => handleMute()}\n backgroundColor={tokens.fillColorInteractionSwipeSecondary}\n />\n </View>\n )\n}\n\nconst ACTION_BUTTON_WIDTH = 120\n\nconst useStyles = () => {\n const { colors } = useTheme()\n return StyleSheet.create({\n swipeableChildContainer: {\n backgroundColor: colors.surfaceColor100,\n },\n actionButtonContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n width: ACTION_BUTTON_WIDTH,\n alignContent: 'stretch',\n },\n swipeableContainer: {\n backgroundColor: colors.surfaceColor090,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"conversation_actions.js","sourceRoot":"","sources":["../../../src/components/conversations/conversation_actions.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAa,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAClF,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAa,SAAS,EAAE,MAAM,cAAc,CAAA;AAC/E,OAAO,mBAEN,MAAM,kDAAkD,CAAA;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAA;AAErD,OAAO,EAAE,6BAA6B,EAAE,MAAM,8CAA8C,CAAA;AAE5F,MAAM,UAAU,mBAAmB,CAAC,EAClC,QAAQ,EACR,YAAY,EACZ,KAAK,EACL,OAAO,GAMR;IACC,MAAM,YAAY,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAA;IACnD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,GAAG,6BAA6B,EAAE,CAAA;IACzF,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC/C,MAAM,aAAa,GAAG,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAA;IAE3C,MAAM,oBAAoB,GAAG,GAAG,EAAE;QAChC,WAAW,CAAC,KAAK,CAAC,CAAA;QAClB,YAAY,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;IAC/B,CAAC,CAAA;IAED,MAAM,mBAAmB,GAAG,GAAG,EAAE;QAC/B,WAAW,CAAC,IAAI,CAAC,CAAA;QACjB,uBAAuB,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;IAC1C,CAAC,CAAA;IAED,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,IAAI,QAAQ,IAAI,CAAC,OAAO;YAAE,OAAM;QAChC,OAAO,EAAE,CAAA;IACX,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;IAEvB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,oBAAoB,KAAK,YAAY,CAAC,EAAE;YAAE,OAAM;QAEpD,oBAAoB,EAAE,CAAA;IACxB,CAAC,EAAE,CAAC,oBAAoB,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC,CAAA;IAE3C,OAAO,CACL,CAAC,mBAAmB,CAClB,GAAG,CAAC,CAAC,YAAY,CAAC,CAClB,sBAAsB,CAAC,CAAC,MAAM,CAAC,uBAAuB,CAAC,CACvD,cAAc,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAC1C,iBAAiB,CAAC,CAAC,CAAC,CAAC,CACrB,aAAa,CAAC,CAAC,aAAa,CAAC,CAC7B,cAAc,CAAC,CAAC,KAAK,CAAC,CACtB,wBAAwB,CAAC,CAAC,mBAAmB,CAAC,CAC9C,gBAAgB,CAAC,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAC3C,iBAAiB,CAAC,CAAC,GAAG,EAAE,CAAC,CACvB,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,EAAG,CAC3E,CAAC,CAEF;MAAA,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAC5C;QAAA,CAAC,QAAQ,CACX;MAAA,EAAE,SAAS,CACb;IAAA,EAAE,mBAAmB,CAAC,CACvB,CAAA;AACH,CAAC;AAOD,SAAS,WAAW,CAAC,EAAE,YAAY,EAAE,OAAO,EAAoB;IAC9D,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;IACtD,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,WAAW,GAAG,CAAC,CAAC,CAAA;IAC5F,MAAM,iBAAiB,GAAG,YAAY,CAAC,oBAAoB,KAAK,IAAI,CAAA;IAEpE,MAAM,iBAAiB,GAAG;QACxB,IAAI,EAAE,EAAE,QAAQ,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,EAAE;QACtD,KAAK,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE;KAC5C,CAAA;IAEV,MAAM,gCAAgC,GAAG;QACvC,IAAI,EAAE,EAAE,QAAQ,EAAE,6BAA6B,EAAE,KAAK,EAAE,WAAW,EAAE;QACrE,KAAK,EAAE,EAAE,QAAQ,EAAE,kCAAkC,EAAE,KAAK,EAAE,aAAa,EAAE;KACrE,CAAA;IAEV,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;QAClC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAA;QAChB,OAAO,EAAE,CAAA;IACX,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAA;IAEpB,MAAM,yBAAyB,GAAG,WAAW,CAAC,GAAG,EAAE;QACjD,sBAAsB,CAAC,CAAC,mBAAmB,CAAC,CAAA;QAC5C,OAAO,EAAE,CAAA;IACX,CAAC,EAAE,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC,CAAA;IAElC,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC,CACxC;MAAA,CAAC,kBAAkB,CACjB,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,oDAAoD;KACpE,QAAQ,CAAC,CAAC,iBAAiB,CAAC,CAC5B,OAAO,CAAC,CAAC,mBAAmB,CAAC,CAC7B,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,yBAAyB,EAAE,CAAC,CAC3C,aAAa,CAAC,CAAC,gCAAgC,CAAC,CAChD,eAAe,CAAC,CAAC,MAAM,CAAC,gCAAgC,CAAC,EAE3D;MAAA,CAAC,kBAAkB,CACjB,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,oDAAoD;KACpE,OAAO,CAAC,CAAC,KAAK,CAAC,CACf,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,CAC5B,aAAa,CAAC,CAAC,iBAAiB,CAAC,CACjC,eAAe,CAAC,CAAC,MAAM,CAAC,kCAAkC,CAAC,EAE/D;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,MAAM,mBAAmB,GAAG,GAAG,CAAA;AAC/B,MAAM,mBAAmB,GAAG,CAAC,CAAA;AAE7B,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,uBAAuB,EAAE;YACvB,eAAe,EAAE,MAAM,CAAC,eAAe;SACxC;QACD,qBAAqB,EAAE;YACrB,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,QAAQ;YACpB,KAAK,EAAE,mBAAmB,GAAG,mBAAmB;YAChD,YAAY,EAAE,SAAS;SACxB;QACD,kBAAkB,EAAE;YAClB,eAAe,EAAE,MAAM,CAAC,eAAe;SACxC;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react'\nimport { Platform, View, StyleSheet, ViewStyle, Pressable } from 'react-native'\nimport ReanimatedSwipeable, {\n SwipeableMethods,\n} from 'react-native-gesture-handler/ReanimatedSwipeable'\nimport { useTheme } from '../../hooks'\nimport { ActionToggleButton } from './action_toggle_button'\nimport { tokens } from '../../vendor/tapestry/tokens'\nimport { ConversationResource } from '../../types'\nimport { useConversationActionsContext } from '../../contexts/swipeable_active_conversation'\n\nexport function ConversationActions({\n children,\n conversation,\n style,\n onPress,\n}: {\n children: ReactNode\n conversation: ConversationResource\n onPress: () => void\n style?: ViewStyle\n}) {\n const swipeableRef = useRef<SwipeableMethods>(null)\n const styles = useStyles()\n const { activeConversationId, setActiveConversationId } = useConversationActionsContext()\n const [disabled, setDisabled] = useState(false)\n const overshootLeft = Platform.OS === 'ios'\n\n const handleSwipeableClose = () => {\n setDisabled(false)\n swipeableRef.current?.close()\n }\n\n const handleSwipeableOpen = () => {\n setDisabled(true)\n setActiveConversationId(conversation.id)\n }\n\n const handlePress = useCallback(() => {\n if (disabled || !onPress) return\n onPress()\n }, [disabled, onPress])\n\n useEffect(() => {\n if (activeConversationId === conversation.id) return\n\n handleSwipeableClose()\n }, [activeConversationId, conversation.id])\n\n return (\n <ReanimatedSwipeable\n ref={swipeableRef}\n childrenContainerStyle={styles.swipeableChildContainer}\n containerStyle={styles.swipeableContainer}\n overshootFriction={8}\n overshootLeft={overshootLeft}\n overshootRight={false}\n onSwipeableOpenStartDrag={handleSwipeableOpen}\n onSwipeableClose={() => setDisabled(false)}\n renderLeftActions={() => (\n <LeftActions conversation={conversation} onClose={handleSwipeableClose} />\n )}\n >\n <Pressable onPress={handlePress} style={style}>\n {children}\n </Pressable>\n </ReanimatedSwipeable>\n )\n}\n\ninterface LeftActionsProps {\n conversation: ConversationResource\n onClose: () => void\n}\n\nfunction LeftActions({ conversation, onClose }: LeftActionsProps) {\n const styles = useStyles()\n const [muted, setMuted] = useState(conversation.muted)\n const [latestMessageUnread, setLatestMessageUnread] = useState(conversation.unreadCount > 0)\n const emptyConversation = conversation.lastMessageCreatedAt === null\n\n const muteToggleContent = {\n true: { iconName: 'general.bellMuted', label: 'Mute' },\n false: { iconName: 'general.bell', label: 'Unmute' },\n } as const\n\n const latestMessageUnreadToggleContent = {\n true: { iconName: 'general.outlinedTextMessage', label: 'Mark read' },\n false: { iconName: 'general.textMessageNotifications', label: 'Mark unread' },\n } as const\n\n const handleMute = useCallback(() => {\n setMuted(!muted)\n onClose()\n }, [muted, onClose])\n\n const handleLatestMessageUnread = useCallback(() => {\n setLatestMessageUnread(!latestMessageUnread)\n onClose()\n }, [latestMessageUnread, onClose])\n\n return (\n <View style={styles.actionButtonContainer}>\n <ActionToggleButton\n loading={false} // TODO: Might need this when there is data fetching\n disabled={emptyConversation}\n toggled={latestMessageUnread}\n onPress={() => handleLatestMessageUnread()}\n toggleContent={latestMessageUnreadToggleContent}\n backgroundColor={tokens.fillColorInteractionSwipeDefault}\n />\n <ActionToggleButton\n loading={false} // TODO: Might need this when there is data fetching\n toggled={muted}\n onPress={() => handleMute()}\n toggleContent={muteToggleContent}\n backgroundColor={tokens.fillColorInteractionSwipeSecondary}\n />\n </View>\n )\n}\n\nconst ACTION_BUTTON_WIDTH = 120\nconst ACTION_BUTTON_COUNT = 2\n\nconst useStyles = () => {\n const { colors } = useTheme()\n return StyleSheet.create({\n swipeableChildContainer: {\n backgroundColor: colors.surfaceColor100,\n },\n actionButtonContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n width: ACTION_BUTTON_WIDTH * ACTION_BUTTON_COUNT,\n alignContent: 'stretch',\n },\n swipeableContainer: {\n backgroundColor: colors.surfaceColor090,\n },\n })\n}\n"]}
@@ -1,10 +1,7 @@
1
1
  import React from 'react';
2
- import { ConversationRequestArgs } from '../../utils/request/conversation';
3
- type ListHeaderComponent = React.ComponentType<any> | React.ReactElement<any, string | React.JSXElementConstructor<any>> | null;
4
- interface ConversationsProps extends Partial<Omit<ConversationRequestArgs, 'group'>> {
5
- chat_group_graph_id?: string;
6
- ListHeaderComponent?: ListHeaderComponent;
2
+ interface ConversationsProps {
3
+ ListHeaderComponent?: React.ComponentType<any> | React.ReactElement<any, string | React.JSXElementConstructor<any>> | null | undefined;
7
4
  }
8
- export declare const Conversations: ({ ListHeaderComponent, filter, chat_group_graph_id, gids, group_source_app_name, }: ConversationsProps) => React.JSX.Element;
5
+ export declare const Conversations: ({ ListHeaderComponent }: ConversationsProps) => React.JSX.Element;
9
6
  export {};
10
7
  //# sourceMappingURL=conversations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../../src/components/conversations/conversations.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAA;AAI1E,KAAK,mBAAmB,GACpB,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,GACxB,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,GAClE,IAAI,CAAA;AAER,UAAU,kBAAmB,SAAQ,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;IAClF,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;CAC1C;AAED,eAAO,MAAM,aAAa,uFAMvB,kBAAkB,sBA0CpB,CAAA"}
1
+ {"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../../src/components/conversations/conversations.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,UAAU,kBAAkB;IAC1B,mBAAmB,CAAC,EAChB,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,GACxB,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,GAClE,IAAI,GACJ,SAAS,CAAA;CACd;AAED,eAAO,MAAM,aAAa,4BAA6B,kBAAkB,sBA0CxE,CAAA"}
@@ -2,22 +2,15 @@ import { useNavigation } from '@react-navigation/native';
2
2
  import { FlashList } from '@shopify/flash-list';
3
3
  import React from 'react';
4
4
  import { StyleSheet, View } from 'react-native';
5
+ import { useConversationsContext } from '../../contexts/conversations_context';
5
6
  import { useTheme } from '../../hooks';
6
- import { useConversationsJoltEvents } from '../../hooks/use_conversation_jolt_events';
7
- import { useConversations } from '../../hooks/use_conversations';
8
7
  import { Text } from '../display';
9
8
  import { ConversationPreview } from './conversation_preview';
10
9
  import { ConversationActionsProvider } from '../../contexts/swipeable_active_conversation';
11
- export const Conversations = ({ ListHeaderComponent, filter, chat_group_graph_id, gids, group_source_app_name, }) => {
10
+ export const Conversations = ({ ListHeaderComponent }) => {
12
11
  const styles = useStyles();
13
- const { conversations, fetchNextPage, refetch, isRefetching, isFetched } = useConversations({
14
- filter,
15
- group: chat_group_graph_id,
16
- gids,
17
- group_source_app_name,
18
- });
12
+ const { conversations, fetchNextPage, refetch, isRefetching, isFetched, args: { chat_group_graph_id }, } = useConversationsContext();
19
13
  const navigation = useNavigation();
20
- useConversationsJoltEvents();
21
14
  const showBadges = !chat_group_graph_id;
22
15
  return (<ConversationActionsProvider>
23
16
  <View style={styles.container}>
@@ -1 +1 @@
1
- {"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../../src/components/conversations/conversations.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport { FlashList } from '@shopify/flash-list'\nimport React from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { useTheme } from '../../hooks'\nimport { useConversationsJoltEvents } from '../../hooks/use_conversation_jolt_events'\nimport { useConversations } from '../../hooks/use_conversations'\nimport { Text } from '../display'\nimport { ConversationRequestArgs } from '../../utils/request/conversation'\nimport { ConversationPreview } from './conversation_preview'\nimport { ConversationActionsProvider } from '../../contexts/swipeable_active_conversation'\n\ntype ListHeaderComponent =\n | React.ComponentType<any>\n | React.ReactElement<any, string | React.JSXElementConstructor<any>>\n | null\n\ninterface ConversationsProps extends Partial<Omit<ConversationRequestArgs, 'group'>> {\n chat_group_graph_id?: string\n ListHeaderComponent?: ListHeaderComponent\n}\n\nexport const Conversations = ({\n ListHeaderComponent,\n filter,\n chat_group_graph_id,\n gids,\n group_source_app_name,\n}: ConversationsProps) => {\n const styles = useStyles()\n\n const { conversations, fetchNextPage, refetch, isRefetching, isFetched } = useConversations({\n filter,\n group: chat_group_graph_id,\n gids,\n group_source_app_name,\n })\n const navigation = useNavigation()\n\n useConversationsJoltEvents()\n\n const showBadges = !chat_group_graph_id\n\n return (\n <ConversationActionsProvider>\n <View style={styles.container}>\n <FlashList\n data={conversations}\n estimatedItemSize={97}\n contentContainerStyle={styles.contentContainer}\n onRefresh={refetch}\n refreshing={!isFetched && isRefetching}\n ListHeaderComponent={ListHeaderComponent}\n ListEmptyComponent={\n <View style={styles.listEmpty}>\n <Text variant=\"secondary\">No conversations found</Text>\n </View>\n }\n renderItem={({ item }) => (\n <ConversationPreview\n conversation={item}\n onPress={() => navigation.navigate('Conversation', { conversation_id: item.id })}\n showBadges={showBadges}\n />\n )}\n onEndReached={() => fetchNextPage()}\n />\n </View>\n </ConversationActionsProvider>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: { flex: 1 },\n contentContainer: { paddingVertical: 16 },\n listItem: { color: colors.fillColorNeutral020 },\n listEmpty: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n paddingVertical: 16,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../../src/components/conversations/conversations.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAA;AAU1F,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAAE,mBAAmB,EAAsB,EAAE,EAAE;IAC3E,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,MAAM,EACJ,aAAa,EACb,aAAa,EACb,OAAO,EACP,YAAY,EACZ,SAAS,EACT,IAAI,EAAE,EAAE,mBAAmB,EAAE,GAC9B,GAAG,uBAAuB,EAAE,CAAA;IAC7B,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAElC,MAAM,UAAU,GAAG,CAAC,mBAAmB,CAAA;IAEvC,OAAO,CACL,CAAC,2BAA2B,CAC1B;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;QAAA,CAAC,SAAS,CACR,IAAI,CAAC,CAAC,aAAa,CAAC,CACpB,iBAAiB,CAAC,CAAC,EAAE,CAAC,CACtB,qBAAqB,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAC/C,SAAS,CAAC,CAAC,OAAO,CAAC,CACnB,UAAU,CAAC,CAAC,CAAC,SAAS,IAAI,YAAY,CAAC,CACvC,mBAAmB,CAAC,CAAC,mBAAmB,CAAC,CACzC,kBAAkB,CAAC,CACjB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;cAAA,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,sBAAsB,EAAE,IAAI,CACxD;YAAA,EAAE,IAAI,CACR,CAAC,CACD,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CACxB,CAAC,mBAAmB,CAClB,YAAY,CAAC,CAAC,IAAI,CAAC,CACnB,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CACjF,UAAU,CAAC,CAAC,UAAU,CAAC,EACvB,CACH,CAAC,CACF,YAAY,CAAC,CAAC,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,EAExC;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,2BAA2B,CAAC,CAC/B,CAAA;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAE7B,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;QACtB,gBAAgB,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE;QACzC,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,mBAAmB,EAAE;QAC/C,SAAS,EAAE;YACT,IAAI,EAAE,CAAC;YACP,cAAc,EAAE,QAAQ;YACxB,UAAU,EAAE,QAAQ;YACpB,eAAe,EAAE,EAAE;SACpB;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport { FlashList } from '@shopify/flash-list'\nimport React from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { useConversationsContext } from '../../contexts/conversations_context'\nimport { useTheme } from '../../hooks'\nimport { Text } from '../display'\nimport { ConversationPreview } from './conversation_preview'\nimport { ConversationActionsProvider } from '../../contexts/swipeable_active_conversation'\n\ninterface ConversationsProps {\n ListHeaderComponent?:\n | React.ComponentType<any>\n | React.ReactElement<any, string | React.JSXElementConstructor<any>>\n | null\n | undefined\n}\n\nexport const Conversations = ({ ListHeaderComponent }: ConversationsProps) => {\n const styles = useStyles()\n\n const {\n conversations,\n fetchNextPage,\n refetch,\n isRefetching,\n isFetched,\n args: { chat_group_graph_id },\n } = useConversationsContext()\n const navigation = useNavigation()\n\n const showBadges = !chat_group_graph_id\n\n return (\n <ConversationActionsProvider>\n <View style={styles.container}>\n <FlashList\n data={conversations}\n estimatedItemSize={97}\n contentContainerStyle={styles.contentContainer}\n onRefresh={refetch}\n refreshing={!isFetched && isRefetching}\n ListHeaderComponent={ListHeaderComponent}\n ListEmptyComponent={\n <View style={styles.listEmpty}>\n <Text variant=\"secondary\">No conversations found</Text>\n </View>\n }\n renderItem={({ item }) => (\n <ConversationPreview\n conversation={item}\n onPress={() => navigation.navigate('Conversation', { conversation_id: item.id })}\n showBadges={showBadges}\n />\n )}\n onEndReached={() => fetchNextPage()}\n />\n </View>\n </ConversationActionsProvider>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: { flex: 1 },\n contentContainer: { paddingVertical: 16 },\n listItem: { color: colors.fillColorNeutral020 },\n listEmpty: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n paddingVertical: 16,\n },\n })\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import React, { PropsWithChildren } from 'react';
2
+ import { ConversationFiltersParams } from '../screens/conversation_filters/screen_props';
3
+ import { UseConversationsValue } from '../hooks/use_conversations';
4
+ interface ConversationsContextValue extends UseConversationsValue {
5
+ activeConversationId?: number;
6
+ setActiveConversationId: (_id: number) => void;
7
+ args: ConversationFiltersParams;
8
+ }
9
+ export declare const ConversationsContextProvider: ({ children, args, }: PropsWithChildren<{
10
+ args: ConversationFiltersParams;
11
+ }>) => React.JSX.Element;
12
+ export declare const useConversationsContext: () => ConversationsContextValue;
13
+ export {};
14
+ //# sourceMappingURL=conversations_context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversations_context.d.ts","sourceRoot":"","sources":["../../src/contexts/conversations_context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAiB,iBAAiB,EAAiC,MAAM,OAAO,CAAA;AAC9F,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAA;AACxF,OAAO,EAAoB,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AASpF,UAAU,yBAA0B,SAAQ,qBAAqB;IAC/D,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,uBAAuB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9C,IAAI,EAAE,yBAAyB,CAAA;CAChC;AAqBD,eAAO,MAAM,4BAA4B,wBAGtC,iBAAiB,CAAC;IAAE,IAAI,EAAE,yBAAyB,CAAA;CAAE,CAAC,sBA6BxD,CAAA;AAUD,eAAO,MAAM,uBAAuB,iCAAyC,CAAA"}
@@ -0,0 +1,47 @@
1
+ import React, { createContext, useContext, useMemo, useState } from 'react';
2
+ import { useConversations } from '../hooks/use_conversations';
3
+ import { useConversationsJoltEvents } from '../hooks/use_conversation_jolt_events';
4
+ const defaultQueryValue = {
5
+ conversations: [],
6
+ refetch: () => Promise.resolve(null),
7
+ error: null,
8
+ isError: false,
9
+ fetchNextPage,
10
+ hasNextPage: false,
11
+ isFetching: false,
12
+ isFetched: false,
13
+ isRefetching: false,
14
+ };
15
+ const ConversationsContext = createContext({
16
+ args: {},
17
+ activeConversationId: undefined,
18
+ setActiveConversationId: () => { },
19
+ ...defaultQueryValue,
20
+ });
21
+ export const ConversationsContextProvider = ({ children, args, }) => {
22
+ const [activeConversationId, setActiveConversationId] = useState();
23
+ const { chat_group_graph_id, group_source_app_name } = args;
24
+ const filter = useMemo(() => {
25
+ if (chat_group_graph_id) {
26
+ return 'group';
27
+ }
28
+ else if (group_source_app_name) {
29
+ return 'group_source_app_name';
30
+ }
31
+ return 'mine_or_not_empty';
32
+ }, [chat_group_graph_id, group_source_app_name]);
33
+ const query = useConversations({ group: chat_group_graph_id, group_source_app_name, filter });
34
+ const value = useMemo(() => ({
35
+ args,
36
+ activeConversationId,
37
+ setActiveConversationId,
38
+ ...query,
39
+ }), [args, activeConversationId, query]);
40
+ useConversationsJoltEvents();
41
+ return <ConversationsContext.Provider value={value}>{children}</ConversationsContext.Provider>;
42
+ };
43
+ function fetchNextPage(_options) {
44
+ throw new Error('Function not implemented.');
45
+ }
46
+ export const useConversationsContext = () => useContext(ConversationsContext);
47
+ //# sourceMappingURL=conversations_context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversations_context.js","sourceRoot":"","sources":["../../src/contexts/conversations_context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,aAAa,EAAqB,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAE9F,OAAO,EAAE,gBAAgB,EAAyB,MAAM,4BAA4B,CAAA;AAOpF,OAAO,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAA;AAQlF,MAAM,iBAAiB,GAA0B;IAC/C,aAAa,EAAE,EAAE;IACjB,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;IACpC,KAAK,EAAE,IAAI;IACX,OAAO,EAAE,KAAK;IACd,aAAa;IACb,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,KAAK;IACjB,SAAS,EAAE,KAAK;IAChB,YAAY,EAAE,KAAK;CACpB,CAAA;AAED,MAAM,oBAAoB,GAAG,aAAa,CAA4B;IACpE,IAAI,EAAE,EAAE;IACR,oBAAoB,EAAE,SAAS;IAC/B,uBAAuB,EAAE,GAAG,EAAE,GAAE,CAAC;IACjC,GAAG,iBAAiB;CACrB,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,EAC3C,QAAQ,EACR,IAAI,GACmD,EAAE,EAAE;IAC3D,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,GAAG,QAAQ,EAAsB,CAAA;IACtF,MAAM,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,GAAG,IAAI,CAAA;IAE3D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE;QAC1B,IAAI,mBAAmB,EAAE,CAAC;YACxB,OAAO,OAAO,CAAA;QAChB,CAAC;aAAM,IAAI,qBAAqB,EAAE,CAAC;YACjC,OAAO,uBAAuB,CAAA;QAChC,CAAC;QAED,OAAO,mBAAmB,CAAA;IAC5B,CAAC,EAAE,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,CAAC,CAAA;IAEhD,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,EAAE,CAAC,CAAA;IAE7F,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC;QACL,IAAI;QACJ,oBAAoB;QACpB,uBAAuB;QACvB,GAAG,KAAK;KACT,CAAC,EACF,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,CAAC,CACpC,CAAA;IAED,0BAA0B,EAAE,CAAA;IAE5B,OAAO,CAAC,oBAAoB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAA;AAChG,CAAC,CAAA;AAED,SAAS,aAAa,CACpB,QAA+B;IAI/B,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;AAC9C,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAA","sourcesContent":["import React, { createContext, PropsWithChildren, useContext, useMemo, useState } from 'react'\nimport { ConversationFiltersParams } from '../screens/conversation_filters/screen_props'\nimport { useConversations, UseConversationsValue } from '../hooks/use_conversations'\nimport {\n FetchNextPageOptions,\n InfiniteQueryObserverResult,\n InfiniteData,\n} from '@tanstack/react-query'\nimport { ApiCollection, ConversationResource } from '../types'\nimport { useConversationsJoltEvents } from '../hooks/use_conversation_jolt_events'\n\ninterface ConversationsContextValue extends UseConversationsValue {\n activeConversationId?: number\n setActiveConversationId: (_id: number) => void\n args: ConversationFiltersParams\n}\n\nconst defaultQueryValue: UseConversationsValue = {\n conversations: [],\n refetch: () => Promise.resolve(null),\n error: null,\n isError: false,\n fetchNextPage,\n hasNextPage: false,\n isFetching: false,\n isFetched: false,\n isRefetching: false,\n}\n\nconst ConversationsContext = createContext<ConversationsContextValue>({\n args: {},\n activeConversationId: undefined,\n setActiveConversationId: () => {},\n ...defaultQueryValue,\n})\n\nexport const ConversationsContextProvider = ({\n children,\n args,\n}: PropsWithChildren<{ args: ConversationFiltersParams }>) => {\n const [activeConversationId, setActiveConversationId] = useState<number | undefined>()\n const { chat_group_graph_id, group_source_app_name } = args\n\n const filter = useMemo(() => {\n if (chat_group_graph_id) {\n return 'group'\n } else if (group_source_app_name) {\n return 'group_source_app_name'\n }\n\n return 'mine_or_not_empty'\n }, [chat_group_graph_id, group_source_app_name])\n\n const query = useConversations({ group: chat_group_graph_id, group_source_app_name, filter })\n\n const value = useMemo(\n () => ({\n args,\n activeConversationId,\n setActiveConversationId,\n ...query,\n }),\n [args, activeConversationId, query]\n )\n\n useConversationsJoltEvents()\n\n return <ConversationsContext.Provider value={value}>{children}</ConversationsContext.Provider>\n}\n\nfunction fetchNextPage(\n _options?: FetchNextPageOptions\n): Promise<\n InfiniteQueryObserverResult<InfiniteData<ApiCollection<ConversationResource>, unknown>, Response>\n> {\n throw new Error('Function not implemented.')\n}\n\nexport const useConversationsContext = () => useContext(ConversationsContext)\n"]}
@@ -1,36 +1,10 @@
1
- import { ConversationResource } from '../types';
1
+ import { InfiniteData, UseSuspenseInfiniteQueryResult } from '@tanstack/react-query';
2
+ import { ApiCollection, ConversationResource } from '../types';
2
3
  import { ConversationRequestArgs } from '../utils/request/conversation';
3
- export declare function useConversations(args?: Partial<ConversationRequestArgs>): {
4
- error: Response | null;
5
- isError: boolean;
6
- isPending: false;
7
- isLoading: false;
8
- isLoadingError: false;
9
- isRefetchError: boolean;
10
- isSuccess: boolean;
11
- status: "error" | "success";
12
- dataUpdatedAt: number;
13
- errorUpdatedAt: number;
14
- failureCount: number;
15
- failureReason: Response | null;
16
- errorUpdateCount: number;
17
- isFetched: boolean;
18
- isFetchedAfterMount: boolean;
19
- isFetching: boolean;
20
- isInitialLoading: boolean;
21
- isPaused: boolean;
22
- isRefetching: boolean;
23
- isStale: boolean;
24
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("@tanstack/query-core").InfiniteData<import("../types").ApiCollection<ConversationResource>, unknown>, Response>>;
25
- fetchStatus: import("@tanstack/query-core").FetchStatus;
26
- fetchNextPage: (options?: import("@tanstack/query-core").FetchNextPageOptions) => Promise<import("@tanstack/query-core").InfiniteQueryObserverResult<import("@tanstack/query-core").InfiniteData<import("../types").ApiCollection<ConversationResource>, unknown>, Response>>;
27
- fetchPreviousPage: (options?: import("@tanstack/query-core").FetchPreviousPageOptions) => Promise<import("@tanstack/query-core").InfiniteQueryObserverResult<import("@tanstack/query-core").InfiniteData<import("../types").ApiCollection<ConversationResource>, unknown>, Response>>;
28
- hasNextPage: boolean;
29
- hasPreviousPage: boolean;
30
- isFetchNextPageError: boolean;
31
- isFetchingNextPage: boolean;
32
- isFetchPreviousPageError: boolean;
33
- isFetchingPreviousPage: boolean;
4
+ export type ConversationPaginationResult = UseSuspenseInfiniteQueryResult<InfiniteData<ApiCollection<ConversationResource>, unknown>, Response>;
5
+ export type UseConversationsValue = Pick<ConversationPaginationResult, 'isFetching' | 'isError' | 'error' | 'fetchNextPage' | 'hasNextPage' | 'isFetched' | 'isRefetching'> & {
34
6
  conversations: ConversationResource[];
7
+ refetch: () => Promise<any>;
35
8
  };
9
+ export declare function useConversations(args?: Partial<ConversationRequestArgs>): UseConversationsValue;
36
10
  //# sourceMappingURL=use_conversations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_conversations.d.ts","sourceRoot":"","sources":["../../src/hooks/use_conversations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAE/C,OAAO,EAAE,uBAAuB,EAA+B,MAAM,+BAA+B,CAAA;AAEpG,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmBvE"}
1
+ {"version":3,"file":"use_conversations.d.ts","sourceRoot":"","sources":["../../src/hooks/use_conversations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAA;AAEpF,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAC9D,OAAO,EAAE,uBAAuB,EAA+B,MAAM,+BAA+B,CAAA;AAGpG,MAAM,MAAM,4BAA4B,GAAG,8BAA8B,CACvE,YAAY,CAAC,aAAa,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC,EAC1D,QAAQ,CACT,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,IAAI,CACtC,4BAA4B,EAC1B,YAAY,GACZ,SAAS,GACT,OAAO,GACP,eAAe,GACf,aAAa,GACb,WAAW,GACX,cAAc,CACjB,GAAG;IACF,aAAa,EAAE,oBAAoB,EAAE,CAAA;IACrC,OAAO,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;CAC5B,CAAA;AAED,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,qBAAqB,CAO/F"}
@@ -1,22 +1,23 @@
1
1
  import { useMemo } from 'react';
2
- import { useSuspensePaginator } from './use_suspense_api';
3
2
  import { getConversationsRequestArgs } from '../utils/request/conversation';
3
+ import { useSuspensePaginator } from './use_suspense_api';
4
4
  export function useConversations(args) {
5
5
  const requestArgs = getConversationsRequestArgs(args);
6
6
  const { data, ...rest } = useSuspensePaginator(requestArgs);
7
- const conversations = useMemo(() => data.sort((a, b) => {
8
- const dateA = a.lastMessageCreatedAt || a.createdAt;
9
- const dateB = b.lastMessageCreatedAt || b.createdAt;
10
- if (a.lastMessageCreatedAt && !b.lastMessageCreatedAt)
11
- return 1;
12
- if (!a.lastMessageCreatedAt && b.lastMessageCreatedAt)
13
- return -1;
14
- if (dateB > dateA)
15
- return 1;
16
- if (dateB < dateA)
17
- return -1;
18
- return 0;
19
- }), [data]);
7
+ const conversations = useMemo(() => data.sort(sortByLastMessage), [data]);
20
8
  return { conversations, ...rest };
21
9
  }
10
+ function sortByLastMessage(a, b) {
11
+ const dateA = a.lastMessageCreatedAt || a.createdAt;
12
+ const dateB = b.lastMessageCreatedAt || b.createdAt;
13
+ if (a.lastMessageCreatedAt && !b.lastMessageCreatedAt)
14
+ return 1;
15
+ if (!a.lastMessageCreatedAt && b.lastMessageCreatedAt)
16
+ return -1;
17
+ if (dateB > dateA)
18
+ return 1;
19
+ if (dateB < dateA)
20
+ return -1;
21
+ return 0;
22
+ }
22
23
  //# sourceMappingURL=use_conversations.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_conversations.js","sourceRoot":"","sources":["../../src/hooks/use_conversations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAA2B,2BAA2B,EAAE,MAAM,+BAA+B,CAAA;AAEpG,MAAM,UAAU,gBAAgB,CAAC,IAAuC;IACtE,MAAM,WAAW,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAA;IACrD,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,oBAAoB,CAAuB,WAAW,CAAC,CAAA;IAEjF,MAAM,aAAa,GAAG,OAAO,CAC3B,GAAG,EAAE,CACH,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjB,MAAM,KAAK,GAAG,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,SAAS,CAAA;QACnD,MAAM,KAAK,GAAG,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,SAAS,CAAA;QACnD,IAAI,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,CAAC,oBAAoB;YAAE,OAAO,CAAC,CAAA;QAC/D,IAAI,CAAC,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,oBAAoB;YAAE,OAAO,CAAC,CAAC,CAAA;QAChE,IAAI,KAAK,GAAG,KAAK;YAAE,OAAO,CAAC,CAAA;QAC3B,IAAI,KAAK,GAAG,KAAK;YAAE,OAAO,CAAC,CAAC,CAAA;QAC5B,OAAO,CAAC,CAAA;IACV,CAAC,CAAC,EACJ,CAAC,IAAI,CAAC,CACP,CAAA;IAED,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,CAAA;AACnC,CAAC","sourcesContent":["import { useMemo } from 'react'\nimport { ConversationResource } from '../types'\nimport { useSuspensePaginator } from './use_suspense_api'\nimport { ConversationRequestArgs, getConversationsRequestArgs } from '../utils/request/conversation'\n\nexport function useConversations(args?: Partial<ConversationRequestArgs>) {\n const requestArgs = getConversationsRequestArgs(args)\n const { data, ...rest } = useSuspensePaginator<ConversationResource>(requestArgs)\n\n const conversations = useMemo(\n () =>\n data.sort((a, b) => {\n const dateA = a.lastMessageCreatedAt || a.createdAt\n const dateB = b.lastMessageCreatedAt || b.createdAt\n if (a.lastMessageCreatedAt && !b.lastMessageCreatedAt) return 1\n if (!a.lastMessageCreatedAt && b.lastMessageCreatedAt) return -1\n if (dateB > dateA) return 1\n if (dateB < dateA) return -1\n return 0\n }),\n [data]\n )\n\n return { conversations, ...rest }\n}\n"]}
1
+ {"version":3,"file":"use_conversations.js","sourceRoot":"","sources":["../../src/hooks/use_conversations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B,OAAO,EAA2B,2BAA2B,EAAE,MAAM,+BAA+B,CAAA;AACpG,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAqBzD,MAAM,UAAU,gBAAgB,CAAC,IAAuC;IACtE,MAAM,WAAW,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAA;IACrD,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,oBAAoB,CAAuB,WAAW,CAAC,CAAA;IAEjF,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEzE,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,CAAA;AACnC,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAuB,EAAE,CAAuB;IACzE,MAAM,KAAK,GAAG,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,SAAS,CAAA;IACnD,MAAM,KAAK,GAAG,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,SAAS,CAAA;IACnD,IAAI,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,CAAC,oBAAoB;QAAE,OAAO,CAAC,CAAA;IAC/D,IAAI,CAAC,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,oBAAoB;QAAE,OAAO,CAAC,CAAC,CAAA;IAChE,IAAI,KAAK,GAAG,KAAK;QAAE,OAAO,CAAC,CAAA;IAC3B,IAAI,KAAK,GAAG,KAAK;QAAE,OAAO,CAAC,CAAC,CAAA;IAC5B,OAAO,CAAC,CAAA;AACV,CAAC","sourcesContent":["import { InfiniteData, UseSuspenseInfiniteQueryResult } from '@tanstack/react-query'\nimport { useMemo } from 'react'\nimport { ApiCollection, ConversationResource } from '../types'\nimport { ConversationRequestArgs, getConversationsRequestArgs } from '../utils/request/conversation'\nimport { useSuspensePaginator } from './use_suspense_api'\n\nexport type ConversationPaginationResult = UseSuspenseInfiniteQueryResult<\n InfiniteData<ApiCollection<ConversationResource>, unknown>,\n Response\n>\n\nexport type UseConversationsValue = Pick<\n ConversationPaginationResult,\n | 'isFetching'\n | 'isError'\n | 'error'\n | 'fetchNextPage'\n | 'hasNextPage'\n | 'isFetched'\n | 'isRefetching'\n> & {\n conversations: ConversationResource[]\n refetch: () => Promise<any>\n}\n\nexport function useConversations(args?: Partial<ConversationRequestArgs>): UseConversationsValue {\n const requestArgs = getConversationsRequestArgs(args)\n const { data, ...rest } = useSuspensePaginator<ConversationResource>(requestArgs)\n\n const conversations = useMemo(() => data.sort(sortByLastMessage), [data])\n\n return { conversations, ...rest }\n}\n\nfunction sortByLastMessage(a: ConversationResource, b: ConversationResource): number {\n const dateA = a.lastMessageCreatedAt || a.createdAt\n const dateB = b.lastMessageCreatedAt || b.createdAt\n if (a.lastMessageCreatedAt && !b.lastMessageCreatedAt) return 1\n if (!a.lastMessageCreatedAt && b.lastMessageCreatedAt) return -1\n if (dateB > dateA) return 1\n if (dateB < dateA) return -1\n return 0\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"conversations_screen.d.ts","sourceRoot":"","sources":["../../../src/screens/conversations/conversations_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAkB,MAAM,OAAO,CAAA;AAKtC,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAG9D,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,CAAC;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B,CAAC,CAAA;AAEF,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,EAAE,uBAAuB,qBA+BrE"}
1
+ {"version":3,"file":"conversations_screen.d.ts","sourceRoot":"","sources":["../../../src/screens/conversations/conversations_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAG9D,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,CAAC;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B,CAAC,CAAA;AAEF,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,EAAE,uBAAuB,qBAiBrE"}
@@ -1,26 +1,19 @@
1
1
  import { useNavigation } from '@react-navigation/native';
2
- import React, { useMemo } from 'react';
2
+ import React from 'react';
3
3
  import { StyleSheet, View } from 'react-native';
4
4
  import { Conversations } from '../../components';
5
5
  import { ActionButton } from '../../components/display/action_button';
6
+ import { ConversationsContextProvider } from '../../contexts/conversations_context';
6
7
  import { useCanCreateConversations } from '../../hooks';
7
8
  import { ListHeaderComponent } from './components/list_header_component';
8
9
  export function ConversationsScreen({ route }) {
9
10
  const navigation = useNavigation();
10
11
  const canCreateConversations = useCanCreateConversations();
11
12
  const styles = useStyles();
12
- const { chat_group_graph_id, group_source_app_name } = route.params || {};
13
- const filter = useMemo(() => {
14
- if (chat_group_graph_id) {
15
- return 'group';
16
- }
17
- else if (group_source_app_name) {
18
- return 'group_source_app_name';
19
- }
20
- return 'mine_or_not_empty';
21
- }, [chat_group_graph_id, group_source_app_name]);
22
13
  return (<View style={styles.container}>
23
- <Conversations ListHeaderComponent={ListHeaderComponent} chat_group_graph_id={chat_group_graph_id} group_source_app_name={group_source_app_name} filter={filter}/>
14
+ <ConversationsContextProvider args={route.params}>
15
+ <Conversations ListHeaderComponent={ListHeaderComponent}/>
16
+ </ConversationsContextProvider>
24
17
  <ActionButton visible={canCreateConversations} title="New conversation" onPress={() => navigation.navigate('Create')}/>
25
18
  </View>);
26
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"conversations_screen.js","sourceRoot":"","sources":["../../../src/screens/conversations/conversations_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAQxE,MAAM,UAAU,mBAAmB,CAAC,EAAE,KAAK,EAA2B;IACpE,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,sBAAsB,GAAG,yBAAyB,EAAE,CAAA;IAC1D,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,CAAA;IAEzE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE;QAC1B,IAAI,mBAAmB,EAAE,CAAC;YACxB,OAAO,OAAO,CAAA;QAChB,CAAC;aAAM,IAAI,qBAAqB,EAAE,CAAC;YACjC,OAAO,uBAAuB,CAAA;QAChC,CAAC;QAED,OAAO,mBAAmB,CAAA;IAC5B,CAAC,EAAE,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,CAAC,CAAA;IAEhD,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;MAAA,CAAC,aAAa,CACZ,mBAAmB,CAAC,CAAC,mBAAmB,CAAC,CACzC,mBAAmB,CAAC,CAAC,mBAAmB,CAAC,CACzC,qBAAqB,CAAC,CAAC,qBAAqB,CAAC,CAC7C,MAAM,CAAC,CAAC,MAAM,CAAC,EAEjB;MAAA,CAAC,YAAY,CACX,OAAO,CAAC,CAAC,sBAAsB,CAAC,CAChC,KAAK,CAAC,kBAAkB,CACxB,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAEjD;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE;YACT,IAAI,EAAE,CAAC;YACP,cAAc,EAAE,QAAQ;SACzB;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { StaticScreenProps, useNavigation } from '@react-navigation/native'\nimport React, { useMemo } from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { Conversations } from '../../components'\nimport { ActionButton } from '../../components/display/action_button'\nimport { useCanCreateConversations } from '../../hooks'\nimport { GraphId } from '../../types/resources/group_resource'\nimport { ListHeaderComponent } from './components/list_header_component'\n\nexport type ConversationScreenProps = StaticScreenProps<{\n title?: string\n chat_group_graph_id?: GraphId\n group_source_app_name?: string\n}>\n\nexport function ConversationsScreen({ route }: ConversationScreenProps) {\n const navigation = useNavigation()\n const canCreateConversations = useCanCreateConversations()\n const styles = useStyles()\n const { chat_group_graph_id, group_source_app_name } = route.params || {}\n\n const filter = useMemo(() => {\n if (chat_group_graph_id) {\n return 'group'\n } else if (group_source_app_name) {\n return 'group_source_app_name'\n }\n\n return 'mine_or_not_empty'\n }, [chat_group_graph_id, group_source_app_name])\n\n return (\n <View style={styles.container}>\n <Conversations\n ListHeaderComponent={ListHeaderComponent}\n chat_group_graph_id={chat_group_graph_id}\n group_source_app_name={group_source_app_name}\n filter={filter}\n />\n <ActionButton\n visible={canCreateConversations}\n title=\"New conversation\"\n onPress={() => navigation.navigate('Create')}\n />\n </View>\n )\n}\n\nconst useStyles = () => {\n return StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: 'center',\n },\n })\n}\n"]}
1
+ {"version":3,"file":"conversations_screen.js","sourceRoot":"","sources":["../../../src/screens/conversations/conversations_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AACrE,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAA;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAQxE,MAAM,UAAU,mBAAmB,CAAC,EAAE,KAAK,EAA2B;IACpE,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,sBAAsB,GAAG,yBAAyB,EAAE,CAAA;IAC1D,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;MAAA,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAC/C;QAAA,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC,mBAAmB,CAAC,EAC1D;MAAA,EAAE,4BAA4B,CAC9B;MAAA,CAAC,YAAY,CACX,OAAO,CAAC,CAAC,sBAAsB,CAAC,CAChC,KAAK,CAAC,kBAAkB,CACxB,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAEjD;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE;YACT,IAAI,EAAE,CAAC;YACP,cAAc,EAAE,QAAQ;SACzB;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { StaticScreenProps, useNavigation } from '@react-navigation/native'\nimport React from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { Conversations } from '../../components'\nimport { ActionButton } from '../../components/display/action_button'\nimport { ConversationsContextProvider } from '../../contexts/conversations_context'\nimport { useCanCreateConversations } from '../../hooks'\nimport { GraphId } from '../../types/resources/group_resource'\nimport { ListHeaderComponent } from './components/list_header_component'\n\nexport type ConversationScreenProps = StaticScreenProps<{\n title?: string\n chat_group_graph_id?: GraphId\n group_source_app_name?: string\n}>\n\nexport function ConversationsScreen({ route }: ConversationScreenProps) {\n const navigation = useNavigation()\n const canCreateConversations = useCanCreateConversations()\n const styles = useStyles()\n\n return (\n <View style={styles.container}>\n <ConversationsContextProvider args={route.params}>\n <Conversations ListHeaderComponent={ListHeaderComponent} />\n </ConversationsContextProvider>\n <ActionButton\n visible={canCreateConversations}\n title=\"New conversation\"\n onPress={() => navigation.navigate('Create')}\n />\n </View>\n )\n}\n\nconst useStyles = () => {\n return StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: 'center',\n },\n })\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.2.0-rc.2",
3
+ "version": "3.2.0-rc.4",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -54,5 +54,5 @@
54
54
  "prettier": "^3.4.2",
55
55
  "typescript": "<5.6.0"
56
56
  },
57
- "gitHead": "cecb2020fc34708707dd27730120197f441d77fa"
57
+ "gitHead": "42cbdf97b47051e3f61aaaf79e000a01a2100612"
58
58
  }
@@ -1,5 +1,6 @@
1
1
  import React from 'react'
2
- import { Pressable, StyleSheet, type PressableProps } from 'react-native'
2
+ import { StyleSheet } from 'react-native'
3
+ import { Pressable, type PressableProps } from 'react-native-gesture-handler'
3
4
  import { Icon, IconString, Spinner, Text } from '../display'
4
5
  import { useCreateAndroidRippleColor, useTheme } from '../../hooks'
5
6
  import { platformFontWeightMedium, platformPressedOpacityStyle } from '../../utils/styles'
@@ -76,22 +76,44 @@ interface LeftActionsProps {
76
76
  function LeftActions({ conversation, onClose }: LeftActionsProps) {
77
77
  const styles = useStyles()
78
78
  const [muted, setMuted] = useState(conversation.muted)
79
+ const [latestMessageUnread, setLatestMessageUnread] = useState(conversation.unreadCount > 0)
80
+ const emptyConversation = conversation.lastMessageCreatedAt === null
81
+
82
+ const muteToggleContent = {
83
+ true: { iconName: 'general.bellMuted', label: 'Mute' },
84
+ false: { iconName: 'general.bell', label: 'Unmute' },
85
+ } as const
86
+
87
+ const latestMessageUnreadToggleContent = {
88
+ true: { iconName: 'general.outlinedTextMessage', label: 'Mark read' },
89
+ false: { iconName: 'general.textMessageNotifications', label: 'Mark unread' },
90
+ } as const
79
91
 
80
92
  const handleMute = useCallback(() => {
81
93
  setMuted(!muted)
82
94
  onClose()
83
95
  }, [muted, onClose])
84
96
 
97
+ const handleLatestMessageUnread = useCallback(() => {
98
+ setLatestMessageUnread(!latestMessageUnread)
99
+ onClose()
100
+ }, [latestMessageUnread, onClose])
101
+
85
102
  return (
86
103
  <View style={styles.actionButtonContainer}>
87
104
  <ActionToggleButton
88
- loading={false}
105
+ loading={false} // TODO: Might need this when there is data fetching
106
+ disabled={emptyConversation}
107
+ toggled={latestMessageUnread}
108
+ onPress={() => handleLatestMessageUnread()}
109
+ toggleContent={latestMessageUnreadToggleContent}
110
+ backgroundColor={tokens.fillColorInteractionSwipeDefault}
111
+ />
112
+ <ActionToggleButton
113
+ loading={false} // TODO: Might need this when there is data fetching
89
114
  toggled={muted}
90
- toggleContent={{
91
- true: { iconName: 'general.bellMuted', label: 'Mute' },
92
- false: { iconName: 'general.bell', label: 'Unmute' },
93
- }}
94
115
  onPress={() => handleMute()}
116
+ toggleContent={muteToggleContent}
95
117
  backgroundColor={tokens.fillColorInteractionSwipeSecondary}
96
118
  />
97
119
  </View>
@@ -99,6 +121,7 @@ function LeftActions({ conversation, onClose }: LeftActionsProps) {
99
121
  }
100
122
 
101
123
  const ACTION_BUTTON_WIDTH = 120
124
+ const ACTION_BUTTON_COUNT = 2
102
125
 
103
126
  const useStyles = () => {
104
127
  const { colors } = useTheme()
@@ -109,7 +132,7 @@ const useStyles = () => {
109
132
  actionButtonContainer: {
110
133
  flexDirection: 'row',
111
134
  alignItems: 'center',
112
- width: ACTION_BUTTON_WIDTH,
135
+ width: ACTION_BUTTON_WIDTH * ACTION_BUTTON_COUNT,
113
136
  alignContent: 'stretch',
114
137
  },
115
138
  swipeableContainer: {
@@ -2,43 +2,33 @@ import { useNavigation } from '@react-navigation/native'
2
2
  import { FlashList } from '@shopify/flash-list'
3
3
  import React from 'react'
4
4
  import { StyleSheet, View } from 'react-native'
5
+ import { useConversationsContext } from '../../contexts/conversations_context'
5
6
  import { useTheme } from '../../hooks'
6
- import { useConversationsJoltEvents } from '../../hooks/use_conversation_jolt_events'
7
- import { useConversations } from '../../hooks/use_conversations'
8
7
  import { Text } from '../display'
9
- import { ConversationRequestArgs } from '../../utils/request/conversation'
10
8
  import { ConversationPreview } from './conversation_preview'
11
9
  import { ConversationActionsProvider } from '../../contexts/swipeable_active_conversation'
12
10
 
13
- type ListHeaderComponent =
14
- | React.ComponentType<any>
15
- | React.ReactElement<any, string | React.JSXElementConstructor<any>>
16
- | null
17
-
18
- interface ConversationsProps extends Partial<Omit<ConversationRequestArgs, 'group'>> {
19
- chat_group_graph_id?: string
20
- ListHeaderComponent?: ListHeaderComponent
11
+ interface ConversationsProps {
12
+ ListHeaderComponent?:
13
+ | React.ComponentType<any>
14
+ | React.ReactElement<any, string | React.JSXElementConstructor<any>>
15
+ | null
16
+ | undefined
21
17
  }
22
18
 
23
- export const Conversations = ({
24
- ListHeaderComponent,
25
- filter,
26
- chat_group_graph_id,
27
- gids,
28
- group_source_app_name,
29
- }: ConversationsProps) => {
19
+ export const Conversations = ({ ListHeaderComponent }: ConversationsProps) => {
30
20
  const styles = useStyles()
31
21
 
32
- const { conversations, fetchNextPage, refetch, isRefetching, isFetched } = useConversations({
33
- filter,
34
- group: chat_group_graph_id,
35
- gids,
36
- group_source_app_name,
37
- })
22
+ const {
23
+ conversations,
24
+ fetchNextPage,
25
+ refetch,
26
+ isRefetching,
27
+ isFetched,
28
+ args: { chat_group_graph_id },
29
+ } = useConversationsContext()
38
30
  const navigation = useNavigation()
39
31
 
40
- useConversationsJoltEvents()
41
-
42
32
  const showBadges = !chat_group_graph_id
43
33
 
44
34
  return (
@@ -0,0 +1,79 @@
1
+ import React, { createContext, PropsWithChildren, useContext, useMemo, useState } from 'react'
2
+ import { ConversationFiltersParams } from '../screens/conversation_filters/screen_props'
3
+ import { useConversations, UseConversationsValue } from '../hooks/use_conversations'
4
+ import {
5
+ FetchNextPageOptions,
6
+ InfiniteQueryObserverResult,
7
+ InfiniteData,
8
+ } from '@tanstack/react-query'
9
+ import { ApiCollection, ConversationResource } from '../types'
10
+ import { useConversationsJoltEvents } from '../hooks/use_conversation_jolt_events'
11
+
12
+ interface ConversationsContextValue extends UseConversationsValue {
13
+ activeConversationId?: number
14
+ setActiveConversationId: (_id: number) => void
15
+ args: ConversationFiltersParams
16
+ }
17
+
18
+ const defaultQueryValue: UseConversationsValue = {
19
+ conversations: [],
20
+ refetch: () => Promise.resolve(null),
21
+ error: null,
22
+ isError: false,
23
+ fetchNextPage,
24
+ hasNextPage: false,
25
+ isFetching: false,
26
+ isFetched: false,
27
+ isRefetching: false,
28
+ }
29
+
30
+ const ConversationsContext = createContext<ConversationsContextValue>({
31
+ args: {},
32
+ activeConversationId: undefined,
33
+ setActiveConversationId: () => {},
34
+ ...defaultQueryValue,
35
+ })
36
+
37
+ export const ConversationsContextProvider = ({
38
+ children,
39
+ args,
40
+ }: PropsWithChildren<{ args: ConversationFiltersParams }>) => {
41
+ const [activeConversationId, setActiveConversationId] = useState<number | undefined>()
42
+ const { chat_group_graph_id, group_source_app_name } = args
43
+
44
+ const filter = useMemo(() => {
45
+ if (chat_group_graph_id) {
46
+ return 'group'
47
+ } else if (group_source_app_name) {
48
+ return 'group_source_app_name'
49
+ }
50
+
51
+ return 'mine_or_not_empty'
52
+ }, [chat_group_graph_id, group_source_app_name])
53
+
54
+ const query = useConversations({ group: chat_group_graph_id, group_source_app_name, filter })
55
+
56
+ const value = useMemo(
57
+ () => ({
58
+ args,
59
+ activeConversationId,
60
+ setActiveConversationId,
61
+ ...query,
62
+ }),
63
+ [args, activeConversationId, query]
64
+ )
65
+
66
+ useConversationsJoltEvents()
67
+
68
+ return <ConversationsContext.Provider value={value}>{children}</ConversationsContext.Provider>
69
+ }
70
+
71
+ function fetchNextPage(
72
+ _options?: FetchNextPageOptions
73
+ ): Promise<
74
+ InfiniteQueryObserverResult<InfiniteData<ApiCollection<ConversationResource>, unknown>, Response>
75
+ > {
76
+ throw new Error('Function not implemented.')
77
+ }
78
+
79
+ export const useConversationsContext = () => useContext(ConversationsContext)
@@ -1,25 +1,43 @@
1
+ import { InfiniteData, UseSuspenseInfiniteQueryResult } from '@tanstack/react-query'
1
2
  import { useMemo } from 'react'
2
- import { ConversationResource } from '../types'
3
- import { useSuspensePaginator } from './use_suspense_api'
3
+ import { ApiCollection, ConversationResource } from '../types'
4
4
  import { ConversationRequestArgs, getConversationsRequestArgs } from '../utils/request/conversation'
5
+ import { useSuspensePaginator } from './use_suspense_api'
5
6
 
6
- export function useConversations(args?: Partial<ConversationRequestArgs>) {
7
+ export type ConversationPaginationResult = UseSuspenseInfiniteQueryResult<
8
+ InfiniteData<ApiCollection<ConversationResource>, unknown>,
9
+ Response
10
+ >
11
+
12
+ export type UseConversationsValue = Pick<
13
+ ConversationPaginationResult,
14
+ | 'isFetching'
15
+ | 'isError'
16
+ | 'error'
17
+ | 'fetchNextPage'
18
+ | 'hasNextPage'
19
+ | 'isFetched'
20
+ | 'isRefetching'
21
+ > & {
22
+ conversations: ConversationResource[]
23
+ refetch: () => Promise<any>
24
+ }
25
+
26
+ export function useConversations(args?: Partial<ConversationRequestArgs>): UseConversationsValue {
7
27
  const requestArgs = getConversationsRequestArgs(args)
8
28
  const { data, ...rest } = useSuspensePaginator<ConversationResource>(requestArgs)
9
29
 
10
- const conversations = useMemo(
11
- () =>
12
- data.sort((a, b) => {
13
- const dateA = a.lastMessageCreatedAt || a.createdAt
14
- const dateB = b.lastMessageCreatedAt || b.createdAt
15
- if (a.lastMessageCreatedAt && !b.lastMessageCreatedAt) return 1
16
- if (!a.lastMessageCreatedAt && b.lastMessageCreatedAt) return -1
17
- if (dateB > dateA) return 1
18
- if (dateB < dateA) return -1
19
- return 0
20
- }),
21
- [data]
22
- )
30
+ const conversations = useMemo(() => data.sort(sortByLastMessage), [data])
23
31
 
24
32
  return { conversations, ...rest }
25
33
  }
34
+
35
+ function sortByLastMessage(a: ConversationResource, b: ConversationResource): number {
36
+ const dateA = a.lastMessageCreatedAt || a.createdAt
37
+ const dateB = b.lastMessageCreatedAt || b.createdAt
38
+ if (a.lastMessageCreatedAt && !b.lastMessageCreatedAt) return 1
39
+ if (!a.lastMessageCreatedAt && b.lastMessageCreatedAt) return -1
40
+ if (dateB > dateA) return 1
41
+ if (dateB < dateA) return -1
42
+ return 0
43
+ }
@@ -1,8 +1,9 @@
1
1
  import { StaticScreenProps, useNavigation } from '@react-navigation/native'
2
- import React, { useMemo } from 'react'
2
+ import React from 'react'
3
3
  import { StyleSheet, View } from 'react-native'
4
4
  import { Conversations } from '../../components'
5
5
  import { ActionButton } from '../../components/display/action_button'
6
+ import { ConversationsContextProvider } from '../../contexts/conversations_context'
6
7
  import { useCanCreateConversations } from '../../hooks'
7
8
  import { GraphId } from '../../types/resources/group_resource'
8
9
  import { ListHeaderComponent } from './components/list_header_component'
@@ -17,26 +18,12 @@ export function ConversationsScreen({ route }: ConversationScreenProps) {
17
18
  const navigation = useNavigation()
18
19
  const canCreateConversations = useCanCreateConversations()
19
20
  const styles = useStyles()
20
- const { chat_group_graph_id, group_source_app_name } = route.params || {}
21
-
22
- const filter = useMemo(() => {
23
- if (chat_group_graph_id) {
24
- return 'group'
25
- } else if (group_source_app_name) {
26
- return 'group_source_app_name'
27
- }
28
-
29
- return 'mine_or_not_empty'
30
- }, [chat_group_graph_id, group_source_app_name])
31
21
 
32
22
  return (
33
23
  <View style={styles.container}>
34
- <Conversations
35
- ListHeaderComponent={ListHeaderComponent}
36
- chat_group_graph_id={chat_group_graph_id}
37
- group_source_app_name={group_source_app_name}
38
- filter={filter}
39
- />
24
+ <ConversationsContextProvider args={route.params}>
25
+ <Conversations ListHeaderComponent={ListHeaderComponent} />
26
+ </ConversationsContextProvider>
40
27
  <ActionButton
41
28
  visible={canCreateConversations}
42
29
  title="New conversation"