@eohjsc/react-native-smart-city 0.7.26 → 0.7.30

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 (74) hide show
  1. package/index.js +2 -0
  2. package/package.json +2 -1
  3. package/src/commons/Dashboard/MyDashboardDevice/__test__/index.test.js +68 -0
  4. package/src/commons/Dashboard/MyDashboardDevice/index.js +46 -11
  5. package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +43 -11
  6. package/src/commons/Dashboard/MyUnit/index.js +40 -32
  7. package/src/commons/ModalAlert/index.js +51 -0
  8. package/src/commons/ModalAlert/styles.js +54 -0
  9. package/src/commons/SubUnit/ShortDetail.js +20 -4
  10. package/src/commons/SubUnit/__test__/ShortDetail.test.js +46 -1
  11. package/src/configs/API.js +6 -0
  12. package/src/configs/AccessibilityLabel.js +1 -0
  13. package/src/configs/Constants.js +7 -0
  14. package/src/configs/SCConfig.js +6 -0
  15. package/src/context/SCContext.tsx +12 -1
  16. package/src/context/SCStore.ts +14 -0
  17. package/src/context/actionType.ts +10 -0
  18. package/src/context/mockStore.ts +30 -1
  19. package/src/context/reducer.ts +35 -0
  20. package/src/hooks/IoT/useRemoteControl.js +4 -1
  21. package/src/hooks/IoT/useWatchSharedChips.js +130 -0
  22. package/src/hooks/Review/__test__/useInAppReview.test.js +99 -0
  23. package/src/hooks/Review/useInAppReview.js +70 -0
  24. package/src/hooks/useMqtt.js +78 -27
  25. package/src/iot/Monitor.js +149 -26
  26. package/src/iot/UpdateStates.js +60 -0
  27. package/src/iot/mqtt.js +177 -22
  28. package/src/navigations/UnitStack.js +16 -0
  29. package/src/screens/ActivityLog/FilterPopup.js +4 -79
  30. package/src/screens/ActivityLog/ItemLog.js +1 -0
  31. package/src/screens/ActivityLog/__test__/FilterPopup.test.js +2 -6
  32. package/src/screens/ActivityLog/__test__/index.test.js +51 -29
  33. package/src/screens/ActivityLog/index.js +0 -1
  34. package/src/screens/ActivityLog/styles/filterPopupStyles.js +5 -2
  35. package/src/screens/AddNewGateway/RenameNewDevices.js +5 -0
  36. package/src/screens/AddNewGateway/__test__/RenameNewDevices.test.js +18 -0
  37. package/src/screens/Automate/AddNewAction/ReceiverSelect.js +208 -0
  38. package/src/screens/Automate/AddNewAction/SetupScriptEmail.js +1 -1
  39. package/src/screens/Automate/AddNewAction/SetupScriptNotify.js +18 -28
  40. package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +22 -129
  41. package/src/screens/Automate/AddNewAction/SetupScriptReceiverNotify.js +59 -0
  42. package/src/screens/Automate/AddNewAction/SetupScriptReceiverSms.js +22 -129
  43. package/src/screens/Automate/AddNewAction/SetupScriptSms.js +1 -1
  44. package/src/screens/Automate/AddNewAction/Styles/{SetupScriptReceiverEmailStyles.js → ReceiverSelectStyles.js} +18 -1
  45. package/src/screens/Automate/AddNewAction/__test__/SetupScriptNotify.test.js +16 -33
  46. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverEmail.test.js +10 -8
  47. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverNotify.test.js +217 -0
  48. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverSms.test.js +10 -8
  49. package/src/screens/Automate/Components/InputName.js +5 -1
  50. package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +18 -0
  51. package/src/screens/Automate/ScriptDetail/index.js +6 -6
  52. package/src/screens/CreatePassword/__test__/index.test.js +133 -0
  53. package/src/screens/CreatePassword/index.js +134 -0
  54. package/src/screens/CreatePassword/styles.js +45 -0
  55. package/src/screens/Device/__test__/DeviceDetail-3rdparty.test.js +447 -0
  56. package/src/screens/Device/__test__/DeviceDetail-arduino.test.js +344 -0
  57. package/src/screens/Device/__test__/{mqttDetail.test.js → DeviceDetail-modbus.test.js} +287 -320
  58. package/src/screens/Device/__test__/DeviceDetail-zigbee.test.js +451 -0
  59. package/src/screens/Device/__test__/DeviceDetail.test.js +502 -0
  60. package/src/screens/Device/__test__/detail.test.js +61 -3
  61. package/src/screens/Device/__test__/sensorDisplayItem.test.js +28 -3
  62. package/src/screens/Device/components/SensorDisplayItem.js +16 -14
  63. package/src/screens/Device/detail.js +14 -6
  64. package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +3 -2
  65. package/src/screens/Device/styles.js +0 -5
  66. package/src/screens/EnterPassword/__test__/EnterPassword.test.js +76 -1
  67. package/src/screens/EnterPassword/index.js +34 -4
  68. package/src/screens/EnterPassword/styles.js +1 -1
  69. package/src/utils/FactoryGateway.js +597 -0
  70. package/src/utils/I18n/translations/en.js +10 -0
  71. package/src/utils/I18n/translations/vi.js +10 -0
  72. package/src/utils/Route/index.js +3 -1
  73. package/src/utils/Validation.js +5 -0
  74. package/src/utils/store.js +5 -0
package/src/iot/mqtt.js CHANGED
@@ -1,6 +1,5 @@
1
- import moment from 'moment';
2
1
  import { getObject, storeObject } from '../utils/Storage';
3
- import { updateGlobalValue } from './Monitor';
2
+ import { getLastUpdated, updateGlobalValue } from './UpdateStates';
4
3
  import { Buffer } from 'buffer';
5
4
 
6
5
  const struct = require('python-struct');
@@ -87,6 +86,84 @@ const float_cdab = (bytes_str) => {
87
86
  return value_unpacked('>f', swapped);
88
87
  };
89
88
 
89
+ const uint_64_abcd = (bytes_str) => {
90
+ return value_unpacked('>Q', bytes_str?.slice(0, 16));
91
+ };
92
+
93
+ const uint_64_dcba = (bytes_str) => {
94
+ return value_unpacked('<Q', bytes_str?.slice(0, 16));
95
+ };
96
+
97
+ const uint_64_badc = (bytes_str) => {
98
+ const swapped =
99
+ bytes_str?.slice(12, 16) +
100
+ bytes_str?.slice(8, 12) +
101
+ bytes_str?.slice(4, 8) +
102
+ bytes_str?.slice(0, 4);
103
+ return value_unpacked('<Q', swapped);
104
+ };
105
+
106
+ const uint_64_cdab = (bytes_str) => {
107
+ const swapped =
108
+ bytes_str?.slice(12, 16) +
109
+ bytes_str?.slice(8, 12) +
110
+ bytes_str?.slice(4, 8) +
111
+ bytes_str?.slice(0, 4);
112
+ return value_unpacked('>Q', swapped);
113
+ };
114
+
115
+ const int_64_abcd = (bytes_str) => {
116
+ return value_unpacked('>q', bytes_str?.slice(0, 16));
117
+ };
118
+
119
+ const int_64_dcba = (bytes_str) => {
120
+ return value_unpacked('<q', bytes_str?.slice(0, 16));
121
+ };
122
+
123
+ const int_64_badc = (bytes_str) => {
124
+ const swapped =
125
+ bytes_str?.slice(12, 16) +
126
+ bytes_str?.slice(8, 12) +
127
+ bytes_str?.slice(4, 8) +
128
+ bytes_str?.slice(0, 4);
129
+ return value_unpacked('<q', swapped);
130
+ };
131
+
132
+ const int_64_cdab = (bytes_str) => {
133
+ const swapped =
134
+ bytes_str?.slice(12, 16) +
135
+ bytes_str?.slice(8, 12) +
136
+ bytes_str?.slice(4, 8) +
137
+ bytes_str?.slice(0, 4);
138
+ return value_unpacked('>q', swapped);
139
+ };
140
+
141
+ const double_abcd = (bytes_str) => {
142
+ return value_unpacked('>d', bytes_str?.slice(0, 16));
143
+ };
144
+
145
+ const double_dcba = (bytes_str) => {
146
+ return value_unpacked('<d', bytes_str?.slice(0, 16));
147
+ };
148
+
149
+ const double_badc = (bytes_str) => {
150
+ const swapped =
151
+ bytes_str?.slice(12, 16) +
152
+ bytes_str?.slice(8, 12) +
153
+ bytes_str?.slice(4, 8) +
154
+ bytes_str?.slice(0, 4);
155
+ return value_unpacked('<d', swapped);
156
+ };
157
+
158
+ const double_cdab = (bytes_str) => {
159
+ const swapped =
160
+ bytes_str?.slice(12, 16) +
161
+ bytes_str?.slice(8, 12) +
162
+ bytes_str?.slice(4, 8) +
163
+ bytes_str?.slice(0, 4);
164
+ return value_unpacked('>d', swapped);
165
+ };
166
+
90
167
  const range_value_converting = (
91
168
  raw_value,
92
169
  raw_min,
@@ -133,6 +210,18 @@ const mappingTransformer = {
133
210
  convert_ai: convert_ai,
134
211
  int_first4: int_first4,
135
212
  int_last4: int_last4,
213
+ double_abcd: double_abcd,
214
+ double_dcba: double_dcba,
215
+ double_badc: double_badc,
216
+ double_cdab: double_cdab,
217
+ uint_64_abcd: uint_64_abcd,
218
+ uint_64_dcba: uint_64_dcba,
219
+ uint_64_badc: uint_64_badc,
220
+ uint_64_cdab: uint_64_cdab,
221
+ int_64_abcd: int_64_abcd,
222
+ int_64_dcba: int_64_dcba,
223
+ int_64_badc: int_64_badc,
224
+ int_64_cdab: int_64_cdab,
136
225
  };
137
226
 
138
227
  const extract_config_value = (register, value_bytes) => {
@@ -227,7 +316,7 @@ const check_filter = (value, config) => {
227
316
  return value < low || value > high;
228
317
  };
229
318
 
230
- const updateGlobalValueMqtt = async (config, value) => {
319
+ const updateGlobalValueMqtt = async (config, value, time) => {
231
320
  if (!config?.id) {
232
321
  return;
233
322
  }
@@ -235,9 +324,10 @@ const updateGlobalValueMqtt = async (config, value) => {
235
324
  return;
236
325
  }
237
326
 
238
- const last_updated = moment().format('YYYY-MM-DDTHH:mm:ss.SSSSSS');
327
+ const { last_updated, last_updated_micro } = getLastUpdated(time);
328
+
239
329
  if (typeof value === 'string') {
240
- updateGlobalValue(config.id, { value, last_updated });
330
+ updateGlobalValue(config.id, { value, last_updated, last_updated_micro });
241
331
  return;
242
332
  }
243
333
 
@@ -248,10 +338,18 @@ const updateGlobalValueMqtt = async (config, value) => {
248
338
  return;
249
339
  }
250
340
 
251
- updateGlobalValue(config.id, { value, last_updated });
341
+ updateGlobalValue(config.id, { value, last_updated, last_updated_micro });
342
+ };
343
+
344
+ export const handleSelfSensorData = (chip, configsById, data, time) => {
345
+ chip?.self_sensor?.configs.forEach((config) => {
346
+ const configId = config.id;
347
+ const value = data?.[config.name];
348
+ updateGlobalValueMqtt(configsById[configId], value, time);
349
+ });
252
350
  };
253
351
 
254
- export const handleModbusData = (chip, configById, data) => {
352
+ export const handleModbusData = (chip, configsById, data, time) => {
255
353
  const modbus_gateway = chip?.modbus_gateway;
256
354
  if (!modbus_gateway) {
257
355
  return;
@@ -269,16 +367,22 @@ export const handleModbusData = (chip, configById, data) => {
269
367
  sensor_data = new_sensor_data;
270
368
 
271
369
  const configId = register?.config;
272
- updateGlobalValueMqtt(configById[configId], value);
370
+ updateGlobalValueMqtt(configsById[configId], value, time);
273
371
  });
274
372
  });
275
373
  };
276
374
 
277
- export const handleChipData = (configById, configId, data) => {
278
- updateGlobalValueMqtt(configById[configId], data?.v);
375
+ export const handleChipData = (configsById, configId, data, time) => {
376
+ updateGlobalValueMqtt(configsById[configId], data?.v, time);
279
377
  };
280
378
 
281
- export const handleZigbeeData = (chip, configById, ieee_address, data) => {
379
+ export const handleZigbeeData = (
380
+ chip,
381
+ configsById,
382
+ ieee_address,
383
+ data,
384
+ time
385
+ ) => {
282
386
  const zigbee_gateway = chip?.zigbee_gateway;
283
387
  if (!zigbee_gateway) {
284
388
  return;
@@ -293,14 +397,20 @@ export const handleZigbeeData = (chip, configById, ieee_address, data) => {
293
397
  const device = zigbee_device_by_ieee[ieee_address];
294
398
  if (device) {
295
399
  (device.configs || []).forEach((config_map) => {
296
- let value = data?.data[config_map?.key];
400
+ let value = data?.data?.[config_map?.key];
297
401
  const configId = config_map?.config;
298
- updateGlobalValueMqtt(configById[configId], value);
402
+ updateGlobalValueMqtt(configsById[configId], value, time);
299
403
  });
300
404
  }
301
405
  };
302
406
 
303
- export const handleThirdPartyData = (chip, configById, device_uid, data) => {
407
+ export const handleThirdPartyData = (
408
+ chip,
409
+ configsById,
410
+ device_uid,
411
+ data,
412
+ time
413
+ ) => {
304
414
  const third_party_gateway = chip?.third_party_gateway;
305
415
  if (!third_party_gateway) {
306
416
  return;
@@ -314,9 +424,9 @@ export const handleThirdPartyData = (chip, configById, device_uid, data) => {
314
424
 
315
425
  const device = third_party_device_by_uid[device_uid];
316
426
  device?.configs?.forEach((config_map) => {
317
- const value = data[config_map?.key];
427
+ const value = data?.[config_map?.key];
318
428
  const configId = config_map?.config;
319
- updateGlobalValueMqtt(configById[configId], value);
429
+ updateGlobalValueMqtt(configsById[configId], value, time);
320
430
  });
321
431
  };
322
432
 
@@ -325,13 +435,29 @@ export const handleMqttMessage = (
325
435
  payloadData,
326
436
  code,
327
437
  chip,
328
- configById
438
+ configsById
329
439
  ) => {
440
+ if (topic === `eoh/chip/${code}/is_online`) {
441
+ // Online Status
442
+ // topic: eoh/chip/${code}/is_online
443
+ // payload: {ol: 1}
444
+ handleSelfSensorData(chip, configsById, { is_online: payloadData?.ol });
445
+ return;
446
+ }
447
+
448
+ if (topic === `eoh/chip/${code}/self_sensor`) {
449
+ // Self Sensor
450
+ // topic: eoh/chip/${code}/self_sensor
451
+ // payload: {is_battery: 1, temperature: 27.5, volt: 3.3, ...}
452
+ handleSelfSensorData(chip, configsById, payloadData, payloadData?.time);
453
+ return;
454
+ }
455
+
330
456
  if (topic === `eoh/chip/${code}/data`) {
331
457
  // Modbus
332
458
  // topic: eoh/chip/${code}/data
333
459
  // payload: {data: '01aa010a', 'ack':'1', 'chip_temperature':5333, 'rssi':-61}
334
- handleModbusData(chip, configById, payloadData.data);
460
+ handleModbusData(chip, configsById, payloadData?.data, payloadData?.time);
335
461
  }
336
462
 
337
463
  const matchArduinoConfigValue = topic.match(/config\/(\d+)\/value/);
@@ -339,7 +465,29 @@ export const handleMqttMessage = (
339
465
  // Arduino
340
466
  // topic: eoh/chip/{code}/config/127363/value
341
467
  // payload: {v: 2130} or {v: 'on'}
342
- handleChipData(configById, matchArduinoConfigValue[1], payloadData);
468
+ handleChipData(
469
+ configsById,
470
+ matchArduinoConfigValue[1],
471
+ payloadData,
472
+ payloadData?.time
473
+ );
474
+ }
475
+
476
+ const matchBatchConfigValue = topic.match(/config_value/);
477
+ if (matchBatchConfigValue) {
478
+ // Arduino
479
+ // topic: eoh/chip/{code}/config_value
480
+ // payload: {1: 2130, 2: 3000}
481
+ // This is a batch update for multiple configs
482
+ Object.keys(payloadData).forEach((key) => {
483
+ handleChipData(
484
+ configsById,
485
+ key,
486
+ { v: payloadData[key] },
487
+ payloadData.time
488
+ );
489
+ });
490
+ return;
343
491
  }
344
492
 
345
493
  const matchZigbeeConfigValue = topic.match(/zigbee\/(.+)\/data/);
@@ -347,7 +495,13 @@ export const handleMqttMessage = (
347
495
  // Zigbee
348
496
  // topic: eoh/chip/code-123/zigbee/IEEE-123/data
349
497
  // payload: {zigbee_data: 'aaa', 'data': {state: 1, state_0: 0}}
350
- handleZigbeeData(chip, configById, matchZigbeeConfigValue[1], payloadData);
498
+ handleZigbeeData(
499
+ chip,
500
+ configsById,
501
+ matchZigbeeConfigValue[1],
502
+ payloadData,
503
+ payloadData?.time
504
+ );
351
505
  }
352
506
 
353
507
  const matchThirdPartyConfigValue = topic.match(/third_party\/(.+)\/data/);
@@ -357,9 +511,10 @@ export const handleMqttMessage = (
357
511
  // payload: {state: 1, temperature: 27.6}
358
512
  handleThirdPartyData(
359
513
  chip,
360
- configById,
514
+ configsById,
361
515
  matchThirdPartyConfigValue[1],
362
- payloadData
516
+ payloadData,
517
+ payloadData?.time
363
518
  );
364
519
  }
365
520
  };
@@ -29,6 +29,7 @@ import SetupScriptDelay from '../screens/Automate/AddNewAction/SetupScriptDelay'
29
29
  import SetupScriptNotify from '../screens/Automate/AddNewAction/SetupScriptNotify';
30
30
  import SetupScriptEmail from '../screens/Automate/AddNewAction/SetupScriptEmail';
31
31
  import SetupScriptReceiverEmail from '../screens/Automate/AddNewAction/SetupScriptReceiverEmail';
32
+ import SetupScriptReceiverNotify from '../screens/Automate/AddNewAction/SetupScriptReceiverNotify';
32
33
  import AddAutomationTypeSmart from '../screens/Automate/AddNewAutoSmart/AddAutomationTypeSmart';
33
34
  import AddUnknownTypeSmart from '../screens/Automate/AddNewAutoSmart/AddUnknownTypeSmart';
34
35
  import EditActionsList from '../screens/Automate/EditActionsList';
@@ -44,6 +45,7 @@ import DeviceDetail from '../screens/Device/detail';
44
45
  import EditDevice from '../screens/Device/EditDevice/index';
45
46
  import DeviceInfo from '../screens/DeviceInfo';
46
47
  import EmergencySetting from '../screens/EmergencySetting';
48
+ import CreatePassword from '../screens/CreatePassword';
47
49
  import EnterPassword from '../screens/EnterPassword';
48
50
  import GuestInfo from '../screens/GuestInfo';
49
51
  import ManageAccessScreen from '../screens/ManageAccess';
@@ -374,6 +376,13 @@ export const UnitStack = memo((props) => {
374
376
  headerShown: false,
375
377
  }}
376
378
  />
379
+ <Stack.Screen
380
+ name={Route.CreatePassword}
381
+ component={CreatePassword}
382
+ options={{
383
+ headerShown: false,
384
+ }}
385
+ />
377
386
  <Stack.Screen
378
387
  name={Route.EnterPassword}
379
388
  component={EnterPassword}
@@ -465,6 +474,13 @@ export const UnitStack = memo((props) => {
465
474
  headerShown: false,
466
475
  }}
467
476
  />
477
+ <Stack.Screen
478
+ name={Route.SetupScriptReceiverNotify}
479
+ component={SetupScriptReceiverNotify}
480
+ options={{
481
+ headerShown: false,
482
+ }}
483
+ />
468
484
  <Stack.Screen
469
485
  name={Route.UpdateReceiverEmailScript}
470
486
  component={UpdateReceiverEmailScript}
@@ -1,6 +1,5 @@
1
1
  import React, { useState, useCallback } from 'react';
2
2
  import { View, ScrollView, TouchableOpacity } from 'react-native';
3
- import DateTimePickerModal from 'react-native-modal-datetime-picker';
4
3
  import moment from 'moment';
5
4
 
6
5
  import BottomButtonView from '../../commons/BottomButtonView';
@@ -8,7 +7,6 @@ import Text from '../../commons/Text';
8
7
  import RadioCircle from '../../commons/RadioCircle';
9
8
  import DateTimeRangeChange from '../../commons/DateTimeRangeChange';
10
9
  import { useTranslations } from '../../hooks/Common/useTranslations';
11
- import { useBoolean } from '../../hooks/Common';
12
10
 
13
11
  import { Colors } from '../../configs';
14
12
  import styles from './styles/filterPopupStyles';
@@ -42,21 +40,16 @@ const RowMember = ({ member, isSelected, onSelect }) => {
42
40
  const FilterPopup = ({
43
41
  isVisible,
44
42
  onHide,
45
- onShow,
46
43
  members,
47
44
  filters,
48
45
  userFilterEnabled,
49
46
  onApply,
50
47
  }) => {
51
48
  const t = useTranslations();
52
- const [lockShowing, acquireLockShowing, releaseLockShowing] =
53
- useBoolean(false);
54
49
  const [selectedUsers, setSelectedUsers] = useState(filters.users);
55
50
  const [stateDatePicker, setStateDatePicker] = useState({
56
- visible: false,
57
51
  startDate: filters.date_from,
58
52
  endDate: filters.date_to,
59
- currentTimeChange: 'start',
60
53
  });
61
54
 
62
55
  const handleOnSelectUser = useCallback(
@@ -78,90 +71,38 @@ const FilterPopup = ({
78
71
  [selectedUsers, setSelectedUsers]
79
72
  );
80
73
 
81
- const selectStart = useCallback(() => {
82
- onHide();
83
- acquireLockShowing();
84
- setStateDatePicker((state) => ({
85
- ...state,
86
- visible: true,
87
- currentTimeChange: 'start',
88
- }));
89
- }, [onHide, acquireLockShowing]);
90
-
91
- const selectEnd = useCallback(() => {
92
- onHide();
93
- acquireLockShowing();
94
- setStateDatePicker((state) => ({
95
- ...state,
96
- visible: true,
97
- currentTimeChange: 'end',
98
- }));
99
- }, [onHide, acquireLockShowing]);
100
-
101
- const onConfirmStartDate = useCallback((date) => {
74
+ const selectStart = useCallback((date) => {
102
75
  setStateDatePicker((state) => {
103
76
  if (moment(date).valueOf() < state.endDate) {
104
77
  return {
105
78
  ...state,
106
- visible: false,
107
79
  startDate: moment(date).valueOf(),
108
80
  };
109
81
  }
110
82
  return {
111
83
  ...state,
112
- visible: false,
113
84
  startDate: moment(date).valueOf(),
114
85
  endDate: moment(date).add(1, 'days').valueOf(),
115
86
  };
116
87
  });
117
88
  }, []);
118
89
 
119
- const onConfirmEndDate = useCallback((date) => {
90
+ const selectEnd = useCallback((date) => {
120
91
  setStateDatePicker((state) => {
121
92
  if (moment(date).valueOf() > state.startDate) {
122
93
  return {
123
94
  ...state,
124
- visible: false,
125
95
  endDate: moment(date).valueOf(),
126
96
  };
127
97
  }
128
98
  return {
129
99
  ...state,
130
- visible: false,
131
100
  startDate: moment(date).add(-1, 'days').valueOf(),
132
101
  endDate: moment(date).valueOf(),
133
102
  };
134
103
  });
135
104
  }, []);
136
105
 
137
- const onConfirmDate = useCallback(
138
- (date) => {
139
- if (stateDatePicker.currentTimeChange === 'start') {
140
- onConfirmStartDate(date);
141
- } else {
142
- onConfirmEndDate(date);
143
- }
144
- onShow();
145
- acquireLockShowing();
146
- },
147
- [
148
- onConfirmStartDate,
149
- onConfirmEndDate,
150
- stateDatePicker,
151
- acquireLockShowing,
152
- onShow,
153
- ]
154
- );
155
-
156
- const onPickerCancel = useCallback(() => {
157
- setStateDatePicker((state) => ({
158
- ...state,
159
- visible: false,
160
- }));
161
- acquireLockShowing();
162
- onShow();
163
- }, [acquireLockShowing, onShow]);
164
-
165
106
  const handleOnApply = useCallback(() => {
166
107
  onApply({
167
108
  users: selectedUsers,
@@ -184,10 +125,9 @@ const FilterPopup = ({
184
125
  return (
185
126
  <>
186
127
  <ModalCustom
187
- isVisible={isVisible && !lockShowing}
128
+ isVisible={isVisible}
188
129
  onBackButtonPress={handleOnCancel}
189
130
  onBackdropPress={handleOnCancel}
190
- onModalHide={releaseLockShowing}
191
131
  useNativeDriver={true}
192
132
  useNativeDriverForBackdrop={true}
193
133
  animationIn={'zoomIn'}
@@ -211,6 +151,7 @@ const FilterPopup = ({
211
151
  selectStart={selectStart}
212
152
  selectEnd={selectEnd}
213
153
  formatType="date"
154
+ style={styles.datePicker}
214
155
  inline={true}
215
156
  />
216
157
  {userFilterEnabled && (
@@ -245,22 +186,6 @@ const FilterPopup = ({
245
186
  />
246
187
  </View>
247
188
  </ModalCustom>
248
- <DateTimePickerModal
249
- isVisible={stateDatePicker.visible && !lockShowing}
250
- date={
251
- stateDatePicker.currentTimeChange === 'start'
252
- ? new Date(stateDatePicker.startDate)
253
- : new Date(stateDatePicker.endDate)
254
- }
255
- mode={'date'}
256
- onConfirm={onConfirmDate}
257
- onCancel={onPickerCancel}
258
- onHide={releaseLockShowing}
259
- display="spinner"
260
- headerTextIOS={t('pick_a_date')}
261
- cancelTextIOS={t('cancel')}
262
- confirmTextIOS={t('confirm')}
263
- />
264
189
  </>
265
190
  );
266
191
  };
@@ -46,6 +46,7 @@ const DetailLog = ({ item }) => {
46
46
  ? `${item.action_name} ${t('by')} `
47
47
  : `${t('activated_by')} `}
48
48
  <Text style={styles.name}>{item.name || item.username}</Text>
49
+ <Text style={styles.text}>{'\n' + item.message}</Text>
49
50
  </Text>
50
51
  );
51
52
  }
@@ -8,7 +8,6 @@ import RadioCircle from '../../../commons/RadioCircle';
8
8
  import { AccessibilityLabel } from '../../../configs/Constants';
9
9
  import BottomButtonView from '../../../commons/BottomButtonView';
10
10
  import DateTimeRangeChange from '../../../commons/DateTimeRangeChange';
11
- import DateTimePickerModal from 'react-native-modal-datetime-picker';
12
11
  import moment from 'moment';
13
12
 
14
13
  const wrapComponent = (props) => (
@@ -125,7 +124,6 @@ it('test date picker pick valid and invalid date', async () => {
125
124
  });
126
125
  const instance = tree.root;
127
126
  const dateTimeRangeChange = instance.findByType(DateTimeRangeChange);
128
- const datePicker = instance.findAllByType(DateTimePickerModal)[2];
129
127
 
130
128
  expect(dateTimeRangeChange.props.startTime).toBe(dateFrom.valueOf());
131
129
  expect(dateTimeRangeChange.props.endTime).toBe(dateTo.valueOf());
@@ -133,11 +131,9 @@ it('test date picker pick valid and invalid date', async () => {
133
131
  const _pickDateAndTest = async (timeChange) => {
134
132
  await act(async () => {
135
133
  if (timeChange === 'start') {
136
- await dateTimeRangeChange.props.selectStart();
137
- await datePicker.props.onConfirm(moment(dateFrom));
134
+ await dateTimeRangeChange.props.selectStart(dateFrom);
138
135
  } else {
139
- await dateTimeRangeChange.props.selectEnd();
140
- await datePicker.props.onConfirm(moment(dateTo));
136
+ await dateTimeRangeChange.props.selectEnd(dateTo);
141
137
  }
142
138
  });
143
139
  expect(dateTimeRangeChange.props.startTime).toBe(dateFrom.valueOf());
@@ -1,17 +1,20 @@
1
+ import { act } from '@testing-library/react-hooks';
2
+ import MockAdapter from 'axios-mock-adapter';
1
3
  import React from 'react';
2
4
  import { SectionList, Text } from 'react-native';
3
5
  import { create } from 'react-test-renderer';
4
- import { act } from '@testing-library/react-hooks';
5
- import MockAdapter from 'axios-mock-adapter';
6
+ import DateTimePickerModal from 'react-native-modal-datetime-picker';
7
+ import moment from 'moment';
6
8
 
7
9
  import ActivityLog from '../';
8
10
  import { API, Constants } from '../../../configs';
9
11
  import { SCProvider } from '../../../context';
10
12
  import { mockSCStore } from '../../../context/mockStore';
11
13
  import ItemLog from '../ItemLog';
14
+ import FilterPopup from '../FilterPopup';
15
+ import BottomButtonView from '../../../commons/BottomButtonView';
12
16
  import DateTimeRangeChange from '../../../commons/DateTimeRangeChange';
13
- import DateTimePickerModal from 'react-native-modal-datetime-picker';
14
- import Modal from 'react-native-modal';
17
+ import DateTimeButton from '../../../commons/DateTimeRangeChange/DateTimeButton';
15
18
  import { AUTOMATE_TYPE, AccessibilityLabel } from '../../../configs/Constants';
16
19
  import api from '../../../utils/Apis/axios';
17
20
 
@@ -88,13 +91,15 @@ describe('Test Activity log', () => {
88
91
  expect(items).toHaveLength(1);
89
92
  });
90
93
 
91
- it('test open and close 2 modal', async () => {
94
+ it('test filter and date picker popup', async () => {
95
+ const dateFrom = moment('2025-08-18T10:00:00.000Z');
96
+ const dateTo = moment(dateFrom).add(7, 'days');
92
97
  await act(async () => {
93
98
  tree = await create(wrapComponent(route));
94
99
  });
95
100
  const instance = tree.root;
96
- const filterPopup = instance.findAllByType(Modal);
97
- expect(filterPopup[0].props.isVisible).toBeFalsy();
101
+ const filterPopup = instance.findByType(FilterPopup);
102
+ expect(filterPopup.props.isVisible).toBeFalsy();
98
103
 
99
104
  const filterButton = instance.findByProps({
100
105
  accessibilityLabel: AccessibilityLabel.FILTER_BUTTON,
@@ -102,43 +107,60 @@ describe('Test Activity log', () => {
102
107
  await act(async () => {
103
108
  filterButton.props.onPress();
104
109
  });
105
- expect(filterPopup[0].props.isVisible).toBeTruthy();
110
+ expect(filterPopup.props.isVisible).toBeTruthy();
106
111
 
107
112
  const dateTimeRangeChange = instance.findByType(DateTimeRangeChange);
108
- const datePicker = instance.findAllByType(DateTimePickerModal)[2];
113
+ const datePickers = instance.findAllByType(DateTimePickerModal);
114
+ const buttonPickers = instance.findAllByType(DateTimeButton);
115
+
116
+ // open popup start date
117
+ await act(async () => {
118
+ await buttonPickers[0].props.onPress();
119
+ });
120
+ expect(datePickers[0].props.isVisible).toBeTruthy();
121
+ expect(filterPopup.props.isVisible).toBeTruthy();
109
122
 
110
123
  // pick start date
111
124
  await act(async () => {
112
- await dateTimeRangeChange.props.selectStart();
113
- await filterPopup[0].props.onModalHide();
125
+ await dateTimeRangeChange.props.selectStart(dateFrom);
114
126
  });
115
- expect(filterPopup[0].props.isVisible).toBeFalsy();
116
- // cancel
127
+ expect(datePickers[0].props.isVisible).toBeTruthy();
128
+ expect(filterPopup.props.isVisible).toBeTruthy();
129
+
130
+ // cancel start date
117
131
  await act(async () => {
118
- await datePicker.props.onCancel();
119
- await datePicker.props.onHide();
132
+ await datePickers[0].props.onCancel();
120
133
  });
121
- expect(filterPopup[0].props.isVisible).toBeTruthy();
122
- expect(datePicker.props.isVisible).toBeFalsy();
123
- // open popup
134
+ expect(datePickers[0].props.isVisible).toBeFalsy();
135
+ expect(filterPopup.props.isVisible).toBeTruthy();
136
+
137
+ // open popup end date
124
138
  await act(async () => {
125
- await filterButton.props.onPress();
139
+ await buttonPickers[1].props.onPress();
126
140
  });
127
- expect(filterPopup[0].props.isVisible).toBeTruthy();
141
+ expect(datePickers[1].props.isVisible).toBeTruthy();
142
+ expect(filterPopup.props.isVisible).toBeTruthy();
143
+
128
144
  // pick end date
129
145
  await act(async () => {
130
- await dateTimeRangeChange.props.selectEnd();
131
- await filterPopup[0].props.onModalHide();
146
+ await dateTimeRangeChange.props.selectEnd(dateTo);
132
147
  });
133
- expect(filterPopup[0].props.isVisible).toBeFalsy();
134
- expect(datePicker.props.isVisible).toBeTruthy();
135
- // confirm
148
+ expect(datePickers[1].props.isVisible).toBeTruthy();
149
+ expect(filterPopup.props.isVisible).toBeTruthy();
150
+
151
+ // confirm end date
152
+ await act(async () => {
153
+ await datePickers[1].props.onConfirm();
154
+ });
155
+ expect(datePickers[1].props.isVisible).toBeFalsy();
156
+ expect(filterPopup.props.isVisible).toBeTruthy();
157
+
158
+ // apply filter
159
+ const applyButton = instance.findByType(BottomButtonView);
136
160
  await act(async () => {
137
- await datePicker.props.onConfirm();
138
- await datePicker.props.onHide();
161
+ await applyButton.props.onPressMain();
139
162
  });
140
- expect(filterPopup[0].props.isVisible).toBeTruthy();
141
- expect(datePicker.props.isVisible).toBeFalsy();
163
+ expect(filterPopup.props.isVisible).toBeFalsy();
142
164
  });
143
165
 
144
166
  const setUpActionLogScreen = () => {
@@ -121,7 +121,6 @@ const ActivityLogScreen = ({ route }) => {
121
121
  <FilterPopup
122
122
  isVisible={showFilterPopup}
123
123
  onHide={setHideFilterPopup}
124
- onShow={setShowFilterPopup}
125
124
  members={members}
126
125
  filters={filters}
127
126
  userFilterEnabled={filterEnabled.user}