@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,21 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
StyleSheet,
|
|
3
|
-
TextInput,
|
|
4
|
-
View,
|
|
5
|
-
Image,
|
|
6
|
-
TouchableOpacity,
|
|
7
|
-
} from 'react-native';
|
|
1
|
+
import { TextInput, View, Image, TouchableOpacity } from 'react-native';
|
|
8
2
|
import { useAppStore } from '../store';
|
|
9
3
|
import { useState } from 'react';
|
|
10
4
|
import { sendCustomerMessage } from '../api';
|
|
11
5
|
import { useThemeColors } from '../hooks/useThemeColors';
|
|
6
|
+
import { ScaledSheet } from './ScaledSheet';
|
|
12
7
|
|
|
13
|
-
const sendDark = require('../assets/
|
|
8
|
+
const sendDark = require('../assets/arrow-right.png');
|
|
14
9
|
|
|
15
10
|
export function MessageInput({
|
|
16
11
|
scrollToBottom,
|
|
17
12
|
}: {
|
|
18
13
|
scrollToBottom: (animated: boolean) => void;
|
|
14
|
+
selectedMessage?: string;
|
|
19
15
|
}) {
|
|
20
16
|
const [value, setValue] = useState('');
|
|
21
17
|
const customer = useAppStore((s) => s.customer!);
|
|
@@ -39,34 +35,65 @@ export function MessageInput({
|
|
|
39
35
|
]);
|
|
40
36
|
sendCustomerMessage(customer.external_id, value, {
|
|
41
37
|
fake: useAppStore.getState().fake,
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
(
|
|
47
|
-
item
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
})
|
|
39
|
+
.then((res) => {
|
|
40
|
+
const data = useAppStore.getState().data;
|
|
41
|
+
if (data) {
|
|
42
|
+
const itemIndex = data.findIndex(
|
|
43
|
+
(item) =>
|
|
44
|
+
item.id === null &&
|
|
45
|
+
new Date(item.created_at).getTime() === date.getTime()
|
|
46
|
+
);
|
|
47
|
+
if (itemIndex === -1) {
|
|
48
|
+
//TODO:??
|
|
49
|
+
} else {
|
|
50
|
+
const alteredData = [...data];
|
|
51
|
+
alteredData[itemIndex] = {
|
|
52
|
+
id: res.message.id,
|
|
53
|
+
content: res.message.content,
|
|
54
|
+
user: res.message.user ?? alteredData[itemIndex]?.user,
|
|
55
|
+
created_at: new Date(res.message.created_at),
|
|
56
|
+
approved: true,
|
|
57
|
+
};
|
|
58
|
+
useAppStore.setState({
|
|
59
|
+
data: alteredData,
|
|
60
|
+
});
|
|
61
|
+
scrollToBottom(false);
|
|
62
|
+
}
|
|
52
63
|
} else {
|
|
53
|
-
|
|
54
|
-
alteredData[itemIndex] = {
|
|
55
|
-
id: res.message.id,
|
|
56
|
-
content: res.message.content,
|
|
57
|
-
user: res.message.user ?? alteredData[itemIndex]?.user,
|
|
58
|
-
created_at: new Date(res.message.created_at),
|
|
59
|
-
approved: true,
|
|
60
|
-
};
|
|
61
|
-
useAppStore.setState({
|
|
62
|
-
data: alteredData,
|
|
63
|
-
});
|
|
64
|
-
scrollToBottom(false);
|
|
64
|
+
//TODO: ??
|
|
65
65
|
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
})
|
|
67
|
+
.catch(() => {
|
|
68
|
+
const data = useAppStore.getState().data;
|
|
69
|
+
if (data) {
|
|
70
|
+
const itemIndex = data.findIndex(
|
|
71
|
+
(item) =>
|
|
72
|
+
item.id === null &&
|
|
73
|
+
new Date(item.created_at).getTime() === date.getTime()
|
|
74
|
+
);
|
|
75
|
+
if (itemIndex === -1) {
|
|
76
|
+
//TODO:??
|
|
77
|
+
} else {
|
|
78
|
+
const alteredData = [...data];
|
|
79
|
+
alteredData[itemIndex] = {
|
|
80
|
+
...alteredData[itemIndex],
|
|
81
|
+
id: alteredData[itemIndex]?.id ?? null,
|
|
82
|
+
content: alteredData[itemIndex]?.content ?? '',
|
|
83
|
+
created_at: alteredData[itemIndex]?.created_at ?? new Date(),
|
|
84
|
+
approved: alteredData[itemIndex]?.approved ?? false,
|
|
85
|
+
user: alteredData[itemIndex]?.user ?? null,
|
|
86
|
+
error: true,
|
|
87
|
+
};
|
|
88
|
+
useAppStore.setState({
|
|
89
|
+
data: alteredData,
|
|
90
|
+
});
|
|
91
|
+
scrollToBottom(false);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
//TODO: ??
|
|
95
|
+
}
|
|
96
|
+
});
|
|
70
97
|
setValue('');
|
|
71
98
|
}
|
|
72
99
|
};
|
|
@@ -80,6 +107,8 @@ export function MessageInput({
|
|
|
80
107
|
onChangeText={(newValue) => setValue(newValue)}
|
|
81
108
|
onSubmitEditing={sendMessage}
|
|
82
109
|
returnKeyType="send"
|
|
110
|
+
multiline={true}
|
|
111
|
+
maxLength={1000}
|
|
83
112
|
style={[
|
|
84
113
|
styles.textInput,
|
|
85
114
|
{
|
|
@@ -92,11 +121,14 @@ export function MessageInput({
|
|
|
92
121
|
placeholderTextColor={themeColors.text + '80'}
|
|
93
122
|
/>
|
|
94
123
|
<TouchableOpacity
|
|
95
|
-
style={[
|
|
124
|
+
style={[
|
|
125
|
+
styles.sendButton,
|
|
126
|
+
{ backgroundColor: themeColors.dark_background },
|
|
127
|
+
]}
|
|
96
128
|
onPress={sendMessage}
|
|
97
129
|
>
|
|
98
130
|
<Image
|
|
99
|
-
style={[styles.sendIcon, { tintColor: themeColors.
|
|
131
|
+
style={[styles.sendIcon, { tintColor: themeColors.light_text }]}
|
|
100
132
|
source={sendDark}
|
|
101
133
|
/>
|
|
102
134
|
</TouchableOpacity>
|
|
@@ -104,30 +136,35 @@ export function MessageInput({
|
|
|
104
136
|
);
|
|
105
137
|
}
|
|
106
138
|
|
|
107
|
-
const styles =
|
|
139
|
+
const styles = ScaledSheet.create({
|
|
108
140
|
container: {
|
|
109
141
|
flexDirection: 'row',
|
|
110
|
-
|
|
111
|
-
|
|
142
|
+
paddingHorizontal: '10@s',
|
|
143
|
+
paddingVertical: '10@vs',
|
|
144
|
+
alignItems: 'center',
|
|
145
|
+
position: 'relative',
|
|
146
|
+
zIndex: 1,
|
|
112
147
|
},
|
|
113
148
|
textInput: {
|
|
114
149
|
flex: 1,
|
|
115
150
|
borderWidth: 1,
|
|
116
|
-
borderRadius: 20,
|
|
117
|
-
paddingHorizontal: 15,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
151
|
+
borderRadius: '20@s',
|
|
152
|
+
paddingHorizontal: '15@s',
|
|
153
|
+
marginRight: '10@s',
|
|
154
|
+
fontSize: '16@vs',
|
|
155
|
+
paddingVertical: '10@vs',
|
|
156
|
+
minHeight: 40,
|
|
157
|
+
maxHeight: 190,
|
|
121
158
|
},
|
|
122
159
|
sendButton: {
|
|
123
|
-
width: 40,
|
|
124
|
-
height: 40,
|
|
125
|
-
borderRadius: 20,
|
|
160
|
+
width: '40@s',
|
|
161
|
+
height: '40@vs',
|
|
162
|
+
borderRadius: '20@vs',
|
|
126
163
|
justifyContent: 'center',
|
|
127
164
|
alignItems: 'center',
|
|
128
165
|
},
|
|
129
166
|
sendIcon: {
|
|
130
|
-
width: 20,
|
|
131
|
-
height: 20,
|
|
167
|
+
width: '20@vs',
|
|
168
|
+
height: '20@vs',
|
|
132
169
|
},
|
|
133
170
|
});
|
|
@@ -1,13 +1,34 @@
|
|
|
1
|
-
import { View, Image } from 'react-native';
|
|
1
|
+
import { View, Image, TouchableOpacity } from 'react-native';
|
|
2
2
|
import { AppText } from './AppText';
|
|
3
3
|
import type { AppConversationMessage } from '../types/Conversation';
|
|
4
|
-
import { StyleSheet } from 'react-native';
|
|
5
4
|
import { useThemeColors } from '../hooks/useThemeColors';
|
|
5
|
+
import { useState, useRef, useEffect } from 'react';
|
|
6
|
+
import { ScaledSheet } from './ScaledSheet';
|
|
6
7
|
|
|
7
|
-
const clockIcon = require('../assets/
|
|
8
|
-
const
|
|
8
|
+
const clockIcon = require('../assets/iconamoon_clock-fill.png');
|
|
9
|
+
const infoIcon = require('../assets/info-circle.png');
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
interface TextLine {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
text: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface MessageLayout {
|
|
20
|
+
lines: number;
|
|
21
|
+
lastLineWidth: number;
|
|
22
|
+
totalWidth: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function MessageItem({
|
|
26
|
+
item,
|
|
27
|
+
onShowPopup,
|
|
28
|
+
}: {
|
|
29
|
+
item: AppConversationMessage;
|
|
30
|
+
onShowPopup: () => void;
|
|
31
|
+
}) {
|
|
11
32
|
const themeColors = useThemeColors();
|
|
12
33
|
const isDeviceOwner = !!item.user;
|
|
13
34
|
const formattedDate = new Date(item.created_at).toLocaleTimeString([], {
|
|
@@ -15,73 +36,144 @@ export function MessageItem({ item }: { item: AppConversationMessage }) {
|
|
|
15
36
|
minute: '2-digit',
|
|
16
37
|
});
|
|
17
38
|
|
|
39
|
+
const layoutRef = useRef<MessageLayout>({
|
|
40
|
+
lines: 0,
|
|
41
|
+
lastLineWidth: 0,
|
|
42
|
+
totalWidth: 0,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const [layoutComplete, setLayoutComplete] = useState(false);
|
|
46
|
+
|
|
47
|
+
const renderFooterContent = () => {
|
|
48
|
+
if (isDeviceOwner && item.error) {
|
|
49
|
+
return <Image source={infoIcon} style={styles.infoIcon} />;
|
|
50
|
+
} else if (isDeviceOwner && !item.error && !item.approved) {
|
|
51
|
+
return <Image source={clockIcon} style={styles.clockIcon} />;
|
|
52
|
+
} else {
|
|
53
|
+
return (
|
|
54
|
+
<AppText
|
|
55
|
+
style={[
|
|
56
|
+
styles.timestamp,
|
|
57
|
+
isDeviceOwner
|
|
58
|
+
? styles.rightTimestamp
|
|
59
|
+
: [styles.leftTimestamp, { color: themeColors.text }],
|
|
60
|
+
]}
|
|
61
|
+
>
|
|
62
|
+
{formattedDate}
|
|
63
|
+
</AppText>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const onTextLayout = (event: any) => {
|
|
69
|
+
const { lines } = event.nativeEvent;
|
|
70
|
+
|
|
71
|
+
const numLines = lines.length;
|
|
72
|
+
let lastLineWidth = 0;
|
|
73
|
+
let totalWidth = 0;
|
|
74
|
+
|
|
75
|
+
if (numLines >= 1) {
|
|
76
|
+
// Get the width of the last line
|
|
77
|
+
lastLineWidth = lines[numLines - 1].width;
|
|
78
|
+
// Use the widest line as the total width
|
|
79
|
+
totalWidth = Math.max(...lines.map((line: TextLine) => line.width));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
layoutRef.current = {
|
|
83
|
+
lines: numLines,
|
|
84
|
+
lastLineWidth,
|
|
85
|
+
totalWidth,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
if (!layoutComplete) {
|
|
89
|
+
setLayoutComplete(true);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
setLayoutComplete(false);
|
|
95
|
+
}, [item.content]);
|
|
96
|
+
|
|
97
|
+
// Check if there's enough space for the timestamp
|
|
98
|
+
const hasSpaceInLastLine =
|
|
99
|
+
layoutRef.current.lines >= 1 &&
|
|
100
|
+
layoutRef.current.lastLineWidth < layoutRef.current.totalWidth * 0.8;
|
|
101
|
+
|
|
102
|
+
// A single line message with enough space for the timestamp
|
|
103
|
+
const isSingleLineWithSpace =
|
|
104
|
+
layoutRef.current.lines === 1 &&
|
|
105
|
+
layoutRef.current.lastLineWidth < layoutRef.current.totalWidth * 0.8;
|
|
106
|
+
|
|
107
|
+
// For multi-line messages, check if the last line has space
|
|
108
|
+
const isMultiLineWithSpace =
|
|
109
|
+
layoutRef.current.lines > 1 && hasSpaceInLastLine;
|
|
110
|
+
|
|
111
|
+
const shouldShowInlineFooter = isSingleLineWithSpace || isMultiLineWithSpace;
|
|
112
|
+
|
|
18
113
|
return (
|
|
19
|
-
<
|
|
114
|
+
<TouchableOpacity
|
|
20
115
|
key={item.id}
|
|
21
116
|
style={[
|
|
22
117
|
styles.messageItem,
|
|
23
118
|
isDeviceOwner ? styles.rightMessage : styles.leftMessage,
|
|
24
119
|
]}
|
|
120
|
+
activeOpacity={isDeviceOwner && item.error ? 0.8 : 1}
|
|
121
|
+
onPress={() => {
|
|
122
|
+
isDeviceOwner && item.error ? onShowPopup() : {};
|
|
123
|
+
}}
|
|
25
124
|
>
|
|
26
125
|
<View
|
|
27
126
|
style={[
|
|
28
127
|
styles.messageBubble,
|
|
29
128
|
isDeviceOwner
|
|
30
|
-
? [styles.rightBubble, { backgroundColor: themeColors.
|
|
31
|
-
: [styles.leftBubble, { backgroundColor: themeColors.
|
|
129
|
+
? [styles.rightBubble, { backgroundColor: themeColors.light_green }]
|
|
130
|
+
: [styles.leftBubble, { backgroundColor: themeColors.ghost }],
|
|
32
131
|
]}
|
|
33
132
|
>
|
|
34
|
-
<
|
|
35
|
-
style={
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
]}
|
|
133
|
+
<View
|
|
134
|
+
style={
|
|
135
|
+
shouldShowInlineFooter
|
|
136
|
+
? styles.inlineContainer
|
|
137
|
+
: styles.multiLineContainer
|
|
138
|
+
}
|
|
41
139
|
>
|
|
42
|
-
{item.content}
|
|
43
|
-
</AppText>
|
|
44
|
-
<View style={styles.footer}>
|
|
45
140
|
<AppText
|
|
46
141
|
style={[
|
|
47
|
-
styles.
|
|
142
|
+
styles.messageText,
|
|
48
143
|
isDeviceOwner
|
|
49
|
-
? styles.
|
|
50
|
-
: [styles.
|
|
144
|
+
? styles.rightMessageText
|
|
145
|
+
: [styles.leftMessageText, { color: themeColors.text }],
|
|
51
146
|
]}
|
|
147
|
+
onTextLayout={onTextLayout}
|
|
52
148
|
>
|
|
53
|
-
{
|
|
149
|
+
{item.content}
|
|
54
150
|
</AppText>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
style={[
|
|
59
|
-
styles.clockIcon,
|
|
60
|
-
isDeviceOwner
|
|
61
|
-
? styles.rightClockIcon
|
|
62
|
-
: [styles.leftClockIcon, { tintColor: themeColors.text }],
|
|
63
|
-
]}
|
|
64
|
-
/>
|
|
65
|
-
) : (
|
|
66
|
-
<Image
|
|
67
|
-
source={doubleCheckIcon}
|
|
151
|
+
|
|
152
|
+
{shouldShowInlineFooter && (
|
|
153
|
+
<View
|
|
68
154
|
style={[
|
|
69
|
-
styles.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
155
|
+
styles.inlineFooter,
|
|
156
|
+
layoutRef.current.lines > 1 &&
|
|
157
|
+
hasSpaceInLastLine &&
|
|
158
|
+
styles.lastLineFooter,
|
|
73
159
|
]}
|
|
74
|
-
|
|
160
|
+
>
|
|
161
|
+
{renderFooterContent()}
|
|
162
|
+
</View>
|
|
75
163
|
)}
|
|
76
164
|
</View>
|
|
165
|
+
|
|
166
|
+
{!shouldShowInlineFooter && (
|
|
167
|
+
<View style={styles.footer}>{renderFooterContent()}</View>
|
|
168
|
+
)}
|
|
77
169
|
</View>
|
|
78
|
-
</
|
|
170
|
+
</TouchableOpacity>
|
|
79
171
|
);
|
|
80
172
|
}
|
|
81
173
|
|
|
82
|
-
const styles =
|
|
174
|
+
const styles = ScaledSheet.create({
|
|
83
175
|
messageItem: {
|
|
84
|
-
marginVertical: 5,
|
|
176
|
+
marginVertical: '5@vs',
|
|
85
177
|
maxWidth: '80%',
|
|
86
178
|
minHeight: 60,
|
|
87
179
|
minWidth: 100,
|
|
@@ -93,8 +185,9 @@ const styles = StyleSheet.create({
|
|
|
93
185
|
alignSelf: 'flex-end',
|
|
94
186
|
},
|
|
95
187
|
messageBubble: {
|
|
96
|
-
|
|
97
|
-
|
|
188
|
+
paddingVertical: '12@vs',
|
|
189
|
+
paddingHorizontal: '12@s',
|
|
190
|
+
borderRadius: '20@vs',
|
|
98
191
|
},
|
|
99
192
|
leftBubble: {
|
|
100
193
|
borderTopLeftRadius: 4,
|
|
@@ -102,40 +195,70 @@ const styles = StyleSheet.create({
|
|
|
102
195
|
rightBubble: {
|
|
103
196
|
borderTopRightRadius: 4,
|
|
104
197
|
},
|
|
198
|
+
inlineContainer: {
|
|
199
|
+
flexDirection: 'row',
|
|
200
|
+
justifyContent: 'space-between',
|
|
201
|
+
alignItems: 'center',
|
|
202
|
+
},
|
|
203
|
+
multiLineContainer: {
|
|
204
|
+
flexDirection: 'column',
|
|
205
|
+
},
|
|
105
206
|
messageText: {
|
|
106
|
-
fontSize: 16,
|
|
207
|
+
fontSize: '16@vs',
|
|
208
|
+
flexShrink: 1,
|
|
107
209
|
},
|
|
108
210
|
leftMessageText: {
|
|
109
211
|
color: '#000000',
|
|
110
212
|
},
|
|
111
213
|
rightMessageText: {
|
|
112
|
-
color: '#
|
|
214
|
+
color: '#000000',
|
|
113
215
|
},
|
|
114
216
|
footer: {
|
|
115
217
|
flexDirection: 'row',
|
|
116
|
-
justifyContent: '
|
|
218
|
+
justifyContent: 'flex-end',
|
|
117
219
|
alignItems: 'center',
|
|
118
|
-
marginTop: 4,
|
|
220
|
+
marginTop: '4@vs',
|
|
221
|
+
},
|
|
222
|
+
inlineFooter: {
|
|
223
|
+
flexDirection: 'row',
|
|
224
|
+
alignItems: 'center',
|
|
225
|
+
marginLeft: '8@s',
|
|
226
|
+
},
|
|
227
|
+
secondLineFooter: {
|
|
228
|
+
position: 'absolute',
|
|
229
|
+
bottom: 0,
|
|
230
|
+
right: 0,
|
|
231
|
+
backgroundColor: 'transparent',
|
|
232
|
+
},
|
|
233
|
+
lastLineFooter: {
|
|
234
|
+
position: 'absolute',
|
|
235
|
+
bottom: 0,
|
|
236
|
+
right: 0,
|
|
237
|
+
backgroundColor: 'transparent',
|
|
119
238
|
},
|
|
120
239
|
timestamp: {
|
|
121
|
-
fontSize:
|
|
240
|
+
fontSize: '10@vs',
|
|
122
241
|
opacity: 0.7,
|
|
123
242
|
},
|
|
124
243
|
leftTimestamp: {
|
|
125
244
|
color: '#666666',
|
|
126
245
|
},
|
|
127
246
|
rightTimestamp: {
|
|
128
|
-
color: '#
|
|
247
|
+
color: '#000000',
|
|
129
248
|
},
|
|
130
249
|
clockIcon: {
|
|
131
|
-
width: 12,
|
|
132
|
-
height: 12,
|
|
133
|
-
marginLeft: 4,
|
|
250
|
+
width: '12@vs',
|
|
251
|
+
height: '12@vs',
|
|
252
|
+
marginLeft: '4@s',
|
|
253
|
+
tintColor: '#000000',
|
|
134
254
|
},
|
|
135
|
-
|
|
136
|
-
|
|
255
|
+
infoIcon: {
|
|
256
|
+
width: '12@vs',
|
|
257
|
+
height: '12@vs',
|
|
258
|
+
marginLeft: '4@s',
|
|
137
259
|
},
|
|
138
|
-
|
|
139
|
-
|
|
260
|
+
iconContainer: {
|
|
261
|
+
paddingVertical: '5@vs',
|
|
262
|
+
paddingHorizontal: '5@vs',
|
|
140
263
|
},
|
|
141
264
|
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ImageStyle,
|
|
3
|
+
StyleSheet,
|
|
4
|
+
type TextStyle,
|
|
5
|
+
type ViewStyle,
|
|
6
|
+
} from 'react-native';
|
|
7
|
+
import deepMap from '../utils/deepMap';
|
|
8
|
+
import { s, vs, ms, mvs } from '../utils/scalingUtils';
|
|
9
|
+
const validScaleSheetRegex =
|
|
10
|
+
/^(-?\d+(?:\.\d{1,3})?)@(mv?s(\d+(?:\.\d{1,2})?)?|s|vs)r?$/;
|
|
11
|
+
|
|
12
|
+
type NamedStyles<T> = { [P in keyof T]: ViewStyle | TextStyle | ImageStyle };
|
|
13
|
+
|
|
14
|
+
const scaleByAnnotation =
|
|
15
|
+
(
|
|
16
|
+
scale: (size: number) => number,
|
|
17
|
+
verticalScale: (size: number) => number,
|
|
18
|
+
moderateScale: (size: number, factor?: number) => number,
|
|
19
|
+
moderateVerticalScale: (size: number, factor?: number) => number
|
|
20
|
+
) =>
|
|
21
|
+
(value: string | number): string | number => {
|
|
22
|
+
if (typeof value !== 'string' || !validScaleSheetRegex.test(value)) {
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Type assertion for regex result
|
|
27
|
+
const regexExecResult = validScaleSheetRegex.exec(value);
|
|
28
|
+
if (!regexExecResult) {
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Safely extract matched groups
|
|
33
|
+
const sizeStr = regexExecResult[1] || '0';
|
|
34
|
+
const size = parseFloat(sizeStr);
|
|
35
|
+
const scaleFunc = regexExecResult[2] || '';
|
|
36
|
+
|
|
37
|
+
// Extract scale factor if present
|
|
38
|
+
let scaleFactor: number | undefined;
|
|
39
|
+
let scaleFuncName = scaleFunc;
|
|
40
|
+
|
|
41
|
+
// Handle ms and mvs cases which may have a factor
|
|
42
|
+
if (scaleFunc.startsWith('ms') || scaleFunc.startsWith('mvs')) {
|
|
43
|
+
const matchResult = /^(ms|mvs)(\d+(?:\.\d{1,2})?)$/.exec(scaleFunc);
|
|
44
|
+
if (matchResult && matchResult[1] && matchResult[2]) {
|
|
45
|
+
scaleFuncName = matchResult[1];
|
|
46
|
+
scaleFactor = parseFloat(matchResult[2]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const shouldRound = value.endsWith('r');
|
|
51
|
+
|
|
52
|
+
let result: number;
|
|
53
|
+
|
|
54
|
+
switch (scaleFuncName) {
|
|
55
|
+
case 's':
|
|
56
|
+
result = scale(size);
|
|
57
|
+
break;
|
|
58
|
+
case 'vs':
|
|
59
|
+
result = verticalScale(size);
|
|
60
|
+
break;
|
|
61
|
+
case 'ms':
|
|
62
|
+
result = moderateScale(size, scaleFactor);
|
|
63
|
+
break;
|
|
64
|
+
case 'mvs':
|
|
65
|
+
result = moderateVerticalScale(size, scaleFactor);
|
|
66
|
+
break;
|
|
67
|
+
default:
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return shouldRound ? Math.round(result) : result;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
type ScaledSheetType = any;
|
|
75
|
+
|
|
76
|
+
const scaledSheetCreator = (
|
|
77
|
+
scale: (size: number) => number,
|
|
78
|
+
verticalScale: (size: number) => number,
|
|
79
|
+
moderateScale: (size: number, factor?: number) => number,
|
|
80
|
+
moderateVerticalScale: (size: number, factor?: number) => number
|
|
81
|
+
): ScaledSheetType => {
|
|
82
|
+
const scaleFunc = scaleByAnnotation(
|
|
83
|
+
scale,
|
|
84
|
+
verticalScale,
|
|
85
|
+
moderateScale,
|
|
86
|
+
moderateVerticalScale
|
|
87
|
+
);
|
|
88
|
+
return {
|
|
89
|
+
create: (styleSheet: NamedStyles<any>) =>
|
|
90
|
+
StyleSheet.create(deepMap(styleSheet, scaleFunc) as NamedStyles<any>),
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
export const ScaledSheet = scaledSheetCreator(s, vs, ms, mvs);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useAppStore } from '../store';
|
|
3
|
+
|
|
4
|
+
interface ISizeMatter {
|
|
5
|
+
baseWidth: number;
|
|
6
|
+
baseHeight: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function SizeMatter({ baseWidth = 390, baseHeight = 844 }: ISizeMatter) {
|
|
10
|
+
const { updateBaseDimensions } = useAppStore((s) => ({
|
|
11
|
+
updateBaseDimensions: s.updateBaseDimensions,
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
updateBaseDimensions({
|
|
16
|
+
baseWidth,
|
|
17
|
+
baseHeight,
|
|
18
|
+
});
|
|
19
|
+
}, [baseHeight, baseWidth, updateBaseDimensions]);
|
|
20
|
+
|
|
21
|
+
return <></>;
|
|
22
|
+
}
|
package/src/index.tsx
CHANGED
package/src/store.ts
CHANGED
|
@@ -8,6 +8,8 @@ import type { AppConversationMessage } from './types/Conversation';
|
|
|
8
8
|
import type { LanguageCode } from './types/Language';
|
|
9
9
|
|
|
10
10
|
interface AppStoreState {
|
|
11
|
+
baseHeight: number;
|
|
12
|
+
baseWidth: number;
|
|
11
13
|
initialized: boolean;
|
|
12
14
|
customer: Customer | null;
|
|
13
15
|
data: AppConversationMessage[] | null;
|
|
@@ -27,9 +29,15 @@ interface AppStoreState {
|
|
|
27
29
|
setLanguage: (language: LanguageCode) => void;
|
|
28
30
|
setTheme: (theme: 'light' | 'dark') => void;
|
|
29
31
|
setFake: (fake: boolean) => void;
|
|
32
|
+
updateBaseDimensions: (config: {
|
|
33
|
+
baseHeight: number;
|
|
34
|
+
baseWidth: number;
|
|
35
|
+
}) => void;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
const storeCreator: StateCreator<AppStoreState> = (set, get) => ({
|
|
39
|
+
baseWidth: 390,
|
|
40
|
+
baseHeight: 844,
|
|
33
41
|
initialized: false,
|
|
34
42
|
customer: null,
|
|
35
43
|
data: null,
|
|
@@ -60,6 +68,9 @@ const storeCreator: StateCreator<AppStoreState> = (set, get) => ({
|
|
|
60
68
|
setFake: (fake: boolean) => {
|
|
61
69
|
set({ fake });
|
|
62
70
|
},
|
|
71
|
+
updateBaseDimensions: ({ baseWidth, baseHeight }) => {
|
|
72
|
+
set({ baseWidth, baseHeight });
|
|
73
|
+
},
|
|
63
74
|
});
|
|
64
75
|
|
|
65
76
|
export const useAppStore = createWithEqualityFn<AppStoreState>()(
|
|
@@ -70,15 +81,14 @@ export const useAppStore = createWithEqualityFn<AppStoreState>()(
|
|
|
70
81
|
partialize: (state) => ({
|
|
71
82
|
customer: state.customer,
|
|
72
83
|
externalId: state.externalId,
|
|
73
|
-
data:
|
|
74
|
-
/* data: state.data
|
|
84
|
+
data: state.data
|
|
75
85
|
?.filter((message) => message.approved)
|
|
76
86
|
.map((message) => ({
|
|
77
87
|
...message,
|
|
78
88
|
created_at: message.created_at
|
|
79
89
|
? new Date(message.created_at)
|
|
80
90
|
: undefined,
|
|
81
|
-
}))
|
|
91
|
+
})),
|
|
82
92
|
}),
|
|
83
93
|
}),
|
|
84
94
|
shallow
|