@developer_tribe/react-native-comnyx 0.3.1 → 0.3.3
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 +355 -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 +16 -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 +357 -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 +11 -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 +2 -2
- 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 +413 -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 +8 -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,92 @@ 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 && (!data || data.length === 0) ? <EmptyList /> : null
|
|
477
|
+
}
|
|
478
|
+
ListFooterComponent={loading ? <LoadingItem /> : null}
|
|
479
|
+
keyExtractor={(item: AppConversationMessage) =>
|
|
480
|
+
item.id + '-' + item.created_at
|
|
481
|
+
}
|
|
482
|
+
removeClippedSubviews={true}
|
|
483
|
+
maxToRenderPerBatch={10}
|
|
484
|
+
windowSize={21}
|
|
485
|
+
initialNumToRender={MESSAGES_PER_PAGE}
|
|
486
|
+
getItemLayout={(_: any, index: number) => ({
|
|
487
|
+
length: MESSAGE_MIN_HEIGHT + 10,
|
|
488
|
+
offset: (MESSAGE_MIN_HEIGHT + 10) * index,
|
|
489
|
+
index,
|
|
490
|
+
})}
|
|
491
|
+
onScroll={handleScroll}
|
|
492
|
+
scrollEventThrottle={16}
|
|
493
|
+
viewabilityConfigCallbackPairs={
|
|
494
|
+
viewabilityConfigCallbackPairs.current
|
|
495
|
+
}
|
|
496
|
+
stickySectionHeadersEnabled={false}
|
|
497
|
+
/>
|
|
498
|
+
</View>
|
|
232
499
|
{isScrollingUp && (
|
|
233
500
|
<TouchableOpacity
|
|
234
501
|
style={[
|
|
@@ -243,21 +510,41 @@ export function ChatList() {
|
|
|
243
510
|
/>
|
|
244
511
|
</TouchableOpacity>
|
|
245
512
|
)}
|
|
246
|
-
<MessageInput
|
|
247
|
-
|
|
513
|
+
<MessageInput
|
|
514
|
+
scrollToBottom={scrollToBottom}
|
|
515
|
+
selectedMessage={selectedMessage}
|
|
516
|
+
/>
|
|
517
|
+
<CustomPopup
|
|
518
|
+
isVisible={popupVisible}
|
|
519
|
+
onClose={() => setPopupVisible(false)}
|
|
520
|
+
title={'chat.list-failed-message.title'}
|
|
521
|
+
description={'chat.list-failed-message.description'}
|
|
522
|
+
onCancelButton={() => {
|
|
523
|
+
setPopupVisible(false);
|
|
524
|
+
}}
|
|
525
|
+
onResendButton={() => {
|
|
526
|
+
resendMessage();
|
|
527
|
+
setPopupVisible(false);
|
|
528
|
+
}}
|
|
529
|
+
buttonText={'chat.list-cancel' as keyof LocalizationKeys}
|
|
530
|
+
/>
|
|
531
|
+
</View>
|
|
248
532
|
);
|
|
249
533
|
}
|
|
250
534
|
|
|
251
|
-
const styles =
|
|
535
|
+
const styles = ScaledSheet.create({
|
|
252
536
|
container: {
|
|
253
537
|
flex: 1,
|
|
538
|
+
paddingVertical: '20@vs',
|
|
539
|
+
position: 'relative',
|
|
254
540
|
},
|
|
255
541
|
list: {
|
|
256
542
|
flex: 1,
|
|
257
543
|
},
|
|
258
544
|
contentContainer: {
|
|
259
|
-
|
|
260
|
-
|
|
545
|
+
paddingHorizontal: '10@s',
|
|
546
|
+
paddingVertical: '10@vs',
|
|
547
|
+
flexGrow: 1,
|
|
261
548
|
},
|
|
262
549
|
loadingItem: {
|
|
263
550
|
height: 200,
|
|
@@ -266,10 +553,11 @@ const styles = StyleSheet.create({
|
|
|
266
553
|
},
|
|
267
554
|
scrollDownButton: {
|
|
268
555
|
position: 'absolute',
|
|
269
|
-
right: 20,
|
|
556
|
+
right: '20@s',
|
|
270
557
|
bottom: '15%',
|
|
271
|
-
borderRadius: 25,
|
|
272
|
-
|
|
558
|
+
borderRadius: '25@s',
|
|
559
|
+
paddingHorizontal: '10@s',
|
|
560
|
+
paddingVertical: '10@vs',
|
|
273
561
|
shadowColor: '#000',
|
|
274
562
|
shadowOffset: {
|
|
275
563
|
width: 0,
|
|
@@ -280,23 +568,88 @@ const styles = StyleSheet.create({
|
|
|
280
568
|
elevation: 5,
|
|
281
569
|
},
|
|
282
570
|
scrollUpIcon: {
|
|
283
|
-
width: 24,
|
|
284
|
-
height: 24,
|
|
571
|
+
width: '24@s',
|
|
572
|
+
height: '24@vs',
|
|
285
573
|
},
|
|
286
574
|
retryContainer: {
|
|
287
575
|
flex: 1,
|
|
288
576
|
alignItems: 'center',
|
|
289
577
|
justifyContent: 'center',
|
|
290
|
-
|
|
578
|
+
paddingHorizontal: '20@s',
|
|
579
|
+
paddingVertical: '20@vs',
|
|
291
580
|
},
|
|
292
581
|
retryButton: {
|
|
293
582
|
padding: 15,
|
|
294
|
-
borderRadius: 8,
|
|
583
|
+
borderRadius: '8@s',
|
|
295
584
|
alignItems: 'center',
|
|
296
585
|
justifyContent: 'center',
|
|
297
586
|
},
|
|
298
587
|
retryText: {
|
|
299
|
-
fontSize: 16,
|
|
588
|
+
fontSize: '16@vs',
|
|
300
589
|
fontWeight: '500',
|
|
301
590
|
},
|
|
591
|
+
headphonesIcon: {
|
|
592
|
+
width: '24@s',
|
|
593
|
+
height: '24@vs',
|
|
594
|
+
},
|
|
595
|
+
header: {
|
|
596
|
+
fontSize: '16@vs',
|
|
597
|
+
textAlign: 'center',
|
|
598
|
+
fontWeight: 600,
|
|
599
|
+
},
|
|
600
|
+
liveChat: {
|
|
601
|
+
fontSize: '16@vs',
|
|
602
|
+
textAlign: 'center',
|
|
603
|
+
fontWeight: 400,
|
|
604
|
+
},
|
|
605
|
+
headerContainer: {
|
|
606
|
+
alignItems: 'center',
|
|
607
|
+
gap: 16,
|
|
608
|
+
borderBottomWidth: 1,
|
|
609
|
+
paddingBottom: '16@vs',
|
|
610
|
+
},
|
|
611
|
+
iconContainer: {
|
|
612
|
+
paddingHorizontal: '20@s',
|
|
613
|
+
paddingVertical: '20@vs',
|
|
614
|
+
position: 'absolute',
|
|
615
|
+
zIndex: 9999,
|
|
616
|
+
},
|
|
617
|
+
closeIcon: {
|
|
618
|
+
width: '24@s',
|
|
619
|
+
height: '24@vs',
|
|
620
|
+
},
|
|
621
|
+
dot: {
|
|
622
|
+
width: '10@s',
|
|
623
|
+
height: '10@vs',
|
|
624
|
+
borderRadius: '8@s',
|
|
625
|
+
},
|
|
626
|
+
headerText: { flexDirection: 'row', alignItems: 'center', gap: 4 },
|
|
627
|
+
sectionHeader: {
|
|
628
|
+
fontSize: '14@vs',
|
|
629
|
+
fontWeight: '400',
|
|
630
|
+
borderRadius: '8@s',
|
|
631
|
+
paddingHorizontal: '8@s',
|
|
632
|
+
paddingVertical: '4@vs',
|
|
633
|
+
alignSelf: 'center',
|
|
634
|
+
marginVertical: '8@vs',
|
|
635
|
+
},
|
|
636
|
+
fixedDateText: {
|
|
637
|
+
fontSize: '14@vs',
|
|
638
|
+
fontWeight: '500',
|
|
639
|
+
borderRadius: '8@s',
|
|
640
|
+
paddingHorizontal: '10@s',
|
|
641
|
+
paddingVertical: '4@s',
|
|
642
|
+
position: 'absolute',
|
|
643
|
+
top: '10@vs',
|
|
644
|
+
zIndex: 10,
|
|
645
|
+
alignSelf: 'center',
|
|
646
|
+
},
|
|
647
|
+
listContainer: {
|
|
648
|
+
flex: 1,
|
|
649
|
+
position: 'relative',
|
|
650
|
+
},
|
|
651
|
+
sectionHeaderContainer: {
|
|
652
|
+
alignItems: 'center',
|
|
653
|
+
marginVertical: '8@vs',
|
|
654
|
+
},
|
|
302
655
|
});
|