@eohjsc/react-native-smart-city 0.7.14 → 0.7.16
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/assets/images/Sms.svg +9 -0
- package/package.json +1 -1
- package/src/commons/Automate/ItemConditionScriptDetailStyles.js +1 -0
- package/src/commons/Widgets/IFrame/IFrame.js +2 -2
- package/src/commons/Widgets/IFrame/IFrameStyles.js +5 -0
- package/src/configs/API.js +8 -2
- package/src/hooks/Common/useBlockBack.js +36 -21
- package/src/hooks/Common/useDevicesStatus.js +16 -13
- package/src/navigations/UnitStack.js +24 -0
- package/src/screens/AddNewGateway/ScanDeviceLocal.js +14 -16
- package/src/screens/AddNewGateway/ScanDeviceLocalStyles.js +6 -1
- package/src/screens/AddNewGateway/__test__/ScanDeviceLocal.test.js +4 -13
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverSms.js +167 -0
- package/src/screens/Automate/AddNewAction/SetupScriptSms.js +73 -0
- package/src/screens/Automate/AddNewAction/Styles/SetupScriptEmailStyles.js +5 -0
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverSms.test.js +105 -0
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptSms.test.js +70 -0
- package/src/screens/Automate/EditActionsList/UpdateReceiverSmsScript.js +178 -0
- package/src/screens/Automate/EditActionsList/UpdateSmsScript.js +66 -0
- package/src/screens/Automate/EditActionsList/__tests__/UpdateReceiverSmsScript.test.js +82 -0
- package/src/screens/Automate/EditActionsList/__tests__/UpdateSmsScript.test.js +71 -0
- package/src/screens/Automate/EditActionsList/index.js +50 -1
- package/src/screens/Automate/ScriptDetail/Components/AddActionScript.js +52 -19
- package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +39 -2
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +106 -38
- package/src/screens/Automate/ScriptDetail/index.js +227 -10
- package/src/screens/SharedUnit/__test__/ShareUnit.test.js +22 -1
- package/src/screens/Sharing/UnitMemberList.js +1 -1
- package/src/screens/Sharing/__test__/UnitMemberList.test.js +10 -0
- package/src/screens/Unit/__test__/Detail.test.js +1 -1
- package/src/utils/I18n/translations/en.js +10 -0
- package/src/utils/I18n/translations/vi.js +10 -0
- package/src/utils/Route/index.js +3 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { useNavigation, useRoute } from '@react-navigation/native';
|
|
2
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import renderer, { act } from 'react-test-renderer';
|
|
5
|
+
import BottomButtonView from '../../../../commons/BottomButtonView';
|
|
6
|
+
import API from '../../../../configs/API';
|
|
7
|
+
import { SCProvider } from '../../../../context';
|
|
8
|
+
import { mockSCStore } from '../../../../context/mockStore';
|
|
9
|
+
import api from '../../../../utils/Apis/axios';
|
|
10
|
+
import Routes from '../../../../utils/Route';
|
|
11
|
+
import { ToastBottomHelper } from '../../../../utils/Utils';
|
|
12
|
+
import SetupScriptReceiverSms from '../SetupScriptReceiverSms';
|
|
13
|
+
import CheckBox from '@react-native-community/checkbox';
|
|
14
|
+
|
|
15
|
+
const mock = new MockAdapter(api.axiosInstance);
|
|
16
|
+
|
|
17
|
+
const wrapComponent = (route) => (
|
|
18
|
+
<SCProvider initState={mockSCStore({})}>
|
|
19
|
+
<SetupScriptReceiverSms route={route} />
|
|
20
|
+
</SCProvider>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
describe('Test SetupScriptReceiverSms', () => {
|
|
24
|
+
const mockedNavigate = useNavigation().navigate;
|
|
25
|
+
|
|
26
|
+
let tree;
|
|
27
|
+
const route = {
|
|
28
|
+
params: {
|
|
29
|
+
unitId: 1,
|
|
30
|
+
automateId: 1,
|
|
31
|
+
automate: {
|
|
32
|
+
id: 1,
|
|
33
|
+
sensor_id: 1,
|
|
34
|
+
},
|
|
35
|
+
closeScreen: Routes.ScriptDetail,
|
|
36
|
+
formData: { message: 'message' },
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const listUser = [
|
|
41
|
+
{
|
|
42
|
+
avatar: 'https://xxx',
|
|
43
|
+
phone_number: '0902xx',
|
|
44
|
+
id: 140,
|
|
45
|
+
name: 'User 1',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
avatar: null,
|
|
49
|
+
phone_number: null,
|
|
50
|
+
id: 56,
|
|
51
|
+
name: 'User 2',
|
|
52
|
+
share_id: 5386,
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
mockedNavigate.mockClear();
|
|
57
|
+
useRoute.mockImplementation(() => route);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('SetupScriptReceiverSms onPress create script sms success', async () => {
|
|
61
|
+
const spyToast = jest.spyOn(ToastBottomHelper, 'success');
|
|
62
|
+
mock.onGet(API.SHARE.UNITS_MEMBERS(1)).reply(200, listUser);
|
|
63
|
+
mock.onPost(API.AUTOMATE.ADD_SCRIPT_SMS(1)).reply(200);
|
|
64
|
+
await act(async () => {
|
|
65
|
+
tree = await renderer.create(wrapComponent(route));
|
|
66
|
+
});
|
|
67
|
+
const instance = tree.root;
|
|
68
|
+
const checkboxs = instance.findAllByType(CheckBox);
|
|
69
|
+
expect(checkboxs).toHaveLength(2);
|
|
70
|
+
expect(checkboxs[0].props.disabled).toBeFalsy();
|
|
71
|
+
expect(checkboxs[1].props.disabled).toBeTruthy();
|
|
72
|
+
await act(async () => {
|
|
73
|
+
checkboxs[0].props.onValueChange(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const button = instance.findByType(BottomButtonView);
|
|
77
|
+
await act(async () => {
|
|
78
|
+
button.props.onPressMain();
|
|
79
|
+
});
|
|
80
|
+
expect(spyToast).toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('SetupScriptReceiverSms onPress create script email fail', async () => {
|
|
84
|
+
const spyToast = jest.spyOn(ToastBottomHelper, 'error');
|
|
85
|
+
mock.onGet(API.SHARE.UNITS_MEMBERS(1)).reply(200, listUser);
|
|
86
|
+
mock.onPost(API.AUTOMATE.ADD_SCRIPT_SMS(1)).reply(400);
|
|
87
|
+
await act(async () => {
|
|
88
|
+
tree = await renderer.create(wrapComponent(route));
|
|
89
|
+
});
|
|
90
|
+
const instance = tree.root;
|
|
91
|
+
const checkboxs = instance.findAllByType(CheckBox);
|
|
92
|
+
expect(checkboxs).toHaveLength(2);
|
|
93
|
+
expect(checkboxs[0].props.disabled).toBeFalsy();
|
|
94
|
+
expect(checkboxs[1].props.disabled).toBeTruthy();
|
|
95
|
+
await act(async () => {
|
|
96
|
+
checkboxs[0].props.onValueChange(true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const button = instance.findByType(BottomButtonView);
|
|
100
|
+
await act(async () => {
|
|
101
|
+
button.props.onPressMain();
|
|
102
|
+
});
|
|
103
|
+
expect(spyToast).toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useNavigation, useRoute } from '@react-navigation/native';
|
|
2
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { TouchableWithoutFeedback } from 'react-native';
|
|
5
|
+
import renderer, { act } from 'react-test-renderer';
|
|
6
|
+
import BottomButtonView from '../../../../commons/BottomButtonView';
|
|
7
|
+
import _TextInput from '../../../../commons/Form/TextInput';
|
|
8
|
+
import API from '../../../../configs/API';
|
|
9
|
+
import { SCProvider } from '../../../../context';
|
|
10
|
+
import { mockSCStore } from '../../../../context/mockStore';
|
|
11
|
+
import api from '../../../../utils/Apis/axios';
|
|
12
|
+
import Routes from '../../../../utils/Route';
|
|
13
|
+
import SetupScriptSms from '../SetupScriptSms';
|
|
14
|
+
|
|
15
|
+
const mock = new MockAdapter(api.axiosInstance);
|
|
16
|
+
|
|
17
|
+
const wrapComponent = (route) => (
|
|
18
|
+
<SCProvider initState={mockSCStore({})}>
|
|
19
|
+
<SetupScriptSms route={route} />
|
|
20
|
+
</SCProvider>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
describe('Test SetupScriptSms', () => {
|
|
24
|
+
const mockedNavigate = useNavigation().navigate;
|
|
25
|
+
|
|
26
|
+
let tree;
|
|
27
|
+
const route = {
|
|
28
|
+
params: {
|
|
29
|
+
unitId: 1,
|
|
30
|
+
automateId: 1,
|
|
31
|
+
scriptName: 'scriptName test',
|
|
32
|
+
automate: {
|
|
33
|
+
id: 1,
|
|
34
|
+
sensor_id: 1,
|
|
35
|
+
},
|
|
36
|
+
closeScreen: Routes.ScriptDetail,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
mockedNavigate.mockClear();
|
|
41
|
+
useRoute.mockImplementation(() => route);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('SetupScriptNotify onPress create script SMS success', async () => {
|
|
45
|
+
mock.onPost(API.AUTOMATE.ADD_SCRIPT_SMS(1)).reply(200);
|
|
46
|
+
await act(async () => {
|
|
47
|
+
tree = await renderer.create(wrapComponent(route));
|
|
48
|
+
});
|
|
49
|
+
const instance = tree.root;
|
|
50
|
+
const inputs = instance.findAllByType(_TextInput);
|
|
51
|
+
expect(inputs).toHaveLength(1);
|
|
52
|
+
|
|
53
|
+
const touchable = instance.findAllByType(TouchableWithoutFeedback);
|
|
54
|
+
await act(async () => {
|
|
55
|
+
touchable[0].props.onPress();
|
|
56
|
+
});
|
|
57
|
+
await act(async () => {
|
|
58
|
+
inputs[0].props.onChange('Message');
|
|
59
|
+
});
|
|
60
|
+
const button = instance.findByType(BottomButtonView);
|
|
61
|
+
await act(async () => {
|
|
62
|
+
button.props.onPressMain();
|
|
63
|
+
});
|
|
64
|
+
expect(mockedNavigate).toHaveBeenCalledWith(Routes.SetupScriptReceiverSms, {
|
|
65
|
+
automate: route.params.automate,
|
|
66
|
+
unitId: 1,
|
|
67
|
+
formData: { message: 'Message', unit: 1 },
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import React, { useCallback, useMemo, useState, useEffect, memo } from 'react';
|
|
2
|
+
import { FlatList, View } from 'react-native';
|
|
3
|
+
import { useNavigation } from '@react-navigation/native';
|
|
4
|
+
import styles from './Styles/UpdateReceiverEmailScriptStyles.js';
|
|
5
|
+
import { CircleView, HeaderCustom, Text } from '../../../commons/index.js';
|
|
6
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
7
|
+
|
|
8
|
+
import BottomButtonView from '../../../commons/BottomButtonView/index.js';
|
|
9
|
+
import { axiosPut, axiosGet } from '../../../utils/Apis/axios.js';
|
|
10
|
+
import { API, Colors } from '../../../configs/index.js';
|
|
11
|
+
import { ToastBottomHelper } from '../../../utils/Utils.js';
|
|
12
|
+
import Routes from '../../../utils/Route/index.js';
|
|
13
|
+
import moment from 'moment';
|
|
14
|
+
import CheckBox from '@react-native-community/checkbox';
|
|
15
|
+
import { useSCContextSelector } from '../../../context';
|
|
16
|
+
import { Image } from 'react-native';
|
|
17
|
+
|
|
18
|
+
const UpdateReceiverSmsScript = ({ route }) => {
|
|
19
|
+
const t = useTranslations();
|
|
20
|
+
const { goBack, navigate } = useNavigation();
|
|
21
|
+
const { automateId, scriptItemId, formData } = route.params;
|
|
22
|
+
const [members, setMembers] = useState([]);
|
|
23
|
+
const [listUser, setListUser] = useState(formData.receiver_ids);
|
|
24
|
+
const currentUserId = useSCContextSelector(
|
|
25
|
+
(state) => state.auth.account.user.id
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const loadMembers = useCallback(async () => {
|
|
29
|
+
const { success, data } = await axiosGet(
|
|
30
|
+
API.SHARE.UNITS_MEMBERS(formData.unit_id)
|
|
31
|
+
);
|
|
32
|
+
if (success) {
|
|
33
|
+
setMembers(data);
|
|
34
|
+
}
|
|
35
|
+
}, [formData.unit_id]);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
loadMembers();
|
|
39
|
+
}, [loadMembers]);
|
|
40
|
+
|
|
41
|
+
const onNext = useCallback(async () => {
|
|
42
|
+
const { success } = await axiosPut(
|
|
43
|
+
API.AUTOMATE.UPDATE_SCRIPT_SMS(automateId),
|
|
44
|
+
{
|
|
45
|
+
id: scriptItemId,
|
|
46
|
+
unit: formData.unit_id,
|
|
47
|
+
message: formData.newMessage,
|
|
48
|
+
receiver: listUser,
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
if (success) {
|
|
52
|
+
ToastBottomHelper.success(t('update_successfully'));
|
|
53
|
+
navigate({
|
|
54
|
+
name: Routes.ScriptDetail,
|
|
55
|
+
merge: true,
|
|
56
|
+
params: { saveAt: moment().valueOf() },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}, [
|
|
60
|
+
automateId,
|
|
61
|
+
formData.newMessage,
|
|
62
|
+
formData.unit_id,
|
|
63
|
+
listUser,
|
|
64
|
+
navigate,
|
|
65
|
+
scriptItemId,
|
|
66
|
+
t,
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
const canSave = useMemo(() => {
|
|
70
|
+
const { newMessage } = formData;
|
|
71
|
+
return !!newMessage && !!listUser.length;
|
|
72
|
+
}, [formData, listUser.length]);
|
|
73
|
+
|
|
74
|
+
const arrColor = useMemo(
|
|
75
|
+
() => [
|
|
76
|
+
Colors.GeekBlue3,
|
|
77
|
+
Colors.Purple3,
|
|
78
|
+
Colors.Orange3,
|
|
79
|
+
Colors.Volcano3,
|
|
80
|
+
Colors.Blue9,
|
|
81
|
+
Colors.Green3,
|
|
82
|
+
Colors.Cyan2,
|
|
83
|
+
],
|
|
84
|
+
[]
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const onChecked = useCallback(
|
|
88
|
+
(id) => (checked) => {
|
|
89
|
+
setListUser((prevListUser) =>
|
|
90
|
+
checked
|
|
91
|
+
? [...prevListUser, id]
|
|
92
|
+
: prevListUser.filter((userId) => userId !== id)
|
|
93
|
+
);
|
|
94
|
+
},
|
|
95
|
+
[]
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const RowMember = memo(({ member, index, onValueChange }) => {
|
|
99
|
+
const { id, name, avatar, share_id, phone_number } = member;
|
|
100
|
+
const [role, roleColor] = useMemo(() => {
|
|
101
|
+
if (!share_id) {
|
|
102
|
+
return [t('owner'), Colors.Primary];
|
|
103
|
+
}
|
|
104
|
+
if (id === currentUserId) {
|
|
105
|
+
return [t('me'), Colors.Primary];
|
|
106
|
+
}
|
|
107
|
+
return [t('member'), Colors.Gray6];
|
|
108
|
+
}, [share_id, id]);
|
|
109
|
+
|
|
110
|
+
const firstWordsInName = useMemo(() => {
|
|
111
|
+
return name.charAt();
|
|
112
|
+
}, [name]);
|
|
113
|
+
|
|
114
|
+
const circleColor = arrColor[index % arrColor.length];
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<View style={styles.rowContainer}>
|
|
118
|
+
<View style={styles.border}>
|
|
119
|
+
<CheckBox
|
|
120
|
+
disabled={!phone_number}
|
|
121
|
+
lineWidth={4}
|
|
122
|
+
value={listUser.includes(id)}
|
|
123
|
+
onValueChange={onValueChange(id)}
|
|
124
|
+
style={styles.checkbox}
|
|
125
|
+
/>
|
|
126
|
+
<View style={styles.paddingLeft16}>
|
|
127
|
+
{avatar ? (
|
|
128
|
+
<Image source={{ uri: avatar }} style={styles.avatar} />
|
|
129
|
+
) : (
|
|
130
|
+
<CircleView size={40} backgroundColor={circleColor} center>
|
|
131
|
+
<Text color={Colors.White}>{firstWordsInName}</Text>
|
|
132
|
+
</CircleView>
|
|
133
|
+
)}
|
|
134
|
+
</View>
|
|
135
|
+
<View style={styles.paddingLeft16}>
|
|
136
|
+
<Text style={styles.titleName}>{name}</Text>
|
|
137
|
+
{phone_number ? (
|
|
138
|
+
<Text style={styles.status}>{phone_number}</Text>
|
|
139
|
+
) : (
|
|
140
|
+
<Text style={styles.invalid}>{t('no_phone_number')}</Text>
|
|
141
|
+
)}
|
|
142
|
+
</View>
|
|
143
|
+
<View style={styles.endFlex}>
|
|
144
|
+
<Text style={[styles.textRole, { color: roleColor }]}>{role}</Text>
|
|
145
|
+
</View>
|
|
146
|
+
</View>
|
|
147
|
+
</View>
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<View style={styles.wrap}>
|
|
153
|
+
<HeaderCustom isShowClose onClose={goBack} title={t('sms_to')} />
|
|
154
|
+
<FlatList
|
|
155
|
+
data={members}
|
|
156
|
+
renderItem={({ item, index }) => (
|
|
157
|
+
<RowMember member={item} index={index} onValueChange={onChecked} />
|
|
158
|
+
)}
|
|
159
|
+
keyExtractor={(item) => item.id.toString()}
|
|
160
|
+
ListEmptyComponent={
|
|
161
|
+
<View style={styles.viewEmpty}>
|
|
162
|
+
<Text style={styles.textCenter}>{t('no_member')}</Text>
|
|
163
|
+
</View>
|
|
164
|
+
}
|
|
165
|
+
/>
|
|
166
|
+
<View style={styles.container}>
|
|
167
|
+
<BottomButtonView
|
|
168
|
+
style={styles.bottomButtonView}
|
|
169
|
+
mainTitle={t('done')}
|
|
170
|
+
onPressMain={onNext}
|
|
171
|
+
typeMain={canSave ? 'primary' : 'disabled'}
|
|
172
|
+
/>
|
|
173
|
+
</View>
|
|
174
|
+
</View>
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export default UpdateReceiverSmsScript;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { useCallback, useState } from 'react';
|
|
2
|
+
import _TextInput from '../../../commons/Form/TextInput';
|
|
3
|
+
import styles from './Styles/indexStyles';
|
|
4
|
+
import AccessibilityLabel from '../../../configs/AccessibilityLabel';
|
|
5
|
+
import { Keyboard, TouchableWithoutFeedback, View } from 'react-native';
|
|
6
|
+
import BottomButtonView from '../../../commons/BottomButtonView';
|
|
7
|
+
import { useNavigation } from '@react-navigation/native';
|
|
8
|
+
import Routes from '../../../utils/Route';
|
|
9
|
+
|
|
10
|
+
const UpdateSmsScript = ({
|
|
11
|
+
automateId,
|
|
12
|
+
scriptItemId,
|
|
13
|
+
sms_script,
|
|
14
|
+
t,
|
|
15
|
+
onClosePopup,
|
|
16
|
+
}) => {
|
|
17
|
+
const { navigate } = useNavigation();
|
|
18
|
+
const { message, unit_id, str_phone_numbers, receiver_ids } = sms_script;
|
|
19
|
+
const [formData, setFormData] = useState({
|
|
20
|
+
newMessage: message,
|
|
21
|
+
unit_id,
|
|
22
|
+
str_phone_numbers,
|
|
23
|
+
receiver_ids,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const onPressNext = useCallback(async () => {
|
|
27
|
+
onClosePopup();
|
|
28
|
+
navigate(Routes.UpdateReceiverSmsScript, {
|
|
29
|
+
automateId,
|
|
30
|
+
scriptItemId,
|
|
31
|
+
formData,
|
|
32
|
+
});
|
|
33
|
+
}, [automateId, formData, navigate, onClosePopup, scriptItemId]);
|
|
34
|
+
|
|
35
|
+
const onChangeMessage = (value) => {
|
|
36
|
+
setFormData((prev) => ({ ...prev, newMessage: value }));
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
|
41
|
+
<View>
|
|
42
|
+
<_TextInput
|
|
43
|
+
label={t('update_message_email')}
|
|
44
|
+
placeholder={t('message_notification')}
|
|
45
|
+
onChange={onChangeMessage}
|
|
46
|
+
textInputStyle={styles.textMessage}
|
|
47
|
+
value={formData.newMessage}
|
|
48
|
+
accessibilityLabel={AccessibilityLabel.AUTOMATE_MESSAGE_NOTIFY}
|
|
49
|
+
multiline={true}
|
|
50
|
+
maxLength={255}
|
|
51
|
+
/>
|
|
52
|
+
<View style={styles.wrapBottom}>
|
|
53
|
+
<BottomButtonView
|
|
54
|
+
mainTitle={t('next')}
|
|
55
|
+
onPressMain={onPressNext}
|
|
56
|
+
typeMain={'primary'}
|
|
57
|
+
accessibilityLabel={AccessibilityLabel.BUTTON_SAVE_EDIT_ACTION_LIST}
|
|
58
|
+
disableKeyBoardAnimated
|
|
59
|
+
/>
|
|
60
|
+
</View>
|
|
61
|
+
</View>
|
|
62
|
+
</TouchableWithoutFeedback>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default UpdateSmsScript;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import renderer, { act } from 'react-test-renderer';
|
|
4
|
+
|
|
5
|
+
import API from '../../../../configs/API';
|
|
6
|
+
import { SCProvider } from '../../../../context';
|
|
7
|
+
import { mockSCStore } from '../../../../context/mockStore';
|
|
8
|
+
|
|
9
|
+
import BottomButtonView from '../../../../commons/BottomButtonView';
|
|
10
|
+
import api from '../../../../utils/Apis/axios';
|
|
11
|
+
import Routes from '../../../../utils/Route';
|
|
12
|
+
import UpdateReceiverSmsScript from '../UpdateReceiverSmsScript';
|
|
13
|
+
import CheckBox from '@react-native-community/checkbox';
|
|
14
|
+
import { ToastBottomHelper } from '../../../../utils/Utils';
|
|
15
|
+
|
|
16
|
+
const mock = new MockAdapter(api.axiosInstance);
|
|
17
|
+
|
|
18
|
+
const listUser = [
|
|
19
|
+
{
|
|
20
|
+
avatar: 'https://xxx',
|
|
21
|
+
phone_number: '0902xxx',
|
|
22
|
+
id: 140,
|
|
23
|
+
name: 'User 1',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
avatar: null,
|
|
27
|
+
phone_number: null,
|
|
28
|
+
id: 56,
|
|
29
|
+
name: 'User 2',
|
|
30
|
+
share_id: 5386,
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
const wrapComponent = () => (
|
|
34
|
+
<SCProvider initState={mockSCStore({})}>
|
|
35
|
+
<UpdateReceiverSmsScript
|
|
36
|
+
route={{
|
|
37
|
+
params: {
|
|
38
|
+
automateId: 1,
|
|
39
|
+
scriptItemId: 1,
|
|
40
|
+
automate: {
|
|
41
|
+
id: 1,
|
|
42
|
+
sensor_id: 1,
|
|
43
|
+
},
|
|
44
|
+
closeScreen: Routes.ScriptDetail,
|
|
45
|
+
formData: {
|
|
46
|
+
message: 'Contend',
|
|
47
|
+
unit_id: 1,
|
|
48
|
+
str_phone_numbers: '0902xxx',
|
|
49
|
+
receiver_ids: [],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
}}
|
|
53
|
+
/>
|
|
54
|
+
</SCProvider>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
describe('Test UpdateReceiverSmsScript', () => {
|
|
58
|
+
let tree;
|
|
59
|
+
|
|
60
|
+
it('test update message', async () => {
|
|
61
|
+
const spyToast = jest.spyOn(ToastBottomHelper, 'success');
|
|
62
|
+
mock.onGet(API.SHARE.UNITS_MEMBERS(1)).reply(200, listUser);
|
|
63
|
+
mock.onPut(API.AUTOMATE.UPDATE_SCRIPT_SMS(1)).reply(200);
|
|
64
|
+
await act(async () => {
|
|
65
|
+
tree = await renderer.create(wrapComponent());
|
|
66
|
+
});
|
|
67
|
+
const instance = tree.root;
|
|
68
|
+
const checkboxs = instance.findAllByType(CheckBox);
|
|
69
|
+
expect(checkboxs).toHaveLength(2);
|
|
70
|
+
expect(checkboxs[0].props.disabled).toBeFalsy();
|
|
71
|
+
expect(checkboxs[1].props.disabled).toBeTruthy();
|
|
72
|
+
await act(async () => {
|
|
73
|
+
checkboxs[0].props.onValueChange(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const button = instance.findByType(BottomButtonView);
|
|
77
|
+
await act(async () => {
|
|
78
|
+
button.props.onPressMain();
|
|
79
|
+
});
|
|
80
|
+
expect(spyToast).toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import renderer, { act } from 'react-test-renderer';
|
|
4
|
+
|
|
5
|
+
import API from '../../../../configs/API';
|
|
6
|
+
import { AccessibilityLabel } from '../../../../configs/Constants';
|
|
7
|
+
import { SCProvider } from '../../../../context';
|
|
8
|
+
import { mockSCStore } from '../../../../context/mockStore';
|
|
9
|
+
|
|
10
|
+
import BottomButtonView from '../../../../commons/BottomButtonView';
|
|
11
|
+
import _TextInput from '../../../../commons/Form/TextInput';
|
|
12
|
+
import api from '../../../../utils/Apis/axios';
|
|
13
|
+
import UpdateSmsScript from '../UpdateSmsScript';
|
|
14
|
+
import Routes from '../../../../utils/Route';
|
|
15
|
+
|
|
16
|
+
const mock = new MockAdapter(api.axiosInstance);
|
|
17
|
+
const mockerOnClosePopup = jest.fn();
|
|
18
|
+
|
|
19
|
+
const wrapComponent = () => (
|
|
20
|
+
<SCProvider initState={mockSCStore({})}>
|
|
21
|
+
<UpdateSmsScript
|
|
22
|
+
automateId={1}
|
|
23
|
+
scriptItemId={1}
|
|
24
|
+
sms_script={{
|
|
25
|
+
message: 'Contend',
|
|
26
|
+
unit_id: 60,
|
|
27
|
+
str_phone_numbers: '0902xxx',
|
|
28
|
+
}}
|
|
29
|
+
t={jest.fn()}
|
|
30
|
+
onClosePopup={mockerOnClosePopup}
|
|
31
|
+
/>
|
|
32
|
+
</SCProvider>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
describe('Test UpdateSmsScript', () => {
|
|
36
|
+
let tree;
|
|
37
|
+
|
|
38
|
+
it('test update message', async () => {
|
|
39
|
+
mock.onPut(API.AUTOMATE.UPDATE_SCRIPT_SMS(1)).reply(200);
|
|
40
|
+
await act(async () => {
|
|
41
|
+
tree = await renderer.create(wrapComponent());
|
|
42
|
+
});
|
|
43
|
+
const instance = tree.root;
|
|
44
|
+
|
|
45
|
+
const message = instance.find(
|
|
46
|
+
(el) =>
|
|
47
|
+
el.props.accessibilityLabel ===
|
|
48
|
+
AccessibilityLabel.AUTOMATE_MESSAGE_NOTIFY && el.type === _TextInput
|
|
49
|
+
);
|
|
50
|
+
await act(async () => {
|
|
51
|
+
message.props.onChange('2');
|
|
52
|
+
});
|
|
53
|
+
const button = instance.findByType(BottomButtonView);
|
|
54
|
+
expect(button.props.typeMain).toEqual('primary');
|
|
55
|
+
await act(async () => {
|
|
56
|
+
button.props.onPressMain();
|
|
57
|
+
});
|
|
58
|
+
expect(global.mockedNavigate).toHaveBeenCalledWith(
|
|
59
|
+
Routes.UpdateReceiverSmsScript,
|
|
60
|
+
{
|
|
61
|
+
automateId: 1,
|
|
62
|
+
formData: {
|
|
63
|
+
newMessage: '2',
|
|
64
|
+
str_phone_numbers: '0902xxx',
|
|
65
|
+
unit_id: 60,
|
|
66
|
+
},
|
|
67
|
+
scriptItemId: 1,
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -9,6 +9,7 @@ import Close from '../../../../assets/images/Close.svg';
|
|
|
9
9
|
import Delay from '../../../../assets/images/Delay.svg';
|
|
10
10
|
import Notify from '../../../../assets/images/Notify.svg';
|
|
11
11
|
import Email from '../../../../assets/images/Email.svg';
|
|
12
|
+
import Sms from '../../../../assets/images/Sms.svg';
|
|
12
13
|
import Rearrange from '../../../../assets/images/Rearrange.svg';
|
|
13
14
|
import { FullLoading } from '../../../commons';
|
|
14
15
|
import FImage from '../../../commons/FImage';
|
|
@@ -25,6 +26,7 @@ import styles from './Styles/indexStyles';
|
|
|
25
26
|
import UpdateDelayScript from './UpdateDelayScript';
|
|
26
27
|
import UpdateNotifyScript from './UpdateNotifyScript';
|
|
27
28
|
import UpdateEmailScript from './UpdateEmailScript';
|
|
29
|
+
import UpdateSmsScript from './UpdateSmsScript';
|
|
28
30
|
|
|
29
31
|
const EditActionsList = () => {
|
|
30
32
|
const t = useTranslations();
|
|
@@ -140,7 +142,13 @@ const EditActionsList = () => {
|
|
|
140
142
|
({ item, getIndex, drag, isActive }) => {
|
|
141
143
|
const index = getIndex();
|
|
142
144
|
const paddedIndex = (index + 1).toString().padStart(2, '0');
|
|
143
|
-
const {
|
|
145
|
+
const {
|
|
146
|
+
action_script,
|
|
147
|
+
notify_script,
|
|
148
|
+
delay_script,
|
|
149
|
+
email_script,
|
|
150
|
+
sms_script,
|
|
151
|
+
} = item;
|
|
144
152
|
if (action_script) {
|
|
145
153
|
const {
|
|
146
154
|
sensor_icon_kit,
|
|
@@ -272,6 +280,34 @@ const EditActionsList = () => {
|
|
|
272
280
|
/>
|
|
273
281
|
);
|
|
274
282
|
}
|
|
283
|
+
if (sms_script) {
|
|
284
|
+
const { message, str_phone_numbers } = sms_script;
|
|
285
|
+
|
|
286
|
+
return (
|
|
287
|
+
<CommonItem
|
|
288
|
+
paddedIndex={paddedIndex}
|
|
289
|
+
icon={
|
|
290
|
+
<View style={styles.iconItem}>
|
|
291
|
+
<Sms />
|
|
292
|
+
</View>
|
|
293
|
+
}
|
|
294
|
+
content={
|
|
295
|
+
<>
|
|
296
|
+
<Text numberOfLines={1} type="H4" color={Colors.Gray9}>
|
|
297
|
+
{message}
|
|
298
|
+
</Text>
|
|
299
|
+
<Text numberOfLines={1} type="H4" color={Colors.Gray9}>
|
|
300
|
+
{str_phone_numbers}
|
|
301
|
+
</Text>
|
|
302
|
+
</>
|
|
303
|
+
}
|
|
304
|
+
onPress={() => onPressRemove(item)}
|
|
305
|
+
onPressUpdate={() => onShowPopupUpdate(item, index)}
|
|
306
|
+
isActive={isActive}
|
|
307
|
+
drag={drag}
|
|
308
|
+
/>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
275
311
|
},
|
|
276
312
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
277
313
|
[needRefresh]
|
|
@@ -283,6 +319,7 @@ const EditActionsList = () => {
|
|
|
283
319
|
notify_script,
|
|
284
320
|
delay_script,
|
|
285
321
|
email_script,
|
|
322
|
+
sms_script,
|
|
286
323
|
id: scriptItemId,
|
|
287
324
|
} = scriptItem;
|
|
288
325
|
|
|
@@ -343,6 +380,18 @@ const EditActionsList = () => {
|
|
|
343
380
|
/>
|
|
344
381
|
);
|
|
345
382
|
}
|
|
383
|
+
if (sms_script) {
|
|
384
|
+
return (
|
|
385
|
+
<UpdateSmsScript
|
|
386
|
+
unitId={unitId}
|
|
387
|
+
automateId={id}
|
|
388
|
+
scriptItemId={scriptItemId}
|
|
389
|
+
sms_script={sms_script}
|
|
390
|
+
t={t}
|
|
391
|
+
onClosePopup={onClosePopup}
|
|
392
|
+
/>
|
|
393
|
+
);
|
|
394
|
+
}
|
|
346
395
|
}, [actionsList, id, navigate, scriptItem, t, unitId, updateIndex]);
|
|
347
396
|
|
|
348
397
|
const onDragEnd = useCallback(
|