@eohjsc/react-native-smart-city 0.2.92 → 0.2.95

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 (89) hide show
  1. package/assets/images/Device/air-dry.svg +3 -0
  2. package/assets/images/Device/auto.svg +3 -0
  3. package/assets/images/Device/circulator.svg +4 -0
  4. package/assets/images/Device/clean.svg +5 -0
  5. package/assets/images/Device/current-state.svg +3 -0
  6. package/assets/images/Device/door-state.svg +3 -0
  7. package/assets/images/Device/wind-strength.svg +12 -0
  8. package/package.json +1 -1
  9. package/src/commons/Action/ItemQuickAction.js +1 -0
  10. package/src/commons/Action/__test__/ItemQuickAction.test.js +49 -2
  11. package/src/commons/ActionGroup/OnOffTemplate/OnOffSimpleTemplateStyle.js +2 -1
  12. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +31 -11
  13. package/src/commons/ActionGroup/OptionsDropdownActionTemplateStyle.js +5 -2
  14. package/src/commons/ActionGroup/StatesGridActionTemplate.js +42 -36
  15. package/src/commons/ActionGroup/StatesGridActionTemplateStyle.js +5 -10
  16. package/src/commons/ActionGroup/TimerActionTemplate.js +14 -10
  17. package/src/commons/ActionGroup/TimerActionTemplateStyles.js +12 -0
  18. package/src/commons/ActionGroup/TwoButtonTemplate/TwoButtonTemplateStyles.js +55 -0
  19. package/src/commons/ActionGroup/TwoButtonTemplate/index.js +170 -0
  20. package/src/commons/ActionGroup/__test__/TimerActionTemplate.test.js +1 -1
  21. package/src/commons/ActionGroup/__test__/TwoButtonTemplate.test.js +112 -0
  22. package/src/commons/ActionGroup/index.js +3 -0
  23. package/src/commons/CameraDevice/index.js +6 -1
  24. package/src/commons/Device/HistoryChart.js +2 -2
  25. package/src/commons/Device/ItemDevice.js +3 -13
  26. package/src/commons/Explore/SearchBox/__test__/SearchBox.test.js +19 -0
  27. package/src/commons/Explore/SearchBox/index.js +2 -0
  28. package/src/commons/IconComponent/index.js +32 -26
  29. package/src/commons/MediaPlayerDetail/index.js +16 -4
  30. package/src/commons/MenuActionMore/index.js +2 -2
  31. package/src/commons/Modal/ModalCustom.js +9 -1
  32. package/src/commons/SubUnit/Favorites/index.js +8 -7
  33. package/src/commons/SubUnit/__test__/Favorites.test.js +33 -35
  34. package/src/configs/API.js +6 -2
  35. package/src/configs/Colors.js +1 -0
  36. package/src/configs/Constants.js +24 -0
  37. package/src/context/actionType.ts +17 -0
  38. package/src/context/mockStore.ts +18 -0
  39. package/src/context/reducer.ts +102 -0
  40. package/src/iot/RemoteControl/Bluetooth.js +2 -0
  41. package/src/iot/RemoteControl/GoogleHome.js +1 -0
  42. package/src/navigations/AutomateStack.js +16 -1
  43. package/src/navigations/UnitStack.js +27 -0
  44. package/src/screens/AddCommon/SelectSubUnit.js +1 -0
  45. package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +2 -0
  46. package/src/screens/AddNewAction/Device/__test__/index.test.js +1 -1
  47. package/src/screens/AddNewAction/SelectAction.js +13 -15
  48. package/src/screens/AddNewAction/__test__/SelectAction.test.js +0 -7
  49. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +2 -0
  50. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +2 -0
  51. package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +9 -0
  52. package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +15 -0
  53. package/src/screens/AddNewGateway/SetupGatewayWifi.js +6 -1
  54. package/src/screens/AddNewGateway/__test__/SetupGateway.test.js +34 -0
  55. package/src/screens/AllCamera/index.js +1 -0
  56. package/src/screens/Automate/MultiUnits.js +9 -9
  57. package/src/screens/Automate/index.js +21 -20
  58. package/src/screens/Device/__test__/detail.test.js +119 -86
  59. package/src/screens/Device/detail.js +38 -51
  60. package/src/screens/Device/hooks/useFavoriteDevice.js +38 -0
  61. package/src/screens/EmergencyContacts/EmergencyContactsList.js +1 -1
  62. package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +41 -44
  63. package/src/screens/EmergencyContacts/__test__/EmergencyContactList.test.js +1 -0
  64. package/src/screens/EmergencyContacts/__test__/EmergencyContactsSelectContacts.test.js +18 -19
  65. package/src/screens/MoveToAnotherSubUnit/index.js +3 -1
  66. package/src/screens/Notification/__test__/NotificationItem.test.js +64 -53
  67. package/src/screens/Notification/components/NotificationItem.js +13 -4
  68. package/src/screens/ScriptDetail/__test__/index.test.js +15 -4
  69. package/src/screens/ScriptDetail/hooks/useStarredScript.js +32 -0
  70. package/src/screens/ScriptDetail/index.js +11 -20
  71. package/src/screens/SharedUnit/__test__/TabHeader.test.js +5 -0
  72. package/src/screens/Sharing/SelectUser.js +3 -23
  73. package/src/screens/Sharing/__test__/SelectUser.test.js +12 -80
  74. package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +33 -0
  75. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +2 -0
  76. package/src/screens/Unit/ChooseLocation.js +5 -0
  77. package/src/screens/Unit/Detail.js +33 -37
  78. package/src/screens/Unit/ManageUnit.js +21 -20
  79. package/src/screens/Unit/ManageUnitStyles.js +1 -0
  80. package/src/screens/Unit/SelectAddress.js +8 -2
  81. package/src/screens/Unit/Summaries.js +12 -15
  82. package/src/screens/Unit/__test__/Detail.test.js +25 -0
  83. package/src/screens/Unit/components/__test__/Header.test.js +32 -0
  84. package/src/screens/Unit/hook/useFavorites.js +28 -0
  85. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +1 -1
  86. package/src/screens/UnitSummary/components/PowerConsumption/index.js +1 -1
  87. package/src/utils/Apis/axios.js +7 -2
  88. package/src/utils/I18n/translations/en.json +2 -5
  89. package/src/utils/I18n/translations/vi.json +1 -4
@@ -16,7 +16,7 @@ import { Icon } from '@ant-design/react-native';
16
16
  import { useCountUp } from './hooks/useCountUp';
17
17
  import { getData as getLocalData } from '../../utils/Storage';
18
18
  import { API, Colors } from '../../configs';
19
- import { axiosGet, axiosPost } from '../../utils/Apis/axios';
19
+ import { axiosGet } from '../../utils/Apis/axios';
20
20
  import {
21
21
  isDeviceConnected,
22
22
  scanBluetoothDevices,
@@ -29,6 +29,7 @@ import {
29
29
  useAlertResolveEmergency,
30
30
  useEmergencyButton,
31
31
  } from './hooks/useEmergencyButton';
32
+ import { useFavoriteDevice } from './hooks/useFavoriteDevice';
32
33
  import BottomButtonView from '../../commons/BottomButtonView';
33
34
  import Text from '../../commons/Text';
34
35
  import { transformDatetime } from '../../utils/Converter/time';
@@ -69,7 +70,6 @@ const DeviceDetail = ({ route }) => {
69
70
  const [unit, setUnit] = useState(unitData || { id: unitId });
70
71
  const [sensor, setSensor] = useState(sensorData || { id: sensorId });
71
72
  const [station, setStation] = useState(sensor?.station);
72
- const [isFavourite, setIsFavourite] = useState(sensor?.is_favourite);
73
73
  const { isOwner } = useIsOwnerOfUnit(unit?.user_id);
74
74
  const [sensorName, setSensorName] = useState(sensor?.name);
75
75
  const [lockShowing, acquireLockShowing, releaseLockShowing] = useBoolean();
@@ -83,9 +83,9 @@ const DeviceDetail = ({ route }) => {
83
83
  const isNetworkConnected = useSCContextSelector(
84
84
  (state) => state.app.isNetworkConnected
85
85
  );
86
- const isBluetoothEnabled = useSCContextSelector(
87
- (state) => state.app.isBluetoothEnabled
88
- );
86
+ const isBluetoothEnabled = useSCContextSelector((state) => {
87
+ return state.app.isBluetoothEnabled;
88
+ });
89
89
 
90
90
  const isDeviceConnectedViaBle = useMemo(
91
91
  () =>
@@ -110,41 +110,28 @@ const DeviceDetail = ({ route }) => {
110
110
 
111
111
  useDisconnectedDevice(sensorName, isDeviceHasBle, serverDown);
112
112
 
113
- const isShowSetupEmergencyContact = useMemo(() => {
114
- display.items.filter(
115
- (item) =>
116
- item.type === 'emergency' && item.configuration.type === 'button'
117
- ).length > 0;
118
- }, [display.items]);
113
+ const isShowSetupEmergencyContact = useMemo(
114
+ () =>
115
+ display.items.filter(
116
+ (item) =>
117
+ item.type === 'emergency' && item.configuration.type === 'button'
118
+ ).length > 0,
119
+ [display.items]
120
+ );
119
121
 
120
- const isShowSetUpSmartLock = useMemo(() => {
121
- display.items.filter(
122
- (item) =>
123
- item.type === 'smartLock' && item.configuration.type === 'button'
124
- ).length > 0;
125
- }, [display.items]);
122
+ const isShowSetUpSmartLock = useMemo(
123
+ () =>
124
+ display.items.filter(
125
+ (item) =>
126
+ item.type === 'smartLock' && item.configuration.type === 'button'
127
+ ).length > 0,
128
+ [display.items]
129
+ );
126
130
 
127
- const addToFavorites = useCallback(async () => {
128
- const { success } = await axiosPost(
129
- API.SENSOR.ADD_TO_FAVOURITES(unit?.id, sensor?.station?.id, sensor?.id)
130
- );
131
- if (success) {
132
- setIsFavourite(true);
133
- }
134
- }, [unit, sensor]);
135
-
136
- const removeFromFavorites = useCallback(async () => {
137
- const { success } = await axiosPost(
138
- API.SENSOR.REMOVE_FROM_FAVOURITES(
139
- unit?.id,
140
- sensor?.station.id,
141
- sensor?.id
142
- )
143
- );
144
- if (success) {
145
- setIsFavourite(false);
146
- }
147
- }, [unit, sensor]);
131
+ const { isFavorite, addToFavorites, removeFromFavorites } = useFavoriteDevice(
132
+ unit,
133
+ sensor
134
+ );
148
135
 
149
136
  const currentUserId = useSelector((state) =>
150
137
  get(state, 'auth.account.user.id', 0)
@@ -162,10 +149,10 @@ const DeviceDetail = ({ route }) => {
162
149
  }, [unitId]);
163
150
 
164
151
  useEffect(() => {
165
- if (unitId) {
152
+ if (unitId && !unitData) {
166
153
  fetchUnitDetail();
167
154
  }
168
- }, [fetchUnitDetail, unitData, unitId]);
155
+ }, [fetchUnitDetail, unitId, unitData]);
169
156
 
170
157
  const fetchSensorDetail = useCallback(async () => {
171
158
  const { success, data } = await axiosGet(
@@ -179,10 +166,10 @@ const DeviceDetail = ({ route }) => {
179
166
  }, [sensorId]);
180
167
 
181
168
  useEffect(() => {
182
- if (sensorId) {
169
+ if (sensorId && !sensorData) {
183
170
  fetchSensorDetail();
184
171
  }
185
- }, [fetchSensorDetail, sensorData, sensorId]);
172
+ }, [fetchSensorDetail, sensorId, sensorData]);
186
173
 
187
174
  const fetchDataDeviceDetail = useCallback(async () => {
188
175
  if (!token) {
@@ -192,7 +179,7 @@ const DeviceDetail = ({ route }) => {
192
179
  return;
193
180
  }
194
181
 
195
- const { success, data, resp_status } = await axiosGet(
182
+ const { success, data } = await axiosGet(
196
183
  API.SENSOR.DISPLAY(sensor?.id),
197
184
  {},
198
185
  true
@@ -216,8 +203,6 @@ const DeviceDetail = ({ route }) => {
216
203
  }
217
204
  }
218
205
  }
219
- } else if (resp_status >= 500) {
220
- setServerDown(true);
221
206
  }
222
207
  setLoading((preState) => ({ ...preState, displayTemplate: false }));
223
208
 
@@ -347,7 +332,7 @@ const DeviceDetail = ({ route }) => {
347
332
  text: t('passcode_list'),
348
333
  });
349
334
  }
350
- if (!isFavourite) {
335
+ if (!isFavorite) {
351
336
  menuItems.unshift({
352
337
  doAction: addToFavorites,
353
338
  text: t('add_to_favorites'),
@@ -365,7 +350,7 @@ const DeviceDetail = ({ route }) => {
365
350
  isShowSetupEmergencyContact,
366
351
  isShowSetUpSmartLock,
367
352
  t,
368
- isFavourite,
353
+ isFavorite,
369
354
  sensor,
370
355
  unit,
371
356
  sensorName,
@@ -434,7 +419,7 @@ const DeviceDetail = ({ route }) => {
434
419
  });
435
420
 
436
421
  const fetchValues = async () => {
437
- const { success, data } = await axiosGet(
422
+ const { success, data, resp_status } = await axiosGet(
438
423
  API.SENSOR.DISPLAY_VALUES_V2(sensor?.id),
439
424
  {
440
425
  params: params,
@@ -445,6 +430,8 @@ const DeviceDetail = ({ route }) => {
445
430
  setConnected(data.is_connected);
446
431
  transformDatetime(data, ['last_updated']);
447
432
  setLastUpdated(data.last_updated);
433
+ } else if (resp_status >= 500) {
434
+ setServerDown(true);
448
435
  }
449
436
  setLoading((preState) => ({ ...preState, isConnected: false }));
450
437
  };
@@ -626,10 +613,10 @@ const DeviceDetail = ({ route }) => {
626
613
  <View style={styles.headerRight}>
627
614
  <TouchableOpacity
628
615
  style={styles.buttonStar}
629
- onPress={isFavourite ? removeFromFavorites : addToFavorites}
616
+ onPress={isFavorite ? removeFromFavorites : addToFavorites}
630
617
  testID={TESTID.HEADER_DEVICE_BUTTON_STAR}
631
618
  >
632
- {isFavourite ? (
619
+ {isFavorite ? (
633
620
  <IconFill name="star" size={25} color={Colors.Yellow6} />
634
621
  ) : (
635
622
  <IconOutline name="star" size={25} />
@@ -653,7 +640,7 @@ const DeviceDetail = ({ route }) => {
653
640
  </View>
654
641
  ),
655
642
  [
656
- isFavourite,
643
+ isFavorite,
657
644
  removeFromFavorites,
658
645
  addToFavorites,
659
646
  isShowSetupEmergencyContact,
@@ -0,0 +1,38 @@
1
+ import { useContext, useCallback } from 'react';
2
+ import { API } from '../../../configs';
3
+ import { SCContext, useSCContextSelector } from '../../../context';
4
+ import { Action } from '../../../context/actionType';
5
+ import { axiosPost } from '../../../utils/Apis/axios';
6
+
7
+ export const useFavoriteDevice = (unit, device) => {
8
+ const { setAction } = useContext(SCContext);
9
+ const favoriteDeviceIds = useSCContextSelector(
10
+ (state) => state.unit.favoriteDeviceIds
11
+ );
12
+
13
+ const isFavorite = favoriteDeviceIds.includes(device.id);
14
+
15
+ const addToFavorites = useCallback(async () => {
16
+ const { success } = await axiosPost(
17
+ API.SENSOR.ADD_TO_FAVOURITES(unit?.id, device?.station?.id, device?.id)
18
+ );
19
+ success && setAction(Action.ADD_DEVICE_TO_FAVORITES, device.id);
20
+ }, [unit, device, setAction]);
21
+
22
+ const removeFromFavorites = useCallback(async () => {
23
+ const { success } = await axiosPost(
24
+ API.SENSOR.REMOVE_FROM_FAVOURITES(
25
+ unit?.id,
26
+ device?.station?.id,
27
+ device?.id
28
+ )
29
+ );
30
+ success && setAction(Action.REMOVE_DEVICE_FROM_FAVORITES, device.id);
31
+ }, [unit, device, setAction]);
32
+
33
+ return {
34
+ isFavorite,
35
+ addToFavorites,
36
+ removeFromFavorites,
37
+ };
38
+ };
@@ -82,7 +82,7 @@ export const EmergencyContactsList = ({ route }) => {
82
82
  id: 2,
83
83
  text: t('select_unit_members'),
84
84
  route: Routes.EmergencyContactsSelectContacts,
85
- data: { unitId },
85
+ data: { unitId, group },
86
86
  },
87
87
  ];
88
88
 
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useState } from 'react';
1
+ import React, { useCallback, useEffect, useState } from 'react';
2
2
  import { SafeAreaView, StyleSheet, View } from 'react-native';
3
3
  import { IconOutline } from '@ant-design/icons-react-native';
4
4
  import { useNavigation } from '@react-navigation/native';
@@ -6,59 +6,55 @@ import { useTranslations } from '../../hooks/Common/useTranslations';
6
6
  import { Section, ViewButtonBottom } from '../../commons';
7
7
  import { RowUser } from '../../commons/RowUser';
8
8
  import WrapHeaderScrollable from '../../commons/Sharing/WrapHeaderScrollable';
9
- import { Colors, Theme } from '../../configs';
9
+ import { API, Colors, Theme } from '../../configs';
10
10
  import { TESTID } from '../../configs/Constants';
11
- // import { useDataMember } from 'containers/Sharing/hooks';
12
-
13
- const dataContact = [
14
- {
15
- id: 1,
16
- name: 'Peter Pan',
17
- phone: '0931245690',
18
- },
19
- {
20
- id: 2,
21
- name: 'John Wick',
22
- phone: '0912345678',
23
- },
24
- {
25
- id: 3,
26
- name: 'Batoze Pre',
27
- phone: '0921456876',
28
- },
29
- ];
11
+ import { axiosGet, axiosPost } from '../../utils/Apis/axios';
12
+ import { ToastBottomHelper } from '../../utils/Utils';
30
13
 
31
14
  export const EmergencyContactsSelectContacts = ({ route }) => {
32
15
  const t = useTranslations();
33
16
  const { goBack } = useNavigation();
34
- // const { unitId } = route.params;
17
+ const { unitId, group } = route.params;
18
+ const [dataContact, setDataContact] = useState([]);
19
+ const [loading, setLoading] = useState(true);
35
20
 
36
- // const { dataMembers, loading, onRefresh } = useDataMember(unitId);
37
- const [currentContacts, setCurrentContact] = useState(
38
- dataContact.map((contact) => contact.phone)
39
- );
21
+ const loadMembers = useCallback(async (id) => {
22
+ setLoading(true);
23
+ const { success, data } = await axiosGet(API.SHARE.UNITS_MEMBERS(id));
24
+ if (success) {
25
+ setLoading(false);
26
+ setDataContact(data);
27
+ }
28
+ }, []);
29
+
30
+ const [currentContacts, setCurrentContact] = useState('');
40
31
 
41
32
  const onPressContact = useCallback(
42
33
  (contact) => () => {
43
- const indexOfContact = currentContacts.indexOf(contact.phone);
44
-
45
- if (indexOfContact > -1) {
46
- const newContacts = [...currentContacts];
47
- newContacts.splice(indexOfContact, 1);
48
- setCurrentContact(newContacts);
49
- } else {
50
- setCurrentContact([...currentContacts, contact.phone]);
51
- }
34
+ setCurrentContact(contact);
52
35
  },
53
- [currentContacts]
36
+ []
54
37
  );
38
+
39
+ const goSave = useCallback(async () => {
40
+ const { success } = await axiosPost(API.EMERGENCY_BUTTON.CREATE_CONTACT(), {
41
+ group: group.id,
42
+ phone_number: currentContacts?.phone_number,
43
+ name: currentContacts?.name,
44
+ });
45
+ if (success) {
46
+ goBack();
47
+ } else {
48
+ ToastBottomHelper.error(t('create_contact_failed'));
49
+ }
50
+ }, [currentContacts, goBack, group.id, t]);
51
+
52
+ useEffect(() => {
53
+ loadMembers(unitId);
54
+ }, [loadMembers, unitId]);
55
55
  return (
56
56
  <SafeAreaView style={styles.container}>
57
- <WrapHeaderScrollable
58
- title={t('select_contacts')}
59
- // loading={loading}
60
- // onRefresh={onRefresh}
61
- >
57
+ <WrapHeaderScrollable title={t('select_contacts')} loading={loading}>
62
58
  <Section type={'border'}>
63
59
  {dataContact.map((contact, index) => (
64
60
  <RowUser
@@ -69,11 +65,11 @@ export const EmergencyContactsSelectContacts = ({ route }) => {
69
65
  <IconOutline name={'user'} size={20} color={Colors.White} />
70
66
  }
71
67
  text={contact.name}
72
- subtext={contact.phone}
68
+ subtext={contact.phone_number}
73
69
  onPress={onPressContact(contact)}
74
70
  rightComponent={
75
71
  <View style={styles.buttonRemove}>
76
- {currentContacts.indexOf(contact.phone) > -1 && (
72
+ {currentContacts?.phone_number === contact.phone_number && (
77
73
  <IconOutline
78
74
  name={'check-circle'}
79
75
  size={20}
@@ -90,7 +86,8 @@ export const EmergencyContactsSelectContacts = ({ route }) => {
90
86
  leftTitle={t('cancel')}
91
87
  onLeftClick={goBack}
92
88
  rightTitle={t('save')}
93
- rightDisabled={true}
89
+ onRightClick={goSave}
90
+ rightDisabled={false}
94
91
  />
95
92
  </SafeAreaView>
96
93
  );
@@ -113,6 +113,7 @@ describe('test EmergencyContactList', () => {
113
113
  Routes.EmergencyContactsSelectContacts,
114
114
  {
115
115
  unitId: route.params.unitId,
116
+ group: route.params.group,
116
117
  }
117
118
  );
118
119
  });
@@ -5,35 +5,34 @@ import { TESTID } from '../../../configs/Constants';
5
5
  import { SCProvider } from '../../../context';
6
6
  import { mockSCStore } from '../../../context/mockStore';
7
7
 
8
- const wrapComponent = (actionGroup) => (
8
+ const wrapComponent = (route) => (
9
9
  <SCProvider initState={mockSCStore({})}>
10
- <EmergencyContactsSelectContacts />
10
+ <EmergencyContactsSelectContacts route={route} />
11
11
  </SCProvider>
12
12
  );
13
13
 
14
14
  describe('test EmergencyContactsSelectContacts', () => {
15
+ let route;
16
+ beforeEach(() => {
17
+ route = {
18
+ params: {
19
+ unitId: 1,
20
+ group: 1,
21
+ },
22
+ };
23
+ });
24
+
15
25
  let tree;
16
26
 
17
- test('onPressContact remove from list', async () => {
27
+ test('onPress ErgencyContactsSelectContacts', async () => {
18
28
  act(() => {
19
- tree = create(wrapComponent());
29
+ tree = create(wrapComponent(route));
20
30
  });
21
31
  const instance = tree.root;
22
- const rowUser = instance.findAllByProps({
23
- testID: TESTID.EMERGENCY_SELECT_CONTACT,
24
- });
25
-
26
- expect(rowUser).toHaveLength(3);
27
- });
28
32
 
29
- test('onPressContact remove and add again from list', async () => {
30
- act(() => {
31
- tree = create(wrapComponent());
32
- });
33
- const instance = tree.root;
34
- const rowUser = instance.findAllByProps({
35
- testID: TESTID.EMERGENCY_SELECT_CONTACT,
36
- });
37
- expect(rowUser).toHaveLength(3);
33
+ const rowUser = instance.findAllByProps(
34
+ (item) => item.props.testID === TESTID.EMERGENCY_SELECT_CONTACT
35
+ );
36
+ expect(rowUser[0]).toBeDefined();
38
37
  });
39
38
  });
@@ -35,7 +35,9 @@ const MoveToAnotherSubUnit = memo(({ route }) => {
35
35
  const { params = {} } = route;
36
36
  const { unit, sensor, station } = params;
37
37
  const { navigate } = useNavigation();
38
- const [selectedSubUnit, setSelectedSubUnit] = useState(station);
38
+ const [selectedSubUnit, setSelectedSubUnit] = useState(
39
+ unit.stations?.find((subUnit) => subUnit.id === station.id)
40
+ );
39
41
 
40
42
  const listStationUnit = useMemo(() => {
41
43
  return unit.stations.slice(2);
@@ -36,7 +36,7 @@ describe('test NotificationItem', () => {
36
36
  id: 1,
37
37
  content_code: '',
38
38
  is_read: true,
39
- params: JSON.stringify({ booking_id: 1, booking_id_new: 1 }),
39
+ params: "{'booking_id': 1, 'booking_id_new': 1}",
40
40
  created_at: '',
41
41
  icon: '',
42
42
  };
@@ -49,62 +49,47 @@ describe('test NotificationItem', () => {
49
49
  {
50
50
  content_code: NOTIFICATION_TYPES.REMIND_TO_MAKE_PAYMENT,
51
51
  screen: Routes.SmartParkingBookingDetails,
52
- params: { id: 1 },
52
+ params: "{ 'id': 1 }",
53
53
  },
54
54
  {
55
55
  content_code: NOTIFICATION_TYPES.EXPIRE_PARKING_SESSION,
56
56
  screen: Routes.SmartParkingBookingDetails,
57
- params: { id: 1 },
57
+ params: "{ 'id': 1 }",
58
58
  },
59
59
  {
60
60
  content_code: NOTIFICATION_TYPES.REMIND_TO_SCAN_QR_CODE,
61
61
  screen: Routes.SmartParkingBookingDetails,
62
- params: { id: 1 },
63
- },
64
- {
65
- content_code: NOTIFICATION_TYPES.USER_CANCEL,
66
- screen: Routes.MyBookingList,
67
- params: { tab: 1 },
68
- },
69
- {
70
- content_code: NOTIFICATION_TYPES.SYSTEM_CANCEL_NO_PAYMENT,
71
- screen: Routes.MyBookingList,
72
- params: { tab: 1 },
62
+ params: "{ 'id': 1 }",
73
63
  },
74
64
  {
75
65
  content_code: NOTIFICATION_TYPES.BOOKING_SUCCESSFULLY,
76
66
  screen: Routes.SmartParkingBookingDetails,
77
- params: { id: 1 },
78
- },
79
- {
80
- content_code: NOTIFICATION_TYPES.PARKING_COMPLETED,
81
- screen: Routes.MyBookingList,
82
- params: { tab: 1 },
67
+ params: "{ 'id': 1 }",
83
68
  },
84
69
  {
85
70
  content_code: NOTIFICATION_TYPES.BOOKING_EXPIRED_AND_VIOLATION_CREATED,
86
71
  screen: Routes.SmartParkingBookingDetails,
87
- params: { id: 1 },
72
+ params: "{ 'id': 1 }",
88
73
  },
89
74
  {
90
75
  content_code: NOTIFICATION_TYPES.MOVE_CAR_WITHOUT_PAY_VIOLATION,
91
76
  screen: Routes.SmartParkingBookingDetails,
92
- params: { id: 1 },
77
+ params: "{ 'id': 1 }",
93
78
  },
94
79
  {
95
80
  content_code: NOTIFICATION_TYPES.PAY_FINE_SUCCESSFULLY,
96
81
  screen: Routes.SmartParkingBookingDetails,
97
- params: { id: 1 },
82
+ params: "{ 'id': 1 }",
98
83
  },
99
84
  {
100
85
  content_code: NOTIFICATION_TYPES.STOP_VIOLATION_FREE_PARKING_ZONE,
101
86
  screen: Routes.SmartParkingBookingDetails,
102
- params: { id: 1 },
87
+ params: "{ 'id': 1 }",
103
88
  },
104
89
  {
105
90
  content_code: NOTIFICATION_TYPES.PAY_FINE_AND_EXTEND_SUCCESSFULLY,
106
91
  screen: Routes.SmartParkingBookingDetails,
107
- params: { id: 1 },
92
+ params: "{ 'id': 1 }",
108
93
  },
109
94
  ];
110
95
 
@@ -121,7 +106,42 @@ describe('test NotificationItem', () => {
121
106
  });
122
107
  expect(mockNavigate).toHaveBeenCalledWith(Routes.SmartParkingStack, {
123
108
  screen: notify.screen,
124
- params: notify.params,
109
+ params: { id: 1 },
110
+ });
111
+ });
112
+ }
113
+
114
+ const listCaseSmartParking2 = [
115
+ {
116
+ content_code: NOTIFICATION_TYPES.USER_CANCEL,
117
+ screen: Routes.MyBookingList,
118
+ params: "{ 'tab': 1 }",
119
+ },
120
+ {
121
+ content_code: NOTIFICATION_TYPES.SYSTEM_CANCEL_NO_PAYMENT,
122
+ screen: Routes.MyBookingList,
123
+ params: "{ 'tab': 1 }",
124
+ },
125
+ {
126
+ content_code: NOTIFICATION_TYPES.PARKING_COMPLETED,
127
+ screen: Routes.MyBookingList,
128
+ params: "{ 'tab': 1 }",
129
+ },
130
+ ];
131
+ for (const notify of listCaseSmartParking2) {
132
+ test(`create ItemNotification ${notify.content_code}`, () => {
133
+ item.content_code = notify.content_code;
134
+ act(() => {
135
+ tree = create(wrapComponent(item));
136
+ });
137
+ const instance = tree.root;
138
+ const button = instance.findByType(TouchableOpacity);
139
+ act(() => {
140
+ button.props.onPress();
141
+ });
142
+ expect(mockNavigate).toHaveBeenCalledWith(Routes.SmartParkingStack, {
143
+ screen: notify.screen,
144
+ params: { tab: 1 },
125
145
  });
126
146
  });
127
147
  }
@@ -160,15 +180,7 @@ describe('test NotificationItem', () => {
160
180
  for (const sensorType of listSensorType) {
161
181
  test(`create ItemNotification NOTIFY_INDICATOR sensor_type ${sensorType}`, () => {
162
182
  item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
163
- item.params = JSON.stringify({
164
- unit_name: 'EoH Office',
165
- status: 'Very Poor',
166
- sensor_type: sensorType,
167
- unit_id: 5,
168
- summary_id: 11,
169
- sensor_id: '',
170
- });
171
-
183
+ item.params = `{'sensor_type': '${sensorType}', 'unit_id': 5, 'summary_id': 11}`;
172
184
  act(() => {
173
185
  tree = create(wrapComponent(item));
174
186
  });
@@ -196,14 +208,7 @@ describe('test NotificationItem', () => {
196
208
  for (const sensorType of listSensorType2) {
197
209
  test(`create ItemNotification NOTIFY_INDICATOR sensor_type ${sensorType}`, () => {
198
210
  item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
199
- item.params = JSON.stringify({
200
- unit_name: 'Lavida Smart Home',
201
- status: '',
202
- sensor_type: sensorType,
203
- unit_id: 70,
204
- summary_id: '',
205
- sensor_id: 394,
206
- });
211
+ item.params = `{'sensor_type': '${sensorType}', 'unit_id': 70, 'sensor_id': 394}`;
207
212
 
208
213
  act(() => {
209
214
  tree = create(wrapComponent(item));
@@ -225,14 +230,8 @@ describe('test NotificationItem', () => {
225
230
 
226
231
  test('test onClick Item Notify', () => {
227
232
  item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
228
- item.params = JSON.stringify({
229
- unit_name: 'EoH Office',
230
- status: 'Very Poor',
231
- sensor_type: 'air_quality',
232
- unit_id: 5,
233
- summary_id: 11,
234
- sensor_id: '',
235
- });
233
+ item.params =
234
+ "{'sensor_type': 'air_quality', 'unit_id': 5, 'summary_id': 11}";
236
235
  item.is_read = false;
237
236
  act(() => {
238
237
  tree = create(wrapComponent(item));
@@ -254,9 +253,21 @@ describe('test NotificationItem', () => {
254
253
 
255
254
  test('test render Notify not in any case', () => {
256
255
  item.content_code = 'NEW CASE';
257
- item.params = JSON.stringify({
258
- unit_id: 1,
256
+ (item.params = "{ 'unit_id': 1 }"),
257
+ act(() => {
258
+ tree = create(wrapComponent(item));
259
+ });
260
+ const instance = tree.root;
261
+ const button = instance.findByType(TouchableOpacity);
262
+ act(() => {
263
+ button.props.onPress();
259
264
  });
265
+ expect(mockNavigate).not.toHaveBeenCalledWith();
266
+ });
267
+
268
+ test('test render Notify params is object', () => {
269
+ item.content_code = 'NEW CASE';
270
+ item.params = { unit_id: 1 };
260
271
  act(() => {
261
272
  tree = create(wrapComponent(item));
262
273
  });
@@ -22,14 +22,24 @@ const NotificationItem = memo(({ item }) => {
22
22
  return /\B'|'\B/g;
23
23
  }, []);
24
24
 
25
+ const paramsJSON = useMemo(() => {
26
+ if (typeof params === 'object') {
27
+ return params;
28
+ }
29
+ // TODO return this later
30
+ let stringParams = JSON.stringify(params);
31
+ stringParams = stringParams.replace(regex, '"');
32
+ stringParams = stringParams.substring(1, stringParams.length - 1);
33
+ return JSON.parse(stringParams);
34
+ }, [params, regex]);
35
+
25
36
  let arrParams = useMemo(() => {
26
37
  const values = [];
27
- const paramsJSON = JSON.parse(params.replace(regex, '"'));
28
38
  Object.entries(paramsJSON).forEach(([key, value]) => {
29
39
  values.push(value);
30
40
  });
31
41
  return values;
32
- }, [params, regex]);
42
+ }, [paramsJSON]);
33
43
 
34
44
  const customColorText = (text, params) => {
35
45
  return text.split('**').map((str, i) =>
@@ -46,7 +56,6 @@ const NotificationItem = memo(({ item }) => {
46
56
  };
47
57
 
48
58
  const renderItem = useCallback(() => {
49
- const paramsJSON = JSON.parse(params.replace(regex, '"'));
50
59
  const booking_id = paramsJSON.booking_id && paramsJSON.booking_id;
51
60
  const unitId = paramsJSON?.unit_id;
52
61
  const sensorId = paramsJSON?.sensor_id;
@@ -513,7 +522,7 @@ const NotificationItem = memo(({ item }) => {
513
522
  iconContent: <Image source={Images.logo} style={styles.logo} />,
514
523
  };
515
524
  }
516
- }, [arrParams, content_code, navigation, params, regex, t]);
525
+ }, [arrParams, content_code, navigation, paramsJSON, t]);
517
526
 
518
527
  const { content, redirect, iconContent } = renderItem() || {};
519
528