@eohjsc/react-native-smart-city 0.2.82 → 0.2.83

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 (43) hide show
  1. package/package.json +3 -3
  2. package/src/commons/ActionGroup/CurtainButtonTemplate.js +32 -21
  3. package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +8 -6
  4. package/src/commons/ActionGroup/OnOffTemplate/index.js +11 -3
  5. package/src/commons/ActionGroup/OneBigButtonTemplate.js +10 -7
  6. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +5 -2
  7. package/src/commons/ActionGroup/StatesGridActionTemplate.js +7 -3
  8. package/src/commons/ActionGroup/ThreeButtonTemplate.js +33 -24
  9. package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +18 -6
  10. package/src/commons/ActionGroup/__test__/OneBigButtonTemplate.test.js +9 -1
  11. package/src/commons/ActionGroup/__test__/OptionsDropdownTemplate.test.js +25 -13
  12. package/src/commons/ActionGroup/__test__/index.test.js +48 -14
  13. package/src/commons/Device/HorizontalBarChart.js +7 -1
  14. package/src/commons/Device/ItemDevice.js +8 -5
  15. package/src/commons/EmergencyButton/AlertSendConfirm.js +2 -2
  16. package/src/commons/EmergencyButton/AlertSent.js +2 -2
  17. package/src/commons/SubUnit/Favorites/index.js +2 -0
  18. package/src/commons/SubUnit/ShortDetail.js +7 -1
  19. package/src/configs/API.js +2 -4
  20. package/src/configs/Constants.js +2 -0
  21. package/src/iot/RemoteControl/Internet.js +8 -1
  22. package/src/iot/RemoteControl/index.js +4 -2
  23. package/src/screens/Device/EditDevice/__test__/EditDevice.test.js +2 -2
  24. package/src/screens/Device/EditDevice/index.js +2 -2
  25. package/src/screens/Device/__test__/detail.test.js +18 -11
  26. package/src/screens/Device/components/SensorConnectStatusViewHeader.js +2 -2
  27. package/src/screens/Device/components/SensorDisplayItem.js +2 -2
  28. package/src/screens/Device/detail.js +58 -20
  29. package/src/screens/Notification/__test__/NotificationItem.test.js +186 -14
  30. package/src/screens/Notification/components/NotificationItem.js +128 -2
  31. package/src/screens/Notification/styles/NotificationItemStyles.js +3 -3
  32. package/src/screens/SubUnit/AddSubUnit.js +4 -1
  33. package/src/screens/SubUnit/__test__/AddSubUnit.test.js +148 -0
  34. package/src/screens/Unit/Detail.js +10 -0
  35. package/src/screens/Unit/Summaries.js +2 -2
  36. package/src/screens/Unit/__test__/CheckSendEmail.test.js +10 -0
  37. package/src/screens/Unit/__test__/Detail.test.js +10 -0
  38. package/src/screens/Unit/components/__test__/SharedUnit.test.js +21 -2
  39. package/src/screens/UnitSummary/__test__/index.test.js +3 -3
  40. package/src/screens/UnitSummary/components/RunningDevices/__test__/index.test.js +2 -2
  41. package/src/screens/UnitSummary/index.js +52 -9
  42. package/src/utils/I18n/translations/en.json +7 -0
  43. package/src/utils/I18n/translations/vi.json +7 -0
@@ -70,9 +70,13 @@ const DeviceDetail = ({ route }) => {
70
70
  // eslint-disable-next-line no-unused-vars
71
71
  const [configValues, setConfigValues] = useConfigGlobalState('configValues');
72
72
 
73
- const { unit, sensor, isGGHomeConnected, station } = route.params;
74
- const [isFavourite, setIsFavourite] = useState(sensor.is_favourite);
75
- const { isOwner } = useIsOwnerOfUnit(unit.user_id);
73
+ const { unitData, unitId, sensorData, sensorId, isGGHomeConnected } =
74
+ route.params;
75
+ const [unit, setUnit] = useState(unitData || { id: unitId });
76
+ const [sensor, setSensor] = useState(sensorData || { id: sensorId });
77
+ const [station, setStation] = useState(sensor?.station);
78
+ const [isFavourite, setIsFavourite] = useState(sensor?.is_favourite);
79
+ const { isOwner } = useIsOwnerOfUnit(unit?.user_id);
76
80
  const [sensorName, setSensorName] = useState(sensor?.name);
77
81
  const [lockShowing, acquireLockShowing, releaseLockShowing] = useBoolean();
78
82
  const [showWindDirection, setShowWindDirection] = useState(false);
@@ -108,7 +112,7 @@ const DeviceDetail = ({ route }) => {
108
112
 
109
113
  const addToFavorites = useCallback(async () => {
110
114
  const { success } = await axiosPost(
111
- API.SENSOR.ADD_TO_FAVOURITES(unit.id, sensor.station.id, sensor.id)
115
+ API.SENSOR.ADD_TO_FAVOURITES(unit?.id, sensor?.station?.id, sensor?.id)
112
116
  );
113
117
  if (success) {
114
118
  setIsFavourite(true);
@@ -117,7 +121,11 @@ const DeviceDetail = ({ route }) => {
117
121
 
118
122
  const removeFromFavorites = useCallback(async () => {
119
123
  const { success } = await axiosPost(
120
- API.SENSOR.REMOVE_FROM_FAVOURITES(unit.id, sensor.station.id, sensor.id)
124
+ API.SENSOR.REMOVE_FROM_FAVOURITES(
125
+ unit?.id,
126
+ sensor?.station.id,
127
+ sensor?.id
128
+ )
121
129
  );
122
130
  if (success) {
123
131
  setIsFavourite(false);
@@ -129,9 +137,39 @@ const DeviceDetail = ({ route }) => {
129
137
  );
130
138
 
131
139
  const canManageSubUnit = useMemo(() => {
132
- return currentUserId === unit.user_id;
140
+ return currentUserId === unit?.user_id;
133
141
  }, [currentUserId, unit]);
134
142
 
143
+ const fetchUnitDetail = useCallback(async () => {
144
+ const { success, data } = await axiosGet(API.UNIT.UNIT_DETAIL(unit?.id));
145
+ if (success) {
146
+ setUnit(data);
147
+ }
148
+ }, [unit?.id]);
149
+
150
+ useEffect(() => {
151
+ if (!unitData && unitId) {
152
+ fetchUnitDetail();
153
+ }
154
+ }, [fetchUnitDetail, unitData, unitId]);
155
+
156
+ const fetchSensorDetail = useCallback(async () => {
157
+ const { success, data } = await axiosGet(
158
+ API.SENSOR.SENSOR_DETAIL(sensor?.id)
159
+ );
160
+ if (success) {
161
+ setSensor(data);
162
+ setSensorName(data.name);
163
+ setStation(data.station);
164
+ }
165
+ }, [sensor?.id]);
166
+
167
+ useEffect(() => {
168
+ if (!sensorData && sensorId) {
169
+ fetchSensorDetail();
170
+ }
171
+ }, [fetchSensorDetail, sensorData, sensorId]);
172
+
135
173
  const fetchDataDeviceDetail = useCallback(async () => {
136
174
  if (!token) {
137
175
  return;
@@ -141,7 +179,7 @@ const DeviceDetail = ({ route }) => {
141
179
  }
142
180
 
143
181
  const displayResult = await axiosGet(
144
- API.SENSOR.DISPLAY(sensor.id),
182
+ API.SENSOR.DISPLAY(sensor?.id),
145
183
  {},
146
184
  true
147
185
  );
@@ -168,7 +206,7 @@ const DeviceDetail = ({ route }) => {
168
206
  setLoading((preState) => ({ ...preState, displayTemplate: false }));
169
207
 
170
208
  const controlResult = await axiosGet(
171
- API.SENSOR.REMOTE_CONTROL_OPTIONS(sensor.id),
209
+ API.SENSOR.REMOTE_CONTROL_OPTIONS(sensor?.id),
172
210
  {},
173
211
  true
174
212
  );
@@ -212,12 +250,12 @@ const DeviceDetail = ({ route }) => {
212
250
  menuItems.push({
213
251
  route: Routes.ActivityLog,
214
252
  data: {
215
- id: sensor.id,
253
+ id: sensor?.id,
216
254
  type: 'action',
217
255
  share: unit,
218
256
  filterEnabled: {
219
257
  date: true,
220
- user: Boolean(unit.id),
258
+ user: Boolean(unit?.id),
221
259
  },
222
260
  },
223
261
  text: t('activity_log'),
@@ -352,7 +390,7 @@ const DeviceDetail = ({ route }) => {
352
390
 
353
391
  const fetchValues = async () => {
354
392
  const { success, data } = await axiosGet(
355
- API.SENSOR.DISPLAY_VALUES_V2(sensor.id),
393
+ API.SENSOR.DISPLAY_VALUES_V2(sensor?.id),
356
394
  {
357
395
  params: params,
358
396
  }
@@ -365,7 +403,7 @@ const DeviceDetail = ({ route }) => {
365
403
  }
366
404
  setLoading((preState) => ({ ...preState, isConnected: false }));
367
405
  };
368
- if (sensor.is_managed_by_backend && !sensor.is_other_device) {
406
+ if (sensor?.is_managed_by_backend && !sensor?.is_other_device) {
369
407
  const updateInterval = setInterval(() => fetchValues(), 5000);
370
408
  fetchValues();
371
409
  return () => clearInterval(updateInterval);
@@ -405,12 +443,12 @@ const DeviceDetail = ({ route }) => {
405
443
  ).length > 0;
406
444
 
407
445
  const onSetupContacts = useCallback(() => {
408
- const group = unit.group;
446
+ const group = unit?.group;
409
447
  navigation.navigate(Routes.EmergencyContactsStack, {
410
448
  screen: Routes.EmergencyContactsList,
411
- params: { unitId: unit.id, group },
449
+ params: { unitId: unit?.id, group },
412
450
  });
413
- }, [navigation, unit.group, unit.id]);
451
+ }, [navigation, unit?.group, unit?.id]);
414
452
 
415
453
  // replace isConnected=True to see template
416
454
  const renderSensorConnected = () => {
@@ -448,12 +486,12 @@ const DeviceDetail = ({ route }) => {
448
486
 
449
487
  const getDataFromLocal = async () => {
450
488
  const displayData = await getLocalData(
451
- `@CACHE_REQUEST_${API.SENSOR.DISPLAY(sensor.id)}`
489
+ `@CACHE_REQUEST_${API.SENSOR.DISPLAY(sensor?.id)}`
452
490
  );
453
491
  displayData && setDisplay(JSON.parse(displayData));
454
492
 
455
493
  const controlOptionData = await getLocalData(
456
- `@CACHE_REQUEST_${API.SENSOR.REMOTE_CONTROL_OPTIONS(sensor.id)}`
494
+ `@CACHE_REQUEST_${API.SENSOR.REMOTE_CONTROL_OPTIONS(sensor?.id)}`
457
495
  );
458
496
  controlOptionData && setControlOptions(JSON.parse(controlOptionData));
459
497
  setLoading((preState) => ({ ...preState, displayTemplate: false }));
@@ -557,7 +595,7 @@ const DeviceDetail = ({ route }) => {
557
595
  onSendNowAlert={onSendNowAlert}
558
596
  onHide={releaseLockShowing}
559
597
  unit={unit}
560
- station={sensor.station}
598
+ station={sensor?.station}
561
599
  />
562
600
 
563
601
  <AlertSent
@@ -566,7 +604,7 @@ const DeviceDetail = ({ route }) => {
566
604
  onPressMain={onViewDetails}
567
605
  onHide={releaseLockShowing}
568
606
  unit={unit}
569
- station={sensor.station}
607
+ station={sensor?.station}
570
608
  />
571
609
  </WrapHeaderScrollable>
572
610
  {isShowEmergencyResolve && (
@@ -605,7 +643,7 @@ const DeviceDetail = ({ route }) => {
605
643
  type="H4"
606
644
  style={styles.textName}
607
645
  >
608
- {unit.name} - {sensor.station.name}
646
+ {unit?.name} - {sensor?.station?.name}
609
647
  </Text>
610
648
  <IconFill
611
649
  testID={TESTID.BUTTON_POPUP_RESOLVED_ICON}
@@ -1,12 +1,14 @@
1
1
  import React from 'react';
2
2
  import { act, create } from 'react-test-renderer';
3
3
  import { TouchableOpacity } from 'react-native';
4
+ import axios from 'axios';
4
5
 
5
6
  import { SCProvider } from '../../../context';
6
7
  import { mockSCStore } from '../../../context/mockStore';
7
8
  import NotificationItem from '../components/NotificationItem';
8
9
  import { NOTIFICATION_TYPES } from '../../../configs/Constants';
9
10
  import Routes from '../../../utils/Route';
11
+ import { API } from '../../../configs';
10
12
 
11
13
  const wrapComponent = (item) => (
12
14
  <SCProvider initState={mockSCStore({})}>
@@ -14,6 +16,8 @@ const wrapComponent = (item) => (
14
16
  </SCProvider>
15
17
  );
16
18
 
19
+ jest.mock('axios');
20
+
17
21
  const mockNavigate = jest.fn();
18
22
  jest.mock('@react-navigation/native', () => {
19
23
  return {
@@ -27,6 +31,7 @@ jest.mock('@react-navigation/native', () => {
27
31
  describe('test NotificationItem', () => {
28
32
  let item = {};
29
33
  beforeEach(() => {
34
+ mockNavigate.mockClear();
30
35
  item = {
31
36
  id: 1,
32
37
  content_code: '',
@@ -41,19 +46,84 @@ describe('test NotificationItem', () => {
41
46
  });
42
47
  let tree;
43
48
  const listCase = [
44
- NOTIFICATION_TYPES.REMIND_TO_MAKE_PAYMENT,
45
- NOTIFICATION_TYPES.EXPIRE_PARKING_SESSION,
46
- NOTIFICATION_TYPES.REMIND_TO_SCAN_QR_CODE,
47
- NOTIFICATION_TYPES.USER_CANCEL,
48
- NOTIFICATION_TYPES.SYSTEM_CANCEL_NO_PAYMENT,
49
- NOTIFICATION_TYPES.BOOKING_SUCCESSFULLY,
50
- NOTIFICATION_TYPES.PARKING_COMPLETED,
51
- NOTIFICATION_TYPES.BOOKING_EXPIRED_AND_VIOLATION_CREATED,
52
- NOTIFICATION_TYPES.MOVE_CAR_WITHOUT_PAY_VIOLATION,
53
- NOTIFICATION_TYPES.PAY_FINE_SUCCESSFULLY,
49
+ {
50
+ content_code: NOTIFICATION_TYPES.REMIND_TO_MAKE_PAYMENT,
51
+ screen: Routes.SmartParkingBookingDetails,
52
+ params: { id: 1 },
53
+ },
54
+ {
55
+ content_code: NOTIFICATION_TYPES.EXPIRE_PARKING_SESSION,
56
+ screen: Routes.SmartParkingBookingDetails,
57
+ params: { id: 1 },
58
+ },
59
+ {
60
+ content_code: NOTIFICATION_TYPES.REMIND_TO_SCAN_QR_CODE,
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 },
73
+ },
74
+ {
75
+ content_code: NOTIFICATION_TYPES.BOOKING_SUCCESSFULLY,
76
+ screen: Routes.SmartParkingBookingDetails,
77
+ params: { id: 1 },
78
+ },
79
+ {
80
+ content_code: NOTIFICATION_TYPES.PARKING_COMPLETED,
81
+ screen: Routes.MyBookingList,
82
+ params: { tab: 1 },
83
+ },
84
+ {
85
+ content_code: NOTIFICATION_TYPES.BOOKING_EXPIRED_AND_VIOLATION_CREATED,
86
+ screen: Routes.SmartParkingBookingDetails,
87
+ params: { id: 1 },
88
+ },
89
+ {
90
+ content_code: NOTIFICATION_TYPES.MOVE_CAR_WITHOUT_PAY_VIOLATION,
91
+ screen: Routes.SmartParkingBookingDetails,
92
+ params: { id: 1 },
93
+ },
94
+ {
95
+ content_code: NOTIFICATION_TYPES.PAY_FINE_SUCCESSFULLY,
96
+ screen: Routes.SmartParkingBookingDetails,
97
+ params: { id: 1 },
98
+ },
54
99
  ];
55
100
 
56
- for (const content_code of listCase) {
101
+ for (const notify of listCase) {
102
+ test(`create ItemNotification ${notify.content_code}`, () => {
103
+ item.content_code = notify.content_code;
104
+ act(() => {
105
+ tree = create(wrapComponent(item));
106
+ });
107
+ const instance = tree.root;
108
+ const button = instance.findByType(TouchableOpacity);
109
+ act(() => {
110
+ button.props.onPress();
111
+ });
112
+ expect(mockNavigate).toHaveBeenCalledWith(Routes.SmartParkingStack, {
113
+ screens: notify.screen,
114
+ params: notify.params,
115
+ });
116
+ });
117
+ }
118
+
119
+ const listCase2 = [
120
+ NOTIFICATION_TYPES.NOTIFY_REMOVE_UNIT,
121
+ NOTIFICATION_TYPES.NOTIFY_REMOVE_MEMBER,
122
+ NOTIFICATION_TYPES.NOTIFY_MEMBER_LEAVE_UNIT,
123
+ 'default case',
124
+ ];
125
+
126
+ for (const content_code of listCase2) {
57
127
  test(`create ItemNotification ${content_code}`, () => {
58
128
  item.content_code = content_code;
59
129
  act(() => {
@@ -64,12 +134,114 @@ describe('test NotificationItem', () => {
64
134
  act(() => {
65
135
  button.props.onPress();
66
136
  });
67
- expect(mockNavigate).toHaveBeenCalledWith(Routes.SmartParkingStack, {
68
- screens: Routes.SmartParkingBookingDetails,
137
+ expect(mockNavigate).not.toHaveBeenCalled();
138
+ });
139
+ }
140
+
141
+ const listSensorType = ['air_quality', 'turbidity', 'ph', 'clo', 'uv'];
142
+ for (const sensorType of listSensorType) {
143
+ test(`create ItemNotification NOTIFY_INDICATOR sensor_type ${sensorType}`, () => {
144
+ item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
145
+ item.params = JSON.stringify({
146
+ unit_name: 'EoH Office',
147
+ status: 'Very Poor',
148
+ sensor_type: sensorType,
149
+ unit_id: 5,
150
+ summary_id: 11,
151
+ sensor_id: '',
152
+ });
153
+
154
+ act(() => {
155
+ tree = create(wrapComponent(item));
156
+ });
157
+ const instance = tree.root;
158
+ const button = instance.findByType(TouchableOpacity);
159
+ act(() => {
160
+ button.props.onPress();
161
+ });
162
+ expect(mockNavigate).toHaveBeenCalledWith(Routes.UnitStack, {
163
+ screen: Routes.UnitSummary,
164
+ params: {
165
+ summaryId: 11,
166
+ unitId: 5,
167
+ },
168
+ });
169
+ });
170
+ }
171
+
172
+ const listSensorType2 = ['smoke', 'fire'];
173
+ for (const sensorType of listSensorType2) {
174
+ test(`create ItemNotification NOTIFY_INDICATOR sensor_type ${sensorType}`, () => {
175
+ item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
176
+ item.params = JSON.stringify({
177
+ unit_name: 'Lavida Smart Home',
178
+ status: '',
179
+ sensor_type: sensorType,
180
+ unit_id: 70,
181
+ summary_id: '',
182
+ sensor_id: 394,
183
+ });
184
+
185
+ act(() => {
186
+ tree = create(wrapComponent(item));
187
+ });
188
+ const instance = tree.root;
189
+ const button = instance.findByType(TouchableOpacity);
190
+ act(() => {
191
+ button.props.onPress();
192
+ });
193
+ expect(mockNavigate).toHaveBeenCalledWith(Routes.UnitStack, {
194
+ screen: Routes.DeviceDetail,
69
195
  params: {
70
- id: 1,
196
+ unitId: 70,
197
+ sensorId: 394,
71
198
  },
72
199
  });
73
200
  });
74
201
  }
202
+
203
+ test('test onClick Item Notify', () => {
204
+ item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
205
+ item.params = JSON.stringify({
206
+ unit_name: 'EoH Office',
207
+ status: 'Very Poor',
208
+ sensor_type: 'air_quality',
209
+ unit_id: 5,
210
+ summary_id: 11,
211
+ sensor_id: '',
212
+ });
213
+ item.is_read = false;
214
+ act(() => {
215
+ tree = create(wrapComponent(item));
216
+ });
217
+ const instance = tree.root;
218
+ const button = instance.findByType(TouchableOpacity);
219
+ act(() => {
220
+ button.props.onPress();
221
+ });
222
+ expect(axios.post).toHaveBeenCalledWith(API.NOTIFICATION.SET_READ(1));
223
+ expect(mockNavigate).toHaveBeenCalledWith(Routes.UnitStack, {
224
+ screen: Routes.UnitSummary,
225
+ params: {
226
+ summaryId: 11,
227
+ unitId: 5,
228
+ },
229
+ });
230
+ });
231
+
232
+ test('test render Notify not in any case', () => {
233
+ item.content_code = 'NEW CASE';
234
+ item.params = JSON.stringify({
235
+ unit_id: 1,
236
+ });
237
+ act(() => {
238
+ tree = create(wrapComponent(item));
239
+ });
240
+ const instance = tree.root;
241
+ const button = instance.findByType(TouchableOpacity);
242
+ act(() => {
243
+ button.props.onPress();
244
+ });
245
+ expect(mockNavigate).not.toHaveBeenCalledWith();
246
+ });
75
247
  });
@@ -34,11 +34,11 @@ const NotificationItem = memo(({ item }) => {
34
34
  const customColorText = (text, params) => {
35
35
  return text.split('**').map((str, i) =>
36
36
  i % 2 === 0 ? (
37
- <Text type="Body" key={i}>
37
+ <Text type="Body" key={i} style={styles.textNotification}>
38
38
  {str}
39
39
  </Text>
40
40
  ) : (
41
- <Text type="Body" bold key={i}>
41
+ <Text type="Body" bold key={i} style={styles.textNotification}>
42
42
  {params[(i - 1) / 2]}
43
43
  </Text>
44
44
  )
@@ -49,6 +49,7 @@ const NotificationItem = memo(({ item }) => {
49
49
  const paramsJSON = JSON.parse(params.replace(regex, '"'));
50
50
  const booking_id = paramsJSON.booking_id && paramsJSON.booking_id;
51
51
  const unitId = paramsJSON?.unit_id;
52
+ const sensorId = paramsJSON?.sensor_id;
52
53
  switch (content_code) {
53
54
  case NOTIFICATION_TYPES.NOTIFY_INVITE_MEMBER:
54
55
  return {
@@ -220,6 +221,131 @@ const NotificationItem = memo(({ item }) => {
220
221
  params: { id: booking_id },
221
222
  }),
222
223
  };
224
+ case NOTIFICATION_TYPES.NOTIFY_INDICATOR:
225
+ const { sensor_type, summary_id } = paramsJSON;
226
+ switch (sensor_type) {
227
+ case 'air_quality':
228
+ return {
229
+ content: customColorText(
230
+ t('text_notification_content_air_quality_high'),
231
+ arrParams
232
+ ),
233
+ redirect: () =>
234
+ navigation.navigate(Routes.UnitStack, {
235
+ screen: Routes.UnitSummary,
236
+ params: {
237
+ summaryId: summary_id,
238
+ unitId,
239
+ },
240
+ }),
241
+ iconContent: <Image source={Images.logo} style={styles.logo} />,
242
+ };
243
+ case 'turbidity':
244
+ return {
245
+ content: customColorText(
246
+ t('text_notification_content_turbility_high'),
247
+ arrParams
248
+ ),
249
+ redirect: () =>
250
+ navigation.navigate(Routes.UnitStack, {
251
+ screen: Routes.UnitSummary,
252
+ params: {
253
+ summaryId: summary_id,
254
+ unitId,
255
+ },
256
+ }),
257
+ iconContent: <Image source={Images.logo} style={styles.logo} />,
258
+ };
259
+ case 'ph':
260
+ return {
261
+ content: customColorText(
262
+ t('text_notification_content_pH_index_high'),
263
+ arrParams
264
+ ),
265
+ redirect: () =>
266
+ navigation.navigate(Routes.UnitStack, {
267
+ screen: Routes.UnitSummary,
268
+ params: {
269
+ summaryId: summary_id,
270
+ unitId,
271
+ },
272
+ }),
273
+ iconContent: <Image source={Images.logo} style={styles.logo} />,
274
+ };
275
+ case 'clo':
276
+ return {
277
+ content: customColorText(
278
+ t('text_notification_content_clo_high'),
279
+ arrParams
280
+ ),
281
+ redirect: () =>
282
+ navigation.navigate(Routes.UnitStack, {
283
+ screen: Routes.UnitSummary,
284
+ params: {
285
+ summaryId: summary_id,
286
+ unitId,
287
+ },
288
+ }),
289
+ iconContent: <Image source={Images.logo} style={styles.logo} />,
290
+ };
291
+ case 'uv':
292
+ return {
293
+ content: customColorText(
294
+ t('text_notification_content_uv_index_high'),
295
+ arrParams
296
+ ),
297
+ redirect: () =>
298
+ navigation.navigate(Routes.UnitStack, {
299
+ screen: Routes.UnitSummary,
300
+ params: {
301
+ summaryId: summary_id,
302
+ unitId,
303
+ },
304
+ }),
305
+ iconContent: <Image source={Images.logo} style={styles.logo} />,
306
+ };
307
+ case 'smoke':
308
+ return {
309
+ content: customColorText(
310
+ t('text_notification_content_smoke'),
311
+ arrParams
312
+ ),
313
+ redirect: () =>
314
+ navigation.navigate(Routes.UnitStack, {
315
+ screen: Routes.DeviceDetail,
316
+ params: {
317
+ unitId,
318
+ sensorId,
319
+ },
320
+ }),
321
+ iconContent: <Image source={Images.logo} style={styles.logo} />,
322
+ };
323
+ case 'fire':
324
+ return {
325
+ content: customColorText(
326
+ t('text_notification_content_fire'),
327
+ arrParams
328
+ ),
329
+ redirect: () =>
330
+ navigation.navigate(Routes.UnitStack, {
331
+ screen: Routes.DeviceDetail,
332
+ params: {
333
+ unitId,
334
+ sensorId,
335
+ },
336
+ }),
337
+ iconContent: <Image source={Images.logo} style={styles.logo} />,
338
+ };
339
+ default:
340
+ return {
341
+ content: customColorText(
342
+ t('this_notification_will_be_updated_soon')
343
+ ),
344
+ redirect: () => null,
345
+ iconContent: <Image source={Images.logo} style={styles.logo} />,
346
+ };
347
+ }
348
+
223
349
  case NOTIFICATION_TYPES.NOTIFY_REMOVE_UNIT:
224
350
  const unitOwerName = paramsJSON?.unit_owner_name;
225
351
  const textNotify = unitOwerName
@@ -27,9 +27,6 @@ export default StyleSheet.create({
27
27
  time: {
28
28
  marginTop: 12,
29
29
  },
30
- textNotification: {
31
- lineHeight: 26,
32
- },
33
30
  iconNotification: {
34
31
  width: '46%',
35
32
  },
@@ -52,4 +49,7 @@ export default StyleSheet.create({
52
49
  height: 20,
53
50
  resizeMode: 'contain',
54
51
  },
52
+ textNotification: {
53
+ lineHeight: 23,
54
+ },
55
55
  });
@@ -182,7 +182,10 @@ const AddSubUnit = ({ route }) => {
182
182
  />
183
183
 
184
184
  {isAddUnit && (
185
- <TouchableWithoutFeedback onPress={onChooseLocation}>
185
+ <TouchableWithoutFeedback
186
+ testID={TESTID.ADD_SUB_UNIT_BUTTON_CHOOSE_LOCATION}
187
+ onPress={onChooseLocation}
188
+ >
186
189
  <View style={styles.wrapGeolocation}>
187
190
  <Text style={styles.addWallpaper}>{t('geolocation')}</Text>
188
191
  <Text