@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.
- package/assets/images/Common/Calendar.svg +3 -0
- package/assets/images/Common/SmartPhone.svg +3 -0
- package/assets/images/Hanet/CaptureFaceID.svg +25 -0
- package/assets/images/Hanet/FaceFrame.svg +6 -0
- package/assets/images/brightnessBlack.svg +12 -0
- package/index.js +4 -0
- package/package.json +3 -3
- package/src/Images/SmartIr/AC.svg +14 -0
- package/src/Images/SmartIr/DIY.svg +3 -0
- package/src/Images/SmartIr/Fan.svg +10 -0
- package/src/Images/SmartIr/Fridge.svg +5 -0
- package/src/Images/SmartIr/Remote.svg +15 -0
- package/src/Images/SmartIr/SmartIr.svg +4 -0
- package/src/Images/SmartIr/TV.svg +10 -0
- package/src/Images/SmartIr/Union.svg +9 -0
- package/src/Images/SmartIr/WM.svg +11 -0
- package/src/Images/SmartIr/index.js +10 -0
- package/src/commons/ActionGroup/ColorPickerTemplate.js +51 -0
- package/src/commons/ActionGroup/ColorPickerTemplateStyles.js +17 -0
- package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/AutoLockStyles.js +40 -0
- package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapper.js +65 -0
- package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapperStyles.js +43 -0
- package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/__test__/index.test.js +48 -0
- package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/index.js +57 -0
- package/src/commons/ActionGroup/{OnOffSmartLock.js → OnOffSmartLock/OnOffSmartLock.js} +5 -5
- package/src/commons/ActionGroup/{OnOffSmartLockStyle.js → OnOffSmartLock/OnOffSmartLockStyle.js} +1 -1
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscode.js +48 -0
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscodeStyles.js +42 -0
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/PasscodeListStyles.js +49 -0
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/index.js +66 -0
- package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/ButtonWrapper.js +96 -0
- package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/SetupGeneratePasscodeStyles.js +98 -0
- package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/__test__/index.test.js +62 -0
- package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/index.js +249 -0
- package/src/commons/ActionGroup/OnOffTemplate/index.js +4 -2
- package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +2 -1
- package/src/commons/ActionGroup/SliderRangeTemplate.js +64 -0
- package/src/commons/ActionGroup/{LightActionTemplateStyles.js → SliderRangeTemplateStyles.js} +0 -8
- package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +167 -186
- package/src/commons/ActionGroup/StatesGridActionTemplate.js +2 -1
- package/src/commons/ActionGroup/index.js +7 -4
- package/src/commons/BottomSheet/index.js +2 -1
- package/src/commons/Device/DisconnectedView.js +7 -1
- package/src/commons/Device/Hanet/ItemHanetDevice.js +109 -0
- package/src/commons/Device/HistoryChart.js +2 -2
- package/src/commons/Device/HorizontalBarChart.js +7 -0
- package/src/commons/Device/ItemDevice.js +18 -15
- package/src/commons/Device/LinearChart.js +14 -41
- package/src/commons/Device/__test__/DisconnectedView.test.js +13 -2
- package/src/commons/RowItem/index.js +12 -7
- package/src/commons/SubUnit/Favorites/index.js +2 -2
- package/src/commons/SubUnit/ShortDetail.js +39 -20
- package/src/commons/WheelDateTimePicker/index.js +18 -4
- package/src/configs/API.js +23 -1
- package/src/configs/Colors.js +1 -0
- package/src/configs/Constants.js +48 -0
- package/src/configs/SCConfig.js +1 -1
- package/src/context/actionType.ts +4 -0
- package/src/context/mockStore.ts +3 -0
- package/src/context/reducer.ts +20 -0
- package/src/iot/RemoteControl/Bluetooth.js +3 -22
- package/src/iot/RemoteControl/index.js +0 -1
- package/src/navigations/HanetCameraStack.js +41 -0
- package/src/navigations/SmartIrStack.js +31 -0
- package/src/navigations/SmartLockStack.js +51 -0
- package/src/navigations/UnitStack.js +46 -4
- package/src/screens/ActivityLog/hooks/index.js +1 -1
- package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +1 -1
- package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +79 -72
- package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +155 -27
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +65 -0
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +26 -2
- package/src/screens/Device/__test__/detail.test.js +0 -10
- package/src/screens/Device/components/SensorConnectStatusViewHeader.js +13 -2
- package/src/screens/Device/detail.js +118 -38
- package/src/screens/Device/hooks/useDisconnectedDevice.js +28 -16
- package/src/screens/GuestInfo/components/AccessScheduleItem.js +9 -2
- package/src/screens/GuestInfo/components/RecurringDetail.js +3 -2
- package/src/screens/GuestInfo/components/TemporaryDetail.js +3 -2
- package/src/screens/GuestInfo/styles/AccessScheduleItemStyles.js +3 -0
- package/src/screens/HanetCamera/CaptureFaceID.js +210 -0
- package/src/screens/HanetCamera/Detail.js +252 -0
- package/src/screens/HanetCamera/ManageAccess.js +173 -0
- package/src/screens/HanetCamera/MemberInfo.js +208 -0
- package/src/screens/HanetCamera/__test__/CaptureFaceID.test.js +133 -0
- package/src/screens/HanetCamera/__test__/Detail.test.js +185 -0
- package/src/screens/HanetCamera/__test__/ManageAccess.test.js +152 -0
- package/src/screens/HanetCamera/__test__/MemberInfo.test.js +178 -0
- package/src/screens/HanetCamera/components/CheckinHeader.js +37 -0
- package/src/screens/HanetCamera/hooks/__test__/useHanetCheckinData.test.js +151 -0
- package/src/screens/HanetCamera/hooks/__test__/useHanetPlaceMembers.test.js +71 -0
- package/src/screens/HanetCamera/hooks/index.js +5 -0
- package/src/screens/HanetCamera/hooks/useHanetCheckinData.js +116 -0
- package/src/screens/HanetCamera/hooks/useHanetPlaceMembers.js +86 -0
- package/src/screens/HanetCamera/hooks/useStateAlertAction.js +62 -0
- package/src/screens/HanetCamera/styles/captureFaceIDStyles.js +50 -0
- package/src/screens/HanetCamera/styles/checkinHeaderStyles.js +24 -0
- package/src/screens/HanetCamera/styles/detailStyles.js +107 -0
- package/src/screens/HanetCamera/styles/manageAccessStyles.js +49 -0
- package/src/screens/HanetCamera/styles/memberInfoStyles.js +73 -0
- package/src/screens/HanetCamera/utils/Monitor.js +52 -0
- package/src/screens/Notification/__test__/NotificationItem.test.js +1 -0
- package/src/screens/Notification/components/NotificationItem.js +16 -0
- package/src/screens/SmartIr/__test__/ButtonsBottom.test.js +31 -0
- package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +80 -0
- package/src/screens/SmartIr/__test__/SelectBrand.test.js +65 -0
- package/src/screens/SmartIr/__test__/SelectDeviceType.test.js +57 -0
- package/src/screens/SmartIr/__test__/SmartIr.test.js +1 -0
- package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottom.js +45 -0
- package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottomStyles.js +31 -0
- package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +208 -0
- package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByTypeStyles.js +113 -0
- package/src/screens/SmartIr/components/SelectBrand.js +61 -0
- package/src/screens/SmartIr/components/SelectBrandStyles.js +14 -0
- package/src/screens/SmartIr/components/SelectDeviceType.js +96 -0
- package/src/screens/SmartIr/components/SelectDeviceTypeStyles.js +30 -0
- package/src/screens/SmartIr/index.js +8 -3
- package/src/screens/Unit/Detail.js +7 -11
- package/src/screens/Unit/__test__/Detail.test.js +0 -10
- package/src/screens/Unit/components/MyUnitDevice/index.js +2 -4
- package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +38 -9
- package/src/utils/I18n/translations/en.json +51 -1
- package/src/utils/I18n/translations/vi.json +51 -1
- package/src/utils/Route/index.js +14 -1
- package/src/commons/ActionGroup/LightActionTemplate.js +0 -103
- 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 {
|
|
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
|
-
() =>
|
|
85
|
-
|
|
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(
|
|
159
|
+
const { success, data } = await axiosGet(API.UNIT.UNIT_DETAIL(unitId));
|
|
144
160
|
if (success) {
|
|
145
161
|
setUnit(data);
|
|
146
162
|
}
|
|
147
|
-
}, [
|
|
163
|
+
}, [unitId]);
|
|
148
164
|
|
|
149
165
|
useEffect(() => {
|
|
150
|
-
if (
|
|
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(
|
|
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
|
-
}, [
|
|
180
|
+
}, [sensorId]);
|
|
165
181
|
|
|
166
182
|
useEffect(() => {
|
|
167
|
-
if (
|
|
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
|
|
196
|
+
const { success, data, resp_status } = await axiosGet(
|
|
181
197
|
API.SENSOR.DISPLAY(sensor?.id),
|
|
182
198
|
{},
|
|
183
199
|
true
|
|
184
200
|
);
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (
|
|
189
|
-
const config =
|
|
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={
|
|
505
|
+
connected={isNetworkConnected && isConnected}
|
|
460
506
|
connectedBlt={
|
|
461
|
-
(!
|
|
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
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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
|
-
|
|
659
|
+
isNetworkConnected !== null &&
|
|
580
660
|
renderSensorConnected()}
|
|
581
661
|
</View>
|
|
582
662
|
{isShowSetupEmergencyContact && canManageSubUnit && (
|
|
@@ -1,23 +1,27 @@
|
|
|
1
|
-
import
|
|
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
|
-
|
|
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 = (
|
|
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
|
|
38
|
-
|
|
42
|
+
const isBluetoothEnabled = useSCContextSelector(
|
|
43
|
+
(state) => state.app.isBluetoothEnabled
|
|
44
|
+
);
|
|
45
|
+
const isNetworkConnected = useSCContextSelector(
|
|
46
|
+
(state) => state.app.isNetworkConnected
|
|
47
|
+
);
|
|
39
48
|
|
|
40
|
-
const
|
|
41
|
-
async (
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
|
|
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 (
|
|
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
|
-
|
|
68
|
-
}, [
|
|
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 = ({
|
|
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
|
|
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>
|
|
@@ -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;
|