@eohjsc/react-native-smart-city 0.7.27 → 0.7.31
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/index.js +2 -0
- package/package.json +2 -1
- package/src/commons/Dashboard/MyDashboardDevice/__test__/index.test.js +68 -0
- package/src/commons/Dashboard/MyDashboardDevice/index.js +46 -11
- package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +43 -11
- package/src/commons/Dashboard/MyUnit/index.js +40 -32
- package/src/commons/ModalAlert/index.js +51 -0
- package/src/commons/ModalAlert/styles.js +54 -0
- package/src/commons/SubUnit/ShortDetail.js +20 -4
- package/src/commons/SubUnit/__test__/ShortDetail.test.js +46 -1
- package/src/configs/API.js +8 -0
- package/src/configs/AccessibilityLabel.js +3 -0
- package/src/configs/Constants.js +7 -0
- package/src/configs/SCConfig.js +6 -0
- package/src/context/SCContext.tsx +12 -1
- package/src/context/SCStore.ts +14 -0
- package/src/context/actionType.ts +10 -0
- package/src/context/mockStore.ts +30 -1
- package/src/context/reducer.ts +35 -0
- package/src/hooks/IoT/useRemoteControl.js +4 -1
- package/src/hooks/IoT/useWatchSharedChips.js +130 -0
- package/src/hooks/Review/__test__/useInAppReview.test.js +99 -0
- package/src/hooks/Review/useInAppReview.js +70 -0
- package/src/hooks/useMqtt.js +78 -27
- package/src/iot/Monitor.js +149 -26
- package/src/iot/UpdateStates.js +60 -0
- package/src/iot/mqtt.js +177 -22
- package/src/navigations/UnitStack.js +16 -0
- package/src/screens/ActivityLog/ItemLog.js +1 -0
- package/src/screens/AddNewGateway/RenameNewDevices.js +5 -0
- package/src/screens/AddNewGateway/__test__/RenameNewDevices.test.js +18 -0
- package/src/screens/Automate/AddNewAction/ReceiverSelect.js +210 -0
- package/src/screens/Automate/AddNewAction/SetupScriptEmail.js +1 -1
- package/src/screens/Automate/AddNewAction/SetupScriptNotify.js +18 -28
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +22 -129
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverNotify.js +59 -0
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverSms.js +22 -129
- package/src/screens/Automate/AddNewAction/SetupScriptSms.js +1 -1
- package/src/screens/Automate/AddNewAction/Styles/{SetupScriptReceiverEmailStyles.js → ReceiverSelectStyles.js} +18 -1
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptNotify.test.js +16 -33
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverEmail.test.js +10 -8
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverNotify.test.js +217 -0
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverSms.test.js +10 -8
- package/src/screens/Automate/Components/InputName.js +5 -1
- package/src/screens/Automate/EditActionsList/UpdateReceiverEmailScript.js +4 -3
- package/src/screens/Automate/EditActionsList/UpdateReceiverSmsScript.js +5 -4
- package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +18 -0
- package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +1 -1
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +116 -2
- package/src/screens/Automate/ScriptDetail/index.js +47 -9
- package/src/screens/CreatePassword/__test__/index.test.js +133 -0
- package/src/screens/CreatePassword/index.js +134 -0
- package/src/screens/CreatePassword/styles.js +45 -0
- package/src/screens/Device/__test__/DeviceDetail-3rdparty.test.js +447 -0
- package/src/screens/Device/__test__/DeviceDetail-arduino.test.js +344 -0
- package/src/screens/Device/__test__/{mqttDetail.test.js → DeviceDetail-modbus.test.js} +287 -320
- package/src/screens/Device/__test__/DeviceDetail-zigbee.test.js +451 -0
- package/src/screens/Device/__test__/DeviceDetail.test.js +502 -0
- package/src/screens/Device/__test__/detail.test.js +61 -3
- package/src/screens/Device/__test__/sensorDisplayItem.test.js +28 -3
- package/src/screens/Device/detail.js +14 -6
- package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +3 -2
- package/src/screens/EnterPassword/__test__/EnterPassword.test.js +76 -1
- package/src/screens/EnterPassword/index.js +34 -4
- package/src/screens/EnterPassword/styles.js +1 -1
- package/src/utils/FactoryGateway.js +597 -0
- package/src/utils/I18n/translations/en.js +11 -0
- package/src/utils/I18n/translations/vi.js +11 -0
- package/src/utils/Route/index.js +3 -1
- package/src/utils/Validation.js +5 -0
- package/src/utils/store.js +5 -0
|
@@ -8,53 +8,43 @@ import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
|
8
8
|
import _TextInput from '../../../commons/Form/TextInput';
|
|
9
9
|
import AccessibilityLabel from '../../../configs/AccessibilityLabel';
|
|
10
10
|
import BottomButtonView from '../../../commons/BottomButtonView';
|
|
11
|
-
import { axiosPost } from '../../../utils/Apis/axios';
|
|
12
|
-
import { API } from '../../../configs';
|
|
13
|
-
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
14
11
|
import Routes from '../../../utils/Route';
|
|
15
|
-
import moment from 'moment';
|
|
16
12
|
|
|
17
13
|
const SetupScriptNotify = ({ route }) => {
|
|
18
14
|
const t = useTranslations();
|
|
19
15
|
const { goBack, navigate } = useNavigation();
|
|
20
|
-
const { automate
|
|
21
|
-
const
|
|
22
|
-
|
|
16
|
+
const { automate, unitId, multiUnit } = route.params || {};
|
|
17
|
+
const initialUnitId = useMemo(
|
|
18
|
+
() => unitId || multiUnit.id,
|
|
19
|
+
[unitId, multiUnit?.id]
|
|
20
|
+
);
|
|
21
|
+
const [formData, setFormData] = useState({ unit: initialUnitId });
|
|
23
22
|
|
|
24
23
|
const onChangeTitle = (value) => {
|
|
25
|
-
|
|
24
|
+
setFormData((state) => ({
|
|
26
25
|
...state,
|
|
27
26
|
title: value,
|
|
28
27
|
}));
|
|
29
28
|
};
|
|
30
29
|
const onChangeMessage = (value) => {
|
|
31
|
-
|
|
30
|
+
setFormData((state) => ({
|
|
32
31
|
...state,
|
|
33
32
|
message: value,
|
|
34
33
|
}));
|
|
35
34
|
};
|
|
36
35
|
|
|
37
36
|
const onNext = useCallback(async () => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
navigate({
|
|
45
|
-
name: Routes.ScriptDetail,
|
|
46
|
-
merge: true,
|
|
47
|
-
params: { saveAt: moment().valueOf() },
|
|
48
|
-
});
|
|
49
|
-
} else {
|
|
50
|
-
ToastBottomHelper.error(t('error_please_try_later'));
|
|
51
|
-
}
|
|
52
|
-
}, [automateId, navigate, notify, t]);
|
|
37
|
+
navigate(Routes.SetupScriptReceiverNotify, {
|
|
38
|
+
automate,
|
|
39
|
+
unitId: initialUnitId,
|
|
40
|
+
formData,
|
|
41
|
+
});
|
|
42
|
+
}, [navigate, automate, initialUnitId, formData]);
|
|
53
43
|
|
|
54
44
|
const canSave = useMemo(() => {
|
|
55
|
-
const { title, message } =
|
|
45
|
+
const { title, message } = formData;
|
|
56
46
|
return !!title && !!message;
|
|
57
|
-
}, [
|
|
47
|
+
}, [formData]);
|
|
58
48
|
|
|
59
49
|
return (
|
|
60
50
|
<View style={styles.wrap}>
|
|
@@ -65,7 +55,7 @@ const SetupScriptNotify = ({ route }) => {
|
|
|
65
55
|
placeholder={t('title_notification')}
|
|
66
56
|
onChange={onChangeTitle}
|
|
67
57
|
textInputStyle={styles.textTitle}
|
|
68
|
-
value={
|
|
58
|
+
value={formData.title}
|
|
69
59
|
accessibilityLabel={AccessibilityLabel.AUTOMATE_TITLE_NOTIFY}
|
|
70
60
|
autoFocus
|
|
71
61
|
/>
|
|
@@ -73,7 +63,7 @@ const SetupScriptNotify = ({ route }) => {
|
|
|
73
63
|
placeholder={t('message_notification')}
|
|
74
64
|
onChange={onChangeMessage}
|
|
75
65
|
textInputStyle={styles.textMessage}
|
|
76
|
-
value={
|
|
66
|
+
value={formData.message}
|
|
77
67
|
accessibilityLabel={AccessibilityLabel.AUTOMATE_MESSAGE_NOTIFY}
|
|
78
68
|
multiline={true}
|
|
79
69
|
maxLength={255}
|
|
@@ -1,41 +1,20 @@
|
|
|
1
|
-
import React, { useCallback,
|
|
2
|
-
import { FlatList, View } from 'react-native';
|
|
1
|
+
import React, { useCallback, useState } from 'react';
|
|
3
2
|
import { useNavigation } from '@react-navigation/native';
|
|
4
|
-
import styles from './Styles/SetupScriptReceiverEmailStyles';
|
|
5
|
-
import { CircleView, HeaderCustom, Text } from '../../../commons';
|
|
6
3
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
7
4
|
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import { API, Colors } from '../../../configs';
|
|
5
|
+
import { axiosPost } from '../../../utils/Apis/axios';
|
|
6
|
+
import { API } from '../../../configs';
|
|
11
7
|
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
12
8
|
import Routes from '../../../utils/Route';
|
|
9
|
+
import ReceiverSelect from './ReceiverSelect';
|
|
13
10
|
import moment from 'moment';
|
|
14
|
-
import CheckBox from '@react-native-community/checkbox';
|
|
15
|
-
import { useSCContextSelector } from '../../../context';
|
|
16
|
-
import { Image } from 'react-native';
|
|
17
11
|
|
|
18
12
|
const SetupScriptReceiverEmail = ({ route }) => {
|
|
19
13
|
const t = useTranslations();
|
|
20
|
-
const {
|
|
21
|
-
const { automate = {}, unitId, formData } = route.params
|
|
14
|
+
const { navigate } = useNavigation();
|
|
15
|
+
const { automate = {}, unitId, formData } = route.params;
|
|
22
16
|
const { id: automateId } = automate;
|
|
23
|
-
const [members, setMembers] = useState([]);
|
|
24
17
|
const [listUser, setListUser] = useState([]);
|
|
25
|
-
const currentUserId = useSCContextSelector(
|
|
26
|
-
(state) => state.auth.account.user.id
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
const loadMembers = useCallback(async () => {
|
|
30
|
-
const { success, data } = await axiosGet(API.SHARE.UNITS_MEMBERS(unitId));
|
|
31
|
-
if (success) {
|
|
32
|
-
setMembers(data);
|
|
33
|
-
}
|
|
34
|
-
}, [unitId]);
|
|
35
|
-
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
loadMembers();
|
|
38
|
-
}, [loadMembers]);
|
|
39
18
|
|
|
40
19
|
const onNext = useCallback(async () => {
|
|
41
20
|
formData.receiver = listUser;
|
|
@@ -55,112 +34,26 @@ const SetupScriptReceiverEmail = ({ route }) => {
|
|
|
55
34
|
}
|
|
56
35
|
}, [automateId, formData, listUser, navigate, t]);
|
|
57
36
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
Colors.GeekBlue3,
|
|
66
|
-
Colors.Purple3,
|
|
67
|
-
Colors.Orange3,
|
|
68
|
-
Colors.Volcano3,
|
|
69
|
-
Colors.Blue9,
|
|
70
|
-
Colors.Green3,
|
|
71
|
-
Colors.Cyan2,
|
|
72
|
-
],
|
|
73
|
-
[]
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const onChecked = useCallback(
|
|
77
|
-
(id) => (checked) => {
|
|
78
|
-
setListUser((prevListUser) =>
|
|
79
|
-
checked
|
|
80
|
-
? [...prevListUser, id]
|
|
81
|
-
: prevListUser.filter((userId) => userId !== id)
|
|
82
|
-
);
|
|
37
|
+
const onLoadOption = useCallback(
|
|
38
|
+
(item) => {
|
|
39
|
+
return {
|
|
40
|
+
label: item.email,
|
|
41
|
+
invalidLabel: t('no_email'),
|
|
42
|
+
disabled: !item.email,
|
|
43
|
+
};
|
|
83
44
|
},
|
|
84
|
-
[]
|
|
45
|
+
[t]
|
|
85
46
|
);
|
|
86
47
|
|
|
87
|
-
const RowMember = memo(({ member, index, onValueChange }) => {
|
|
88
|
-
const { id, name, avatar, share_id, email } = member;
|
|
89
|
-
const [role, roleColor] = useMemo(() => {
|
|
90
|
-
if (!share_id) {
|
|
91
|
-
return [t('owner'), Colors.Primary];
|
|
92
|
-
}
|
|
93
|
-
if (id === currentUserId) {
|
|
94
|
-
return [t('me'), Colors.Primary];
|
|
95
|
-
}
|
|
96
|
-
return [t('member'), Colors.Gray6];
|
|
97
|
-
}, [share_id, id]);
|
|
98
|
-
|
|
99
|
-
const firstWordsInName = useMemo(() => {
|
|
100
|
-
return name.charAt();
|
|
101
|
-
}, [name]);
|
|
102
|
-
|
|
103
|
-
const circleColor = arrColor[index % arrColor.length];
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
<View style={styles.rowContainer}>
|
|
107
|
-
<View style={styles.border}>
|
|
108
|
-
<CheckBox
|
|
109
|
-
disabled={!email}
|
|
110
|
-
lineWidth={4}
|
|
111
|
-
value={listUser.includes(id)}
|
|
112
|
-
onValueChange={onValueChange(id)}
|
|
113
|
-
style={styles.checkbox}
|
|
114
|
-
/>
|
|
115
|
-
<View style={styles.paddingLeft16}>
|
|
116
|
-
{avatar ? (
|
|
117
|
-
<Image source={{ uri: avatar }} style={styles.avatar} />
|
|
118
|
-
) : (
|
|
119
|
-
<CircleView size={40} backgroundColor={circleColor} center>
|
|
120
|
-
<Text color={Colors.White}>{firstWordsInName}</Text>
|
|
121
|
-
</CircleView>
|
|
122
|
-
)}
|
|
123
|
-
</View>
|
|
124
|
-
<View style={styles.paddingLeft16}>
|
|
125
|
-
<Text style={styles.titleName}>{name}</Text>
|
|
126
|
-
{email ? (
|
|
127
|
-
<Text style={styles.status}>{email}</Text>
|
|
128
|
-
) : (
|
|
129
|
-
<Text style={styles.invalid}>{t('no_email')}</Text>
|
|
130
|
-
)}
|
|
131
|
-
</View>
|
|
132
|
-
<View style={styles.endFlex}>
|
|
133
|
-
<Text style={[styles.textRole, { color: roleColor }]}>{role}</Text>
|
|
134
|
-
</View>
|
|
135
|
-
</View>
|
|
136
|
-
</View>
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
48
|
return (
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
ListEmptyComponent={
|
|
150
|
-
<View style={styles.viewEmpty}>
|
|
151
|
-
<Text style={styles.textCenter}>{t('no_member')}</Text>
|
|
152
|
-
</View>
|
|
153
|
-
}
|
|
154
|
-
/>
|
|
155
|
-
<View style={styles.container}>
|
|
156
|
-
<BottomButtonView
|
|
157
|
-
style={styles.bottomButtonView}
|
|
158
|
-
mainTitle={t('done')}
|
|
159
|
-
onPressMain={onNext}
|
|
160
|
-
typeMain={canSave ? 'primary' : 'disabled'}
|
|
161
|
-
/>
|
|
162
|
-
</View>
|
|
163
|
-
</View>
|
|
49
|
+
<ReceiverSelect
|
|
50
|
+
listUser={listUser}
|
|
51
|
+
unitId={unitId}
|
|
52
|
+
title={t('notify_to')}
|
|
53
|
+
setListUser={setListUser}
|
|
54
|
+
onLoadOption={onLoadOption}
|
|
55
|
+
onNext={onNext}
|
|
56
|
+
/>
|
|
164
57
|
);
|
|
165
58
|
};
|
|
166
59
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React, { useCallback, useState } from 'react';
|
|
2
|
+
import { useNavigation } from '@react-navigation/native';
|
|
3
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
4
|
+
|
|
5
|
+
import { axiosPost } from '../../../utils/Apis/axios';
|
|
6
|
+
import { API } from '../../../configs';
|
|
7
|
+
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
8
|
+
import Routes from '../../../utils/Route';
|
|
9
|
+
import ReceiverSelect from './ReceiverSelect';
|
|
10
|
+
import moment from 'moment';
|
|
11
|
+
|
|
12
|
+
const SetupScriptReceiverNotify = ({ route }) => {
|
|
13
|
+
const t = useTranslations();
|
|
14
|
+
const { navigate } = useNavigation();
|
|
15
|
+
const { automate = {}, unitId, formData } = route.params;
|
|
16
|
+
const { id: automateId } = automate;
|
|
17
|
+
const [listUser, setListUser] = useState([]);
|
|
18
|
+
|
|
19
|
+
const onNext = useCallback(async () => {
|
|
20
|
+
formData.receiver = listUser;
|
|
21
|
+
const { success } = await axiosPost(
|
|
22
|
+
API.AUTOMATE.ADD_SCRIPT_NOTIFY(automateId),
|
|
23
|
+
formData
|
|
24
|
+
);
|
|
25
|
+
if (success) {
|
|
26
|
+
ToastBottomHelper.success(t('text_done'));
|
|
27
|
+
navigate({
|
|
28
|
+
name: Routes.ScriptDetail,
|
|
29
|
+
merge: true,
|
|
30
|
+
params: { saveAt: moment().valueOf() },
|
|
31
|
+
});
|
|
32
|
+
} else {
|
|
33
|
+
ToastBottomHelper.error(t('error_please_try_later'));
|
|
34
|
+
}
|
|
35
|
+
}, [automateId, formData, listUser, navigate, t]);
|
|
36
|
+
|
|
37
|
+
const onLoadOption = useCallback(
|
|
38
|
+
(item) => {
|
|
39
|
+
return {
|
|
40
|
+
label: item.phone_number,
|
|
41
|
+
invalidLabel: t('no_phone_number'),
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
[t]
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<ReceiverSelect
|
|
49
|
+
listUser={listUser}
|
|
50
|
+
unitId={unitId}
|
|
51
|
+
title={t('notify_to')}
|
|
52
|
+
setListUser={setListUser}
|
|
53
|
+
onLoadOption={onLoadOption}
|
|
54
|
+
onNext={onNext}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default SetupScriptReceiverNotify;
|
|
@@ -1,41 +1,20 @@
|
|
|
1
|
-
import React, { useCallback,
|
|
2
|
-
import { FlatList, View } from 'react-native';
|
|
1
|
+
import React, { useCallback, useState } from 'react';
|
|
3
2
|
import { useNavigation } from '@react-navigation/native';
|
|
4
|
-
import styles from './Styles/SetupScriptReceiverEmailStyles';
|
|
5
|
-
import { CircleView, HeaderCustom, Text } from '../../../commons';
|
|
6
3
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
7
4
|
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import { API, Colors } from '../../../configs';
|
|
5
|
+
import { axiosPost } from '../../../utils/Apis/axios';
|
|
6
|
+
import { API } from '../../../configs';
|
|
11
7
|
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
12
8
|
import Routes from '../../../utils/Route';
|
|
9
|
+
import ReceiverSelect from './ReceiverSelect';
|
|
13
10
|
import moment from 'moment';
|
|
14
|
-
import CheckBox from '@react-native-community/checkbox';
|
|
15
|
-
import { useSCContextSelector } from '../../../context';
|
|
16
|
-
import { Image } from 'react-native';
|
|
17
11
|
|
|
18
12
|
const SetupScriptReceiverSms = ({ route }) => {
|
|
19
13
|
const t = useTranslations();
|
|
20
|
-
const {
|
|
21
|
-
const { automate = {}, unitId, formData } = route.params
|
|
14
|
+
const { navigate } = useNavigation();
|
|
15
|
+
const { automate = {}, unitId, formData } = route.params;
|
|
22
16
|
const { id: automateId } = automate;
|
|
23
|
-
const [members, setMembers] = useState([]);
|
|
24
17
|
const [listUser, setListUser] = useState([]);
|
|
25
|
-
const currentUserId = useSCContextSelector(
|
|
26
|
-
(state) => state.auth.account.user.id
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
const loadMembers = useCallback(async () => {
|
|
30
|
-
const { success, data } = await axiosGet(API.SHARE.UNITS_MEMBERS(unitId));
|
|
31
|
-
if (success) {
|
|
32
|
-
setMembers(data);
|
|
33
|
-
}
|
|
34
|
-
}, [unitId]);
|
|
35
|
-
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
loadMembers();
|
|
38
|
-
}, [loadMembers]);
|
|
39
18
|
|
|
40
19
|
const onNext = useCallback(async () => {
|
|
41
20
|
formData.receiver = listUser;
|
|
@@ -55,112 +34,26 @@ const SetupScriptReceiverSms = ({ route }) => {
|
|
|
55
34
|
}
|
|
56
35
|
}, [automateId, formData, listUser, navigate, t]);
|
|
57
36
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
Colors.GeekBlue3,
|
|
66
|
-
Colors.Purple3,
|
|
67
|
-
Colors.Orange3,
|
|
68
|
-
Colors.Volcano3,
|
|
69
|
-
Colors.Blue9,
|
|
70
|
-
Colors.Green3,
|
|
71
|
-
Colors.Cyan2,
|
|
72
|
-
],
|
|
73
|
-
[]
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const onChecked = useCallback(
|
|
77
|
-
(id) => (checked) => {
|
|
78
|
-
setListUser((prevListUser) =>
|
|
79
|
-
checked
|
|
80
|
-
? [...prevListUser, id]
|
|
81
|
-
: prevListUser.filter((userId) => userId !== id)
|
|
82
|
-
);
|
|
37
|
+
const onLoadOption = useCallback(
|
|
38
|
+
(item) => {
|
|
39
|
+
return {
|
|
40
|
+
label: item.phone_number,
|
|
41
|
+
invalidLabel: t('no_phone_number'),
|
|
42
|
+
disabled: !item.phone_number,
|
|
43
|
+
};
|
|
83
44
|
},
|
|
84
|
-
[]
|
|
45
|
+
[t]
|
|
85
46
|
);
|
|
86
47
|
|
|
87
|
-
const RowMember = memo(({ member, index, onValueChange }) => {
|
|
88
|
-
const { id, name, avatar, share_id, phone_number } = member;
|
|
89
|
-
const [role, roleColor] = useMemo(() => {
|
|
90
|
-
if (!share_id) {
|
|
91
|
-
return [t('owner'), Colors.Primary];
|
|
92
|
-
}
|
|
93
|
-
if (id === currentUserId) {
|
|
94
|
-
return [t('me'), Colors.Primary];
|
|
95
|
-
}
|
|
96
|
-
return [t('member'), Colors.Gray6];
|
|
97
|
-
}, [share_id, id]);
|
|
98
|
-
|
|
99
|
-
const firstWordsInName = useMemo(() => {
|
|
100
|
-
return name.charAt();
|
|
101
|
-
}, [name]);
|
|
102
|
-
|
|
103
|
-
const circleColor = arrColor[index % arrColor.length];
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
<View style={styles.rowContainer}>
|
|
107
|
-
<View style={styles.border}>
|
|
108
|
-
<CheckBox
|
|
109
|
-
disabled={!phone_number}
|
|
110
|
-
lineWidth={4}
|
|
111
|
-
value={listUser.includes(id)}
|
|
112
|
-
onValueChange={onValueChange(id)}
|
|
113
|
-
style={styles.checkbox}
|
|
114
|
-
/>
|
|
115
|
-
<View style={styles.paddingLeft16}>
|
|
116
|
-
{avatar ? (
|
|
117
|
-
<Image source={{ uri: avatar }} style={styles.avatar} />
|
|
118
|
-
) : (
|
|
119
|
-
<CircleView size={40} backgroundColor={circleColor} center>
|
|
120
|
-
<Text color={Colors.White}>{firstWordsInName}</Text>
|
|
121
|
-
</CircleView>
|
|
122
|
-
)}
|
|
123
|
-
</View>
|
|
124
|
-
<View style={styles.paddingLeft16}>
|
|
125
|
-
<Text style={styles.titleName}>{name}</Text>
|
|
126
|
-
{phone_number ? (
|
|
127
|
-
<Text style={styles.status}>{phone_number}</Text>
|
|
128
|
-
) : (
|
|
129
|
-
<Text style={styles.invalid}>{t('no_phone_number')}</Text>
|
|
130
|
-
)}
|
|
131
|
-
</View>
|
|
132
|
-
<View style={styles.endFlex}>
|
|
133
|
-
<Text style={[styles.textRole, { color: roleColor }]}>{role}</Text>
|
|
134
|
-
</View>
|
|
135
|
-
</View>
|
|
136
|
-
</View>
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
48
|
return (
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
ListEmptyComponent={
|
|
150
|
-
<View style={styles.viewEmpty}>
|
|
151
|
-
<Text style={styles.textCenter}>{t('no_member')}</Text>
|
|
152
|
-
</View>
|
|
153
|
-
}
|
|
154
|
-
/>
|
|
155
|
-
<View style={styles.container}>
|
|
156
|
-
<BottomButtonView
|
|
157
|
-
style={styles.bottomButtonView}
|
|
158
|
-
mainTitle={t('done')}
|
|
159
|
-
onPressMain={onNext}
|
|
160
|
-
typeMain={canSave ? 'primary' : 'disabled'}
|
|
161
|
-
/>
|
|
162
|
-
</View>
|
|
163
|
-
</View>
|
|
49
|
+
<ReceiverSelect
|
|
50
|
+
listUser={listUser}
|
|
51
|
+
unitId={unitId}
|
|
52
|
+
title={t('notify_to')}
|
|
53
|
+
setListUser={setListUser}
|
|
54
|
+
onLoadOption={onLoadOption}
|
|
55
|
+
onNext={onNext}
|
|
56
|
+
/>
|
|
164
57
|
);
|
|
165
58
|
};
|
|
166
59
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
|
-
import { Colors, Constants } from '../../../../configs';
|
|
3
2
|
import { getBottomSpace } from 'react-native-iphone-x-helper';
|
|
3
|
+
import { Colors, Constants } from '../../../../configs';
|
|
4
4
|
|
|
5
5
|
export default StyleSheet.create({
|
|
6
6
|
wrap: {
|
|
@@ -82,4 +82,21 @@ export default StyleSheet.create({
|
|
|
82
82
|
width: 24,
|
|
83
83
|
height: 24,
|
|
84
84
|
},
|
|
85
|
+
|
|
86
|
+
wrapSelectAll: {
|
|
87
|
+
paddingHorizontal: 16,
|
|
88
|
+
paddingVertical: 8,
|
|
89
|
+
},
|
|
90
|
+
wrapCheckboxSelectAll: {
|
|
91
|
+
flexDirection: 'row',
|
|
92
|
+
alignItems: 'center',
|
|
93
|
+
},
|
|
94
|
+
checkboxSelectAll: {
|
|
95
|
+
marginRight: 8,
|
|
96
|
+
},
|
|
97
|
+
borderSelectAll: {
|
|
98
|
+
height: 1,
|
|
99
|
+
backgroundColor: Colors.Gray4,
|
|
100
|
+
marginHorizontal: 16,
|
|
101
|
+
},
|
|
85
102
|
});
|
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import { useNavigation, useRoute } from '@react-navigation/native';
|
|
2
|
-
import MockAdapter from 'axios-mock-adapter';
|
|
3
2
|
import React from 'react';
|
|
4
3
|
import { TouchableWithoutFeedback } from 'react-native';
|
|
5
4
|
import renderer, { act } from 'react-test-renderer';
|
|
6
5
|
import BottomButtonView from '../../../../commons/BottomButtonView';
|
|
7
6
|
import _TextInput from '../../../../commons/Form/TextInput';
|
|
8
|
-
import API from '../../../../configs/API';
|
|
9
7
|
import { SCProvider } from '../../../../context';
|
|
10
8
|
import { mockSCStore } from '../../../../context/mockStore';
|
|
11
|
-
import api from '../../../../utils/Apis/axios';
|
|
12
9
|
import Routes from '../../../../utils/Route';
|
|
13
|
-
import { ToastBottomHelper } from '../../../../utils/Utils';
|
|
14
10
|
import SetupScriptNotify from '../SetupScriptNotify';
|
|
15
11
|
|
|
16
|
-
const mock = new MockAdapter(api.axiosInstance);
|
|
17
|
-
|
|
18
12
|
const wrapComponent = (route) => (
|
|
19
13
|
<SCProvider initState={mockSCStore({})}>
|
|
20
14
|
<SetupScriptNotify route={route} />
|
|
@@ -43,8 +37,6 @@ describe('Test SetupScriptNotify', () => {
|
|
|
43
37
|
});
|
|
44
38
|
|
|
45
39
|
it('SetupScriptNotify onPress create script notify success', async () => {
|
|
46
|
-
const spyToast = jest.spyOn(ToastBottomHelper, 'success');
|
|
47
|
-
mock.onPost(API.AUTOMATE.ADD_SCRIPT_NOTIFY(1)).reply(200);
|
|
48
40
|
await act(async () => {
|
|
49
41
|
tree = await renderer.create(wrapComponent(route));
|
|
50
42
|
});
|
|
@@ -66,14 +58,19 @@ describe('Test SetupScriptNotify', () => {
|
|
|
66
58
|
await act(async () => {
|
|
67
59
|
button.props.onPressMain();
|
|
68
60
|
});
|
|
69
|
-
expect(
|
|
61
|
+
expect(mockedNavigate).toHaveBeenCalledWith(
|
|
62
|
+
Routes.SetupScriptReceiverNotify,
|
|
63
|
+
{
|
|
64
|
+
automate: route.params.automate,
|
|
65
|
+
unitId: 1,
|
|
66
|
+
formData: { message: 'Message', title: 'Title', unit: 1 },
|
|
67
|
+
}
|
|
68
|
+
);
|
|
70
69
|
});
|
|
71
70
|
|
|
72
71
|
it('SetupScriptNotify onPress create script notify success with multi unit', async () => {
|
|
73
72
|
route.params.unitId = null;
|
|
74
73
|
route.params.multiUnit = { id: 1 };
|
|
75
|
-
const spyToast = jest.spyOn(ToastBottomHelper, 'success');
|
|
76
|
-
mock.onPost(API.AUTOMATE.ADD_SCRIPT_NOTIFY(1)).reply(200);
|
|
77
74
|
await act(async () => {
|
|
78
75
|
tree = await renderer.create(wrapComponent(route));
|
|
79
76
|
});
|
|
@@ -95,27 +92,13 @@ describe('Test SetupScriptNotify', () => {
|
|
|
95
92
|
await act(async () => {
|
|
96
93
|
button.props.onPressMain();
|
|
97
94
|
});
|
|
98
|
-
expect(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
});
|
|
107
|
-
const instance = tree.root;
|
|
108
|
-
const inputs = instance.findAllByType(_TextInput);
|
|
109
|
-
expect(inputs).toHaveLength(2);
|
|
110
|
-
|
|
111
|
-
await act(async () => {
|
|
112
|
-
inputs[0].props.onChange('Title');
|
|
113
|
-
inputs[1].props.onChange('Message');
|
|
114
|
-
});
|
|
115
|
-
const button = instance.findByType(BottomButtonView);
|
|
116
|
-
await act(async () => {
|
|
117
|
-
button.props.onPressMain();
|
|
118
|
-
});
|
|
119
|
-
expect(spyToast).toHaveBeenCalled();
|
|
95
|
+
expect(mockedNavigate).toHaveBeenCalledWith(
|
|
96
|
+
Routes.SetupScriptReceiverNotify,
|
|
97
|
+
{
|
|
98
|
+
automate: route.params.automate,
|
|
99
|
+
unitId: 1,
|
|
100
|
+
formData: { message: 'Message', title: 'Title', unit: 1 },
|
|
101
|
+
}
|
|
102
|
+
);
|
|
120
103
|
});
|
|
121
104
|
});
|
|
@@ -66,11 +66,12 @@ describe('Test SetupScriptReceiverEmail', () => {
|
|
|
66
66
|
});
|
|
67
67
|
const instance = tree.root;
|
|
68
68
|
const checkboxs = instance.findAllByType(CheckBox);
|
|
69
|
-
expect(checkboxs).toHaveLength(
|
|
70
|
-
expect(checkboxs[0].props.
|
|
71
|
-
expect(checkboxs[1].props.disabled).
|
|
69
|
+
expect(checkboxs).toHaveLength(3);
|
|
70
|
+
expect(checkboxs[0].props.value).toBeFalsy(); // Select All
|
|
71
|
+
expect(checkboxs[1].props.disabled).toBeFalsy();
|
|
72
|
+
expect(checkboxs[2].props.disabled).toBeTruthy();
|
|
72
73
|
await act(async () => {
|
|
73
|
-
checkboxs[
|
|
74
|
+
checkboxs[1].props.onValueChange(true);
|
|
74
75
|
});
|
|
75
76
|
|
|
76
77
|
const button = instance.findByType(BottomButtonView);
|
|
@@ -89,11 +90,12 @@ describe('Test SetupScriptReceiverEmail', () => {
|
|
|
89
90
|
});
|
|
90
91
|
const instance = tree.root;
|
|
91
92
|
const checkboxs = instance.findAllByType(CheckBox);
|
|
92
|
-
expect(checkboxs).toHaveLength(
|
|
93
|
-
expect(checkboxs[0].props.
|
|
94
|
-
expect(checkboxs[1].props.disabled).
|
|
93
|
+
expect(checkboxs).toHaveLength(3);
|
|
94
|
+
expect(checkboxs[0].props.value).toBeFalsy(); // Select All
|
|
95
|
+
expect(checkboxs[1].props.disabled).toBeFalsy();
|
|
96
|
+
expect(checkboxs[2].props.disabled).toBeTruthy();
|
|
95
97
|
await act(async () => {
|
|
96
|
-
checkboxs[
|
|
98
|
+
checkboxs[1].props.onValueChange(true);
|
|
97
99
|
});
|
|
98
100
|
|
|
99
101
|
const button = instance.findByType(BottomButtonView);
|