@droppii-org/chat-mobile 0.2.49 → 0.2.51
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/lib/module/components/StickerPicker/StickerCategoryTabs.js +86 -0
- package/lib/module/components/StickerPicker/StickerCategoryTabs.js.map +1 -0
- package/lib/module/components/StickerPicker/StickerPickerPlaceholder.js +18 -0
- package/lib/module/components/StickerPicker/StickerPickerPlaceholder.js.map +1 -0
- package/lib/module/components/StickerPicker/StickerPickerRowItem.js +35 -0
- package/lib/module/components/StickerPicker/StickerPickerRowItem.js.map +1 -0
- package/lib/module/components/StickerPicker/StickerSectionList.js +110 -0
- package/lib/module/components/StickerPicker/StickerSectionList.js.map +1 -0
- package/lib/module/components/StickerPicker/constants.js +14 -0
- package/lib/module/components/StickerPicker/constants.js.map +1 -0
- package/lib/module/components/StickerPicker/index.js +134 -0
- package/lib/module/components/StickerPicker/index.js.map +1 -0
- package/lib/module/components/ThreadCard/MuteThread.js +4 -28
- package/lib/module/components/ThreadCard/MuteThread.js.map +1 -1
- package/lib/module/components/ThreadCard/PinThread.js +45 -0
- package/lib/module/components/ThreadCard/PinThread.js.map +1 -0
- package/lib/module/components/ThreadCard/ThreadCard.js +14 -9
- package/lib/module/components/ThreadCard/ThreadCard.js.map +1 -1
- package/lib/module/components/messages/stickerMessage/index.js +28 -0
- package/lib/module/components/messages/stickerMessage/index.js.map +1 -0
- package/lib/module/config/api-endpoints.js +4 -1
- package/lib/module/config/api-endpoints.js.map +1 -1
- package/lib/module/hooks/conversation/useGetConversationDetail.js +15 -0
- package/lib/module/hooks/conversation/useGetConversationDetail.js.map +1 -1
- package/lib/module/hooks/flows/useGetConversationFlowMainMenu.js +1 -1
- package/lib/module/hooks/flows/useGetConversationFlowMainMenu.js.map +1 -1
- package/lib/module/hooks/message/useSendMessage.js +45 -18
- package/lib/module/hooks/message/useSendMessage.js.map +1 -1
- package/lib/module/hooks/query-keys.js +7 -0
- package/lib/module/hooks/query-keys.js.map +1 -1
- package/lib/module/hooks/stickers/useFetchStickerByCategory.js +12 -0
- package/lib/module/hooks/stickers/useFetchStickerByCategory.js.map +1 -0
- package/lib/module/hooks/stickers/useStickerCategories.js +14 -0
- package/lib/module/hooks/stickers/useStickerCategories.js.map +1 -0
- package/lib/module/hooks/stickers/useStickerHistory.js +16 -0
- package/lib/module/hooks/stickers/useStickerHistory.js.map +1 -0
- package/lib/module/hooks/useChatCompose.js +1 -18
- package/lib/module/hooks/useChatCompose.js.map +1 -1
- package/lib/module/hooks/useMuteConversation.js +34 -15
- package/lib/module/hooks/useMuteConversation.js.map +1 -1
- package/lib/module/hooks/usePinConversation.js +72 -0
- package/lib/module/hooks/usePinConversation.js.map +1 -0
- package/lib/module/screens/chat-detail/ChatComposer.js +64 -16
- package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetail.js +6 -20
- package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
- package/lib/module/screens/chat-detail/hooks/useChatComposerAnimation.js +15 -4
- package/lib/module/screens/chat-detail/hooks/useChatComposerAnimation.js.map +1 -1
- package/lib/module/screens/chat-detail/hooks/useChatComposerState.js +3 -0
- package/lib/module/screens/chat-detail/hooks/useChatComposerState.js.map +1 -1
- package/lib/module/screens/chat-detail/legend/LegendChatMessage.js +5 -6
- package/lib/module/screens/chat-detail/legend/LegendChatMessage.js.map +1 -1
- package/lib/module/services/attachmentOrchestrator.js +1 -1
- package/lib/module/services/attachmentOrchestrator.js.map +1 -1
- package/lib/module/services/endpoints.js +4 -1
- package/lib/module/services/endpoints.js.map +1 -1
- package/lib/module/store/conversation.js +1 -20
- package/lib/module/store/conversation.js.map +1 -1
- package/lib/module/translation/resources/i18n.js +10 -1
- package/lib/module/translation/resources/i18n.js.map +1 -1
- package/lib/module/types/chat.js +6 -0
- package/lib/module/types/chat.js.map +1 -1
- package/lib/module/types/sticker.js +2 -0
- package/lib/module/types/sticker.js.map +1 -0
- package/lib/module/utils/conversation.js +1 -24
- package/lib/module/utils/conversation.js.map +1 -1
- package/lib/module/utils/messageUtils.js +2 -0
- package/lib/module/utils/messageUtils.js.map +1 -1
- package/lib/typescript/src/components/StickerPicker/StickerCategoryTabs.d.ts +9 -0
- package/lib/typescript/src/components/StickerPicker/StickerCategoryTabs.d.ts.map +1 -0
- package/lib/typescript/src/components/StickerPicker/StickerPickerPlaceholder.d.ts +2 -0
- package/lib/typescript/src/components/StickerPicker/StickerPickerPlaceholder.d.ts.map +1 -0
- package/lib/typescript/src/components/StickerPicker/StickerPickerRowItem.d.ts +8 -0
- package/lib/typescript/src/components/StickerPicker/StickerPickerRowItem.d.ts.map +1 -0
- package/lib/typescript/src/components/StickerPicker/StickerSectionList.d.ts +15 -0
- package/lib/typescript/src/components/StickerPicker/StickerSectionList.d.ts.map +1 -0
- package/lib/typescript/src/components/StickerPicker/constants.d.ts +11 -0
- package/lib/typescript/src/components/StickerPicker/constants.d.ts.map +1 -0
- package/lib/typescript/src/components/StickerPicker/index.d.ts +7 -0
- package/lib/typescript/src/components/StickerPicker/index.d.ts.map +1 -0
- package/lib/typescript/src/components/ThreadCard/MuteThread.d.ts.map +1 -1
- package/lib/typescript/src/components/ThreadCard/PinThread.d.ts +10 -0
- package/lib/typescript/src/components/ThreadCard/PinThread.d.ts.map +1 -0
- package/lib/typescript/src/components/ThreadCard/ThreadCard.d.ts.map +1 -1
- package/lib/typescript/src/components/messages/stickerMessage/index.d.ts +3 -0
- package/lib/typescript/src/components/messages/stickerMessage/index.d.ts.map +1 -0
- package/lib/typescript/src/config/api-endpoints.d.ts +3 -0
- package/lib/typescript/src/config/api-endpoints.d.ts.map +1 -1
- package/lib/typescript/src/hooks/conversation/useGetConversationDetail.d.ts +2 -1
- package/lib/typescript/src/hooks/conversation/useGetConversationDetail.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts +5 -3
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/query-keys.d.ts +7 -0
- package/lib/typescript/src/hooks/query-keys.d.ts.map +1 -1
- package/lib/typescript/src/hooks/stickers/useFetchStickerByCategory.d.ts +3 -0
- package/lib/typescript/src/hooks/stickers/useFetchStickerByCategory.d.ts.map +1 -0
- package/lib/typescript/src/hooks/stickers/useStickerCategories.d.ts +3 -0
- package/lib/typescript/src/hooks/stickers/useStickerCategories.d.ts.map +1 -0
- package/lib/typescript/src/hooks/stickers/useStickerHistory.d.ts +3 -0
- package/lib/typescript/src/hooks/stickers/useStickerHistory.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useChatCompose.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useMuteConversation.d.ts.map +1 -1
- package/lib/typescript/src/hooks/usePinConversation.d.ts +6 -0
- package/lib/typescript/src/hooks/usePinConversation.d.ts.map +1 -0
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts +2 -2
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/hooks/useChatComposerAnimation.d.ts +2 -1
- package/lib/typescript/src/screens/chat-detail/hooks/useChatComposerAnimation.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/hooks/useChatComposerState.d.ts +3 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useChatComposerState.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts.map +1 -1
- package/lib/typescript/src/services/endpoints.d.ts +4 -1
- package/lib/typescript/src/services/endpoints.d.ts.map +1 -1
- package/lib/typescript/src/store/conversation.d.ts +0 -3
- package/lib/typescript/src/store/conversation.d.ts.map +1 -1
- package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
- package/lib/typescript/src/types/chat.d.ts +12 -19
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/types/sticker.d.ts +21 -0
- package/lib/typescript/src/types/sticker.d.ts.map +1 -0
- package/lib/typescript/src/utils/conversation.d.ts +1 -2
- package/lib/typescript/src/utils/conversation.d.ts.map +1 -1
- package/lib/typescript/src/utils/messageUtils.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/StickerPicker/StickerCategoryTabs.tsx +103 -0
- package/src/components/StickerPicker/StickerPickerPlaceholder.tsx +16 -0
- package/src/components/StickerPicker/StickerPickerRowItem.tsx +43 -0
- package/src/components/StickerPicker/StickerSectionList.tsx +141 -0
- package/src/components/StickerPicker/constants.ts +20 -0
- package/src/components/StickerPicker/index.tsx +166 -0
- package/src/components/ThreadCard/MuteThread.tsx +4 -28
- package/src/components/ThreadCard/PinThread.tsx +58 -0
- package/src/components/ThreadCard/ThreadCard.tsx +11 -5
- package/src/components/messages/stickerMessage/index.tsx +26 -0
- package/src/config/api-endpoints.ts +6 -0
- package/src/hooks/conversation/useGetConversationDetail.ts +20 -1
- package/src/hooks/flows/useGetConversationFlowMainMenu.ts +1 -1
- package/src/hooks/message/useSendMessage.ts +49 -27
- package/src/hooks/query-keys.ts +10 -0
- package/src/hooks/stickers/useFetchStickerByCategory.ts +15 -0
- package/src/hooks/stickers/useStickerCategories.ts +17 -0
- package/src/hooks/stickers/useStickerHistory.ts +19 -0
- package/src/hooks/useChatCompose.ts +0 -19
- package/src/hooks/useMuteConversation.ts +32 -17
- package/src/hooks/usePinConversation.ts +87 -0
- package/src/screens/chat-detail/ChatComposer.tsx +106 -19
- package/src/screens/chat-detail/ChatDetail.tsx +5 -19
- package/src/screens/chat-detail/hooks/useChatComposerAnimation.ts +21 -5
- package/src/screens/chat-detail/hooks/useChatComposerState.ts +7 -0
- package/src/screens/chat-detail/legend/LegendChatMessage.tsx +4 -5
- package/src/services/attachmentOrchestrator.ts +1 -1
- package/src/services/endpoints.ts +6 -1
- package/src/store/conversation.ts +0 -24
- package/src/translation/resources/i18n.ts +11 -0
- package/src/types/chat.ts +13 -21
- package/src/types/sticker.ts +23 -0
- package/src/utils/conversation.ts +0 -28
- package/src/utils/messageUtils.ts +3 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
|
|
2
|
+
import { KColors, KContainer } from '@droppii/libs';
|
|
3
|
+
import type {
|
|
4
|
+
StickerCategory,
|
|
5
|
+
StickerItem,
|
|
6
|
+
StickerRow,
|
|
7
|
+
} from '../../types/sticker';
|
|
8
|
+
import { useStickerCategories } from '../../hooks/stickers/useStickerCategories';
|
|
9
|
+
import { useStickerHistory } from '../../hooks/stickers/useStickerHistory';
|
|
10
|
+
import { useFetchStickerByCategory } from '../../hooks/stickers/useFetchStickerByCategory';
|
|
11
|
+
import {
|
|
12
|
+
RECENT_CATEGORY_ID,
|
|
13
|
+
STICKER_COLUMNS,
|
|
14
|
+
STICKER_PICKER_HEIGHT,
|
|
15
|
+
} from './constants';
|
|
16
|
+
import { StickerCategoryTabs } from './StickerCategoryTabs';
|
|
17
|
+
import {
|
|
18
|
+
StickerSectionList,
|
|
19
|
+
type StickerPickerSection,
|
|
20
|
+
} from './StickerSectionList';
|
|
21
|
+
import { trans } from '../../translation';
|
|
22
|
+
|
|
23
|
+
interface Props {
|
|
24
|
+
onSelectSticker: (sticker: StickerItem) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const chunkIntoRows = (items: StickerItem[], columns: number): StickerRow[] => {
|
|
28
|
+
const rows: StickerRow[] = [];
|
|
29
|
+
for (let i = 0; i < items.length; i += columns) {
|
|
30
|
+
rows.push(items.slice(i, i + columns));
|
|
31
|
+
}
|
|
32
|
+
return rows;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const makePlaceholderRows = (count: number, columns: number): StickerRow[] => {
|
|
36
|
+
const rows: StickerRow[] = [];
|
|
37
|
+
for (let i = 0; i < count; i += columns) {
|
|
38
|
+
const rowSize = Math.min(columns, count - i);
|
|
39
|
+
rows.push(Array.from({ length: rowSize }, () => null));
|
|
40
|
+
}
|
|
41
|
+
return rows;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const StickerPicker = ({ onSelectSticker }: Props) => {
|
|
45
|
+
const { data: categoriesData } = useStickerCategories();
|
|
46
|
+
const { data: recentStickers } = useStickerHistory();
|
|
47
|
+
const { mutateAsync: fetchStickersByCategory } = useFetchStickerByCategory();
|
|
48
|
+
|
|
49
|
+
const allCategories = useMemo<StickerCategory[]>(() => {
|
|
50
|
+
const recent: StickerCategory = {
|
|
51
|
+
id: RECENT_CATEGORY_ID,
|
|
52
|
+
name: trans('recent'),
|
|
53
|
+
icon: null,
|
|
54
|
+
stickerCount: 0,
|
|
55
|
+
};
|
|
56
|
+
return [recent, ...(categoriesData || [])];
|
|
57
|
+
}, [categoriesData]);
|
|
58
|
+
|
|
59
|
+
const [activeCategory, setActiveCategory] = useState(RECENT_CATEGORY_ID);
|
|
60
|
+
const [sectionDataMap, setSectionDataMap] = useState<
|
|
61
|
+
Record<string, StickerRow[]>
|
|
62
|
+
>({});
|
|
63
|
+
|
|
64
|
+
const loadedIdsRef = useRef(new Set<string>([RECENT_CATEGORY_ID]));
|
|
65
|
+
const sectionListRef = useRef<any>(null);
|
|
66
|
+
const suppressCategoryChangeRef = useRef(false);
|
|
67
|
+
const suppressTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
68
|
+
|
|
69
|
+
// Populate recent section when history data arrives
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (recentStickers) {
|
|
72
|
+
setSectionDataMap((prev) => ({
|
|
73
|
+
...prev,
|
|
74
|
+
[RECENT_CATEGORY_ID]: chunkIntoRows(recentStickers, STICKER_COLUMNS),
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
}, [recentStickers]);
|
|
78
|
+
|
|
79
|
+
// Cleanup suppress timer on unmount
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
return () => {
|
|
82
|
+
if (suppressTimerRef.current) clearTimeout(suppressTimerRef.current);
|
|
83
|
+
};
|
|
84
|
+
}, []);
|
|
85
|
+
|
|
86
|
+
const sections = useMemo<StickerPickerSection[]>(
|
|
87
|
+
() =>
|
|
88
|
+
allCategories.map((cat) => ({
|
|
89
|
+
categoryId: cat.id,
|
|
90
|
+
title: cat.name,
|
|
91
|
+
data:
|
|
92
|
+
sectionDataMap[cat.id] ??
|
|
93
|
+
makePlaceholderRows(cat.stickerCount, STICKER_COLUMNS),
|
|
94
|
+
})),
|
|
95
|
+
[allCategories, sectionDataMap]
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const handleSectionVisible = useCallback(
|
|
99
|
+
async (categoryId: string) => {
|
|
100
|
+
if (categoryId === RECENT_CATEGORY_ID) return;
|
|
101
|
+
if (loadedIdsRef.current.has(categoryId)) return;
|
|
102
|
+
loadedIdsRef.current.add(categoryId);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const stickers = await fetchStickersByCategory(categoryId);
|
|
106
|
+
setSectionDataMap((prev) => ({
|
|
107
|
+
...prev,
|
|
108
|
+
[categoryId]: chunkIntoRows(stickers, STICKER_COLUMNS),
|
|
109
|
+
}));
|
|
110
|
+
} catch {
|
|
111
|
+
loadedIdsRef.current.delete(categoryId);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
[fetchStickersByCategory]
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const handleActiveCategoryChange = useCallback((categoryId: string) => {
|
|
118
|
+
if (suppressCategoryChangeRef.current) return;
|
|
119
|
+
setActiveCategory(categoryId);
|
|
120
|
+
}, []);
|
|
121
|
+
|
|
122
|
+
const handleCategoryPress = useCallback(
|
|
123
|
+
(categoryId: string) => {
|
|
124
|
+
setActiveCategory(categoryId);
|
|
125
|
+
|
|
126
|
+
suppressCategoryChangeRef.current = true;
|
|
127
|
+
if (suppressTimerRef.current) clearTimeout(suppressTimerRef.current);
|
|
128
|
+
suppressTimerRef.current = setTimeout(() => {
|
|
129
|
+
suppressCategoryChangeRef.current = false;
|
|
130
|
+
}, 600);
|
|
131
|
+
|
|
132
|
+
const sectionIndex = allCategories.findIndex((c) => c.id === categoryId);
|
|
133
|
+
if (sectionIndex >= 0 && sectionListRef.current) {
|
|
134
|
+
try {
|
|
135
|
+
sectionListRef.current.scrollToLocation({
|
|
136
|
+
sectionIndex,
|
|
137
|
+
itemIndex: 0,
|
|
138
|
+
animated: true,
|
|
139
|
+
viewOffset: 0,
|
|
140
|
+
});
|
|
141
|
+
} catch {}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
[allCategories]
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<KContainer.View
|
|
149
|
+
style={{ height: STICKER_PICKER_HEIGHT }}
|
|
150
|
+
background={KColors.white}
|
|
151
|
+
>
|
|
152
|
+
<StickerCategoryTabs
|
|
153
|
+
categories={allCategories}
|
|
154
|
+
activeCategory={activeCategory}
|
|
155
|
+
onSelectCategory={handleCategoryPress}
|
|
156
|
+
/>
|
|
157
|
+
<StickerSectionList
|
|
158
|
+
ref={sectionListRef}
|
|
159
|
+
sections={sections}
|
|
160
|
+
onSectionVisible={handleSectionVisible}
|
|
161
|
+
onActiveCategoryChange={handleActiveCategoryChange}
|
|
162
|
+
onSelectSticker={onSelectSticker}
|
|
163
|
+
/>
|
|
164
|
+
</KContainer.View>
|
|
165
|
+
);
|
|
166
|
+
};
|
|
@@ -58,20 +58,8 @@ export const MuteThread = memo(
|
|
|
58
58
|
label: trans('chat:mute_confirm_primary'),
|
|
59
59
|
kind: 'primary',
|
|
60
60
|
onPress: async () => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
UIUtils.toast.open({
|
|
64
|
-
title: trans('chat:mute_toast_success'),
|
|
65
|
-
theme: 'light',
|
|
66
|
-
});
|
|
67
|
-
} catch {
|
|
68
|
-
UIUtils.toast.open({
|
|
69
|
-
title: trans('chat:generic_error'),
|
|
70
|
-
theme: 'error',
|
|
71
|
-
});
|
|
72
|
-
} finally {
|
|
73
|
-
swipeableMethods.close();
|
|
74
|
-
}
|
|
61
|
+
swipeableMethods.close();
|
|
62
|
+
await muteConversation(conversation);
|
|
75
63
|
},
|
|
76
64
|
},
|
|
77
65
|
],
|
|
@@ -81,20 +69,8 @@ export const MuteThread = memo(
|
|
|
81
69
|
}, [swipeableMethods, conversation, muteConversation]);
|
|
82
70
|
|
|
83
71
|
const handleUnmutePress = useCallback(async () => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
UIUtils.toast.open({
|
|
87
|
-
title: trans('chat:unmute_toast_success'),
|
|
88
|
-
theme: 'light',
|
|
89
|
-
});
|
|
90
|
-
} catch {
|
|
91
|
-
UIUtils.toast.open({
|
|
92
|
-
title: trans('chat:generic_error'),
|
|
93
|
-
theme: 'error',
|
|
94
|
-
});
|
|
95
|
-
} finally {
|
|
96
|
-
swipeableMethods.close();
|
|
97
|
-
}
|
|
72
|
+
swipeableMethods.close();
|
|
73
|
+
await unmuteConversation(conversation);
|
|
98
74
|
}, [swipeableMethods, conversation, unmuteConversation]);
|
|
99
75
|
|
|
100
76
|
return (
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { memo, useCallback } from 'react';
|
|
2
|
+
import type { SwipeableMethods } from 'react-native-gesture-handler/ReanimatedSwipeable';
|
|
3
|
+
import { KContainer, KImage, KLabel, KColors } from '@droppii/libs';
|
|
4
|
+
import { usePinConversation } from '../../hooks/usePinConversation';
|
|
5
|
+
import { trans } from '../../translation';
|
|
6
|
+
import { type ConversationItem } from '@droppii/openim-rn-client-sdk';
|
|
7
|
+
|
|
8
|
+
interface PinThreadProps {
|
|
9
|
+
isPinned: boolean;
|
|
10
|
+
conversation?: ConversationItem;
|
|
11
|
+
swipeableMethods: SwipeableMethods;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const PinThread = memo(
|
|
15
|
+
({ isPinned, conversation, swipeableMethods }: PinThreadProps) => {
|
|
16
|
+
const { pinConversation, unpinConversation } = usePinConversation();
|
|
17
|
+
|
|
18
|
+
const handlePress = useCallback(async () => {
|
|
19
|
+
swipeableMethods.close();
|
|
20
|
+
if (isPinned) {
|
|
21
|
+
await unpinConversation(conversation);
|
|
22
|
+
} else {
|
|
23
|
+
await pinConversation(conversation);
|
|
24
|
+
}
|
|
25
|
+
}, [
|
|
26
|
+
isPinned,
|
|
27
|
+
conversation,
|
|
28
|
+
pinConversation,
|
|
29
|
+
unpinConversation,
|
|
30
|
+
swipeableMethods,
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<KContainer.Touchable
|
|
35
|
+
width={76}
|
|
36
|
+
alignItems="center"
|
|
37
|
+
justifyContent="center"
|
|
38
|
+
background={KColors.palette.primary.w400}
|
|
39
|
+
onPress={handlePress}
|
|
40
|
+
>
|
|
41
|
+
<KImage.VectorIcons
|
|
42
|
+
name={isPinned ? 'thumbtack-off-b' : 'thumbtack-b'}
|
|
43
|
+
provider="DroppiiNew"
|
|
44
|
+
size={16}
|
|
45
|
+
color={KColors.white}
|
|
46
|
+
/>
|
|
47
|
+
<KLabel.Text
|
|
48
|
+
typo="Text2XsMedium"
|
|
49
|
+
color={KColors.white}
|
|
50
|
+
marginT="0.25rem"
|
|
51
|
+
textAlign="center"
|
|
52
|
+
>
|
|
53
|
+
{isPinned ? trans('chat:unpin_thread') : trans('chat:pin_thread')}
|
|
54
|
+
</KLabel.Text>
|
|
55
|
+
</KContainer.Touchable>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
);
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type MessageItem,
|
|
18
18
|
} from '@droppii/openim-rn-client-sdk';
|
|
19
19
|
import { MuteThread } from './MuteThread';
|
|
20
|
+
import { PinThread } from './PinThread';
|
|
20
21
|
import { useIsJoinedGroup } from '../../hooks/useIsJoinedGroup';
|
|
21
22
|
import isEmpty from 'lodash/isEmpty';
|
|
22
23
|
|
|
@@ -84,6 +85,11 @@ const ThreadCard = memo(({ item, onPress }: ThreadCardProps) => {
|
|
|
84
85
|
) => (
|
|
85
86
|
<>
|
|
86
87
|
<KContainer.VisibleView visible={!isNotInGroup}>
|
|
88
|
+
<PinThread
|
|
89
|
+
conversation={conversation}
|
|
90
|
+
isPinned={Boolean(isPinned)}
|
|
91
|
+
swipeableMethods={swipeableMethods}
|
|
92
|
+
/>
|
|
87
93
|
<MuteThread
|
|
88
94
|
conversation={conversation}
|
|
89
95
|
isMuted={isMuted}
|
|
@@ -92,7 +98,7 @@ const ThreadCard = memo(({ item, onPress }: ThreadCardProps) => {
|
|
|
92
98
|
</KContainer.VisibleView>
|
|
93
99
|
</>
|
|
94
100
|
),
|
|
95
|
-
[isMuted, conversation, isNotInGroup]
|
|
101
|
+
[isMuted, conversation, isNotInGroup, isPinned]
|
|
96
102
|
);
|
|
97
103
|
|
|
98
104
|
return (
|
|
@@ -164,10 +170,10 @@ const ThreadCard = memo(({ item, onPress }: ThreadCardProps) => {
|
|
|
164
170
|
<KContainer.VisibleView visible={Boolean(isPinned)}>
|
|
165
171
|
<KContainer.View marginL="0.5rem">
|
|
166
172
|
<KImage.VectorIcons
|
|
167
|
-
name=
|
|
168
|
-
provider="
|
|
169
|
-
size={
|
|
170
|
-
color={KColors.
|
|
173
|
+
name={'thumbtack-b'}
|
|
174
|
+
provider="DroppiiNew"
|
|
175
|
+
size={16}
|
|
176
|
+
color={KColors.primary.normal}
|
|
171
177
|
/>
|
|
172
178
|
</KContainer.View>
|
|
173
179
|
</KContainer.VisibleView>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { memo } from 'react';
|
|
2
|
+
import type { BaseLegendMessageProps } from '../types';
|
|
3
|
+
import { KContainer, KImage } from '@droppii/libs';
|
|
4
|
+
import { StyleSheet } from 'react-native';
|
|
5
|
+
|
|
6
|
+
const STICKER_SIZE = 120;
|
|
7
|
+
export const StickerMessage = memo(({ message }: BaseLegendMessageProps) => {
|
|
8
|
+
return (
|
|
9
|
+
<KContainer.View style={styles.message}>
|
|
10
|
+
<KImage.Base
|
|
11
|
+
uri={message?.stickerElem?.content || ''}
|
|
12
|
+
width={STICKER_SIZE}
|
|
13
|
+
height={STICKER_SIZE}
|
|
14
|
+
/>
|
|
15
|
+
</KContainer.View>
|
|
16
|
+
);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const styles = StyleSheet.create({
|
|
20
|
+
message: {
|
|
21
|
+
width: STICKER_SIZE,
|
|
22
|
+
height: STICKER_SIZE,
|
|
23
|
+
justifyContent: 'center',
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
@@ -17,6 +17,9 @@ export interface ApiEndpoints {
|
|
|
17
17
|
imageUpload: string;
|
|
18
18
|
bot: string;
|
|
19
19
|
uploadFcmToken: string;
|
|
20
|
+
stickerCategories: string;
|
|
21
|
+
stickersByCategory: string;
|
|
22
|
+
stickerHistory: string;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
const DEFAULT_ENDPOINTS: ApiEndpoints = {
|
|
@@ -25,6 +28,9 @@ const DEFAULT_ENDPOINTS: ApiEndpoints = {
|
|
|
25
28
|
imageUpload: '/uploader-service/v1/uploader/permanently',
|
|
26
29
|
bot: '/chat-service/v1/app/bots/',
|
|
27
30
|
uploadFcmToken: '/chat-service/third/fcm_update_token',
|
|
31
|
+
stickerCategories: '/chat-service/v1/app/sticker-categories',
|
|
32
|
+
stickersByCategory: '/chat-service/v1/app/sticker-categories',
|
|
33
|
+
stickerHistory: '/chat-service/v1/app/stickers/history',
|
|
28
34
|
};
|
|
29
35
|
|
|
30
36
|
let endpoints: ApiEndpoints = { ...DEFAULT_ENDPOINTS };
|
|
@@ -3,7 +3,7 @@ import OpenIMSDK, { SessionType } from '@droppii/openim-rn-client-sdk';
|
|
|
3
3
|
import { useConversationStore } from '../../store/conversation';
|
|
4
4
|
import { apiInstance } from '../../services/apis';
|
|
5
5
|
import type { BaseResponse } from '../../types/auth';
|
|
6
|
-
import type { DBotStatus } from '../../types/chat';
|
|
6
|
+
import type { DBotStatus, DConversationTarget } from '../../types/chat';
|
|
7
7
|
import { conversationQueryKeys } from '../query-keys';
|
|
8
8
|
import { ENDPOINTS } from '../../services/endpoints';
|
|
9
9
|
|
|
@@ -46,6 +46,25 @@ export const useGetStatusConversationBot = (botId?: string) => {
|
|
|
46
46
|
refetchOnMount: 'always',
|
|
47
47
|
});
|
|
48
48
|
};
|
|
49
|
+
export const useGetConversationTarget = (conversationId?: string) =>
|
|
50
|
+
useQuery({
|
|
51
|
+
queryKey: conversationQueryKeys.conversationTarget(conversationId || ''),
|
|
52
|
+
queryFn: async () => {
|
|
53
|
+
try {
|
|
54
|
+
const res = await apiInstance?.get<BaseResponse<DConversationTarget>>(
|
|
55
|
+
ENDPOINTS.chatService.getConversationTarget(conversationId || '')
|
|
56
|
+
);
|
|
57
|
+
return res?.data?.data || undefined;
|
|
58
|
+
} catch {
|
|
59
|
+
return undefined; // fail-open: unresolved status => compose stays enabled
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
enabled: !!conversationId,
|
|
63
|
+
staleTime: 0,
|
|
64
|
+
gcTime: 0,
|
|
65
|
+
refetchOnMount: 'always',
|
|
66
|
+
});
|
|
67
|
+
|
|
49
68
|
export const useGetOneConversation = ({
|
|
50
69
|
targetUserId,
|
|
51
70
|
targetGroupId,
|
|
@@ -12,7 +12,7 @@ export const useGetConversationFlowMainMenu = (conversationId?: string) => {
|
|
|
12
12
|
const res = await apiInstance?.get<BaseResponse<InputButtonItem[]>>(
|
|
13
13
|
ENDPOINTS.chatService.conversationFlowMainMenu(conversationId || '')
|
|
14
14
|
);
|
|
15
|
-
return res?.data?.data ||
|
|
15
|
+
return res?.data?.data || ([] as InputButtonItem[]);
|
|
16
16
|
},
|
|
17
17
|
enabled: !!conversationId,
|
|
18
18
|
});
|
|
@@ -16,10 +16,7 @@ import {
|
|
|
16
16
|
type IMessageItemEx,
|
|
17
17
|
} from '../../types/chat';
|
|
18
18
|
import { useChatContext, useChatDetailContext } from '../../context';
|
|
19
|
-
import {
|
|
20
|
-
generateContentBasedOnMessageType,
|
|
21
|
-
getBotId,
|
|
22
|
-
} from '../../utils/conversation';
|
|
19
|
+
import { getBotId } from '../../utils/conversation';
|
|
23
20
|
import { markMessageRevoked, useMessageStore } from '../../store/message';
|
|
24
21
|
import uuid from 'react-native-uuid';
|
|
25
22
|
|
|
@@ -27,34 +24,36 @@ import type { IUrlMetadata } from '../../types/common';
|
|
|
27
24
|
import type { IRunConversationFlowPayload } from '../../types/flows';
|
|
28
25
|
import { DeviceEventEmitter } from 'react-native';
|
|
29
26
|
import { ChatEvent } from '../../types/events';
|
|
27
|
+
import type { StickerItem } from '../../types/sticker';
|
|
28
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
29
|
+
import { stickerQueryKeys } from '../query-keys';
|
|
30
|
+
import { getMessagePreview } from '../../utils/messageUtils';
|
|
30
31
|
|
|
31
32
|
const buildSendParams = (
|
|
32
33
|
message: MessageItem,
|
|
33
34
|
recvID: string,
|
|
34
35
|
groupID: string,
|
|
35
|
-
extendMessageInfo: IMessageItemEx
|
|
36
|
-
plainText: string
|
|
36
|
+
extendMessageInfo: IMessageItemEx
|
|
37
37
|
) => ({
|
|
38
38
|
groupID,
|
|
39
39
|
recvID,
|
|
40
40
|
message: { ...message, ex: JSON.stringify(extendMessageInfo) || '{}' },
|
|
41
|
-
offlinePushInfo: generateOfflinePushInfo(message
|
|
41
|
+
offlinePushInfo: generateOfflinePushInfo(message),
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
export const useSendMessage = () => {
|
|
45
45
|
const applicationType = useChatContext().applicationType;
|
|
46
46
|
const pushNewMessage = useMessageStore((state) => state.pushNewMessage);
|
|
47
47
|
const updateOneMessage = useMessageStore((state) => state.updateOneMessage);
|
|
48
|
-
const deleteOneMessage = useMessageStore((state) => state.deleteOneMessage);
|
|
49
48
|
const { quotedMessage, setQuotedMessage } = useChatDetailContext();
|
|
49
|
+
const queryClient = useQueryClient();
|
|
50
50
|
|
|
51
51
|
const dispatchSend = useCallback(
|
|
52
52
|
async (
|
|
53
53
|
message: MessageItem,
|
|
54
54
|
recvID: string,
|
|
55
55
|
groupID: string,
|
|
56
|
-
extendMessageInfo: IMessageItemEx
|
|
57
|
-
plainText: string
|
|
56
|
+
extendMessageInfo: IMessageItemEx
|
|
58
57
|
) => {
|
|
59
58
|
pushNewMessage({ ...message, status: MessageStatus.Sending });
|
|
60
59
|
|
|
@@ -63,12 +62,10 @@ export const useSendMessage = () => {
|
|
|
63
62
|
message,
|
|
64
63
|
recvID,
|
|
65
64
|
groupID,
|
|
66
|
-
extendMessageInfo
|
|
67
|
-
plainText
|
|
65
|
+
extendMessageInfo
|
|
68
66
|
);
|
|
69
67
|
// console.log('[useSendMessage] dispatchSend params', sendParams);
|
|
70
68
|
const sent = await OpenIMSDK.sendMessage(sendParams);
|
|
71
|
-
deleteOneMessage(message.clientMsgID);
|
|
72
69
|
pushNewMessage(sent);
|
|
73
70
|
} catch {
|
|
74
71
|
updateOneMessage({ ...message, status: MessageStatus.Failed });
|
|
@@ -76,7 +73,7 @@ export const useSendMessage = () => {
|
|
|
76
73
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
77
74
|
DeviceEventEmitter.emit(ChatEvent.ScrollToBottom);
|
|
78
75
|
},
|
|
79
|
-
[pushNewMessage, updateOneMessage
|
|
76
|
+
[pushNewMessage, updateOneMessage]
|
|
80
77
|
);
|
|
81
78
|
|
|
82
79
|
const sendMessage = useCallback(
|
|
@@ -85,11 +82,13 @@ export const useSendMessage = () => {
|
|
|
85
82
|
urlMetadata,
|
|
86
83
|
flow,
|
|
87
84
|
customMessage,
|
|
85
|
+
sticker,
|
|
88
86
|
}: {
|
|
89
87
|
plainText?: string;
|
|
90
88
|
urlMetadata?: IUrlMetadata;
|
|
91
89
|
flow?: IRunConversationFlowPayload;
|
|
92
90
|
customMessage?: CustomMessagePayload;
|
|
91
|
+
sticker?: StickerItem;
|
|
93
92
|
}) => {
|
|
94
93
|
const currentConversation = useConversationStore
|
|
95
94
|
.getState()
|
|
@@ -143,23 +142,39 @@ export const useSendMessage = () => {
|
|
|
143
142
|
messageList.push(message);
|
|
144
143
|
}
|
|
145
144
|
|
|
145
|
+
//sticker msg
|
|
146
|
+
if (!!sticker && !!sticker?.file?.fullUrl) {
|
|
147
|
+
let stickerMessage = await createStickerMessage(sticker?.file?.fullUrl);
|
|
148
|
+
if (!stickerMessage) return;
|
|
149
|
+
messageList.push(stickerMessage);
|
|
150
|
+
}
|
|
151
|
+
|
|
146
152
|
for (const message of messageList) {
|
|
147
153
|
const extendMessageInfo: IMessageItemEx = {
|
|
148
154
|
applicationType,
|
|
149
155
|
urlMetadata,
|
|
150
156
|
flow,
|
|
157
|
+
stickerId: sticker?.id,
|
|
151
158
|
};
|
|
152
159
|
|
|
153
160
|
await dispatchSend(
|
|
154
161
|
message,
|
|
155
162
|
recvID || '',
|
|
156
163
|
groupID || '',
|
|
157
|
-
extendMessageInfo
|
|
158
|
-
plainText || ''
|
|
164
|
+
extendMessageInfo
|
|
159
165
|
);
|
|
160
166
|
}
|
|
167
|
+
if (!!sticker && !!sticker?.id) {
|
|
168
|
+
queryClient.invalidateQueries({ queryKey: stickerQueryKeys.recent() });
|
|
169
|
+
}
|
|
161
170
|
},
|
|
162
|
-
[
|
|
171
|
+
[
|
|
172
|
+
applicationType,
|
|
173
|
+
dispatchSend,
|
|
174
|
+
quotedMessage,
|
|
175
|
+
setQuotedMessage,
|
|
176
|
+
queryClient,
|
|
177
|
+
]
|
|
163
178
|
);
|
|
164
179
|
|
|
165
180
|
const retryMessage = useCallback(
|
|
@@ -185,7 +200,7 @@ export const useSendMessage = () => {
|
|
|
185
200
|
recvID: recvID || '',
|
|
186
201
|
groupID: groupID || '',
|
|
187
202
|
message,
|
|
188
|
-
offlinePushInfo: generateOfflinePushInfo(message
|
|
203
|
+
offlinePushInfo: generateOfflinePushInfo(message),
|
|
189
204
|
};
|
|
190
205
|
|
|
191
206
|
try {
|
|
@@ -196,11 +211,9 @@ export const useSendMessage = () => {
|
|
|
196
211
|
message,
|
|
197
212
|
recvID || '',
|
|
198
213
|
groupID || '',
|
|
199
|
-
JSON.parse(message.ex || '{}') as IMessageItemEx
|
|
200
|
-
''
|
|
214
|
+
JSON.parse(message.ex || '{}') as IMessageItemEx
|
|
201
215
|
)
|
|
202
216
|
);
|
|
203
|
-
deleteOneMessage(message.clientMsgID);
|
|
204
217
|
pushNewMessage(sent);
|
|
205
218
|
} catch {
|
|
206
219
|
updateOneMessage({ ...message, status: MessageStatus.Failed });
|
|
@@ -208,7 +221,7 @@ export const useSendMessage = () => {
|
|
|
208
221
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
209
222
|
DeviceEventEmitter.emit(ChatEvent.ScrollToBottom);
|
|
210
223
|
},
|
|
211
|
-
[pushNewMessage, updateOneMessage
|
|
224
|
+
[pushNewMessage, updateOneMessage]
|
|
212
225
|
);
|
|
213
226
|
|
|
214
227
|
const revokeMessage = useCallback(async (message: MessageItem) => {
|
|
@@ -232,16 +245,13 @@ export const useSendMessage = () => {
|
|
|
232
245
|
};
|
|
233
246
|
};
|
|
234
247
|
|
|
235
|
-
export const generateOfflinePushInfo = (
|
|
236
|
-
contentType: MessageType,
|
|
237
|
-
plainText: string
|
|
238
|
-
) => {
|
|
248
|
+
export const generateOfflinePushInfo = (message: MessageItem) => {
|
|
239
249
|
const conversationData = useConversationStore
|
|
240
250
|
?.getState?.()
|
|
241
251
|
?.getCurrentConversation();
|
|
242
252
|
const operatorUserID = useUserStore.getState().user?.userID || '';
|
|
243
253
|
const title = conversationData?.showName || 'Droppii';
|
|
244
|
-
const desc =
|
|
254
|
+
const desc = getMessagePreview(message);
|
|
245
255
|
return {
|
|
246
256
|
title,
|
|
247
257
|
desc,
|
|
@@ -310,3 +320,15 @@ export const createQuotedMessage = async (params: QuoteMsgParams) => {
|
|
|
310
320
|
});
|
|
311
321
|
return quotedMessage;
|
|
312
322
|
};
|
|
323
|
+
|
|
324
|
+
export const createStickerMessage = async (sticker: string) => {
|
|
325
|
+
let stickerMessage = await OpenIMSDK.createStickerMessage(sticker, uuid.v4())
|
|
326
|
+
.then((data) => {
|
|
327
|
+
return data;
|
|
328
|
+
})
|
|
329
|
+
.catch(({ errCode, errMsg }) => {
|
|
330
|
+
console.error('createStickerMessage', errCode, errMsg);
|
|
331
|
+
return null;
|
|
332
|
+
});
|
|
333
|
+
return stickerMessage;
|
|
334
|
+
};
|
package/src/hooks/query-keys.ts
CHANGED
|
@@ -12,6 +12,8 @@ export const conversationQueryKeys = {
|
|
|
12
12
|
detail: (conversationId: string) =>
|
|
13
13
|
[...conversationQueryKeys.details(), conversationId] as const,
|
|
14
14
|
getStatusBot: (botId: string) => ['getStatusBot', botId] as const,
|
|
15
|
+
conversationTarget: (conversationId: string) =>
|
|
16
|
+
['conversationTarget', conversationId] as const,
|
|
15
17
|
flow: (conversationId: string) => ['conversationFlow', conversationId],
|
|
16
18
|
flowMainMenu: (conversationId: string) => [
|
|
17
19
|
'conversationFlowMainMenu',
|
|
@@ -34,3 +36,11 @@ export const usersQueryKeys = {
|
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
export type ConversationQueryKeys = typeof conversationQueryKeys;
|
|
39
|
+
|
|
40
|
+
export const stickerQueryKeys = {
|
|
41
|
+
all: ['stickers'] as const,
|
|
42
|
+
categories: () => [...stickerQueryKeys.all, 'categories'] as const,
|
|
43
|
+
byCategory: (categoryId: string) =>
|
|
44
|
+
[...stickerQueryKeys.all, 'category', categoryId] as const,
|
|
45
|
+
recent: () => [...stickerQueryKeys.all, 'recent'] as const,
|
|
46
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useMutation } from '@tanstack/react-query';
|
|
2
|
+
import { apiInstance } from '../../services/apis';
|
|
3
|
+
import { ENDPOINTS } from '../../services/endpoints';
|
|
4
|
+
import type { BaseResponse } from '../../types/auth';
|
|
5
|
+
import type { StickerItem } from '../../types/sticker';
|
|
6
|
+
|
|
7
|
+
export const useFetchStickerByCategory = () =>
|
|
8
|
+
useMutation({
|
|
9
|
+
mutationFn: async (categoryId: string) => {
|
|
10
|
+
const res = await apiInstance?.get<BaseResponse<StickerItem[]>>(
|
|
11
|
+
ENDPOINTS.chatService.stickersByCategoryId(categoryId)
|
|
12
|
+
);
|
|
13
|
+
return res?.data?.data || [];
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { apiInstance } from '../../services/apis';
|
|
3
|
+
import { stickerQueryKeys } from '../query-keys';
|
|
4
|
+
import { ENDPOINTS } from '../../services/endpoints';
|
|
5
|
+
import type { BaseResponse } from '../../types/auth';
|
|
6
|
+
import type { StickerCategory } from '../../types/sticker';
|
|
7
|
+
|
|
8
|
+
export const useStickerCategories = () =>
|
|
9
|
+
useQuery({
|
|
10
|
+
queryKey: stickerQueryKeys.categories(),
|
|
11
|
+
queryFn: async () => {
|
|
12
|
+
const res = await apiInstance?.get<BaseResponse<StickerCategory[]>>(
|
|
13
|
+
ENDPOINTS.chatService.stickerCategories()
|
|
14
|
+
);
|
|
15
|
+
return res?.data?.data || [];
|
|
16
|
+
},
|
|
17
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { apiInstance } from '../../services/apis';
|
|
3
|
+
import { stickerQueryKeys } from '../query-keys';
|
|
4
|
+
import { ENDPOINTS } from '../../services/endpoints';
|
|
5
|
+
import type { BaseResponse } from '../../types/auth';
|
|
6
|
+
import type { StickerItem } from '../../types/sticker';
|
|
7
|
+
|
|
8
|
+
export const useStickerHistory = () =>
|
|
9
|
+
useQuery({
|
|
10
|
+
queryKey: stickerQueryKeys.recent(),
|
|
11
|
+
queryFn: async () => {
|
|
12
|
+
const res = await apiInstance?.get<BaseResponse<StickerItem[]>>(
|
|
13
|
+
ENDPOINTS.chatService.stickerHistory()
|
|
14
|
+
);
|
|
15
|
+
return res?.data?.data || [];
|
|
16
|
+
},
|
|
17
|
+
staleTime: 0,
|
|
18
|
+
gcTime: 0,
|
|
19
|
+
});
|