@eohjsc/react-native-smart-city 0.3.0 → 0.3.3

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 (134) hide show
  1. package/README.md +1 -1
  2. package/package.json +4 -4
  3. package/react-native-smart-city.podspec +1 -0
  4. package/src/commons/Action/ItemQuickAction.js +11 -2
  5. package/src/commons/Action/__test__/ItemQuickAction.test.js +11 -6
  6. package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +31 -20
  7. package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +3 -2
  8. package/src/commons/ActionGroup/TwoButtonTemplate/index.js +0 -1
  9. package/src/commons/ActionGroup/__test__/NumberUpDownTemplate.test.js +45 -48
  10. package/src/commons/ActionGroup/__test__/index.test.js +2 -2
  11. package/src/commons/ConnectingProcess/DeviceItem/DeviceItem.js +7 -3
  12. package/src/commons/ConnectingProcess/DeviceItem/DeviceItemStyles.js +8 -11
  13. package/src/commons/ConnectingProcess/__test__/DeviceItem.test.js +3 -2
  14. package/src/commons/ConnectingProcess/index.js +71 -24
  15. package/src/commons/Device/ConnectedViewHeader.js +1 -1
  16. package/src/commons/Device/HistoryChart.js +3 -3
  17. package/src/commons/Device/ItemDevice.js +15 -11
  18. package/src/commons/Device/SonosSpeaker/index.js +1 -1
  19. package/src/commons/FieldTemplate/ScheduleField/index.js +2 -2
  20. package/src/commons/Header/HeaderCustom.js +2 -1
  21. package/src/commons/HorizontalPicker/index.js +2 -2
  22. package/src/commons/MediaPlayerDetail/Styles/MediaPlayerDetailStyles.js +0 -6
  23. package/src/commons/MediaPlayerDetail/index.js +24 -55
  24. package/src/commons/SubUnit/Favorites/index.js +2 -3
  25. package/src/commons/SubUnit/ShortDetail.js +25 -9
  26. package/src/commons/SubUnit/__test__/Item.test.js +0 -1
  27. package/src/commons/SubUnit/__test__/ShortDetail.test.js +8 -1
  28. package/src/commons/UnitSummary/ConfigHistoryChart/index.js +2 -13
  29. package/src/commons/UnitSummary/ConfigHistoryChart.js +22 -13
  30. package/src/commons/WheelDateTimePicker/index.js +2 -2
  31. package/src/configs/API.js +7 -12
  32. package/src/configs/Constants.js +13 -0
  33. package/src/context/actionType.ts +8 -0
  34. package/src/context/mockStore.ts +10 -0
  35. package/src/context/reducer.ts +38 -2
  36. package/src/hooks/Common/index.js +2 -0
  37. package/src/hooks/Common/useGGHomeDeviceConnected.js +16 -0
  38. package/src/hooks/Common/useGetIdUser.js +1 -5
  39. package/src/hooks/Common/useSensorsStatus.js +4 -4
  40. package/src/hooks/IoT/__test__/useGGHomeConnection.test.js +198 -0
  41. package/src/hooks/IoT/__test__/useRemoteControl.test.js +198 -0
  42. package/src/hooks/IoT/index.js +4 -0
  43. package/src/hooks/IoT/useGGHomeConnection.js +91 -0
  44. package/src/hooks/IoT/useRemoteControl.js +79 -0
  45. package/src/hooks/index.js +4 -0
  46. package/src/hooks/useReceiveNotifications.js +9 -5
  47. package/src/iot/Monitor.js +3 -2
  48. package/src/iot/RemoteControl/Bluetooth.js +1 -1
  49. package/src/iot/RemoteControl/GoogleHome.js +75 -49
  50. package/src/iot/RemoteControl/Internet.js +1 -1
  51. package/src/iot/RemoteControl/__test__/GoogleHome.test.js +90 -21
  52. package/src/iot/RemoteControl/__test__/Internet.test.js +4 -4
  53. package/src/iot/RemoteControl/__test__/LgThinq.test.js +5 -5
  54. package/src/iot/RemoteControl/index.js +52 -52
  55. package/src/screens/ActivityLog/hooks/__test__/index.test.js +3 -3
  56. package/src/screens/ActivityLog/hooks/index.js +1 -1
  57. package/src/screens/AddLocationMaps/index.js +5 -4
  58. package/src/screens/AddNewAction/SelectAction.js +8 -8
  59. package/src/screens/AddNewAction/SetupSensor.js +7 -7
  60. package/src/screens/AddNewAction/__test__/SelectAction.test.js +2 -2
  61. package/src/screens/AddNewDevice/ConnectingDevices.js +1 -1
  62. package/src/screens/AddNewDevice/__test__/ConnectingDevices.test.js +2 -2
  63. package/src/screens/AddNewDevice/hooks/ConnectDevices.js +1 -1
  64. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +23 -17
  65. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +3 -3
  66. package/src/screens/AddNewGateway/SetupGatewayWifi.js +1 -0
  67. package/src/screens/AllCamera/index.js +4 -4
  68. package/src/screens/Automate/MultiUnits.js +8 -8
  69. package/src/screens/Automate/index.js +3 -3
  70. package/src/screens/Device/EditDevice/__test__/EditDevice.test.js +4 -4
  71. package/src/screens/Device/EditDevice/index.js +2 -2
  72. package/src/screens/Device/__test__/detail.test.js +13 -5
  73. package/src/screens/Device/components/DetailHistoryChart.js +1 -1
  74. package/src/screens/Device/components/SensorConnectStatusViewHeader.js +1 -0
  75. package/src/screens/Device/components/SensorDisplayItem.js +5 -2
  76. package/src/screens/Device/detail.js +49 -16
  77. package/src/screens/Device/hooks/useDisconnectedDevice.js +4 -4
  78. package/src/screens/EditActionsList/index.js +1 -1
  79. package/src/screens/EmergencySetting/components/DropDownItem.js +2 -2
  80. package/src/screens/HanetCamera/Detail.js +1 -1
  81. package/src/screens/HanetCamera/__test__/Detail.test.js +2 -2
  82. package/src/screens/HanetCamera/components/RequestFaceIDPopup.js +3 -2
  83. package/src/screens/HanetCamera/hooks/useHanetCheckinData.js +11 -11
  84. package/src/screens/HanetCamera/hooks/useHanetPlaceMembers.js +11 -11
  85. package/src/screens/ManageAccess/hooks/index.js +7 -4
  86. package/src/screens/MoveToAnotherSubUnit/__test__/index.test.js +2 -2
  87. package/src/screens/MoveToAnotherSubUnit/index.js +1 -1
  88. package/src/screens/Notification/__test__/NotificationItem.test.js +4 -4
  89. package/src/screens/Notification/components/NotificationItem.js +17 -20
  90. package/src/screens/Notification/index.js +9 -2
  91. package/src/screens/PlayBackCamera/Timer.js +2 -2
  92. package/src/screens/PlayBackCamera/index.js +3 -3
  93. package/src/screens/ScanChipQR/hooks/index.js +15 -16
  94. package/src/screens/ScriptDetail/index.js +14 -10
  95. package/src/screens/SelectUnit/index.js +4 -2
  96. package/src/screens/SetSchedule/index.js +9 -9
  97. package/src/screens/Sharing/Components/SensorItem.js +10 -12
  98. package/src/screens/Sharing/SelectPermission.js +14 -6
  99. package/src/screens/SideMenuDetail/__test__/index.test.js +4 -4
  100. package/src/screens/SideMenuDetail/index.js +2 -3
  101. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +3 -2
  102. package/src/screens/SubUnit/Detail.js +1 -2
  103. package/src/screens/SubUnit/ManageSubUnit.js +12 -7
  104. package/src/screens/SubUnit/__test__/Detail.test.js +1 -1
  105. package/src/screens/SubUnit/__test__/ManageSubUnit.test.js +27 -1
  106. package/src/screens/SubUnit/hooks/__test__/useManageSubUnit.test.js +1 -1
  107. package/src/screens/SubUnit/hooks/useManageSubUnit.js +7 -7
  108. package/src/screens/Unit/ChooseLocation.js +6 -13
  109. package/src/screens/Unit/Detail.js +30 -75
  110. package/src/screens/Unit/SelectAddress.js +34 -21
  111. package/src/screens/Unit/SmartAccount.js +4 -4
  112. package/src/screens/Unit/Summaries.js +17 -1
  113. package/src/screens/Unit/__test__/CheckSendEmail.test.js +9 -1
  114. package/src/screens/Unit/__test__/Detail.test.js +16 -15
  115. package/src/screens/Unit/__test__/SelectAddress.test.js +72 -13
  116. package/src/screens/Unit/__test__/SmartAccount.test.js +1 -1
  117. package/src/screens/Unit/__test__/Summaries.test.js +100 -0
  118. package/src/screens/Unit/hook/useUnitConnectRemoteDevices.js +50 -0
  119. package/src/screens/Unit/styles.js +4 -0
  120. package/src/screens/UnitSummary/__test__/index.test.js +55 -1
  121. package/src/screens/UnitSummary/components/3PPowerConsumption/__test__/3PPowerConsumption.test.js +31 -2
  122. package/src/screens/UnitSummary/components/PowerConsumeHistoryChart/index.js +2 -13
  123. package/src/screens/UnitSummary/components/PowerConsumption/__test__/ItemPower.test.js +0 -1
  124. package/src/screens/UnitSummary/components/RunningDevices/__test__/index.test.js +11 -2
  125. package/src/screens/UnitSummary/components/RunningDevices/index.js +7 -10
  126. package/src/screens/UnitSummary/components/Temperature/index.js +4 -4
  127. package/src/screens/UnitSummary/components/WaterQuality/Item/index.js +10 -2
  128. package/src/screens/UnitSummary/index.js +15 -1
  129. package/src/utils/Apis/axios.js +16 -25
  130. package/src/utils/Converter/time.js +0 -18
  131. package/src/utils/I18n/translations/en.json +4 -1
  132. package/src/utils/I18n/translations/vi.json +5 -1
  133. package/src/utils/Permission/common.js +67 -0
  134. package/src/utils/Utils.js +5 -1
@@ -59,7 +59,7 @@ describe('Test SideMenuDetail', () => {
59
59
  expect(popup.props.isVisible).toBeFalsy();
60
60
  };
61
61
 
62
- const inputPasscode = async (instance) => {
62
+ const enterPasscode = async (instance) => {
63
63
  const inputPasscode = instance.find(
64
64
  (item) => item.props.testID === TESTID.PASSCODE_FIELD
65
65
  );
@@ -124,12 +124,12 @@ describe('Test SideMenuDetail', () => {
124
124
  };
125
125
 
126
126
  mock
127
- .onGet(API.SENSOR.SIDE_MENU_DETAIL(1, 1))
127
+ .onGet(API.DEVICE.SIDE_MENU_DETAIL(1, 1))
128
128
  .reply(200, response_side_menu.data);
129
129
  mock
130
130
  .onGet(API.SHARE.UNITS_MEMBERS(1))
131
131
  .reply(200, response_unit_members.data);
132
- mock.onPost(API.SENSOR.QUICK_ACTION(1)).reply(200, []);
132
+ mock.onPost(API.DEVICE.TRIGGER_ACTION(1)).reply(200, []);
133
133
 
134
134
  const route = {
135
135
  params: {
@@ -147,7 +147,7 @@ describe('Test SideMenuDetail', () => {
147
147
  await onPressSubmitData(instance);
148
148
  expect(spyToastError).toBeCalled();
149
149
 
150
- await inputPasscode(instance);
150
+ await enterPasscode(instance);
151
151
  await onPressSubmitData(instance);
152
152
  expect(spyToastSuccess).toBeCalled();
153
153
  });
@@ -61,7 +61,6 @@ const SideMenuDetail = memo(({ route }) => {
61
61
  return null;
62
62
  }
63
63
  },
64
- // eslint-disable-next-line react-hooks/exhaustive-deps
65
64
  [unit, dataForm]
66
65
  );
67
66
 
@@ -88,7 +87,7 @@ const SideMenuDetail = memo(({ route }) => {
88
87
 
89
88
  data.action_zigbee = actionZigbee;
90
89
 
91
- const { success } = await axiosPost(API.SENSOR.QUICK_ACTION(sensor.id), {
90
+ const { success } = await axiosPost(API.DEVICE.TRIGGER_ACTION(sensor.id), {
92
91
  key: sideMenu.action,
93
92
  data,
94
93
  source: 'smart_lock',
@@ -105,7 +104,7 @@ const SideMenuDetail = memo(({ route }) => {
105
104
 
106
105
  const fetchSideMenuDetail = useCallback(async () => {
107
106
  const { success, data } = await axiosGet(
108
- API.SENSOR.SIDE_MENU_DETAIL(sensor.id, side_menu.id)
107
+ API.DEVICE.SIDE_MENU_DETAIL(sensor.id, side_menu.id)
109
108
  );
110
109
  if (success) {
111
110
  setSideMenu(data);
@@ -1,5 +1,5 @@
1
1
  import React, { memo, useCallback, useState, useMemo } from 'react';
2
- import { View, TouchableOpacity, Alert } from 'react-native';
2
+ import { View, TouchableOpacity } from 'react-native';
3
3
  import WrapHeaderScrollable from '../../../../commons/Sharing/WrapHeaderScrollable';
4
4
  import { useTranslations } from '../../../../hooks/Common/useTranslations';
5
5
  import SmartTiviActionTemplate from '../../../../commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate';
@@ -14,6 +14,7 @@ import { Remote, SmartIr, Union } from '../../../../Images/SmartIr';
14
14
 
15
15
  import styles from './GroupButtonByTypeStyles';
16
16
  import { TESTID } from '../../../../configs/Constants';
17
+ import { notImplemented } from '../../../../utils/Utils';
17
18
 
18
19
  const GroupButtonByType = memo(({ route }) => {
19
20
  const t = useTranslations();
@@ -38,7 +39,7 @@ const GroupButtonByType = memo(({ route }) => {
38
39
  case 'reload':
39
40
  case 'more':
40
41
  case 'done':
41
- return Alert.alert(t('feature_under_development'));
42
+ return notImplemented(t);
42
43
  default:
43
44
  return <></>;
44
45
  }
@@ -16,7 +16,7 @@ import styles from './DetailStyles';
16
16
 
17
17
  const SubUnitDetail = ({ route }) => {
18
18
  const t = useTranslations();
19
- const { unit, station, isGGHomeConnected } = route.params;
19
+ const { unit, station } = route.params;
20
20
  const language = useSCContextSelector((state) => state.language);
21
21
  const navigation = useNavigation();
22
22
  const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
@@ -125,7 +125,6 @@ const SubUnitDetail = ({ route }) => {
125
125
  sensor={item}
126
126
  unit={unit}
127
127
  station={station}
128
- isGGHomeConnected={isGGHomeConnected}
129
128
  />
130
129
  );
131
130
  })}
@@ -20,13 +20,14 @@ import Routes from '../../utils/Route';
20
20
  import { RowItem } from '../../commons/RowItem';
21
21
  import NoSubUnitImage from '../../../assets/images/Illustrations.svg';
22
22
  import useManageSubUnit from './hooks/useManageSubUnit';
23
+ import { TESTID } from '../../configs/Constants';
23
24
 
24
25
  const ManageSubUnit = memo((props) => {
25
26
  const t = useTranslations();
26
27
  const { unit } = props.route.params;
27
28
  const navigation = useNavigation();
28
29
  const isFocused = useIsFocused();
29
- const { station, isRefresh, isLoading, onRefresh } = useManageSubUnit(unit);
30
+ const { stations, isRefresh, isLoading, onRefresh } = useManageSubUnit(unit);
30
31
 
31
32
  const addSubUnit = useCallback(() => {
32
33
  navigation.navigate(Routes.AddSubUnitStack, {
@@ -35,7 +36,7 @@ const ManageSubUnit = memo((props) => {
35
36
  });
36
37
  }, [navigation, unit]);
37
38
 
38
- const goToEditSubUnit = (station, unit) => {
39
+ const goToEditSubUnit = (station) => {
39
40
  navigation.navigate(Routes.UnitStack, {
40
41
  screen: Routes.EditSubUnit,
41
42
  params: {
@@ -48,7 +49,11 @@ const ManageSubUnit = memo((props) => {
48
49
  const rightComponent = useMemo(
49
50
  () => (
50
51
  <View style={styles.rightComponent}>
51
- <TouchableOpacity onPress={addSubUnit} style={styles.headerButton}>
52
+ <TouchableOpacity
53
+ testID={TESTID.ADD_SUB_UNIT}
54
+ onPress={addSubUnit}
55
+ style={styles.headerButton}
56
+ >
52
57
  <Icon name={'plus'} size={27} color={Colors.Black} />
53
58
  </TouchableOpacity>
54
59
  <TouchableOpacity
@@ -84,8 +89,8 @@ const ManageSubUnit = memo((props) => {
84
89
  scrollIndicatorInsets={{ right: 1 }}
85
90
  >
86
91
  <View>
87
- {!!station.length &&
88
- station.map((item, index) => {
92
+ {!!stations.length &&
93
+ stations.map((item, index) => {
89
94
  return (
90
95
  <RowItem
91
96
  type={'noneBG'}
@@ -100,7 +105,7 @@ const ManageSubUnit = memo((props) => {
100
105
  }
101
106
  text={item.name}
102
107
  subtext={`${
103
- item.sensors ? item.sensors.length : '0'
108
+ item.devices ? item.devices.length : '0'
104
109
  } devices`}
105
110
  onPress={() => goToEditSubUnit(item, unit)}
106
111
  rightComponent={
@@ -113,7 +118,7 @@ const ManageSubUnit = memo((props) => {
113
118
  />
114
119
  );
115
120
  })}
116
- {!station.length && !isRefresh && !isLoading && (
121
+ {!stations.length && !isRefresh && !isLoading && (
117
122
  <View style={styles.NoSubUnit}>
118
123
  <NoSubUnitImage />
119
124
  <Text semibold type="H4" center>
@@ -138,7 +138,7 @@ describe('Test SubUnitDetail', () => {
138
138
  expect(mockedDangerouslyGetStatePop).toHaveBeenCalledWith(2);
139
139
  });
140
140
 
141
- test.only('click Menu ActionMore', async () => {
141
+ test('click Menu ActionMore', async () => {
142
142
  mockedDangerouslyGetState.mockImplementation(() => ({
143
143
  routes: [
144
144
  { name: 'route 1' },
@@ -1,5 +1,5 @@
1
1
  import React, { useState } from 'react';
2
- import { ScrollView } from 'react-native';
2
+ import { ScrollView, TouchableOpacity } from 'react-native';
3
3
  import { create } from 'react-test-renderer';
4
4
  import { act } from '@testing-library/react-hooks';
5
5
  import ManageSubUnit from '../ManageSubUnit';
@@ -7,6 +7,7 @@ import { SCProvider } from '../../../context';
7
7
  import { mockSCStore } from '../../../context/mockStore';
8
8
  import { RowItem } from '../../../commons/RowItem';
9
9
  import Routes from '../../../utils/Route';
10
+ import { TESTID } from '../../../configs/Constants';
10
11
 
11
12
  const mockSetState = jest.fn();
12
13
 
@@ -76,4 +77,29 @@ describe('Test ManageSubUnit', () => {
76
77
  screen: 'EditSubUnit',
77
78
  });
78
79
  });
80
+ it('ManageSubUnit add sub unit', async () => {
81
+ let route = {
82
+ params: { unit: { id: 1, name: 'unit 1' } },
83
+ };
84
+ await act(() => {
85
+ tree = create(wrapComponent(route));
86
+ });
87
+ const instance = tree.root;
88
+ const buttonAddSubUnit = instance.find(
89
+ (el) =>
90
+ el.props.testID === TESTID.ADD_SUB_UNIT && el.type === TouchableOpacity
91
+ );
92
+ act(() => {
93
+ buttonAddSubUnit.props.onPress();
94
+ });
95
+ expect(mockedNavigate).toHaveBeenCalledWith(Routes.AddSubUnitStack, {
96
+ params: {
97
+ unit: {
98
+ id: 1,
99
+ name: 'unit 1',
100
+ },
101
+ },
102
+ screen: Routes.AddSubUnit,
103
+ });
104
+ });
79
105
  });
@@ -30,7 +30,7 @@ describe('Test Manage Access', () => {
30
30
 
31
31
  it('Test init', () => {
32
32
  const { result } = renderHook(() => useManageSubUnit(unit));
33
- expect(result.current.station).toEqual([]);
33
+ expect(result.current.stations).toEqual([]);
34
34
  expect(result.current.isLoading).toBeFalsy();
35
35
  expect(result.current.isRefreshing).toBeFalsy();
36
36
  });
@@ -3,11 +3,11 @@ import { axiosGet } from '../../../utils/Apis/axios';
3
3
  import API from '../../../configs/API';
4
4
 
5
5
  export default (unit) => {
6
- const [station, setStation] = useState([]);
6
+ const [stations, setStations] = useState([]);
7
7
  const [isLoading, setIsLoading] = useState(false);
8
8
  const [isRefresh, setRefresh] = useState(false);
9
9
 
10
- const fetchData = useCallback(async (unit) => {
10
+ const fetchData = useCallback(async () => {
11
11
  setIsLoading(true);
12
12
  const { success, data } = await axiosGet(
13
13
  API.UNIT.UNIT_DETAIL(unit?.id),
@@ -15,19 +15,19 @@ export default (unit) => {
15
15
  true
16
16
  );
17
17
  if (success) {
18
- setStation(data?.stations);
18
+ setStations(data?.stations);
19
19
  }
20
20
  setIsLoading(false);
21
- }, []);
21
+ }, [unit]);
22
22
 
23
23
  const onRefresh = useCallback(async () => {
24
24
  setRefresh(true);
25
- await fetchData(unit);
25
+ await fetchData();
26
26
  setRefresh(false);
27
- }, [unit, fetchData]);
27
+ }, [fetchData]);
28
28
 
29
29
  return {
30
- station,
30
+ stations,
31
31
  isRefresh,
32
32
  onRefresh,
33
33
  isLoading,
@@ -1,4 +1,3 @@
1
- /* eslint-disable react-hooks/exhaustive-deps */
2
1
  import React, { memo, useCallback, useRef, useState } from 'react';
3
2
  import { View } from 'react-native';
4
3
  import MapView, { PROVIDER_GOOGLE } from 'react-native-maps';
@@ -8,20 +7,13 @@ import BottomButtonView from '../../commons/BottomButtonView';
8
7
  import { FullLoading } from '../../commons';
9
8
  import { useTranslations } from '../../hooks/Common/useTranslations';
10
9
 
11
- navigator.geolocation = require('@react-native-community/geolocation');
12
-
13
10
  import styles from './ChooseLocationStyles';
14
11
  import { API } from '../../configs';
15
12
  import { axiosGet } from '../../utils/Apis/axios';
16
13
  import { SCConfig } from '../../configs';
14
+ import { MAP_INITIAL_REGION, EOH_LOCATION } from '../../configs/Constants';
17
15
 
18
- const initialRegion = {
19
- latitudeDelta: 0.0922,
20
- longitudeDelta: 0.0421,
21
- };
22
-
23
- const DEFAULT_LATITUDE = 10.7974046; // EoH center
24
- const DEFAULT_LONGITUDE = 106.7035663;
16
+ navigator.geolocation = require('@react-native-community/geolocation');
25
17
 
26
18
  const ChooseLocation = memo(({ route }) => {
27
19
  const t = useTranslations();
@@ -76,9 +68,10 @@ const ChooseLocation = memo(({ route }) => {
76
68
  provider={PROVIDER_GOOGLE}
77
69
  style={styles.mapView}
78
70
  initialRegion={{
79
- ...initialRegion,
80
- latitude: location?.latitude || DEFAULT_LATITUDE,
81
- longitude: location?.longitude || DEFAULT_LONGITUDE,
71
+ latitude: location?.latitude || EOH_LOCATION.LAT,
72
+ longitude: location?.longitude || EOH_LOCATION.LNG,
73
+ latitudeDelta: MAP_INITIAL_REGION.LAT,
74
+ longitudeDelta: MAP_INITIAL_REGION.LNG,
82
75
  }}
83
76
  followUserLocation={true}
84
77
  onRegionChangeComplete={onRegionChange}
@@ -1,14 +1,15 @@
1
1
  import React, {
2
2
  useCallback,
3
- useContext,
4
3
  useEffect,
5
4
  useState,
6
5
  useRef,
6
+ useContext,
7
7
  } from 'react';
8
8
  import { AppState, RefreshControl, View } from 'react-native';
9
9
  import { useIsFocused } from '@react-navigation/native';
10
- import { useTranslations } from '../../hooks/Common/useTranslations';
10
+ import { VLCPlayer } from 'react-native-vlc-media-player';
11
11
 
12
+ import { useTranslations } from '../../hooks/Common/useTranslations';
12
13
  import styles from './styles';
13
14
  import AddMenu from './AddMenu';
14
15
  import MoreMenu from './MoreMenu';
@@ -23,10 +24,8 @@ import {
23
24
  usePopover,
24
25
  } from '../../hooks/Common';
25
26
  import { useFavorites } from './hook/useFavorites';
26
- import { scanBluetoothDevices } from '../../iot/RemoteControl/Bluetooth';
27
- import { googleHomeConnect } from '../../iot/RemoteControl/GoogleHome';
28
- import { axiosPost, fetchWithCache, axiosGet } from '../../utils/Apis/axios';
29
- import { lgThinqConnect } from '../../iot/RemoteControl/LG';
27
+ import { useUnitConnectRemoteDevices } from './hook/useUnitConnectRemoteDevices';
28
+ import { fetchWithCache, axiosGet } from '../../utils/Apis/axios';
30
29
  import ShortDetailSubUnit from '../../commons/SubUnit/ShortDetail';
31
30
  import NavBar from '../../commons/NavBar';
32
31
  import WrapParallaxScrollView from '../../commons/WrapParallaxScrollView';
@@ -51,6 +50,7 @@ import PreventAccess from '../../commons/PreventAccess';
51
50
 
52
51
  const UnitDetail = ({ route }) => {
53
52
  const t = useTranslations();
53
+ const { setAction } = useContext(SCContext);
54
54
 
55
55
  const {
56
56
  unitId,
@@ -63,7 +63,6 @@ const UnitDetail = ({ route }) => {
63
63
  } = route.params;
64
64
 
65
65
  const isFocused = useIsFocused();
66
- const { stateData, setAction } = useContext(SCContext);
67
66
  const { navigate, goBack } = useNavigation();
68
67
  const RouterHardware = useCallback(
69
68
  (routeHardware) => () => {
@@ -76,15 +75,14 @@ const UnitDetail = ({ route }) => {
76
75
  isSuccessfullyConnected ? RouterHardware(Routes.Dashboard) : goBack
77
76
  );
78
77
  const user = useSCContextSelector((state) => state?.auth?.account?.user);
79
- const isLavidaSource = useSCContextSelector(
80
- (state) => state.app.isLavidaSource
78
+ const { isLavidaSource, isFirstOpenCamera } = useSCContextSelector(
79
+ (state) => state.app
81
80
  );
82
81
 
83
82
  const [unit, setUnit] = useState(unitData || { id: unitId });
84
83
  const [listMenuItem, setListMenuItem] = useState([]);
85
84
  const [listStation, setListStation] = useState([]);
86
85
  const [listAutomate, setListAutomate] = useState([]);
87
- const [isGGHomeConnected, setIsGGHomeConnected] = useState(false);
88
86
  const [station, setStation] = useState({});
89
87
  const [indexStation, setIndexStation] = useState(0);
90
88
  const [showAdd, setShowAdd, setHideAdd] = useBoolean();
@@ -191,61 +189,7 @@ const UnitDetail = ({ route }) => {
191
189
  };
192
190
  }, [fetchDetails]);
193
191
 
194
- const handleGoogleHomeConnect = useCallback(
195
- async (options) => {
196
- let isConnected = await googleHomeConnect(options); // this may wrong if have multiple connection
197
- setIsGGHomeConnected(isConnected);
198
- let chipId = options[0].chip_id;
199
- if (!isConnected) {
200
- setAction(Action.LIST_DEVICE_TYPES, {
201
- chipId: chipId,
202
- sentEmail: true,
203
- });
204
- await axiosPost(API.GOOGLE_HOME.CHECK_SEND_EMAIL(), {
205
- chip_id: chipId,
206
- is_connected: false,
207
- });
208
- } else if (isConnected && stateData?.listDevice[chipId]?.sentEmail) {
209
- setAction(Action.LIST_DEVICE_TYPES, {
210
- chipId: chipId,
211
- sentEmail: false,
212
- });
213
- await axiosPost(API.GOOGLE_HOME.CHECK_SEND_EMAIL(), {
214
- chip_id: chipId,
215
- is_connected: true,
216
- });
217
- }
218
- },
219
- // eslint-disable-next-line react-hooks/exhaustive-deps
220
- []
221
- );
222
-
223
- let isCalled = false;
224
-
225
- const handleLgThinqConnect = useCallback(async (options) => {
226
- if (isCalled) {
227
- return;
228
- }
229
- // eslint-disable-next-line react-hooks/exhaustive-deps
230
- isCalled = true;
231
- await lgThinqConnect(options);
232
- }, []);
233
-
234
- useEffect(() => {
235
- if (unit.remote_control_options) {
236
- if (unit.remote_control_options.bluetooth) {
237
- scanBluetoothDevices(unit.remote_control_options.bluetooth);
238
- }
239
- if (unit.remote_control_options.googlehome?.length) {
240
- handleGoogleHomeConnect(unit.remote_control_options.googlehome);
241
- }
242
- if (unit.remote_control_options.lg_thinq) {
243
- (async () => {
244
- await handleLgThinqConnect(unit.remote_control_options.lg_thinq);
245
- })();
246
- }
247
- }
248
- }, [handleGoogleHomeConnect, handleLgThinqConnect, unit]);
192
+ useUnitConnectRemoteDevices(unit);
249
193
 
250
194
  useEffect(() => {
251
195
  if (isFocused) {
@@ -264,7 +208,7 @@ const UnitDetail = ({ route }) => {
264
208
  setListMenuItem(listMenu);
265
209
  setListStation(listMenu.concat([{ text: '' }]));
266
210
  }
267
- }, [unit, indexStation, isGGHomeConnected]);
211
+ }, [unit, indexStation]);
268
212
 
269
213
  useEffect(() => {
270
214
  isOneTap && setIndexStation(1);
@@ -308,7 +252,6 @@ const UnitDetail = ({ route }) => {
308
252
  favoriteDevices={favoriteDevices}
309
253
  favoriteAutomates={favoriteAutomates}
310
254
  wrapItemStyle={styles.wrapItemStyle}
311
- isGGHomeConnected={isGGHomeConnected}
312
255
  />
313
256
  );
314
257
  }
@@ -330,13 +273,7 @@ const UnitDetail = ({ route }) => {
330
273
  />
331
274
  );
332
275
  } else if (station) {
333
- return (
334
- <ShortDetailSubUnit
335
- unit={unit}
336
- station={station}
337
- isGGHomeConnected={isGGHomeConnected}
338
- />
339
- );
276
+ return <ShortDetailSubUnit unit={unit} station={station} />;
340
277
  }
341
278
  };
342
279
 
@@ -353,6 +290,15 @@ const UnitDetail = ({ route }) => {
353
290
  return () => unwatchNotificationData(user);
354
291
  }, [user, onRefresh]);
355
292
 
293
+ useEffect(() => {
294
+ if (isFirstOpenCamera) {
295
+ const to = setTimeout(() => {
296
+ setAction(Action.IS_FIRST_OPEN_CAMERA, false);
297
+ clearTimeout(to);
298
+ }, 5000);
299
+ }
300
+ }, [isFirstOpenCamera, setAction]);
301
+
356
302
  return (
357
303
  <WrapParallaxScrollView
358
304
  uriImg={unit.background}
@@ -367,6 +313,16 @@ const UnitDetail = ({ route }) => {
367
313
  hideRightPlus={!isOwner}
368
314
  onBack={(isSuccessfullyConnected && Dashboard) || (routeName && onBack)}
369
315
  >
316
+ {/* NOTE: This is a trick to fix camera not full screen on first open app */}
317
+ {isFirstOpenCamera && (
318
+ <VLCPlayer
319
+ source={{
320
+ uri: 'rtsp://admin:Eoh@2020@101.99.33.220:30554/main',
321
+ }}
322
+ style={styles.camera}
323
+ />
324
+ )}
325
+
370
326
  <View style={styles.container}>
371
327
  <Summaries unit={unit} />
372
328
  <NavBar
@@ -383,7 +339,6 @@ const UnitDetail = ({ route }) => {
383
339
  </View>
384
340
  )}
385
341
  </View>
386
-
387
342
  <AddMenu
388
343
  unit={unit}
389
344
  afterItemClick={hidePopover}
@@ -1,9 +1,9 @@
1
- /* eslint-disable react-hooks/exhaustive-deps */
2
1
  import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
3
2
  import { TouchableOpacity, View, ScrollView } from 'react-native';
4
3
  import MapView, { Marker, Circle, PROVIDER_GOOGLE } from 'react-native-maps';
5
4
  import { useNavigation } from '@react-navigation/native';
6
5
  import { IconOutline, IconFill } from '@ant-design/icons-react-native';
6
+ import { check, RESULTS } from 'react-native-permissions';
7
7
 
8
8
  import BottomButtonView from '../../commons/BottomButtonView';
9
9
  import SearchBarLocation from '../../commons/SearchLocation';
@@ -11,22 +11,23 @@ import RowLocation from '../../commons/SearchLocation/RowLocation';
11
11
  import Text from '../../commons/Text';
12
12
  import { FullLoading } from '../../commons';
13
13
  import { useTranslations } from '../../hooks/Common/useTranslations';
14
-
15
- navigator.geolocation = require('@react-native-community/geolocation');
14
+ import {
15
+ GEOLOCATION_ERROR,
16
+ keyPermission,
17
+ OpenSetting,
18
+ } from '../../utils/Permission/common';
16
19
 
17
20
  import styles from './SelectAddressStyles';
18
21
  import { API, Colors, SCConfig } from '../../configs';
19
22
  import { axiosGet } from '../../utils/Apis/axios';
20
23
  import Routes from '../../utils/Route';
21
- import { TESTID } from '../../configs/Constants';
24
+ import {
25
+ TESTID,
26
+ MAP_INITIAL_REGION,
27
+ EOH_LOCATION,
28
+ } from '../../configs/Constants';
22
29
 
23
- const initialRegion = {
24
- latitudeDelta: 0.0922,
25
- longitudeDelta: 0.0421,
26
- };
27
-
28
- const DEFAULT_LATITUDE = 10.7974046; // EoH center
29
- const DEFAULT_LONGITUDE = 106.7035663;
30
+ navigator.geolocation = require('@react-native-community/geolocation');
30
31
 
31
32
  const SelectAddress = memo(({ route }) => {
32
33
  const t = useTranslations();
@@ -46,9 +47,9 @@ const SelectAddress = memo(({ route }) => {
46
47
  goBack();
47
48
  }, [goBack, updateLocation, searchedLocation]);
48
49
 
49
- const onTextInput = useCallback(async (input) => {
50
- setInput(input);
51
- if (input === '') {
50
+ const onTextInput = useCallback(async (value) => {
51
+ setInput(value);
52
+ if (value === '') {
52
53
  setSearchData([]);
53
54
  setSearchedLocation(null);
54
55
  return;
@@ -56,7 +57,7 @@ const SelectAddress = memo(({ route }) => {
56
57
  try {
57
58
  const config = {
58
59
  params: {
59
- input: input,
60
+ input: value,
60
61
  key: SCConfig.GOOGLE_MAP_API_KEY,
61
62
  sessiontoken: 123456324,
62
63
  strictBounds: false,
@@ -71,6 +72,7 @@ const SelectAddress = memo(({ route }) => {
71
72
  if (success) {
72
73
  setSearchData(data.predictions);
73
74
  }
75
+ // eslint-disable-next-line no-empty
74
76
  } catch (error) {}
75
77
  }, []);
76
78
 
@@ -83,7 +85,8 @@ const SelectAddress = memo(({ route }) => {
83
85
  {
84
86
  latitude: lat,
85
87
  longitude: lng,
86
- ...initialRegion,
88
+ latitudeDelta: MAP_INITIAL_REGION.LAT,
89
+ longitudeDelta: MAP_INITIAL_REGION.LNG,
87
90
  },
88
91
  600
89
92
  );
@@ -140,10 +143,19 @@ const SelectAddress = memo(({ route }) => {
140
143
  setLoading(false);
141
144
  },
142
145
  // eslint-disable-next-line promise/prefer-await-to-callbacks
143
- (error) => {}
146
+ async (error) => {
147
+ if (error.code === GEOLOCATION_ERROR.PERMISSION_DENIED) {
148
+ const permissionResult = await check(keyPermission.LOCATION);
149
+ permissionResult === RESULTS.BLOCKED &&
150
+ OpenSetting(
151
+ t('location_rationale_title'),
152
+ t('location_require_message')
153
+ );
154
+ }
155
+ }
144
156
  // { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 } enable on emulator
145
157
  );
146
- }, []);
158
+ }, [t]);
147
159
 
148
160
  const chooseOnMap = useCallback(() => {
149
161
  navigate(Routes.ChooseLocation, {
@@ -202,9 +214,10 @@ const SelectAddress = memo(({ route }) => {
202
214
  provider={PROVIDER_GOOGLE}
203
215
  style={styles.mapView}
204
216
  initialRegion={{
205
- ...initialRegion,
206
- latitude: DEFAULT_LATITUDE,
207
- longitude: DEFAULT_LONGITUDE,
217
+ latitude: EOH_LOCATION.LAT,
218
+ longitude: EOH_LOCATION.LNG,
219
+ latitudeDelta: MAP_INITIAL_REGION.LAT,
220
+ longitudeDelta: MAP_INITIAL_REGION.LNG,
208
221
  }}
209
222
  followUserLocation={true}
210
223
  >
@@ -29,13 +29,13 @@ const ListSmartAccount = ({ route }) => {
29
29
  const [loadingRemoveItem, setLoadingRemoveItem] = useState(false);
30
30
 
31
31
  const getAllSmartAccounts = useCallback(async () => {
32
- const { success, data } = await axiosGet(
33
- API.SMART_ACCOUNT.LIST_SMART_ACCOUNT()
32
+ const { success, data: accountData } = await axiosGet(
33
+ API.SMART_ACCOUNT.LIST_SMART_ACCOUNT(unitId)
34
34
  );
35
35
  if (success) {
36
- setData(data);
36
+ setData(accountData);
37
37
  }
38
- }, []);
38
+ }, [unitId]);
39
39
 
40
40
  const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
41
41
  usePopover();