@developer_tribe/react-native-comnyx 0.3.2 → 0.3.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/lib/commonjs/App.js +8 -3
- package/lib/commonjs/App.js.map +1 -1
- package/lib/commonjs/assets/arrow-right.png +0 -0
- package/lib/commonjs/assets/headphones-01.png +0 -0
- package/lib/commonjs/assets/iconamoon_clock-fill.png +0 -0
- package/lib/commonjs/assets/info-circle.png +0 -0
- package/lib/commonjs/assets/message-notification-square.png +0 -0
- package/lib/commonjs/assets/x-close.png +0 -0
- package/lib/commonjs/components/ChatList.js +356 -50
- package/lib/commonjs/components/ChatList.js.map +1 -1
- package/lib/commonjs/components/CustomAlert.js +132 -0
- package/lib/commonjs/components/CustomAlert.js.map +1 -0
- package/lib/commonjs/components/CustomerForm.js +252 -198
- package/lib/commonjs/components/CustomerForm.js.map +1 -1
- package/lib/commonjs/components/EmptyList.js +36 -11
- package/lib/commonjs/components/EmptyList.js.map +1 -1
- package/lib/commonjs/components/InitFailed.js +8 -5
- package/lib/commonjs/components/InitFailed.js.map +1 -1
- package/lib/commonjs/components/MessageInput.js +49 -16
- package/lib/commonjs/components/MessageInput.js.map +1 -1
- package/lib/commonjs/components/MessageItem.js +133 -42
- package/lib/commonjs/components/MessageItem.js.map +1 -1
- package/lib/commonjs/components/ScaledSheet.js +67 -0
- package/lib/commonjs/components/ScaledSheet.js.map +1 -0
- package/lib/commonjs/components/SizeMatter.js +27 -0
- package/lib/commonjs/components/SizeMatter.js.map +1 -0
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/store.js +15 -9
- package/lib/commonjs/store.js.map +1 -1
- package/lib/commonjs/types/Theme.js +20 -2
- package/lib/commonjs/types/Theme.js.map +1 -1
- package/lib/commonjs/utils/deepMap.js +38 -0
- package/lib/commonjs/utils/deepMap.js.map +1 -0
- package/lib/commonjs/utils/formatDate.js +20 -0
- package/lib/commonjs/utils/formatDate.js.map +1 -0
- package/lib/commonjs/utils/scalingUtils.js +33 -0
- package/lib/commonjs/utils/scalingUtils.js.map +1 -0
- package/lib/commonjs/viewabilityConfig.js +11 -0
- package/lib/commonjs/viewabilityConfig.js.map +1 -0
- package/lib/module/App.js +8 -3
- package/lib/module/App.js.map +1 -1
- package/lib/module/assets/arrow-right.png +0 -0
- package/lib/module/assets/headphones-01.png +0 -0
- package/lib/module/assets/iconamoon_clock-fill.png +0 -0
- package/lib/module/assets/info-circle.png +0 -0
- package/lib/module/assets/message-notification-square.png +0 -0
- package/lib/module/assets/x-close.png +0 -0
- package/lib/module/components/ChatList.js +358 -54
- package/lib/module/components/ChatList.js.map +1 -1
- package/lib/module/components/CustomAlert.js +127 -0
- package/lib/module/components/CustomAlert.js.map +1 -0
- package/lib/module/components/CustomerForm.js +253 -200
- package/lib/module/components/CustomerForm.js.map +1 -1
- package/lib/module/components/EmptyList.js +38 -13
- package/lib/module/components/EmptyList.js.map +1 -1
- package/lib/module/components/InitFailed.js +9 -6
- package/lib/module/components/InitFailed.js.map +1 -1
- package/lib/module/components/MessageInput.js +50 -17
- package/lib/module/components/MessageInput.js.map +1 -1
- package/lib/module/components/MessageItem.js +134 -44
- package/lib/module/components/MessageItem.js.map +1 -1
- package/lib/module/components/ScaledSheet.js +62 -0
- package/lib/module/components/ScaledSheet.js.map +1 -0
- package/lib/module/components/SizeMatter.js +23 -0
- package/lib/module/components/SizeMatter.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/store.js +15 -9
- package/lib/module/store.js.map +1 -1
- package/lib/module/types/Theme.js +20 -2
- package/lib/module/types/Theme.js.map +1 -1
- package/lib/module/utils/deepMap.js +34 -0
- package/lib/module/utils/deepMap.js.map +1 -0
- package/lib/module/utils/formatDate.js +15 -0
- package/lib/module/utils/formatDate.js.map +1 -0
- package/lib/module/utils/scalingUtils.js +25 -0
- package/lib/module/utils/scalingUtils.js.map +1 -0
- package/lib/module/viewabilityConfig.js +7 -0
- package/lib/module/viewabilityConfig.js.map +1 -0
- package/lib/typescript/commonjs/src/App.d.ts +2 -1
- package/lib/typescript/commonjs/src/App.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/ChatList.d.ts +3 -1
- package/lib/typescript/commonjs/src/components/ChatList.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/CustomAlert.d.ts +15 -0
- package/lib/typescript/commonjs/src/components/CustomAlert.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/components/CustomerForm.d.ts +3 -1
- package/lib/typescript/commonjs/src/components/CustomerForm.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/EmptyList.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/InitFailed.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/MessageInput.d.ts +1 -0
- package/lib/typescript/commonjs/src/components/MessageInput.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/MessageItem.d.ts +2 -1
- package/lib/typescript/commonjs/src/components/MessageItem.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/ScaledSheet.d.ts +2 -0
- package/lib/typescript/commonjs/src/components/ScaledSheet.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/components/SizeMatter.d.ts +7 -0
- package/lib/typescript/commonjs/src/components/SizeMatter.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +1 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/store.d.ts +6 -0
- package/lib/typescript/commonjs/src/store.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/types/Conversation.d.ts +2 -0
- package/lib/typescript/commonjs/src/types/Conversation.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/types/Theme.d.ts +9 -0
- package/lib/typescript/commonjs/src/types/Theme.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/utils/deepMap.d.ts +7 -0
- package/lib/typescript/commonjs/src/utils/deepMap.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/utils/formatDate.d.ts +2 -0
- package/lib/typescript/commonjs/src/utils/formatDate.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/utils/scalingUtils.d.ts +10 -0
- package/lib/typescript/commonjs/src/utils/scalingUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/viewabilityConfig.d.ts +5 -0
- package/lib/typescript/commonjs/src/viewabilityConfig.d.ts.map +1 -0
- package/lib/typescript/module/src/App.d.ts +2 -1
- package/lib/typescript/module/src/App.d.ts.map +1 -1
- package/lib/typescript/module/src/components/ChatList.d.ts +3 -1
- package/lib/typescript/module/src/components/ChatList.d.ts.map +1 -1
- package/lib/typescript/module/src/components/CustomAlert.d.ts +15 -0
- package/lib/typescript/module/src/components/CustomAlert.d.ts.map +1 -0
- package/lib/typescript/module/src/components/CustomerForm.d.ts +3 -1
- package/lib/typescript/module/src/components/CustomerForm.d.ts.map +1 -1
- package/lib/typescript/module/src/components/EmptyList.d.ts.map +1 -1
- package/lib/typescript/module/src/components/InitFailed.d.ts.map +1 -1
- package/lib/typescript/module/src/components/MessageInput.d.ts +1 -0
- package/lib/typescript/module/src/components/MessageInput.d.ts.map +1 -1
- package/lib/typescript/module/src/components/MessageItem.d.ts +2 -1
- package/lib/typescript/module/src/components/MessageItem.d.ts.map +1 -1
- package/lib/typescript/module/src/components/ScaledSheet.d.ts +2 -0
- package/lib/typescript/module/src/components/ScaledSheet.d.ts.map +1 -0
- package/lib/typescript/module/src/components/SizeMatter.d.ts +7 -0
- package/lib/typescript/module/src/components/SizeMatter.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +1 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/store.d.ts +6 -0
- package/lib/typescript/module/src/store.d.ts.map +1 -1
- package/lib/typescript/module/src/types/Conversation.d.ts +2 -0
- package/lib/typescript/module/src/types/Conversation.d.ts.map +1 -1
- package/lib/typescript/module/src/types/Theme.d.ts +9 -0
- package/lib/typescript/module/src/types/Theme.d.ts.map +1 -1
- package/lib/typescript/module/src/utils/deepMap.d.ts +7 -0
- package/lib/typescript/module/src/utils/deepMap.d.ts.map +1 -0
- package/lib/typescript/module/src/utils/formatDate.d.ts +2 -0
- package/lib/typescript/module/src/utils/formatDate.d.ts.map +1 -0
- package/lib/typescript/module/src/utils/scalingUtils.d.ts +10 -0
- package/lib/typescript/module/src/utils/scalingUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/viewabilityConfig.d.ts +5 -0
- package/lib/typescript/module/src/viewabilityConfig.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/App.tsx +4 -2
- package/src/assets/arrow-right.png +0 -0
- package/src/assets/headphones-01.png +0 -0
- package/src/assets/iconamoon_clock-fill.png +0 -0
- package/src/assets/info-circle.png +0 -0
- package/src/assets/message-notification-square.png +0 -0
- package/src/assets/x-close.png +0 -0
- package/src/components/ChatList.tsx +420 -60
- package/src/components/CustomAlert.tsx +132 -0
- package/src/components/CustomerForm.tsx +272 -224
- package/src/components/EmptyList.tsx +31 -7
- package/src/components/InitFailed.tsx +9 -6
- package/src/components/MessageInput.tsx +86 -49
- package/src/components/MessageItem.tsx +181 -58
- package/src/components/ScaledSheet.ts +93 -0
- package/src/components/SizeMatter.tsx +22 -0
- package/src/index.tsx +1 -0
- package/src/store.ts +13 -3
- package/src/types/Conversation.ts +2 -0
- package/src/types/Theme.ts +27 -0
- package/src/utils/deepMap.ts +47 -0
- package/src/utils/formatDate.ts +13 -0
- package/src/utils/scalingUtils.ts +27 -0
- package/src/viewabilityConfig.ts +4 -0
- package/lib/commonjs/assets/double-check.png +0 -0
- package/lib/commonjs/assets/send.png +0 -0
- package/lib/module/assets/double-check.png +0 -0
- package/lib/module/assets/send.png +0 -0
- package/src/assets/double-check.png +0 -0
- package/src/assets/send.png +0 -0
|
@@ -1,24 +1,29 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useRef, useState, useMemo } from 'react';
|
|
2
2
|
import { useAppStore } from '../store';
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
SectionList,
|
|
5
5
|
View,
|
|
6
6
|
useWindowDimensions,
|
|
7
7
|
ActivityIndicator,
|
|
8
8
|
Image,
|
|
9
9
|
TouchableOpacity,
|
|
10
|
-
Keyboard,
|
|
11
|
-
Pressable,
|
|
12
10
|
} from 'react-native';
|
|
13
|
-
import { getCustomerConversation } from '../api';
|
|
11
|
+
import { getCustomerConversation, sendCustomerMessage } from '../api';
|
|
14
12
|
import type { AppConversationMessage } from '../types/Conversation';
|
|
15
|
-
import { StyleSheet } from 'react-native';
|
|
16
13
|
import { MessageItem } from './MessageItem';
|
|
17
14
|
import { MessageInput } from './MessageInput';
|
|
18
15
|
import { useThemeColors } from '../hooks/useThemeColors';
|
|
19
16
|
import { AppText } from './AppText';
|
|
20
17
|
import { InitFailed } from './InitFailed';
|
|
21
18
|
import { EmptyList } from './EmptyList';
|
|
19
|
+
import CustomPopup from './CustomAlert';
|
|
20
|
+
import type { LocalizationKeys } from '../types/LocalizationKeys';
|
|
21
|
+
import { ScaledSheet } from './ScaledSheet';
|
|
22
|
+
import { formatDate } from '../utils/formatDate';
|
|
23
|
+
import { viewabilityConfig } from '../viewabilityConfig';
|
|
24
|
+
|
|
25
|
+
const headphonesIcon = require('../assets/headphones-01.png');
|
|
26
|
+
const closeIcon = require('../assets/x-close.png');
|
|
22
27
|
|
|
23
28
|
function LoadingItem() {
|
|
24
29
|
const themeColors = useThemeColors();
|
|
@@ -31,7 +36,7 @@ function LoadingItem() {
|
|
|
31
36
|
);
|
|
32
37
|
}
|
|
33
38
|
|
|
34
|
-
export function ChatList() {
|
|
39
|
+
export function ChatList({ onBack }: { onBack?: () => void }) {
|
|
35
40
|
const themeColors = useThemeColors();
|
|
36
41
|
const { height: windowHeight } = useWindowDimensions();
|
|
37
42
|
const MESSAGE_MIN_HEIGHT = 60;
|
|
@@ -45,13 +50,124 @@ export function ChatList() {
|
|
|
45
50
|
data: s.data,
|
|
46
51
|
setData: s.setData,
|
|
47
52
|
}));
|
|
48
|
-
const ref = useRef<
|
|
53
|
+
const ref = useRef<SectionList<AppConversationMessage>>(null);
|
|
49
54
|
const [page, setPage] = useState(1);
|
|
50
55
|
const nextPageStatus = useRef<'fail' | 'loading' | 'empty'>();
|
|
51
56
|
const [nexPageFailed, setNexPageFailed] = useState(false);
|
|
52
57
|
const [initFailed, setInitFailed] = useState(false);
|
|
53
58
|
const [isScrollingUp, setIsScrollingUp] = useState(false);
|
|
54
59
|
const listChangedRef = useRef(false);
|
|
60
|
+
const [popupVisible, setPopupVisible] = useState(false);
|
|
61
|
+
const [selectedMessage, setSelectedMessage] = useState<string>('');
|
|
62
|
+
const [currentSection, setCurrentSection] = useState<string>('');
|
|
63
|
+
|
|
64
|
+
const sections = useMemo(() => {
|
|
65
|
+
if (!data || data.length === 0) return [];
|
|
66
|
+
|
|
67
|
+
const messagesByDate: Record<string, AppConversationMessage[]> = {};
|
|
68
|
+
|
|
69
|
+
data.forEach((message: AppConversationMessage) => {
|
|
70
|
+
const dateKey = formatDate(message?.created_at);
|
|
71
|
+
if (!messagesByDate[dateKey]) {
|
|
72
|
+
messagesByDate[dateKey] = [];
|
|
73
|
+
}
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
messagesByDate[dateKey].push(message);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return Object.entries(messagesByDate).map(([title, messages]) => ({
|
|
79
|
+
title,
|
|
80
|
+
data: messages.sort(
|
|
81
|
+
(a, b) => b.created_at.getTime() - a.created_at.getTime()
|
|
82
|
+
),
|
|
83
|
+
}));
|
|
84
|
+
}, [data]);
|
|
85
|
+
|
|
86
|
+
const resendMessage = useCallback(() => {
|
|
87
|
+
if (selectedMessage && customer?.external_id) {
|
|
88
|
+
const currentMessage = useAppStore.getState().data || [];
|
|
89
|
+
const messageIndex = currentMessage.findIndex(
|
|
90
|
+
(msg) => msg.content === selectedMessage
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (messageIndex === -1) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const updatedValue = [...currentMessage];
|
|
98
|
+
const existingValue = updatedValue[messageIndex];
|
|
99
|
+
|
|
100
|
+
if (existingValue) {
|
|
101
|
+
updatedValue[messageIndex] = {
|
|
102
|
+
...existingValue,
|
|
103
|
+
approved: false,
|
|
104
|
+
error: false,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
useAppStore.setState({
|
|
108
|
+
data: updatedValue,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
sendCustomerMessage(customer.external_id, selectedMessage, {
|
|
112
|
+
fake: useAppStore.getState().fake,
|
|
113
|
+
})
|
|
114
|
+
.then((res: any) => {
|
|
115
|
+
const currentData = useAppStore.getState().data || [];
|
|
116
|
+
const dataIndex = currentData.findIndex(
|
|
117
|
+
(msg) => msg.content === selectedMessage
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
if (dataIndex !== -1) {
|
|
121
|
+
const updatedData = [...currentData];
|
|
122
|
+
const existingMessage = updatedData[dataIndex];
|
|
123
|
+
|
|
124
|
+
if (existingMessage) {
|
|
125
|
+
updatedData[dataIndex] = {
|
|
126
|
+
...existingMessage,
|
|
127
|
+
id: res.message.id,
|
|
128
|
+
content: res.message.content,
|
|
129
|
+
user: res.message.user || existingMessage.user,
|
|
130
|
+
approved: true,
|
|
131
|
+
error: false,
|
|
132
|
+
created_at: new Date(res.message.created_at),
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
useAppStore.setState({
|
|
136
|
+
data: updatedData,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
setSelectedMessage('');
|
|
142
|
+
})
|
|
143
|
+
.catch((error) => {
|
|
144
|
+
const currentData = useAppStore.getState().data || [];
|
|
145
|
+
const dataIndex = currentData.findIndex(
|
|
146
|
+
(msg) => msg.content === selectedMessage
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (dataIndex !== -1) {
|
|
150
|
+
const updatedMessage = [...currentData];
|
|
151
|
+
const existingData = updatedMessage[dataIndex];
|
|
152
|
+
|
|
153
|
+
if (existingData) {
|
|
154
|
+
updatedMessage[dataIndex] = {
|
|
155
|
+
...existingData,
|
|
156
|
+
error: true,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
useAppStore.setState({
|
|
160
|
+
data: updatedMessage,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
console.error('Mesajı yeniden gönderme hatası:', error);
|
|
166
|
+
setSelectedMessage('');
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}, [selectedMessage, customer]);
|
|
55
171
|
|
|
56
172
|
const nextPage = useCallback(() => {
|
|
57
173
|
if (nextPageStatus.current) {
|
|
@@ -105,34 +221,121 @@ export function ChatList() {
|
|
|
105
221
|
}, [MESSAGES_PER_PAGE, customer?.external_id, page, setData]);
|
|
106
222
|
|
|
107
223
|
const renderItem = useCallback(
|
|
108
|
-
({ item }: { item: AppConversationMessage }) =>
|
|
224
|
+
({ item }: { item: AppConversationMessage }) => {
|
|
225
|
+
return (
|
|
226
|
+
<MessageItem
|
|
227
|
+
item={item}
|
|
228
|
+
onShowPopup={() => {
|
|
229
|
+
setSelectedMessage(item.content);
|
|
230
|
+
setPopupVisible(true);
|
|
231
|
+
}}
|
|
232
|
+
/>
|
|
233
|
+
);
|
|
234
|
+
},
|
|
109
235
|
[]
|
|
110
236
|
);
|
|
111
237
|
|
|
238
|
+
const handleViewabilityChange = useCallback(
|
|
239
|
+
(info: { viewableItems: any[] }) => {
|
|
240
|
+
if (info.viewableItems && info.viewableItems.length > 0) {
|
|
241
|
+
// Find the first viewable item with a section
|
|
242
|
+
for (const viewableItem of info.viewableItems) {
|
|
243
|
+
if (viewableItem.section && viewableItem.section.title) {
|
|
244
|
+
const title = viewableItem.section.title;
|
|
245
|
+
if (title !== currentSection) {
|
|
246
|
+
setCurrentSection(title);
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
[currentSection]
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
const viewabilityConfigCallbackPairs = useRef([
|
|
257
|
+
{
|
|
258
|
+
viewabilityConfig,
|
|
259
|
+
onViewableItemsChanged: handleViewabilityChange,
|
|
260
|
+
},
|
|
261
|
+
]);
|
|
262
|
+
|
|
263
|
+
// We'll use onScroll instead of onMomentumScrollEnd for more responsive updates
|
|
112
264
|
const handleScroll = useCallback(
|
|
113
265
|
(event: any) => {
|
|
114
266
|
const currentScrollY = event.nativeEvent.contentOffset.y;
|
|
115
267
|
const contentHeight = event.nativeEvent.contentSize.height;
|
|
116
268
|
const scrollViewHeight = event.nativeEvent.layoutMeasurement.height;
|
|
269
|
+
|
|
117
270
|
setIsScrollingUp(currentScrollY > 100);
|
|
118
271
|
|
|
272
|
+
// Only proceed if we have sections and the list is scrolled enough
|
|
273
|
+
if (sections && sections.length > 0 && currentScrollY > 0) {
|
|
274
|
+
// Create visibility info for each section
|
|
275
|
+
let visibleSectionIndex = -1;
|
|
276
|
+
let maxVisibility = 0;
|
|
277
|
+
|
|
278
|
+
// For inverted lists, we need to iterate through sections to find which one is most visible
|
|
279
|
+
for (let i = 0; i < sections.length; i++) {
|
|
280
|
+
const section = sections[i];
|
|
281
|
+
if (!section || !section.data) continue;
|
|
282
|
+
|
|
283
|
+
const sectionStartPercent = i / sections.length;
|
|
284
|
+
const sectionEndPercent = (i + 1) / sections.length;
|
|
285
|
+
|
|
286
|
+
// Convert percentages to scroll positions
|
|
287
|
+
const sectionStartPosition = contentHeight * sectionStartPercent;
|
|
288
|
+
const sectionEndPosition = contentHeight * sectionEndPercent;
|
|
289
|
+
|
|
290
|
+
// Calculate how much of this section is visible
|
|
291
|
+
const visibleTop = Math.max(currentScrollY, sectionStartPosition);
|
|
292
|
+
const visibleBottom = Math.min(
|
|
293
|
+
currentScrollY + scrollViewHeight,
|
|
294
|
+
sectionEndPosition
|
|
295
|
+
);
|
|
296
|
+
const visibleHeight = Math.max(0, visibleBottom - visibleTop);
|
|
297
|
+
|
|
298
|
+
// Track which section has the most visibility
|
|
299
|
+
if (visibleHeight > maxVisibility) {
|
|
300
|
+
maxVisibility = visibleHeight;
|
|
301
|
+
visibleSectionIndex = i;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// If we found a visible section, update the header
|
|
306
|
+
if (visibleSectionIndex >= 0 && visibleSectionIndex < sections.length) {
|
|
307
|
+
const visibleSection = sections[visibleSectionIndex];
|
|
308
|
+
if (
|
|
309
|
+
visibleSection?.title &&
|
|
310
|
+
visibleSection.title !== currentSection
|
|
311
|
+
) {
|
|
312
|
+
console.log(
|
|
313
|
+
`Most visible section: ${visibleSection.title} (index ${visibleSectionIndex})`
|
|
314
|
+
);
|
|
315
|
+
setCurrentSection(visibleSection.title);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Check if we need to load more data
|
|
119
321
|
if (currentScrollY >= contentHeight - scrollViewHeight - 200) {
|
|
120
322
|
nextPage();
|
|
121
323
|
}
|
|
122
324
|
},
|
|
123
|
-
[nextPage]
|
|
325
|
+
[nextPage, sections, currentSection]
|
|
124
326
|
);
|
|
125
327
|
|
|
126
328
|
const scrollToBottom = useCallback(
|
|
127
329
|
(animated: boolean) => {
|
|
128
|
-
if (ref.current &&
|
|
129
|
-
ref.current.
|
|
130
|
-
|
|
330
|
+
if (ref.current && sections.length) {
|
|
331
|
+
ref.current.scrollToLocation({
|
|
332
|
+
sectionIndex: 0,
|
|
333
|
+
itemIndex: 0,
|
|
131
334
|
animated,
|
|
132
335
|
});
|
|
133
336
|
}
|
|
134
337
|
},
|
|
135
|
-
[
|
|
338
|
+
[sections]
|
|
136
339
|
);
|
|
137
340
|
|
|
138
341
|
useEffect(() => {
|
|
@@ -145,18 +348,18 @@ export function ChatList() {
|
|
|
145
348
|
setData((prevData) => {
|
|
146
349
|
const newMessages = newData?.page?.data ?? [];
|
|
147
350
|
const existingIds = new Set(prevData?.map((msg) => msg.id));
|
|
148
|
-
const uniqueNewMessages = newMessages
|
|
149
|
-
(msg) => !existingIds
|
|
351
|
+
const uniqueNewMessages = newMessages?.filter(
|
|
352
|
+
(msg) => !existingIds?.has(msg.id)
|
|
150
353
|
);
|
|
151
|
-
const processedMessages = uniqueNewMessages
|
|
354
|
+
const processedMessages = uniqueNewMessages?.map((u) => ({
|
|
152
355
|
...u,
|
|
153
356
|
created_at: new Date(u.created_at),
|
|
154
357
|
approved: true,
|
|
155
358
|
}));
|
|
156
359
|
useAppStore.setState({
|
|
157
|
-
firstMessage: processedMessages[0],
|
|
360
|
+
firstMessage: processedMessages?.[0],
|
|
158
361
|
});
|
|
159
|
-
if (processedMessages
|
|
362
|
+
if (processedMessages?.length === 0) {
|
|
160
363
|
setLoading(false);
|
|
161
364
|
}
|
|
162
365
|
return processedMessages;
|
|
@@ -165,10 +368,20 @@ export function ChatList() {
|
|
|
165
368
|
.catch((e) => {
|
|
166
369
|
setInitFailed(true);
|
|
167
370
|
console.error(e);
|
|
371
|
+
})
|
|
372
|
+
.finally(() => {
|
|
373
|
+
setLoading(false);
|
|
168
374
|
});
|
|
169
375
|
}
|
|
170
376
|
}, [MESSAGES_PER_PAGE, customer?.external_id, initFailed, setData]);
|
|
171
377
|
|
|
378
|
+
// Initialize the current section when sections are loaded
|
|
379
|
+
useEffect(() => {
|
|
380
|
+
if (sections.length > 0 && sections[0]?.title) {
|
|
381
|
+
setCurrentSection(sections[0].title);
|
|
382
|
+
}
|
|
383
|
+
}, [sections]);
|
|
384
|
+
|
|
172
385
|
if (nexPageFailed) {
|
|
173
386
|
return (
|
|
174
387
|
<View
|
|
@@ -197,38 +410,94 @@ export function ChatList() {
|
|
|
197
410
|
if (initFailed) {
|
|
198
411
|
return <InitFailed setInitFailed={setInitFailed} />;
|
|
199
412
|
}
|
|
413
|
+
|
|
200
414
|
return (
|
|
201
|
-
<
|
|
415
|
+
<View
|
|
202
416
|
style={[styles.container, { backgroundColor: themeColors.background }]}
|
|
203
|
-
onPress={Keyboard.dismiss}
|
|
204
417
|
>
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
418
|
+
<TouchableOpacity style={[styles.iconContainer]} onPress={onBack}>
|
|
419
|
+
<Image
|
|
420
|
+
source={closeIcon}
|
|
421
|
+
style={[styles.closeIcon, { tintColor: themeColors.text }]}
|
|
422
|
+
/>
|
|
423
|
+
</TouchableOpacity>
|
|
424
|
+
<View
|
|
425
|
+
style={[
|
|
426
|
+
styles.headerContainer,
|
|
427
|
+
{
|
|
428
|
+
backgroundColor: themeColors.background,
|
|
429
|
+
borderBottomColor: themeColors.lavender,
|
|
430
|
+
},
|
|
213
431
|
]}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
432
|
+
>
|
|
433
|
+
<AppText
|
|
434
|
+
localization="chat.empty"
|
|
435
|
+
style={[styles.header, { color: themeColors.text }]}
|
|
436
|
+
/>
|
|
437
|
+
<View
|
|
438
|
+
style={[
|
|
439
|
+
styles.headerText,
|
|
440
|
+
{ backgroundColor: themeColors.background },
|
|
441
|
+
]}
|
|
442
|
+
>
|
|
443
|
+
<Image
|
|
444
|
+
source={headphonesIcon}
|
|
445
|
+
style={[styles.headphonesIcon, { tintColor: themeColors.text }]}
|
|
446
|
+
/>
|
|
447
|
+
<AppText
|
|
448
|
+
localization="chat.empty"
|
|
449
|
+
style={[styles.liveChat, { color: themeColors.text }]}
|
|
450
|
+
/>
|
|
451
|
+
<View style={[styles.dot, { backgroundColor: themeColors.green }]} />
|
|
452
|
+
</View>
|
|
453
|
+
</View>
|
|
454
|
+
|
|
455
|
+
<View style={styles.listContainer}>
|
|
456
|
+
<AppText
|
|
457
|
+
style={[
|
|
458
|
+
styles.fixedDateText,
|
|
459
|
+
{ color: themeColors.slate, backgroundColor: themeColors.ghost },
|
|
460
|
+
]}
|
|
461
|
+
>
|
|
462
|
+
{currentSection}
|
|
463
|
+
</AppText>
|
|
464
|
+
|
|
465
|
+
<SectionList
|
|
466
|
+
ref={ref}
|
|
467
|
+
sections={sections}
|
|
468
|
+
inverted
|
|
469
|
+
renderItem={renderItem}
|
|
470
|
+
contentContainerStyle={[
|
|
471
|
+
styles.contentContainer,
|
|
472
|
+
{ backgroundColor: themeColors.background },
|
|
473
|
+
]}
|
|
474
|
+
style={styles.list}
|
|
475
|
+
ListEmptyComponent={
|
|
476
|
+
!loading && (!sections || sections.length === 0) ? (
|
|
477
|
+
<EmptyList />
|
|
478
|
+
) : null
|
|
479
|
+
}
|
|
480
|
+
ListFooterComponent={loading ? <LoadingItem /> : null}
|
|
481
|
+
keyExtractor={(item: AppConversationMessage) =>
|
|
482
|
+
item.id + '-' + item.created_at
|
|
483
|
+
}
|
|
484
|
+
removeClippedSubviews={true}
|
|
485
|
+
maxToRenderPerBatch={10}
|
|
486
|
+
windowSize={21}
|
|
487
|
+
initialNumToRender={MESSAGES_PER_PAGE}
|
|
488
|
+
getItemLayout={(_: any, index: number) => ({
|
|
489
|
+
length: MESSAGE_MIN_HEIGHT + 10,
|
|
490
|
+
offset: (MESSAGE_MIN_HEIGHT + 10) * index,
|
|
491
|
+
index,
|
|
492
|
+
})}
|
|
493
|
+
onScroll={handleScroll}
|
|
494
|
+
scrollEventThrottle={16}
|
|
495
|
+
viewabilityConfigCallbackPairs={
|
|
496
|
+
viewabilityConfigCallbackPairs.current
|
|
497
|
+
}
|
|
498
|
+
stickySectionHeadersEnabled={false}
|
|
499
|
+
/>
|
|
500
|
+
</View>
|
|
232
501
|
{isScrollingUp && (
|
|
233
502
|
<TouchableOpacity
|
|
234
503
|
style={[
|
|
@@ -243,21 +512,42 @@ export function ChatList() {
|
|
|
243
512
|
/>
|
|
244
513
|
</TouchableOpacity>
|
|
245
514
|
)}
|
|
246
|
-
<MessageInput
|
|
247
|
-
|
|
515
|
+
<MessageInput
|
|
516
|
+
scrollToBottom={scrollToBottom}
|
|
517
|
+
selectedMessage={selectedMessage}
|
|
518
|
+
/>
|
|
519
|
+
<CustomPopup
|
|
520
|
+
isVisible={popupVisible}
|
|
521
|
+
onClose={() => setPopupVisible(false)}
|
|
522
|
+
title={'chat.list-failed-message.title'}
|
|
523
|
+
description={'chat.list-failed-message.description'}
|
|
524
|
+
onCancelButton={() => {
|
|
525
|
+
setPopupVisible(false);
|
|
526
|
+
}}
|
|
527
|
+
onResendButton={() => {
|
|
528
|
+
resendMessage();
|
|
529
|
+
setPopupVisible(false);
|
|
530
|
+
}}
|
|
531
|
+
buttonText={'chat.list-cancel' as keyof LocalizationKeys}
|
|
532
|
+
/>
|
|
533
|
+
</View>
|
|
248
534
|
);
|
|
249
535
|
}
|
|
250
536
|
|
|
251
|
-
const styles =
|
|
537
|
+
const styles = ScaledSheet.create({
|
|
252
538
|
container: {
|
|
253
539
|
flex: 1,
|
|
540
|
+
paddingBottom: '20@vs',
|
|
541
|
+
paddingTop: '40@vs',
|
|
542
|
+
position: 'relative',
|
|
254
543
|
},
|
|
255
544
|
list: {
|
|
256
545
|
flex: 1,
|
|
257
546
|
},
|
|
258
547
|
contentContainer: {
|
|
259
|
-
|
|
260
|
-
|
|
548
|
+
paddingHorizontal: '10@s',
|
|
549
|
+
paddingVertical: '10@vs',
|
|
550
|
+
flexGrow: 1,
|
|
261
551
|
},
|
|
262
552
|
loadingItem: {
|
|
263
553
|
height: 200,
|
|
@@ -266,10 +556,11 @@ const styles = StyleSheet.create({
|
|
|
266
556
|
},
|
|
267
557
|
scrollDownButton: {
|
|
268
558
|
position: 'absolute',
|
|
269
|
-
right: 20,
|
|
559
|
+
right: '20@s',
|
|
270
560
|
bottom: '15%',
|
|
271
|
-
borderRadius: 25,
|
|
272
|
-
|
|
561
|
+
borderRadius: '25@s',
|
|
562
|
+
paddingHorizontal: '10@s',
|
|
563
|
+
paddingVertical: '10@vs',
|
|
273
564
|
shadowColor: '#000',
|
|
274
565
|
shadowOffset: {
|
|
275
566
|
width: 0,
|
|
@@ -280,23 +571,92 @@ const styles = StyleSheet.create({
|
|
|
280
571
|
elevation: 5,
|
|
281
572
|
},
|
|
282
573
|
scrollUpIcon: {
|
|
283
|
-
width: 24,
|
|
284
|
-
height: 24,
|
|
574
|
+
width: '24@s',
|
|
575
|
+
height: '24@vs',
|
|
285
576
|
},
|
|
286
577
|
retryContainer: {
|
|
287
578
|
flex: 1,
|
|
288
579
|
alignItems: 'center',
|
|
289
580
|
justifyContent: 'center',
|
|
290
|
-
|
|
581
|
+
paddingHorizontal: '20@s',
|
|
582
|
+
paddingVertical: '20@vs',
|
|
291
583
|
},
|
|
292
584
|
retryButton: {
|
|
293
585
|
padding: 15,
|
|
294
|
-
borderRadius: 8,
|
|
586
|
+
borderRadius: '8@s',
|
|
295
587
|
alignItems: 'center',
|
|
296
588
|
justifyContent: 'center',
|
|
297
589
|
},
|
|
298
590
|
retryText: {
|
|
299
|
-
fontSize: 16,
|
|
591
|
+
fontSize: '16@vs',
|
|
300
592
|
fontWeight: '500',
|
|
301
593
|
},
|
|
594
|
+
headphonesIcon: {
|
|
595
|
+
width: '24@vs',
|
|
596
|
+
height: '24@vs',
|
|
597
|
+
},
|
|
598
|
+
header: {
|
|
599
|
+
fontSize: '16@vs',
|
|
600
|
+
textAlign: 'center',
|
|
601
|
+
fontWeight: 600,
|
|
602
|
+
},
|
|
603
|
+
liveChat: {
|
|
604
|
+
fontSize: '16@vs',
|
|
605
|
+
textAlign: 'center',
|
|
606
|
+
fontWeight: 400,
|
|
607
|
+
},
|
|
608
|
+
headerContainer: {
|
|
609
|
+
alignItems: 'center',
|
|
610
|
+
gap: 16,
|
|
611
|
+
borderBottomWidth: 1,
|
|
612
|
+
paddingBottom: '16@vs',
|
|
613
|
+
},
|
|
614
|
+
iconContainer: {
|
|
615
|
+
paddingHorizontal: '20@s',
|
|
616
|
+
paddingVertical: '40@vs',
|
|
617
|
+
position: 'absolute',
|
|
618
|
+
zIndex: 9999,
|
|
619
|
+
},
|
|
620
|
+
closeIcon: {
|
|
621
|
+
width: '24@vs',
|
|
622
|
+
height: '24@vs',
|
|
623
|
+
},
|
|
624
|
+
dot: {
|
|
625
|
+
width: '10@vs',
|
|
626
|
+
height: '10@vs',
|
|
627
|
+
borderRadius: '8@s',
|
|
628
|
+
},
|
|
629
|
+
headerText: {
|
|
630
|
+
flexDirection: 'row',
|
|
631
|
+
alignItems: 'center',
|
|
632
|
+
gap: 4,
|
|
633
|
+
},
|
|
634
|
+
sectionHeader: {
|
|
635
|
+
fontSize: '14@vs',
|
|
636
|
+
fontWeight: '400',
|
|
637
|
+
borderRadius: '8@s',
|
|
638
|
+
paddingHorizontal: '8@s',
|
|
639
|
+
paddingVertical: '4@vs',
|
|
640
|
+
alignSelf: 'center',
|
|
641
|
+
marginVertical: '8@vs',
|
|
642
|
+
},
|
|
643
|
+
fixedDateText: {
|
|
644
|
+
fontSize: '14@vs',
|
|
645
|
+
fontWeight: '500',
|
|
646
|
+
borderRadius: '8@s',
|
|
647
|
+
paddingHorizontal: '10@s',
|
|
648
|
+
paddingVertical: '4@s',
|
|
649
|
+
position: 'absolute',
|
|
650
|
+
top: '10@vs',
|
|
651
|
+
zIndex: 10,
|
|
652
|
+
alignSelf: 'center',
|
|
653
|
+
},
|
|
654
|
+
listContainer: {
|
|
655
|
+
flex: 1,
|
|
656
|
+
position: 'relative',
|
|
657
|
+
},
|
|
658
|
+
sectionHeaderContainer: {
|
|
659
|
+
alignItems: 'center',
|
|
660
|
+
marginVertical: '8@vs',
|
|
661
|
+
},
|
|
302
662
|
});
|