@eohjsc/react-native-smart-city 0.2.98 → 0.2.99

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 (47) hide show
  1. package/README.md +35 -14
  2. package/package.json +1 -1
  3. package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +2 -2
  4. package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +3 -3
  5. package/src/commons/ActionGroup/OnOffTemplate/OnOffSimpleTemplate.js +1 -3
  6. package/src/commons/ActionGroup/OnOffTemplate/index.js +15 -45
  7. package/src/commons/ActionGroup/TwoButtonTemplate/index.js +6 -6
  8. package/src/commons/FieldTemplate/ChooseUserField/ChooseFieldStyles.js +25 -0
  9. package/src/commons/FieldTemplate/ChooseUserField/ChoosePopup.js +96 -0
  10. package/src/commons/FieldTemplate/ChooseUserField/ChoosePopupStyles.js +39 -0
  11. package/src/commons/FieldTemplate/ChooseUserField/__test__/index.test.js +113 -0
  12. package/src/commons/FieldTemplate/ChooseUserField/index.js +62 -0
  13. package/src/commons/FieldTemplate/PasscodeField/PasscodeFieldStyles.js +30 -0
  14. package/src/commons/FieldTemplate/PasscodeField/__test__/index.test.js +93 -0
  15. package/src/commons/FieldTemplate/PasscodeField/index.js +43 -0
  16. package/src/commons/FieldTemplate/ScheduleField/ScheduleFieldStyles.js +13 -0
  17. package/src/commons/FieldTemplate/ScheduleField/__test__/index.test.js +182 -0
  18. package/src/commons/FieldTemplate/ScheduleField/index.js +176 -0
  19. package/src/commons/WheelDateTimePicker/index.js +2 -1
  20. package/src/configs/API.js +3 -0
  21. package/src/configs/Constants.js +12 -1
  22. package/src/context/actionType.ts +0 -1
  23. package/src/context/reducer.ts +0 -3
  24. package/src/navigations/UnitStack.js +8 -0
  25. package/src/screens/AddNewAction/SelectSensorDevices.js +2 -1
  26. package/src/screens/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +3 -1
  27. package/src/screens/AddNewAutoSmart/index.js +5 -2
  28. package/src/screens/AddNewOneTap/__test__/AddNewOneTap.test.js +1 -1
  29. package/src/screens/AddNewOneTap/index.js +2 -1
  30. package/src/screens/Device/__test__/detail.test.js +4 -4
  31. package/src/screens/Device/detail.js +29 -12
  32. package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +5 -2
  33. package/src/screens/GuestInfo/__test__/index.test.js +1 -1
  34. package/src/screens/GuestInfo/components/RecurringDetail.js +1 -0
  35. package/src/screens/GuestInfo/components/TemporaryDetail.js +2 -2
  36. package/src/screens/ScanChipQR/components/QRScan/index.js +1 -0
  37. package/src/screens/ScriptDetail/index.js +1 -1
  38. package/src/screens/SelectUnit/__test__/index.test.js +1 -1
  39. package/src/screens/SelectUnit/index.js +4 -2
  40. package/src/screens/SetSchedule/index.js +2 -1
  41. package/src/screens/Sharing/SelectPermission.js +0 -1
  42. package/src/screens/SideMenuDetail/SideMenuDetailStyles.js +28 -0
  43. package/src/screens/SideMenuDetail/__test__/index.test.js +165 -0
  44. package/src/screens/SideMenuDetail/index.js +149 -0
  45. package/src/utils/I18n/translations/en.json +1 -0
  46. package/src/utils/I18n/translations/vi.json +1 -0
  47. package/src/utils/Route/index.js +1 -0
@@ -0,0 +1,30 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors } from '../../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ wrapper: {
6
+ flexDirection: 'row',
7
+ justifyContent: 'space-between',
8
+ alignItems: 'center',
9
+ paddingTop: 30,
10
+ },
11
+ invalid: {
12
+ width: 90,
13
+ textAlign: 'center',
14
+ borderWidth: 0,
15
+ borderBottomWidth: 1,
16
+ borderBottomColor: Colors.Red,
17
+ },
18
+ valid: {
19
+ width: 90,
20
+ textAlign: 'center',
21
+ borderWidth: 0,
22
+ borderBottomWidth: 1,
23
+ borderBottomColor: Colors.Primary,
24
+ },
25
+ textHeadLine: {
26
+ fontSize: 16,
27
+ color: Colors.Gray9,
28
+ fontWeight: 'bold',
29
+ },
30
+ });
@@ -0,0 +1,93 @@
1
+ import React from 'react';
2
+ import axios from 'axios';
3
+ import { act, create } from 'react-test-renderer';
4
+ import { TESTID } from '../../../../configs/Constants';
5
+ import { mockSCStore } from '../../../../context/mockStore';
6
+ import { SCProvider } from '../../../../context';
7
+ import PasscodeField from '../index';
8
+
9
+ jest.mock('axios');
10
+ const mockSetState = jest.fn();
11
+
12
+ const wrapComponent = (
13
+ dataItem = {
14
+ type: 'passcode',
15
+ key: 'passcode',
16
+ action: {
17
+ type: 'action_zigbee',
18
+ id: 1,
19
+ },
20
+ },
21
+ index = 0,
22
+ dataForm = [
23
+ {
24
+ type: 'passcode',
25
+ key: 'passcode',
26
+ action: {
27
+ type: 'action_zigbee',
28
+ id: 1,
29
+ },
30
+ },
31
+ ]
32
+ ) => (
33
+ <SCProvider initState={mockSCStore({})}>
34
+ <PasscodeField
35
+ dataItem={dataItem}
36
+ index={index}
37
+ setDataForm={mockSetState}
38
+ dataForm={dataForm}
39
+ />
40
+ </SCProvider>
41
+ );
42
+
43
+ describe('Test PasscodeField', () => {
44
+ let tree;
45
+
46
+ afterEach(() => {
47
+ axios.get.mockClear();
48
+ mockSetState.mockClear();
49
+ });
50
+
51
+ test('render PasscodeField', async () => {
52
+ await act(async () => {
53
+ tree = create(wrapComponent());
54
+ });
55
+
56
+ const instance = tree.root;
57
+ const inputPasscode = instance.find(
58
+ (item) => item.props.testID === TESTID.PASSCODE_FIELD
59
+ );
60
+
61
+ await act(async () => {
62
+ await inputPasscode.props.onChangeText('123');
63
+ });
64
+ expect(mockSetState).toBeCalledWith([
65
+ {
66
+ key: 'passcode',
67
+ type: 'passcode',
68
+ valid: false,
69
+ action: {
70
+ id: 1,
71
+ type: 'action_zigbee',
72
+ },
73
+ },
74
+ ]);
75
+
76
+ await act(async () => {
77
+ await inputPasscode.props.onChangeText('123456');
78
+ });
79
+ expect(mockSetState).toBeCalledWith([
80
+ {
81
+ key: 'passcode',
82
+ type: 'passcode',
83
+ data: '123456',
84
+ valid: true,
85
+ action: {
86
+ id: 1,
87
+ type: 'action_zigbee',
88
+ },
89
+ action_zigbee: 1,
90
+ },
91
+ ]);
92
+ });
93
+ });
@@ -0,0 +1,43 @@
1
+ import React, { memo, useCallback, useState } from 'react';
2
+ import { Text, TextInput, View } from 'react-native';
3
+ import { TESTID } from '../../../configs/Constants';
4
+
5
+ import styles from './PasscodeFieldStyles';
6
+
7
+ const PasscodeField = ({ dataItem, index, setDataForm, dataForm }) => {
8
+ const [invalid, setInvaild] = useState(false);
9
+ const onChangeText = useCallback(
10
+ (value) => {
11
+ if (value.length >= 4 && value.length <= 10) {
12
+ dataItem.data = value;
13
+ dataItem.valid = true;
14
+ dataItem[dataItem.action.type] = dataItem.action.id;
15
+ dataForm[index] = dataItem;
16
+ setInvaild(false);
17
+ setDataForm([...dataForm]);
18
+ } else {
19
+ dataItem.valid = false;
20
+ dataForm[index] = dataItem;
21
+ setInvaild(true);
22
+ setDataForm([...dataForm]);
23
+ }
24
+ },
25
+ // eslint-disable-next-line react-hooks/exhaustive-deps
26
+ []
27
+ );
28
+
29
+ return (
30
+ <View style={styles.wrapper}>
31
+ <Text style={styles.textHeadLine}>{'Passcode'}</Text>
32
+ <TextInput
33
+ testID={TESTID.PASSCODE_FIELD}
34
+ style={invalid ? styles.invalid : styles.valid}
35
+ placeholder={'******'}
36
+ keyboardType={'numeric'}
37
+ maxLength={10}
38
+ onChangeText={onChangeText}
39
+ />
40
+ </View>
41
+ );
42
+ };
43
+ export default memo(PasscodeField);
@@ -0,0 +1,13 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors } from '../../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ wrapper: {
6
+ paddingTop: 30,
7
+ },
8
+ textHeadLine: {
9
+ fontSize: 16,
10
+ color: Colors.Gray9,
11
+ fontWeight: 'bold',
12
+ },
13
+ });
@@ -0,0 +1,182 @@
1
+ import React from 'react';
2
+ import axios from 'axios';
3
+ import { act, create } from 'react-test-renderer';
4
+ import { mockSCStore } from '../../../../context/mockStore';
5
+ import { SCProvider } from '../../../../context';
6
+ import ScheduleField from '../index';
7
+ import { TESTID } from '../../../../configs/Constants';
8
+ import { TouchableOpacity } from 'react-native';
9
+
10
+ jest.mock('axios');
11
+ const mockSetState = jest.fn();
12
+
13
+ const wrapComponent = (
14
+ dataItem = {
15
+ type: 'schedule',
16
+ key: 'schedule',
17
+ action: {
18
+ type: 'action_zigbee',
19
+ id: {
20
+ always: 2,
21
+ recurring: 4,
22
+ temporary: 5,
23
+ },
24
+ },
25
+ },
26
+ index = 0,
27
+ dataForm = [
28
+ {
29
+ type: 'schedule',
30
+ key: 'schedule',
31
+ action: {
32
+ type: 'action_zigbee',
33
+ id: {
34
+ always: 2,
35
+ recurring: 4,
36
+ temporary: 5,
37
+ },
38
+ },
39
+ },
40
+ ]
41
+ ) => (
42
+ <SCProvider initState={mockSCStore({})}>
43
+ <ScheduleField
44
+ dataItem={dataItem}
45
+ index={index}
46
+ setDataForm={mockSetState}
47
+ dataForm={dataForm}
48
+ />
49
+ </SCProvider>
50
+ );
51
+
52
+ describe('Test ScheduleField', () => {
53
+ let tree;
54
+ beforeEach(() => {
55
+ Date.now = jest.fn(() => new Date('2022-05-30T15:50:36+01:00'));
56
+ });
57
+ afterEach(() => {
58
+ axios.get.mockClear();
59
+ mockSetState.mockClear();
60
+ });
61
+
62
+ const onPressRecurring = async (instance, schedule) => {
63
+ await act(async () => {
64
+ await schedule.props.onPress();
65
+ });
66
+ const recurring = instance.find(
67
+ (el) =>
68
+ el.props.testID === '0' + TESTID.RECURRING_REPEAT_ITEM &&
69
+ el.type === TouchableOpacity
70
+ );
71
+ await act(async () => {
72
+ await recurring.props.onPress();
73
+ });
74
+ expect(mockSetState).toBeCalledWith([
75
+ {
76
+ key: 'schedule',
77
+ type: 'schedule',
78
+ data: {
79
+ access_schedule: 'recurring',
80
+ recurring_time_end: '2022-05-30T16:50:36+01:00',
81
+ recurring_time_repeat: ['6'],
82
+ recurring_time_start: '2022-05-30T15:50:36+01:00',
83
+ },
84
+ valid: true,
85
+ action: {
86
+ id: {
87
+ always: 2,
88
+ recurring: 4,
89
+ temporary: 5,
90
+ },
91
+ type: 'action_zigbee',
92
+ },
93
+ action_zigbee: 4,
94
+ },
95
+ ]);
96
+ mockSetState.mockClear();
97
+ };
98
+
99
+ const onPressTemporary = async (instance, schedule) => {
100
+ await act(async () => {
101
+ await schedule.props.onPress();
102
+ });
103
+
104
+ expect(mockSetState).toBeCalledWith([
105
+ {
106
+ key: 'schedule',
107
+ type: 'schedule',
108
+ data: {
109
+ access_schedule: 'temporary',
110
+ temporary_time_end: '2022-05-31T15:50:36+01:00',
111
+ temporary_time_start: '2022-05-30T15:50:36+01:00',
112
+ },
113
+ valid: true,
114
+ action: {
115
+ id: {
116
+ always: 2,
117
+ recurring: 4,
118
+ temporary: 5,
119
+ },
120
+ type: 'action_zigbee',
121
+ },
122
+ action_zigbee: 5,
123
+ },
124
+ ]);
125
+ const temporaryEnd = instance.find(
126
+ (el) =>
127
+ el.props.testID === TESTID.TEMPORARY_END_TEXT_BUTTON &&
128
+ el.type === TouchableOpacity
129
+ );
130
+ await act(async () => {
131
+ await temporaryEnd.props.onPress();
132
+ });
133
+ const dateTimePicker = instance.find(
134
+ (el) => el.props.testID === TESTID.WHEEL_DATE_TIME_PICKER
135
+ );
136
+ expect(dateTimePicker.props.isVisible).toBeTruthy();
137
+ const popupDateTimePickerDone = instance.find(
138
+ (el) =>
139
+ el.props.testID ===
140
+ `${TESTID.WHEEL_DATE_TIME_PICKER_BUTTON}${TESTID.VIEW_BUTTON_BOTTOM_RIGHT_BUTTON}` &&
141
+ el.type === TouchableOpacity
142
+ );
143
+ await act(async () => {
144
+ await popupDateTimePickerDone.props.onPress();
145
+ });
146
+ expect(dateTimePicker.props.isVisible).toBeFalsy();
147
+ mockSetState.mockClear();
148
+ };
149
+
150
+ test('render ScheduleField choose schedule', async () => {
151
+ await act(async () => {
152
+ tree = await create(wrapComponent());
153
+ });
154
+ expect(mockSetState).toBeCalledWith([
155
+ {
156
+ key: 'schedule',
157
+ type: 'schedule',
158
+ data: { access_schedule: 'always' },
159
+ valid: true,
160
+ action: {
161
+ id: {
162
+ always: 2,
163
+ recurring: 4,
164
+ temporary: 5,
165
+ },
166
+ type: 'action_zigbee',
167
+ },
168
+ action_zigbee: 2,
169
+ },
170
+ ]);
171
+ mockSetState.mockClear();
172
+ const instance = tree.root;
173
+ const schedule = instance.findAll(
174
+ (el) =>
175
+ el.props.testID === TESTID.ACCESS_SCHEDULE_RADIO_BUTTON &&
176
+ el.type === TouchableOpacity
177
+ );
178
+ expect(schedule).toHaveLength(3);
179
+ await onPressRecurring(instance, schedule[1]);
180
+ await onPressTemporary(instance, schedule[2]);
181
+ });
182
+ });
@@ -0,0 +1,176 @@
1
+ import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { View } from 'react-native';
3
+ import styles from './ScheduleFieldStyles';
4
+ import moment from 'moment';
5
+
6
+ import Text from '../../Text';
7
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
8
+ import AccessScheduleItem from '../../../screens/GuestInfo/components/AccessScheduleItem';
9
+ import RecurringDetail from '../../../screens/GuestInfo/components/RecurringDetail';
10
+ import TemporaryDetail from '../../../screens/GuestInfo/components/TemporaryDetail';
11
+ import { useBoolean } from '../../../hooks/Common';
12
+ import WheelDateTimePicker from '../../WheelDateTimePicker';
13
+ import { ACCESS_SCHEDULE } from '../../../screens/GuestInfo/constant';
14
+
15
+ const ScheduleField = ({ dataItem, index, setDataForm, dataForm }) => {
16
+ const t = useTranslations();
17
+ const [accessSchedule, setAccessSchedule] = useState('always');
18
+ const [lockShowing, releaseLockShowing, acquireLockShowing] =
19
+ useBoolean(true);
20
+
21
+ const [stateDateTimePicker, setStateDateTimePicker] = useState({
22
+ isVisible: false,
23
+ mode: 'time',
24
+ defaultValue: moment(),
25
+ setter: null,
26
+ });
27
+ const [recurringTimeStart, setRecurringTimeStart] = useState(moment());
28
+ const [recurringTimeEnd, setRecurringTimeEnd] = useState(
29
+ moment().add(1, 'hours')
30
+ );
31
+ const [recurringTimeRepeat, setRecurringTimeRepeat] = useState([]);
32
+ const [temporaryTimeStart, setTemporaryTimeStart] = useState(moment());
33
+ const [temporaryTimeEnd, setTemporaryTimeEnd] = useState(
34
+ moment().add(1, 'days')
35
+ );
36
+ useEffect(() => {
37
+ if (accessSchedule === ACCESS_SCHEDULE.ALWAYS) {
38
+ dataItem.valid = true;
39
+ dataItem.data = {
40
+ access_schedule: accessSchedule,
41
+ };
42
+ } else if (accessSchedule === ACCESS_SCHEDULE.RECURRING) {
43
+ dataItem.valid = true;
44
+ dataItem.data = {
45
+ access_schedule: accessSchedule,
46
+ recurring_time_start: recurringTimeStart.format(),
47
+ recurring_time_end: recurringTimeEnd.format(),
48
+ recurring_time_repeat: recurringTimeRepeat,
49
+ };
50
+ } else if (accessSchedule === ACCESS_SCHEDULE.TEMPORARY) {
51
+ if (temporaryTimeStart > temporaryTimeEnd) {
52
+ dataItem.valid = false;
53
+ } else {
54
+ dataItem.valid = true;
55
+ dataItem.data = {
56
+ access_schedule: accessSchedule,
57
+ temporary_time_start: temporaryTimeStart.format(),
58
+ temporary_time_end: temporaryTimeEnd.format(),
59
+ };
60
+ }
61
+ }
62
+ dataItem[dataItem.action.type] = dataItem.action.id[accessSchedule];
63
+ dataForm[index] = dataItem;
64
+ setDataForm([...dataForm]);
65
+ // eslint-disable-next-line react-hooks/exhaustive-deps
66
+ }, [
67
+ accessSchedule,
68
+ recurringTimeEnd,
69
+ recurringTimeRepeat,
70
+ recurringTimeStart,
71
+ temporaryTimeEnd,
72
+ temporaryTimeStart,
73
+ ]);
74
+ const onShowSetDateTime = useCallback(
75
+ (currentValue, setter, mode) => {
76
+ releaseLockShowing();
77
+ setStateDateTimePicker((state) => ({
78
+ ...state,
79
+ isVisible: true,
80
+ mode: mode,
81
+ defaultValue: currentValue,
82
+ setter: setter,
83
+ }));
84
+ },
85
+ [releaseLockShowing]
86
+ );
87
+
88
+ const onHideSetDateTime = useCallback(() => {
89
+ acquireLockShowing();
90
+ setStateDateTimePicker((state) => ({
91
+ ...state,
92
+ isVisible: false,
93
+ }));
94
+ }, [setStateDateTimePicker, acquireLockShowing]);
95
+
96
+ const onDateTimePicked = useCallback(
97
+ (timeData) => {
98
+ const setter = stateDateTimePicker.setter;
99
+ setter && setter(moment(timeData));
100
+ },
101
+ [stateDateTimePicker]
102
+ );
103
+
104
+ const listAccessSchedule = useMemo(
105
+ () => [
106
+ {
107
+ text: t(`${ACCESS_SCHEDULE.ALWAYS}`),
108
+ value: ACCESS_SCHEDULE.ALWAYS,
109
+ detail: () => <></>,
110
+ },
111
+ {
112
+ text: t(`${ACCESS_SCHEDULE.RECURRING}`),
113
+ value: ACCESS_SCHEDULE.RECURRING,
114
+ detail: () => (
115
+ <RecurringDetail
116
+ onShowSetDateTime={onShowSetDateTime}
117
+ recurringTimeStart={recurringTimeStart}
118
+ recurringTimeEnd={recurringTimeEnd}
119
+ recurringTimeRepeat={recurringTimeRepeat}
120
+ setRecurringTimeStart={setRecurringTimeStart}
121
+ setRecurringTimeEnd={setRecurringTimeEnd}
122
+ setRecurringTimeRepeat={setRecurringTimeRepeat}
123
+ />
124
+ ),
125
+ },
126
+ {
127
+ text: t(`${ACCESS_SCHEDULE.TEMPORARY}`),
128
+ value: ACCESS_SCHEDULE.TEMPORARY,
129
+ detail: () => (
130
+ <TemporaryDetail
131
+ onShowSetDateTime={onShowSetDateTime}
132
+ temporaryTimeStart={temporaryTimeStart}
133
+ temporaryTimeEnd={temporaryTimeEnd}
134
+ setTemporaryTimeStart={setTemporaryTimeStart}
135
+ setTemporaryTimeEnd={setTemporaryTimeEnd}
136
+ />
137
+ ),
138
+ },
139
+ ],
140
+ // eslint-disable-next-line react-hooks/exhaustive-deps
141
+ [
142
+ onShowSetDateTime,
143
+ recurringTimeEnd,
144
+ recurringTimeRepeat,
145
+ recurringTimeStart,
146
+ temporaryTimeEnd,
147
+ temporaryTimeStart,
148
+ ]
149
+ );
150
+
151
+ return (
152
+ <View style={styles.wrapper}>
153
+ <Text style={styles.textHeadLine}>{t('access_schedule')}</Text>
154
+
155
+ {listAccessSchedule.map((item, index) => (
156
+ <AccessScheduleItem
157
+ key={index}
158
+ item={item}
159
+ isSelected={item.value === accessSchedule}
160
+ onSelect={setAccessSchedule}
161
+ isSetupGeneratePasscode
162
+ />
163
+ ))}
164
+ <WheelDateTimePicker
165
+ mode={stateDateTimePicker.mode}
166
+ isVisible={stateDateTimePicker.isVisible && lockShowing}
167
+ defaultValue={stateDateTimePicker.defaultValue}
168
+ onPicked={onDateTimePicked}
169
+ onCancel={onHideSetDateTime}
170
+ onHide={releaseLockShowing}
171
+ />
172
+ </View>
173
+ );
174
+ };
175
+
176
+ export default memo(ScheduleField);
@@ -104,6 +104,7 @@ const WheelDateTimePicker = ({
104
104
 
105
105
  return (
106
106
  <BottomSheet
107
+ testID={TESTID.WHEEL_DATE_TIME_PICKER}
107
108
  isVisible={isVisible}
108
109
  onBackdropPress={onPickerCancel}
109
110
  onHide={onHide}
@@ -173,7 +174,7 @@ const WheelDateTimePicker = ({
173
174
  onLeftClick={onPickerCancel}
174
175
  rightTitle={t('done')}
175
176
  onRightClick={onDone}
176
- testIDPrefix={TESTID.WHEEL_DATE_TIME_PICKER}
177
+ testIDPrefix={TESTID.WHEEL_DATE_TIME_PICKER_BUTTON}
177
178
  />
178
179
  </BottomSheet>
179
180
  );
@@ -65,6 +65,9 @@ const API = {
65
65
  SCConfig.apiRoot + `/property_manager/sensors/${id}/`,
66
66
  DISPLAY: (id) =>
67
67
  SCConfig.apiRoot + `/property_manager/sensors/${id}/display/`,
68
+ SIDE_MENU_DETAIL: (id, side_menu_id) =>
69
+ SCConfig.apiRoot +
70
+ `/property_manager/sensors/${id}/display/side_menu/${side_menu_id}/`,
68
71
  DISPLAY_VALUES: (id) =>
69
72
  SCConfig.apiRoot + `/property_manager/sensors/${id}/display_values/`,
70
73
  DISPLAY_VALUES_V2: (id) =>
@@ -674,13 +674,16 @@ export const TESTID = {
674
674
 
675
675
  // WheelDateTimePicker
676
676
  WHEEL_DATE_TIME_PICKER: 'WHEEL_DATE_TIME_PICKER',
677
+ WHEEL_DATE_TIME_PICKER_BUTTON: 'WHEEL_DATE_TIME_PICKER_BUTTON',
677
678
 
678
679
  // GuestInfo
679
680
  SAVE_ACCESS_SCHEDULE: 'SAVE_ACCESS_SCHEDULE',
680
681
  ACCESS_SCHEDULE_RADIO_BUTTON: 'ACCESS_SCHEDULE_RADIO_BUTTON',
681
682
  ACCESS_SCHEDULE_SHEET: 'ACCESS_SCHEDULE_SHEET',
682
683
  RECURRING_TEXT_BUTTON: 'RECURRING_TEXT_BUTTON',
683
- TEMPORARY_TEXT_BUTTON: 'TEMPORARY_TEXT_BUTTON',
684
+ RECURRING_REPEAT_ITEM: 'RECURRING_REPEAT_ITEM',
685
+ TEMPORARY_START_TEXT_BUTTON: 'TEMPORARY_START_TEXT_BUTTON',
686
+ TEMPORARY_END_TEXT_BUTTON: 'TEMPORARY_END_TEXT_BUTTON',
684
687
 
685
688
  // ActivityLog
686
689
  FILTER_BUTTON: 'FILTER_BUTTON',
@@ -726,6 +729,14 @@ export const TESTID = {
726
729
  //PreventAccess
727
730
  BUTTON_PREVENT_ACCESS: 'BUTTON_PREVENT_ACCESS',
728
731
  TEXT_PREVENT_ACCESS: 'TEXT_PREVENT_ACCESS',
732
+
733
+ //Template field
734
+ CHOOSE_FIELD: 'CHOOSE_FIELD',
735
+ CHOOSE_POPUP: 'CHOOSE_POPUP',
736
+ CHOOSE_ITEM: 'CHOOSE_ITEM',
737
+
738
+ PASSCODE_FIELD: 'PASSCODE_FIELD',
739
+ SUBMIT: 'SUBMIT',
729
740
  };
730
741
 
731
742
  export const NOTIFICATION_TYPES = {
@@ -17,7 +17,6 @@ export const Action = {
17
17
  SET_STARRED_SCRIPTS: 'SET_STARRED_SCRIPTS',
18
18
  STAR_SCRIPT: 'STAR_SCRIPT',
19
19
  UNSTAR_SCRIPT: 'UNSTAR_SCRIPT',
20
- IS_FULL_LOADING: 'IS_FULL_LOADING',
21
20
  };
22
21
 
23
22
  export type AuthData = {
@@ -42,7 +42,6 @@ export const initialState = {
42
42
  statusBar: {} as StatusBar,
43
43
  listDevice: {} as ListDevice,
44
44
  listAction: [] as ListAction,
45
- isFullLoading: false as Boolean,
46
45
  unit: {
47
46
  favoriteDeviceIds: [],
48
47
  },
@@ -67,8 +66,6 @@ export const reducer = (currentState: ContextData, action: Action) => {
67
66
  return { ...currentState, auth: payload };
68
67
  case Action.STORE_STATUS_BAR:
69
68
  return { ...currentState, statusBar: payload };
70
- case Action.IS_FULL_LOADING:
71
- return { ...currentState, isFullLoading: payload };
72
69
  case Action.UPDATE_LANGUAGE:
73
70
  return { ...currentState, language: payload };
74
71
  case Action.LIST_DEVICE_TYPES:
@@ -55,6 +55,7 @@ import { HanetCameraStack } from './HanetCameraStack';
55
55
 
56
56
  import { axiosGet } from '../utils/Apis/axios';
57
57
  import { API } from '../configs';
58
+ import SideMenuDetail from '../screens/SideMenuDetail';
58
59
 
59
60
  const Stack = createStackNavigator();
60
61
 
@@ -263,6 +264,13 @@ export const UnitStack = memo((props) => {
263
264
  headerShown: false,
264
265
  }}
265
266
  />
267
+ <Stack.Screen
268
+ name={Route.SideMenuDetail}
269
+ component={SideMenuDetail}
270
+ options={{
271
+ headerShown: false,
272
+ }}
273
+ />
266
274
  <Stack.Screen
267
275
  name={Route.UnitMemberList}
268
276
  component={SharingMemberList}
@@ -28,6 +28,7 @@ const SelectSensorDevices = memo(({ route }) => {
28
28
  isAutomateTab,
29
29
  isCreateNewAction,
30
30
  isMultiUnits,
31
+ oldType,
31
32
  } = route.params;
32
33
 
33
34
  const [listStation, setListStation] = useState([]);
@@ -137,7 +138,7 @@ const SelectSensorDevices = memo(({ route }) => {
137
138
  navigate(Routes.ScriptDetail, {
138
139
  id: automateId,
139
140
  name: scriptName,
140
- type: type,
141
+ type: oldType,
141
142
  havePermission: true,
142
143
  unit,
143
144
  isMultiUnits,
@@ -69,12 +69,13 @@ describe('test AddNewAutoSmart', () => {
69
69
  automate: {},
70
70
  automateId: undefined,
71
71
  title: 'select_sensor',
72
- type: 'value_change',
72
+ oldType: 'value_change',
73
73
  scriptName: undefined,
74
74
  unit: { id: 1 },
75
75
  isAutomateTab: undefined,
76
76
  isMultiUnits: undefined,
77
77
  routeName: 'SelectSensorDevices',
78
+ type: 'value_change',
78
79
  });
79
80
  });
80
81
 
@@ -102,6 +103,7 @@ describe('test AddNewAutoSmart', () => {
102
103
  automate: {},
103
104
  automateId: undefined,
104
105
  type: 'schedule',
106
+ oldType: 'value_change',
105
107
  routeName: 'SetSchedule',
106
108
  scriptName: undefined,
107
109
  unit: route.params.unit,