@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.
- package/build/components/conversations/action_toggle_button.d.ts +1 -1
- package/build/components/conversations/action_toggle_button.d.ts.map +1 -1
- package/build/components/conversations/action_toggle_button.js +2 -1
- package/build/components/conversations/action_toggle_button.js.map +1 -1
- package/build/components/conversations/conversation_actions.js +20 -5
- package/build/components/conversations/conversation_actions.js.map +1 -1
- package/build/components/conversations/conversations.d.ts +3 -6
- package/build/components/conversations/conversations.d.ts.map +1 -1
- package/build/components/conversations/conversations.js +3 -10
- package/build/components/conversations/conversations.js.map +1 -1
- package/build/contexts/conversations_context.d.ts +14 -0
- package/build/contexts/conversations_context.d.ts.map +1 -0
- package/build/contexts/conversations_context.js +47 -0
- package/build/contexts/conversations_context.js.map +1 -0
- package/build/hooks/use_conversations.d.ts +6 -32
- package/build/hooks/use_conversations.d.ts.map +1 -1
- package/build/hooks/use_conversations.js +15 -14
- package/build/hooks/use_conversations.js.map +1 -1
- package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
- package/build/screens/conversations/conversations_screen.js +5 -12
- package/build/screens/conversations/conversations_screen.js.map +1 -1
- package/package.json +2 -2
- package/src/components/conversations/action_toggle_button.tsx +2 -1
- package/src/components/conversations/conversation_actions.tsx +29 -6
- package/src/components/conversations/conversations.tsx +16 -26
- package/src/contexts/conversations_context.tsx +79 -0
- package/src/hooks/use_conversations.ts +34 -16
- 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;
|
|
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 {
|
|
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":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,
|
|
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}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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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
|
|
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 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
|
-
|
|
3
|
-
|
|
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
|
|
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;
|
|
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
|
|
10
|
+
export const Conversations = ({ ListHeaderComponent }) => {
|
|
12
11
|
const styles = useStyles();
|
|
13
|
-
const { conversations, fetchNextPage, refetch, isRefetching, isFetched } =
|
|
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":"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,
|
|
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 {
|
|
1
|
+
import { InfiniteData, UseSuspenseInfiniteQueryResult } from '@tanstack/react-query';
|
|
2
|
+
import { ApiCollection, ConversationResource } from '../types';
|
|
2
3
|
import { ConversationRequestArgs } from '../utils/request/conversation';
|
|
3
|
-
export
|
|
4
|
-
|
|
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":"
|
|
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(
|
|
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":"
|
|
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,
|
|
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
|
|
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
|
-
<
|
|
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,
|
|
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.
|
|
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": "
|
|
57
|
+
"gitHead": "42cbdf97b47051e3f61aaaf79e000a01a2100612"
|
|
58
58
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import {
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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 {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
|
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
|
|
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
|
-
<
|
|
35
|
-
ListHeaderComponent={ListHeaderComponent}
|
|
36
|
-
|
|
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"
|