@eohjsc/react-native-smart-city 0.2.86 → 0.2.89

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 (126) hide show
  1. package/assets/images/Common/Calendar.svg +3 -0
  2. package/assets/images/Common/SmartPhone.svg +3 -0
  3. package/assets/images/Hanet/CaptureFaceID.svg +25 -0
  4. package/assets/images/Hanet/FaceFrame.svg +6 -0
  5. package/assets/images/brightnessBlack.svg +12 -0
  6. package/index.js +4 -0
  7. package/package.json +3 -3
  8. package/src/Images/SmartIr/AC.svg +14 -0
  9. package/src/Images/SmartIr/DIY.svg +3 -0
  10. package/src/Images/SmartIr/Fan.svg +10 -0
  11. package/src/Images/SmartIr/Fridge.svg +5 -0
  12. package/src/Images/SmartIr/Remote.svg +15 -0
  13. package/src/Images/SmartIr/SmartIr.svg +4 -0
  14. package/src/Images/SmartIr/TV.svg +10 -0
  15. package/src/Images/SmartIr/Union.svg +9 -0
  16. package/src/Images/SmartIr/WM.svg +11 -0
  17. package/src/Images/SmartIr/index.js +10 -0
  18. package/src/commons/ActionGroup/ColorPickerTemplate.js +51 -0
  19. package/src/commons/ActionGroup/ColorPickerTemplateStyles.js +17 -0
  20. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/AutoLockStyles.js +40 -0
  21. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapper.js +65 -0
  22. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapperStyles.js +43 -0
  23. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/__test__/index.test.js +48 -0
  24. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/index.js +57 -0
  25. package/src/commons/ActionGroup/{OnOffSmartLock.js → OnOffSmartLock/OnOffSmartLock.js} +5 -5
  26. package/src/commons/ActionGroup/{OnOffSmartLockStyle.js → OnOffSmartLock/OnOffSmartLockStyle.js} +1 -1
  27. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscode.js +48 -0
  28. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscodeStyles.js +42 -0
  29. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/PasscodeListStyles.js +49 -0
  30. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/index.js +66 -0
  31. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/ButtonWrapper.js +96 -0
  32. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/SetupGeneratePasscodeStyles.js +98 -0
  33. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/__test__/index.test.js +62 -0
  34. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/index.js +249 -0
  35. package/src/commons/ActionGroup/OnOffTemplate/index.js +4 -2
  36. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +2 -1
  37. package/src/commons/ActionGroup/SliderRangeTemplate.js +64 -0
  38. package/src/commons/ActionGroup/{LightActionTemplateStyles.js → SliderRangeTemplateStyles.js} +0 -8
  39. package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +167 -186
  40. package/src/commons/ActionGroup/StatesGridActionTemplate.js +2 -1
  41. package/src/commons/ActionGroup/index.js +7 -4
  42. package/src/commons/BottomSheet/index.js +2 -1
  43. package/src/commons/Device/DisconnectedView.js +7 -1
  44. package/src/commons/Device/Hanet/ItemHanetDevice.js +109 -0
  45. package/src/commons/Device/HistoryChart.js +2 -2
  46. package/src/commons/Device/HorizontalBarChart.js +7 -0
  47. package/src/commons/Device/ItemDevice.js +18 -15
  48. package/src/commons/Device/LinearChart.js +14 -41
  49. package/src/commons/Device/__test__/DisconnectedView.test.js +13 -2
  50. package/src/commons/RowItem/index.js +12 -7
  51. package/src/commons/SubUnit/Favorites/index.js +2 -2
  52. package/src/commons/SubUnit/ShortDetail.js +39 -20
  53. package/src/commons/WheelDateTimePicker/index.js +18 -4
  54. package/src/configs/API.js +23 -1
  55. package/src/configs/Colors.js +1 -0
  56. package/src/configs/Constants.js +48 -0
  57. package/src/configs/SCConfig.js +1 -1
  58. package/src/context/actionType.ts +4 -0
  59. package/src/context/mockStore.ts +3 -0
  60. package/src/context/reducer.ts +20 -0
  61. package/src/iot/RemoteControl/Bluetooth.js +3 -22
  62. package/src/iot/RemoteControl/index.js +0 -1
  63. package/src/navigations/HanetCameraStack.js +41 -0
  64. package/src/navigations/SmartIrStack.js +31 -0
  65. package/src/navigations/SmartLockStack.js +51 -0
  66. package/src/navigations/UnitStack.js +46 -4
  67. package/src/screens/ActivityLog/hooks/index.js +1 -1
  68. package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +1 -1
  69. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +79 -72
  70. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +155 -27
  71. package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +65 -0
  72. package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +26 -2
  73. package/src/screens/Device/__test__/detail.test.js +0 -10
  74. package/src/screens/Device/components/SensorConnectStatusViewHeader.js +13 -2
  75. package/src/screens/Device/detail.js +118 -38
  76. package/src/screens/Device/hooks/useDisconnectedDevice.js +28 -16
  77. package/src/screens/GuestInfo/components/AccessScheduleItem.js +9 -2
  78. package/src/screens/GuestInfo/components/RecurringDetail.js +3 -2
  79. package/src/screens/GuestInfo/components/TemporaryDetail.js +3 -2
  80. package/src/screens/GuestInfo/styles/AccessScheduleItemStyles.js +3 -0
  81. package/src/screens/HanetCamera/CaptureFaceID.js +210 -0
  82. package/src/screens/HanetCamera/Detail.js +252 -0
  83. package/src/screens/HanetCamera/ManageAccess.js +173 -0
  84. package/src/screens/HanetCamera/MemberInfo.js +208 -0
  85. package/src/screens/HanetCamera/__test__/CaptureFaceID.test.js +133 -0
  86. package/src/screens/HanetCamera/__test__/Detail.test.js +185 -0
  87. package/src/screens/HanetCamera/__test__/ManageAccess.test.js +152 -0
  88. package/src/screens/HanetCamera/__test__/MemberInfo.test.js +178 -0
  89. package/src/screens/HanetCamera/components/CheckinHeader.js +37 -0
  90. package/src/screens/HanetCamera/hooks/__test__/useHanetCheckinData.test.js +151 -0
  91. package/src/screens/HanetCamera/hooks/__test__/useHanetPlaceMembers.test.js +71 -0
  92. package/src/screens/HanetCamera/hooks/index.js +5 -0
  93. package/src/screens/HanetCamera/hooks/useHanetCheckinData.js +116 -0
  94. package/src/screens/HanetCamera/hooks/useHanetPlaceMembers.js +86 -0
  95. package/src/screens/HanetCamera/hooks/useStateAlertAction.js +62 -0
  96. package/src/screens/HanetCamera/styles/captureFaceIDStyles.js +50 -0
  97. package/src/screens/HanetCamera/styles/checkinHeaderStyles.js +24 -0
  98. package/src/screens/HanetCamera/styles/detailStyles.js +107 -0
  99. package/src/screens/HanetCamera/styles/manageAccessStyles.js +49 -0
  100. package/src/screens/HanetCamera/styles/memberInfoStyles.js +73 -0
  101. package/src/screens/HanetCamera/utils/Monitor.js +52 -0
  102. package/src/screens/Notification/__test__/NotificationItem.test.js +1 -0
  103. package/src/screens/Notification/components/NotificationItem.js +16 -0
  104. package/src/screens/SmartIr/__test__/ButtonsBottom.test.js +31 -0
  105. package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +80 -0
  106. package/src/screens/SmartIr/__test__/SelectBrand.test.js +65 -0
  107. package/src/screens/SmartIr/__test__/SelectDeviceType.test.js +57 -0
  108. package/src/screens/SmartIr/__test__/SmartIr.test.js +1 -0
  109. package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottom.js +45 -0
  110. package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottomStyles.js +31 -0
  111. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +208 -0
  112. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByTypeStyles.js +113 -0
  113. package/src/screens/SmartIr/components/SelectBrand.js +61 -0
  114. package/src/screens/SmartIr/components/SelectBrandStyles.js +14 -0
  115. package/src/screens/SmartIr/components/SelectDeviceType.js +96 -0
  116. package/src/screens/SmartIr/components/SelectDeviceTypeStyles.js +30 -0
  117. package/src/screens/SmartIr/index.js +8 -3
  118. package/src/screens/Unit/Detail.js +7 -11
  119. package/src/screens/Unit/__test__/Detail.test.js +0 -10
  120. package/src/screens/Unit/components/MyUnitDevice/index.js +2 -4
  121. package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +38 -9
  122. package/src/utils/I18n/translations/en.json +51 -1
  123. package/src/utils/I18n/translations/vi.json +51 -1
  124. package/src/utils/Route/index.js +14 -1
  125. package/src/commons/ActionGroup/LightActionTemplate.js +0 -103
  126. package/src/commons/ActionGroup/__test__/LightActionTemplate.test.js +0 -59
@@ -46,7 +46,7 @@ import { useSCContextSelector } from '../../context';
46
46
  import { EmergencyCountdown } from './components/EmergencyCountdown';
47
47
  import { SensorConnectStatusViewHeader } from './components/SensorConnectStatusViewHeader';
48
48
  import { useDisconnectedDevice } from './hooks/useDisconnectedDevice';
49
- import { useNetInfo } from '@react-native-community/netinfo';
49
+ import { Card } from '../../commons/CardShadow';
50
50
 
51
51
  const DeviceDetail = ({ route }) => {
52
52
  const t = useTranslations();
@@ -79,10 +79,20 @@ const DeviceDetail = ({ route }) => {
79
79
  isConnected: true,
80
80
  displayTemplate: true,
81
81
  });
82
+ const [serverDown, setServerDown] = useState(false);
83
+
84
+ const isNetworkConnected = useSCContextSelector(
85
+ (state) => state.app.isNetworkConnected
86
+ );
87
+ const isBluetoothEnabled = useSCContextSelector(
88
+ (state) => state.app.isBluetoothEnabled
89
+ );
82
90
 
83
91
  const isDeviceConnectedViaBle = useMemo(
84
- () => isDeviceConnected(sensor?.remote_control_options?.bluetooth?.address),
85
- [sensor]
92
+ () =>
93
+ isBluetoothEnabled &&
94
+ isDeviceConnected(sensor?.remote_control_options?.bluetooth?.address),
95
+ [sensor, isBluetoothEnabled]
86
96
  );
87
97
 
88
98
  const isDeviceHasBle = useMemo(() => {
@@ -99,15 +109,21 @@ const DeviceDetail = ({ route }) => {
99
109
  });
100
110
  }, [display]);
101
111
 
102
- useDisconnectedDevice(sensorName, isDeviceHasBle);
103
-
104
- const netInfo = useNetInfo();
112
+ useDisconnectedDevice(sensorName, isDeviceHasBle, serverDown);
105
113
 
106
- const isShowSetupEmergencyContact =
114
+ const isShowSetupEmergencyContact = useMemo(() => {
107
115
  display.items.filter(
108
116
  (item) =>
109
117
  item.type === 'emergency' && item.configuration.type === 'button'
110
118
  ).length > 0;
119
+ }, [display.items]);
120
+
121
+ const isShowSetUpSmartLock = useMemo(() => {
122
+ display.items.filter(
123
+ (item) =>
124
+ item.type === 'smartLock' && item.configuration.type === 'button'
125
+ ).length > 0;
126
+ }, [display.items]);
111
127
 
112
128
  const addToFavorites = useCallback(async () => {
113
129
  const { success } = await axiosPost(
@@ -140,31 +156,31 @@ const DeviceDetail = ({ route }) => {
140
156
  }, [currentUserId, unit]);
141
157
 
142
158
  const fetchUnitDetail = useCallback(async () => {
143
- const { success, data } = await axiosGet(API.UNIT.UNIT_DETAIL(unit?.id));
159
+ const { success, data } = await axiosGet(API.UNIT.UNIT_DETAIL(unitId));
144
160
  if (success) {
145
161
  setUnit(data);
146
162
  }
147
- }, [unit?.id]);
163
+ }, [unitId]);
148
164
 
149
165
  useEffect(() => {
150
- if (!unitData && unitId) {
166
+ if (unitId) {
151
167
  fetchUnitDetail();
152
168
  }
153
169
  }, [fetchUnitDetail, unitData, unitId]);
154
170
 
155
171
  const fetchSensorDetail = useCallback(async () => {
156
172
  const { success, data } = await axiosGet(
157
- API.SENSOR.SENSOR_DETAIL(sensor?.id)
173
+ API.SENSOR.SENSOR_DETAIL(sensorId)
158
174
  );
159
175
  if (success) {
160
176
  setSensor(data);
161
177
  setSensorName(data.name);
162
178
  setStation(data.station);
163
179
  }
164
- }, [sensor?.id]);
180
+ }, [sensorId]);
165
181
 
166
182
  useEffect(() => {
167
- if (!sensorData && sensorId) {
183
+ if (sensorId) {
168
184
  fetchSensorDetail();
169
185
  }
170
186
  }, [fetchSensorDetail, sensorData, sensorId]);
@@ -177,16 +193,16 @@ const DeviceDetail = ({ route }) => {
177
193
  return;
178
194
  }
179
195
 
180
- const displayResult = await axiosGet(
196
+ const { success, data, resp_status } = await axiosGet(
181
197
  API.SENSOR.DISPLAY(sensor?.id),
182
198
  {},
183
199
  true
184
200
  );
185
-
186
- if (displayResult.success) {
187
- setDisplay(displayResult.data);
188
- if (displayResult.data.items.length) {
189
- const config = displayResult.data.items[0].configuration;
201
+ if (success) {
202
+ setDisplay(data);
203
+ setServerDown(false);
204
+ if (data.items.length) {
205
+ const config = data.items[0].configuration;
190
206
  if (config.hasOwnProperty('max_value')) {
191
207
  setMaxValue(config.max_value);
192
208
  }
@@ -201,6 +217,8 @@ const DeviceDetail = ({ route }) => {
201
217
  }
202
218
  }
203
219
  }
220
+ } else if (resp_status >= 500) {
221
+ setServerDown(true);
204
222
  }
205
223
  setLoading((preState) => ({ ...preState, displayTemplate: false }));
206
224
 
@@ -303,6 +321,33 @@ const DeviceDetail = ({ route }) => {
303
321
  deviceInfo: display.items.filter((item) => item.type === 'device_info'),
304
322
  },
305
323
  });
324
+ if (isShowSetUpSmartLock) {
325
+ menuItems.push({
326
+ route: Routes.SmartLockStack,
327
+ data: {
328
+ screen: Routes.AutoLock,
329
+ },
330
+ text: t('auto_lock'),
331
+ });
332
+ }
333
+ if (isOwner && isShowSetUpSmartLock) {
334
+ menuItems.push({
335
+ route: Routes.SmartLockStack,
336
+ data: {
337
+ screen: Routes.SetupGeneratePasscode,
338
+ },
339
+ text: t('setup_generate_passcode'),
340
+ });
341
+ }
342
+ if (isShowSetUpSmartLock) {
343
+ menuItems.push({
344
+ route: Routes.SmartLockStack,
345
+ data: {
346
+ screen: Routes.PasscodeList,
347
+ },
348
+ text: t('passcode_list'),
349
+ });
350
+ }
306
351
  if (!isFavourite) {
307
352
  menuItems.unshift({
308
353
  doAction: addToFavorites,
@@ -319,11 +364,12 @@ const DeviceDetail = ({ route }) => {
319
364
  display.items,
320
365
  isOwner,
321
366
  isShowSetupEmergencyContact,
367
+ isShowSetUpSmartLock,
322
368
  t,
323
369
  isFavourite,
324
370
  sensor,
325
- sensorName,
326
371
  unit,
372
+ sensorName,
327
373
  station,
328
374
  emergencyDeviceId,
329
375
  addToFavorites,
@@ -456,31 +502,65 @@ const DeviceDetail = ({ route }) => {
456
502
  return (
457
503
  <SensorConnectStatusViewHeader
458
504
  sensor={sensor}
459
- connected={netInfo.isConnected && isConnected}
505
+ connected={isNetworkConnected && isConnected}
460
506
  connectedBlt={
461
- (!netInfo.isConnected || (netInfo.isConnected && !isConnected)) &&
507
+ (!isNetworkConnected || (isNetworkConnected && !isConnected)) &&
462
508
  isDeviceConnectedViaBle
463
509
  }
464
510
  lastUpdated={lastUpdated}
465
511
  isDisplayTime={isShowSetupEmergencyContact ? false : isDisplayTime}
466
512
  showWindDirection={showWindDirection}
467
513
  isGGHomeConnected={isGGHomeConnected}
514
+ isDeviceHasBle={isDeviceHasBle}
468
515
  >
469
- {display.items.map((item) => (
470
- <SensorDisplayItem
471
- testID={TESTID.SENSOR_DISPLAY_ITEM}
472
- key={item.id.toString()}
473
- item={item}
474
- emergency={onEmergencyButtonPress}
475
- sensor={sensor}
476
- getData={getData}
477
- maxValue={maxValue}
478
- offsetTitle={offsetTitle}
479
- setOffsetTitle={setOffsetTitle}
480
- setShowWindDirection={setShowWindDirection}
481
- background={station?.background}
482
- />
483
- ))}
516
+ {display.items.map((item) => {
517
+ switch (item?.configuration?.template) {
518
+ case 'color_picker_template':
519
+ case 'slider_range_template':
520
+ return <></>;
521
+ default:
522
+ return (
523
+ <SensorDisplayItem
524
+ testID={TESTID.SENSOR_DISPLAY_ITEM}
525
+ key={item.id.toString()}
526
+ item={item}
527
+ emergency={onEmergencyButtonPress}
528
+ sensor={sensor}
529
+ getData={getData}
530
+ maxValue={maxValue}
531
+ offsetTitle={offsetTitle}
532
+ setOffsetTitle={setOffsetTitle}
533
+ setShowWindDirection={setShowWindDirection}
534
+ background={station?.background}
535
+ />
536
+ );
537
+ }
538
+ })}
539
+ <Card title={t('controller')}>
540
+ {display.items.map((item) => {
541
+ switch (item?.configuration?.template) {
542
+ case 'color_picker_template':
543
+ case 'slider_range_template':
544
+ return (
545
+ <SensorDisplayItem
546
+ testID={TESTID.SENSOR_DISPLAY_ITEM}
547
+ key={item.id.toString()}
548
+ item={item}
549
+ emergency={onEmergencyButtonPress}
550
+ sensor={sensor}
551
+ getData={getData}
552
+ maxValue={maxValue}
553
+ offsetTitle={offsetTitle}
554
+ setOffsetTitle={setOffsetTitle}
555
+ setShowWindDirection={setShowWindDirection}
556
+ background={station?.background}
557
+ />
558
+ );
559
+ default:
560
+ return <></>;
561
+ }
562
+ })}
563
+ </Card>
484
564
  </SensorConnectStatusViewHeader>
485
565
  );
486
566
  };
@@ -576,7 +656,7 @@ const DeviceDetail = ({ route }) => {
576
656
  <View style={styles.wrapTemplate}>
577
657
  {loading.displayTemplate === false &&
578
658
  loading.isConnected === false &&
579
- netInfo.isConnected !== null &&
659
+ isNetworkConnected !== null &&
580
660
  renderSensorConnected()}
581
661
  </View>
582
662
  {isShowSetupEmergencyContact && canManageSubUnit && (
@@ -1,23 +1,27 @@
1
- import NetInfo from '@react-native-community/netinfo';
1
+ import { useNavigation } from '@react-navigation/native';
2
2
  import { useCallback, useEffect } from 'react';
3
3
  import { Alert, Linking, Platform } from 'react-native';
4
4
  import { useTranslations } from '../../../hooks/Common/useTranslations';
5
- import {
6
- enableBluetoothForAndroid,
7
- useIsBluetoothEnabled,
8
- } from '../../../iot/RemoteControl/Bluetooth';
5
+ import { useSCContextSelector } from '../../../context';
6
+ import { enableBluetoothForAndroid } from '../../../iot/RemoteControl/Bluetooth';
9
7
  import { ToastBottomHelper } from '../../../utils/Utils';
10
8
 
11
- export const useDisconnectedDevice = (sensorName, isDeviceHasBle) => {
9
+ export const useDisconnectedDevice = (
10
+ sensorName,
11
+ isDeviceHasBle,
12
+ serverDown
13
+ ) => {
12
14
  const t = useTranslations();
13
15
  const openBluetoothIOS = () => {
14
16
  Linking.openURL('App-Prefs:Bluetooth');
15
17
  };
18
+ const { goBack } = useNavigation();
16
19
  const actions =
17
20
  Platform.OS === 'ios'
18
21
  ? [
19
22
  {
20
23
  text: 'Skip',
24
+ onPress: () => goBack(),
21
25
  },
22
26
  {
23
27
  text: 'Open',
@@ -27,6 +31,7 @@ export const useDisconnectedDevice = (sensorName, isDeviceHasBle) => {
27
31
  : [
28
32
  {
29
33
  text: 'Skip',
34
+ onPress: () => goBack(),
30
35
  },
31
36
  {
32
37
  text: 'Open',
@@ -34,21 +39,28 @@ export const useDisconnectedDevice = (sensorName, isDeviceHasBle) => {
34
39
  },
35
40
  ];
36
41
 
37
- const netState = NetInfo.useNetInfo();
38
- const isBluetoothEnabled = useIsBluetoothEnabled();
42
+ const isBluetoothEnabled = useSCContextSelector(
43
+ (state) => state.app.isBluetoothEnabled
44
+ );
45
+ const isNetworkConnected = useSCContextSelector(
46
+ (state) => state.app.isNetworkConnected
47
+ );
39
48
 
40
- const checkNetWorkConnect = useCallback(
41
- async (isHavingInternet, isBtEnabled) => {
42
- if (isHavingInternet === false && isDeviceHasBle) {
43
- // TODO avoid case first render isHavingInternet == null
44
- if (isBtEnabled === true) {
49
+ const checkNetworkConnect = useCallback(
50
+ async (isNetworkConnected, isBluetoothEnabled, serverDown) => {
51
+ if (!isDeviceHasBle) {
52
+ return;
53
+ }
54
+ if (isNetworkConnected === false || serverDown) {
55
+ // TODO avoid case first render isNetworkConnected == null
56
+ if (isBluetoothEnabled === true) {
45
57
  ToastBottomHelper.info(
46
58
  t('your_internet_is_disconnected', { name: sensorName }),
47
59
  t('change_to_control_via_bluetooth_connection', {
48
60
  name: sensorName,
49
61
  })
50
62
  );
51
- } else if (isBtEnabled === false) {
63
+ } else if (isBluetoothEnabled === false) {
52
64
  Alert.alert(
53
65
  '',
54
66
  t(
@@ -64,6 +76,6 @@ export const useDisconnectedDevice = (sensorName, isDeviceHasBle) => {
64
76
  );
65
77
 
66
78
  useEffect(() => {
67
- checkNetWorkConnect(netState.isConnected, isBluetoothEnabled);
68
- }, [netState.isConnected, isBluetoothEnabled, checkNetWorkConnect]);
79
+ checkNetworkConnect(isNetworkConnected, isBluetoothEnabled, serverDown);
80
+ }, [isNetworkConnected, isBluetoothEnabled, checkNetworkConnect, serverDown]);
69
81
  };
@@ -5,14 +5,21 @@ import Text from '../../../commons/Text';
5
5
  import { TESTID } from '../../../configs/Constants';
6
6
  import styles from '../styles/AccessScheduleItemStyles';
7
7
 
8
- const AccessScheduleItem = ({ item, isSelected, onSelect }) => {
8
+ const AccessScheduleItem = ({
9
+ item,
10
+ isSelected,
11
+ onSelect,
12
+ isSetupGeneratePasscode,
13
+ }) => {
9
14
  const DetailComponent = item.detail;
10
15
  const handleOnSelect = useCallback(() => {
11
16
  onSelect(item.value);
12
17
  }, [item.value, onSelect]);
13
18
 
14
19
  return (
15
- <View style={styles.rowWrap}>
20
+ <View
21
+ style={isSetupGeneratePasscode ? styles.WrapnotPadding : styles.rowWrap}
22
+ >
16
23
  <View style={styles.rowContent}>
17
24
  <TouchableOpacity
18
25
  style={styles.row}
@@ -7,6 +7,7 @@ import { Colors } from '../../../configs';
7
7
  import { REPEAT_ITEMS } from '../constant';
8
8
  import styles from '../styles/AccessScheduleDetailStyles';
9
9
  import { TESTID } from '../../../configs/Constants';
10
+ import moment from 'moment';
10
11
 
11
12
  const RecurringDetail = ({
12
13
  onShowSetDateTime,
@@ -73,7 +74,7 @@ const RecurringDetail = ({
73
74
  testID={TESTID.RECURRING_TEXT_BUTTON}
74
75
  >
75
76
  <Text type="Body" color={Colors.Orange} style={styles.value}>
76
- {recurringTimeStart.format('hh:mm A')}
77
+ {moment(recurringTimeStart).format('hh:mm A')}
77
78
  </Text>
78
79
  </TouchableOpacity>
79
80
  <Text type="Body" color={Colors.Gray8} style={styles.title}>
@@ -84,7 +85,7 @@ const RecurringDetail = ({
84
85
  testID={TESTID.RECURRING_TEXT_BUTTON}
85
86
  >
86
87
  <Text type="Body" color={Colors.Orange} style={styles.value}>
87
- {recurringTimeEnd.format('hh:mm A')}
88
+ {moment(recurringTimeEnd).format('hh:mm A')}
88
89
  </Text>
89
90
  </TouchableOpacity>
90
91
  <Text type="Body" color={Colors.Gray8} style={styles.title}>
@@ -5,6 +5,7 @@ import Text from '../../../commons/Text';
5
5
  import { Colors } from '../../../configs';
6
6
  import styles from '../styles/AccessScheduleDetailStyles';
7
7
  import { TESTID } from '../../../configs/Constants';
8
+ import moment from 'moment';
8
9
 
9
10
  const TemporaryDetail = ({
10
11
  onShowSetDateTime,
@@ -32,7 +33,7 @@ const TemporaryDetail = ({
32
33
  testID={TESTID.TEMPORARY_TEXT_BUTTON}
33
34
  >
34
35
  <Text type="Body" color={Colors.Orange} style={styles.value}>
35
- {temporaryTimeStart.format('hh:mm A DD/MM/YYYY')}
36
+ {moment(temporaryTimeStart).format('hh:mm A DD/MM/YYYY')}
36
37
  </Text>
37
38
  </TouchableOpacity>
38
39
  <Text type="Body" color={Colors.Gray8} style={styles.title}>
@@ -43,7 +44,7 @@ const TemporaryDetail = ({
43
44
  testID={TESTID.TEMPORARY_TEXT_BUTTON}
44
45
  >
45
46
  <Text type="Body" color={Colors.Orange} style={styles.value}>
46
- {temporaryTimeEnd.format('hh:mm A DD/MM/YYYY')}
47
+ {moment(temporaryTimeEnd).format('hh:mm A DD/MM/YYYY')}
47
48
  </Text>
48
49
  </TouchableOpacity>
49
50
  </View>
@@ -5,6 +5,9 @@ export default StyleSheet.create({
5
5
  rowWrap: {
6
6
  paddingHorizontal: 16,
7
7
  },
8
+ WrapnotPadding: {
9
+ paddingHorizontal: 0,
10
+ },
8
11
  rowContent: {
9
12
  paddingVertical: 24,
10
13
  },
@@ -0,0 +1,210 @@
1
+ import React, { memo, useState, useRef } from 'react';
2
+ import { View, ActivityIndicator, TouchableOpacity } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+ import { RNCamera } from 'react-native-camera';
5
+ import { HeaderCustom } from '../../commons/Header';
6
+ import { FullLoading } from '../../commons';
7
+ import Text from '../../commons/Text';
8
+ import { useTranslations } from '../../hooks/Common/useTranslations';
9
+ import CaptureFaceIDSvg from '../../../assets/images/Hanet/CaptureFaceID.svg';
10
+ import FaceFrameSvg from '../../../assets/images/Hanet/FaceFrame.svg';
11
+ import { axiosPatch } from '../../utils/Apis/axios';
12
+ import { Colors, Constants, API } from '../../configs';
13
+ import styles from './styles/captureFaceIDStyles';
14
+ import Routes from '../../utils/Route';
15
+
16
+ const LoadingCamera = memo(() => {
17
+ return (
18
+ <View style={styles.containerLoading}>
19
+ <ActivityIndicator />
20
+ </View>
21
+ );
22
+ });
23
+
24
+ const CaptureFaceID = ({ route }) => {
25
+ const t = useTranslations();
26
+ const { navigate, goBack } = useNavigation();
27
+ const { title, hanetPlace, hanetMember, setMemberAvatar, isAddNewMember } =
28
+ route.params;
29
+ const [openCamera, setOpenCamera] = useState(false);
30
+ const [capturing, setCapturing] = useState(false);
31
+ const [imageUri, setImageUri] = useState();
32
+ const [loading, setLoading] = useState(false);
33
+
34
+ const refCamera = useRef();
35
+
36
+ const beginCaptureFace = async () => {
37
+ setCapturing(true);
38
+ setOpenCamera(true);
39
+ };
40
+
41
+ const captureFace = async () => {
42
+ if (refCamera.current) {
43
+ const options = {
44
+ quality: 0.7,
45
+ height: 1280,
46
+ width: 736,
47
+ imageType: 'jpg',
48
+ pauseAfterCapture: true,
49
+ forceUpOrientation: true,
50
+ fixOrientation: true,
51
+ orientation: 'portrait',
52
+ };
53
+ const data = await refCamera.current.takePictureAsync(options);
54
+ setImageUri(data.uri);
55
+ setCapturing(false);
56
+ }
57
+ };
58
+
59
+ const resumeCapture = () => {
60
+ if (refCamera.current) {
61
+ setCapturing(true);
62
+ refCamera.current.resumePreview();
63
+ }
64
+ };
65
+
66
+ const updateMemberFaceID = async () => {
67
+ const formData = new FormData();
68
+ const name = imageUri.split('/').pop();
69
+ const ext = imageUri.split('.').pop();
70
+ formData.append('face_id', {
71
+ name: name,
72
+ type: `image/${ext}`,
73
+ uri: imageUri,
74
+ });
75
+ setLoading(true);
76
+ const { success, data } = await axiosPatch(
77
+ API.CAMERA.HANET.UPDATE_FACE_ID(
78
+ hanetPlace.place_id,
79
+ hanetMember.alias_id
80
+ ),
81
+ formData,
82
+ {
83
+ headers: { 'Content-Type': 'multipart/form-data' },
84
+ }
85
+ );
86
+ if (success) {
87
+ setMemberAvatar(data.avatar_uri);
88
+ goBack();
89
+ }
90
+ setLoading(false);
91
+ };
92
+
93
+ const newMemberDoneGetFaceID = () => {
94
+ navigate(Routes.HanetMemberInfo, {
95
+ hanetPlace: hanetPlace,
96
+ hanetMember: {
97
+ ...hanetMember,
98
+ avatar_uri: imageUri,
99
+ },
100
+ isAddNewMember: true,
101
+ });
102
+ };
103
+
104
+ const processFaceID = async () => {
105
+ if (isAddNewMember) {
106
+ newMemberDoneGetFaceID();
107
+ } else {
108
+ await updateMemberFaceID();
109
+ }
110
+ };
111
+
112
+ return (
113
+ <View style={styles.container}>
114
+ <HeaderCustom title={title} isShowSeparator />
115
+ {openCamera && (
116
+ <View style={styles.wrapCamera}>
117
+ <RNCamera
118
+ ref={refCamera}
119
+ style={{
120
+ height: Constants.height,
121
+ width: Constants.width,
122
+ }}
123
+ type={RNCamera.Constants.Type.back}
124
+ >
125
+ {({ camera, status, recordAudioPermissionStatus }) => {
126
+ if (status !== 'READY') {
127
+ return <LoadingCamera />;
128
+ }
129
+ return (
130
+ <View style={styles.maskOutter}>
131
+ <FaceFrameSvg />
132
+ </View>
133
+ );
134
+ }}
135
+ </RNCamera>
136
+ </View>
137
+ )}
138
+ {!openCamera && (
139
+ <View style={styles.center}>
140
+ <CaptureFaceIDSvg />
141
+ <Text type="H3" color={Colors.Gray9} bold style={styles.textDes}>
142
+ {t('text_des_capture_face_id')}
143
+ </Text>
144
+ </View>
145
+ )}
146
+ <View
147
+ style={[
148
+ styles.wrapBottom,
149
+ // eslint-disable-next-line react-native/no-inline-styles
150
+ openCamera && { height: '30%' },
151
+ openCamera &&
152
+ // eslint-disable-next-line react-native/no-inline-styles
153
+ !capturing && { justifyContent: 'flex-end', paddingBottom: 0 },
154
+ ]}
155
+ >
156
+ {!openCamera && (
157
+ <TouchableOpacity
158
+ onPress={beginCaptureFace}
159
+ style={styles.bottomButton}
160
+ >
161
+ <Text type="H4" semibold color={Colors.White}>
162
+ {t('begin')}
163
+ </Text>
164
+ </TouchableOpacity>
165
+ )}
166
+ {openCamera && capturing && (
167
+ <>
168
+ <Text
169
+ type="H3"
170
+ color={Colors.Gray9}
171
+ bold
172
+ center
173
+ style={styles.textLocateFace}
174
+ >
175
+ {t('text_des_locate_hanet_face_id')}
176
+ </Text>
177
+ <TouchableOpacity onPress={captureFace} style={styles.bottomButton}>
178
+ <Text type="H4" semibold color={Colors.White}>
179
+ {t('capture')}
180
+ </Text>
181
+ </TouchableOpacity>
182
+ </>
183
+ )}
184
+ {openCamera && !capturing && (
185
+ <>
186
+ <TouchableOpacity
187
+ onPress={processFaceID}
188
+ style={styles.bottomButton}
189
+ >
190
+ <Text type="H4" semibold color={Colors.White}>
191
+ {t('continue')}
192
+ </Text>
193
+ </TouchableOpacity>
194
+ <TouchableOpacity
195
+ onPress={resumeCapture}
196
+ style={[styles.bottomButton, styles.bottomButton2]}
197
+ >
198
+ <Text type="H4" semibold color={Colors.Primary}>
199
+ {t('capture_again')}
200
+ </Text>
201
+ </TouchableOpacity>
202
+ </>
203
+ )}
204
+ </View>
205
+ {loading && <FullLoading />}
206
+ </View>
207
+ );
208
+ };
209
+
210
+ export default CaptureFaceID;