@eohjsc/react-native-smart-city 0.7.15 → 0.7.17

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.
Files changed (25) hide show
  1. package/assets/images/Sms.svg +9 -0
  2. package/package.json +1 -1
  3. package/src/commons/Automate/ItemConditionScriptDetailStyles.js +1 -0
  4. package/src/commons/Unit/__test__/SharedUnit.test.js +57 -0
  5. package/src/configs/API.js +6 -1
  6. package/src/configs/AccessibilityLabel.js +4 -0
  7. package/src/hooks/Common/useBlockBack.js +10 -2
  8. package/src/navigations/UnitStack.js +24 -0
  9. package/src/screens/Automate/AddNewAction/SetupScriptReceiverSms.js +167 -0
  10. package/src/screens/Automate/AddNewAction/SetupScriptSms.js +73 -0
  11. package/src/screens/Automate/AddNewAction/Styles/SetupScriptEmailStyles.js +5 -0
  12. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverSms.test.js +105 -0
  13. package/src/screens/Automate/AddNewAction/__test__/SetupScriptSms.test.js +70 -0
  14. package/src/screens/Automate/EditActionsList/UpdateReceiverSmsScript.js +178 -0
  15. package/src/screens/Automate/EditActionsList/UpdateSmsScript.js +66 -0
  16. package/src/screens/Automate/EditActionsList/__tests__/UpdateReceiverSmsScript.test.js +82 -0
  17. package/src/screens/Automate/EditActionsList/__tests__/UpdateSmsScript.test.js +71 -0
  18. package/src/screens/Automate/EditActionsList/index.js +50 -1
  19. package/src/screens/Automate/ScriptDetail/Components/AddActionScript.js +52 -19
  20. package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +39 -2
  21. package/src/screens/Automate/ScriptDetail/__test__/index.test.js +295 -57
  22. package/src/screens/Automate/ScriptDetail/index.js +234 -32
  23. package/src/utils/I18n/translations/en.js +10 -0
  24. package/src/utils/I18n/translations/vi.js +10 -0
  25. package/src/utils/Route/index.js +3 -0
@@ -0,0 +1,9 @@
1
+ <svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M30.3334 0.333313H3.66671C1.83337 0.333313 0.350041 1.83331 0.350041 3.66665L0.333374 33.6666L7.00004 27H30.3334C32.1667 27 33.6667 25.5 33.6667 23.6666V3.66665C33.6667 1.83331 32.1667 0.333313 30.3334 0.333313ZM12 15.3333H8.66671V12H12V15.3333ZM18.6667 15.3333H15.3334V12H18.6667V15.3333ZM25.3334 15.3333H22V12H25.3334V15.3333Z" fill="url(#paint0_linear_3441_1581)"/>
3
+ <defs>
4
+ <linearGradient id="paint0_linear_3441_1581" x1="0.333374" y1="0.333313" x2="33.6298" y2="33.6667" gradientUnits="userSpaceOnUse">
5
+ <stop stop-color="#2B6B9F"/>
6
+ <stop offset="1" stop-color="#D5FFCB"/>
7
+ </linearGradient>
8
+ </defs>
9
+ </svg>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eohjsc/react-native-smart-city",
3
3
  "title": "React Native Smart Home",
4
- "version": "0.7.15",
4
+ "version": "0.7.17",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -11,6 +11,7 @@ export default StyleSheet.create({
11
11
  justifyContent: 'space-between',
12
12
  borderRadius: 8,
13
13
  marginTop: 16,
14
+ marginBottom: 16,
14
15
  shadowColor: Colors.Gray6,
15
16
  shadowOffset: {
16
17
  width: 0,
@@ -109,6 +109,63 @@ describe('Test SharedUnit', () => {
109
109
  });
110
110
  });
111
111
 
112
+ it('Test remove pin and start shared unit', async () => {
113
+ const navigation = useNavigation();
114
+ item.is_pin = true;
115
+ item.is_star = true;
116
+ const mockedRenewItem = jest.fn();
117
+ await act(async () => {
118
+ tree = await create(
119
+ wrapComponent(item, navigation, undefined, mockedRenewItem)
120
+ );
121
+ });
122
+ const instance = tree.root;
123
+
124
+ const iconAddPinSharedUnit = instance.findAll(
125
+ (el) =>
126
+ el.props.accessibilityLabel ===
127
+ AccessibilityLabel.ICON_ADD_PIN_SHARED_UNIT + '-69'
128
+ );
129
+ const iconAddStarSharedUnit = instance.findAll(
130
+ (el) =>
131
+ el.props.accessibilityLabel ===
132
+ AccessibilityLabel.ICON_ADD_STAR_SHARED_UNIT + '-69'
133
+ );
134
+
135
+ const iconRemovePinSharedUnit = instance.find(
136
+ (el) =>
137
+ el.props.accessibilityLabel ===
138
+ AccessibilityLabel.ICON_REMOVE_PIN_SHARED_UNIT + '-69'
139
+ );
140
+ mock.onPost(API.UNIT.UNPIN_UNIT(3)).reply(200);
141
+ await act(async () => {
142
+ iconRemovePinSharedUnit.props.onPress();
143
+ });
144
+ mock.onPost(API.UNIT.UNPIN_UNIT(3)).reply(400);
145
+ await act(async () => {
146
+ iconRemovePinSharedUnit.props.onPress();
147
+ });
148
+ expect(mockedRenewItem).toHaveBeenCalledTimes(1);
149
+
150
+ const iconRemoveStarSharedUnit = instance.find(
151
+ (el) =>
152
+ el.props.accessibilityLabel ===
153
+ AccessibilityLabel.ICON_REMOVE_STAR_SHARED_UNIT + '-69'
154
+ );
155
+ mock.onPost(API.UNIT.UNSTAR_UNIT(3)).reply(200);
156
+ await act(async () => {
157
+ iconRemoveStarSharedUnit.props.onPress();
158
+ });
159
+ mock.onPost(API.UNIT.UNSTAR_UNIT(3)).reply(400);
160
+ await act(async () => {
161
+ iconRemoveStarSharedUnit.props.onPress();
162
+ });
163
+
164
+ expect(mockedRenewItem).toHaveBeenCalledTimes(2);
165
+ expect(iconAddPinSharedUnit).toHaveLength(0);
166
+ expect(iconAddStarSharedUnit).toHaveLength(0);
167
+ });
168
+
112
169
  // it('test create SharedUnit unit without unit owner', async () => {
113
170
  // const navigation = useNavigation();
114
171
  // delete unit.owner_name;
@@ -108,6 +108,8 @@ const API = {
108
108
  `/property_manager/automate/${automateId}/update_script_action/`,
109
109
  UPDATE_SCRIPT_EMAIL: (automateId) =>
110
110
  `/property_manager/automate/${automateId}/update_script_email/`,
111
+ UPDATE_SCRIPT_SMS: (automateId) =>
112
+ `/property_manager/automate/${automateId}/update_script_sms/`,
111
113
  ADD_SCRIPT_ACTION: (id) =>
112
114
  `/property_manager/automate/${id}/add_script_action/`,
113
115
  ADD_SCRIPT_NOTIFY: (id) =>
@@ -116,7 +118,7 @@ const API = {
116
118
  `/property_manager/automate/${id}/add_script_delay/`,
117
119
  ADD_SCRIPT_EMAIL: (id) =>
118
120
  `/property_manager/automate/${id}/add_script_email/`,
119
-
121
+ ADD_SCRIPT_SMS: (id) => `/property_manager/automate/${id}/add_script_sms/`,
120
122
  FETCH_AUTOMATE: (automateId) => `/property_manager/automate/${automateId}/`,
121
123
  CREATE_AUTOMATE: () => '/property_manager/automate/',
122
124
  UPDATE_AUTOMATE: (automateId) =>
@@ -131,6 +133,8 @@ const API = {
131
133
  GET_MULTI_UNITS: () => '/property_manager/automate/multi_unit/',
132
134
  ACTIVITY_LOG: (id) => `/property_manager/automate/${id}/logs/`,
133
135
  STARRED_SCRIPTS: () => '/property_manager/automate/starred_scripts/',
136
+ ENABLE_LOCAL_CONTROL: (id) =>
137
+ `/property_manager/automate/${id}/enable_local_control/`,
134
138
  },
135
139
  HOME_ASSISTANT: {
136
140
  CHECK_SEND_EMAIL: () =>
@@ -245,6 +249,7 @@ const API = {
245
249
  COUNT: () => '/chip_manager/developer_mode_chips/count/',
246
250
  DETAIL: (id) => `/chip_manager/developer_mode_chips/${id}/`,
247
251
  REBOOT: (id) => `/chip_manager/developer_mode_chips/${id}/reboot_chip/`,
252
+ SHARED: () => '/property_manager/iot_dashboard/filters/chip_shared/',
248
253
  },
249
254
  ARDUINO: {
250
255
  DETAIL: (id) => `/iot/modules/arduino/gateways/${id}/`,
@@ -251,6 +251,10 @@ export default {
251
251
  AUTOMATE_TITLE_NOTIFY: 'AUTOMATE_TITLE_NOTIFY',
252
252
  AUTOMATE_MESSAGE_NOTIFY: 'AUTOMATE_MESSAGE_NOTIFY',
253
253
  AUTOMATE_INPUT_DELAY: 'AUTOMATE_INPUT_DELAY',
254
+ AUTOMATE_SHOW_LOCAL_CONTROL: 'AUTOMATE_SHOW_LOCAL_CONTROL',
255
+ AUTOMATE_DISABLE_LOCAL_CONTROL: 'AUTOMATE_DISABLE_LOCAL_CONTROL',
256
+ AUTOMATE_ENABLE_LOCAL_CONTROL: 'AUTOMATE_ENABLE_LOCAL_CONTROL',
257
+
254
258
  // Parking input maunaly spot
255
259
  PARKING_SPOT_INFO_BUTTON: 'PARKING_SPOT_INFO_BUTTON',
256
260
  PARKING_SPOT_CONFIRM_SPOT: 'PARKING_SPOT_CONFIRM_SPOT',
@@ -5,6 +5,7 @@ import { BackHandler, Platform } from 'react-native';
5
5
  export const useBlockBack = (actionBack) => {
6
6
  const navigation = useNavigation();
7
7
  const isListening = useRef(false);
8
+ const isBeforeRemoveHandled = useRef(false);
8
9
 
9
10
  const blockBack = useCallback(() => {
10
11
  actionBack && actionBack();
@@ -13,8 +14,15 @@ export const useBlockBack = (actionBack) => {
13
14
 
14
15
  const blockBeforeRemove = useCallback(
15
16
  (e) => {
16
- e.preventDefault();
17
- blockBack();
17
+ if (isBeforeRemoveHandled.current) {
18
+ return;
19
+ }
20
+ const { type } = e.data.action;
21
+ if (type === 'GO_BACK' || type === 'POP') {
22
+ isBeforeRemoveHandled.current = true;
23
+ e.preventDefault();
24
+ blockBack();
25
+ }
18
26
  },
19
27
  [blockBack]
20
28
  );
@@ -72,6 +72,9 @@ import { HanetCameraStack } from './HanetCameraStack';
72
72
  import { styles } from './UnitStackStyles';
73
73
  import { bleManager } from '../utils/bluetooth';
74
74
  import UpdateReceiverEmailScript from '../screens/Automate/EditActionsList/UpdateReceiverEmailScript';
75
+ import SetupScriptSms from '../screens/Automate/AddNewAction/SetupScriptSms';
76
+ import SetupScriptReceiverSms from '../screens/Automate/AddNewAction/SetupScriptReceiverSms';
77
+ import UpdateReceiverSmsScript from '../screens/Automate/EditActionsList/UpdateReceiverSmsScript';
75
78
 
76
79
  const Stack = createNativeStackNavigator();
77
80
 
@@ -446,6 +449,27 @@ export const UnitStack = memo((props) => {
446
449
  headerShown: false,
447
450
  }}
448
451
  />
452
+ <Stack.Screen
453
+ name={Route.SetupScriptSms}
454
+ component={SetupScriptSms}
455
+ options={{
456
+ headerShown: false,
457
+ }}
458
+ />
459
+ <Stack.Screen
460
+ name={Route.SetupScriptReceiverSms}
461
+ component={SetupScriptReceiverSms}
462
+ options={{
463
+ headerShown: false,
464
+ }}
465
+ />
466
+ <Stack.Screen
467
+ name={Route.UpdateReceiverSmsScript}
468
+ component={UpdateReceiverSmsScript}
469
+ options={{
470
+ headerShown: false,
471
+ }}
472
+ />
449
473
  <Stack.Screen
450
474
  name={Route.AddAutomationTypeSmart}
451
475
  component={AddAutomationTypeSmart}
@@ -0,0 +1,167 @@
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/SetupScriptReceiverEmailStyles';
5
+ import { CircleView, HeaderCustom, Text } from '../../../commons';
6
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
7
+
8
+ import BottomButtonView from '../../../commons/BottomButtonView';
9
+ import { axiosPost, axiosGet } from '../../../utils/Apis/axios';
10
+ import { API, Colors } from '../../../configs';
11
+ import { ToastBottomHelper } from '../../../utils/Utils';
12
+ import Routes from '../../../utils/Route';
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 SetupScriptReceiverSms = ({ route }) => {
19
+ const t = useTranslations();
20
+ const { goBack, navigate } = useNavigation();
21
+ const { automate = {}, unitId, formData } = route.params || {};
22
+ const { id: automateId } = automate;
23
+ const [members, setMembers] = useState([]);
24
+ 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
+
40
+ const onNext = useCallback(async () => {
41
+ formData.receiver = listUser;
42
+ const { success } = await axiosPost(
43
+ API.AUTOMATE.ADD_SCRIPT_SMS(automateId),
44
+ formData
45
+ );
46
+ if (success) {
47
+ ToastBottomHelper.success(t('text_done'));
48
+ navigate({
49
+ name: Routes.ScriptDetail,
50
+ merge: true,
51
+ params: { saveAt: moment().valueOf() },
52
+ });
53
+ } else {
54
+ ToastBottomHelper.error(t('error_please_try_later'));
55
+ }
56
+ }, [automateId, formData, listUser, navigate, t]);
57
+
58
+ const canSave = useMemo(() => {
59
+ const { message } = formData;
60
+ return !!message && !!listUser.length;
61
+ }, [formData, listUser.length]);
62
+
63
+ const arrColor = useMemo(
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
+ );
83
+ },
84
+ []
85
+ );
86
+
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
+ return (
141
+ <View style={styles.wrap}>
142
+ <HeaderCustom isShowClose onClose={goBack} title={t('sms_to')} />
143
+ <FlatList
144
+ data={members}
145
+ renderItem={({ item, index }) => (
146
+ <RowMember member={item} index={index} onValueChange={onChecked} />
147
+ )}
148
+ keyExtractor={(item) => item.id.toString()}
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>
164
+ );
165
+ };
166
+
167
+ export default SetupScriptReceiverSms;
@@ -0,0 +1,73 @@
1
+ import React, { useCallback, useMemo, useState } from 'react';
2
+ import { Keyboard, TouchableWithoutFeedback, View } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+ import styles from './Styles/SetupScriptEmailStyles';
5
+ import { HeaderCustom, Text } from '../../../commons';
6
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
7
+
8
+ import _TextInput from '../../../commons/Form/TextInput';
9
+ import AccessibilityLabel from '../../../configs/AccessibilityLabel';
10
+ import BottomButtonView from '../../../commons/BottomButtonView';
11
+ import Routes from '../../../utils/Route';
12
+ import { Colors } from '../../../configs';
13
+
14
+ const SetupScriptSms = ({ route }) => {
15
+ const t = useTranslations();
16
+ const { goBack, navigate } = useNavigation();
17
+ const { automate, unitId, multiUnit } = route.params || {};
18
+ const initialUnitId = useMemo(
19
+ () => unitId || multiUnit.id,
20
+ [unitId, multiUnit?.id]
21
+ );
22
+ const [formData, setFormData] = useState({ unit: initialUnitId });
23
+
24
+ const onChangeMessage = (value) => {
25
+ setFormData((state) => ({
26
+ ...state,
27
+ message: value,
28
+ }));
29
+ };
30
+
31
+ const onNext = useCallback(async () => {
32
+ navigate(Routes.SetupScriptReceiverSms, {
33
+ automate,
34
+ unitId: initialUnitId,
35
+ formData,
36
+ });
37
+ }, [navigate, automate, initialUnitId, formData]);
38
+
39
+ const canSave = useMemo(() => {
40
+ const { message } = formData || {};
41
+ return !!message;
42
+ }, [formData]);
43
+
44
+ return (
45
+ <View style={styles.wrap}>
46
+ <HeaderCustom isShowClose onClose={goBack} title={t('sms_content')} />
47
+ <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
48
+ <View style={styles.container}>
49
+ <_TextInput
50
+ placeholder={t('message_sms')}
51
+ onChange={onChangeMessage}
52
+ textInputStyle={styles.textMessage}
53
+ value={formData?.message}
54
+ accessibilityLabel={AccessibilityLabel.AUTOMATE_MESSAGE_NOTIFY}
55
+ multiline={true}
56
+ maxLength={255}
57
+ />
58
+ <View style={styles.textWarning}>
59
+ <Text color={Colors.Gray}>{t('only_in_local_control')}</Text>
60
+ </View>
61
+ <BottomButtonView
62
+ style={styles.bottomButtonView}
63
+ mainTitle={t('next')}
64
+ onPressMain={onNext}
65
+ typeMain={canSave ? 'primary' : 'disabled'}
66
+ />
67
+ </View>
68
+ </TouchableWithoutFeedback>
69
+ </View>
70
+ );
71
+ };
72
+
73
+ export default SetupScriptSms;
@@ -27,6 +27,11 @@ export default StyleSheet.create({
27
27
  borderStyle: 'solid',
28
28
  borderRadius: 10,
29
29
  },
30
+ textWarning: {
31
+ marginTop: 5,
32
+ justifyContent: 'center',
33
+ alignItems: 'center',
34
+ },
30
35
  bottomButtonView: {
31
36
  paddingTop: 24,
32
37
  paddingBottom: 32,
@@ -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
+ });