@eohjsc/react-native-smart-city 0.2.85 → 0.2.88

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 (148) hide show
  1. package/assets/images/Common/Calendar.svg +3 -0
  2. package/assets/images/Common/SmartPhone.svg +3 -0
  3. package/assets/images/Device/button-lock.svg +3 -0
  4. package/assets/images/Device/button-unlock.svg +3 -0
  5. package/assets/images/Hanet/CaptureFaceID.svg +25 -0
  6. package/assets/images/Hanet/FaceFrame.svg +6 -0
  7. package/assets/images/brightnessBlack.svg +12 -0
  8. package/index.js +4 -0
  9. package/package.json +2 -2
  10. package/src/Images/SmartIr/AC.svg +14 -0
  11. package/src/Images/SmartIr/DIY.svg +3 -0
  12. package/src/Images/SmartIr/Fan.svg +10 -0
  13. package/src/Images/SmartIr/Fridge.svg +5 -0
  14. package/src/Images/SmartIr/Remote.svg +15 -0
  15. package/src/Images/SmartIr/SmartIr.svg +4 -0
  16. package/src/Images/SmartIr/TV.svg +10 -0
  17. package/src/Images/SmartIr/Union.svg +9 -0
  18. package/src/Images/SmartIr/WM.svg +11 -0
  19. package/src/Images/SmartIr/index.js +10 -0
  20. package/src/commons/ActionGroup/ColorPickerTemplate.js +51 -0
  21. package/src/commons/ActionGroup/ColorPickerTemplateStyles.js +17 -0
  22. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/AutoLockStyles.js +40 -0
  23. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapper.js +65 -0
  24. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapperStyles.js +43 -0
  25. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/__test__/index.test.js +48 -0
  26. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/index.js +57 -0
  27. package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +48 -0
  28. package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLockStyle.js +51 -0
  29. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscode.js +48 -0
  30. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscodeStyles.js +42 -0
  31. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/PasscodeListStyles.js +49 -0
  32. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/index.js +66 -0
  33. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/ButtonWrapper.js +96 -0
  34. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/SetupGeneratePasscodeStyles.js +98 -0
  35. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/__test__/index.test.js +62 -0
  36. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/index.js +249 -0
  37. package/src/commons/ActionGroup/OnOffTemplate/index.js +4 -2
  38. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +2 -1
  39. package/src/commons/ActionGroup/SliderRangeTemplate.js +64 -0
  40. package/src/commons/ActionGroup/{LightActionTemplateStyles.js → SliderRangeTemplateStyles.js} +0 -8
  41. package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +167 -186
  42. package/src/commons/ActionGroup/StatesGridActionTemplate.js +2 -1
  43. package/src/commons/ActionGroup/index.js +9 -3
  44. package/src/commons/BottomSheet/index.js +2 -1
  45. package/src/commons/ConnectingProcess/index.js +5 -2
  46. package/src/commons/Device/DisconnectedView.js +7 -1
  47. package/src/commons/Device/Hanet/ItemHanetDevice.js +109 -0
  48. package/src/commons/Device/HistoryChart.js +2 -2
  49. package/src/commons/Device/HorizontalBarChart.js +7 -0
  50. package/src/commons/Device/ItemDevice.js +24 -16
  51. package/src/commons/Device/LinearChart.js +14 -41
  52. package/src/commons/Device/__test__/DisconnectedView.test.js +13 -2
  53. package/src/commons/MediaPlayer/__test__/index.test.js +45 -0
  54. package/src/commons/RowItem/index.js +12 -7
  55. package/src/commons/SubUnit/Favorites/index.js +2 -2
  56. package/src/commons/SubUnit/ShortDetail.js +48 -41
  57. package/src/commons/SubUnit/__test__/ShortDetail.test.js +57 -48
  58. package/src/commons/WheelDateTimePicker/index.js +18 -4
  59. package/src/configs/API.js +24 -2
  60. package/src/configs/Colors.js +1 -0
  61. package/src/configs/Constants.js +61 -0
  62. package/src/configs/SCConfig.js +1 -1
  63. package/src/context/actionType.ts +4 -0
  64. package/src/context/mockStore.ts +3 -0
  65. package/src/context/reducer.ts +20 -0
  66. package/src/iot/RemoteControl/Bluetooth.js +3 -22
  67. package/src/iot/RemoteControl/index.js +0 -1
  68. package/src/navigations/HanetCameraStack.js +41 -0
  69. package/src/navigations/SmartIrStack.js +31 -0
  70. package/src/navigations/SmartLockStack.js +51 -0
  71. package/src/navigations/UnitStack.js +46 -4
  72. package/src/screens/ActivityLog/hooks/index.js +17 -3
  73. package/src/screens/ActivityLog/index.js +3 -0
  74. package/src/screens/AddCommon/SelectSubUnit.js +1 -0
  75. package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +1 -1
  76. package/src/screens/AddNewAction/SelectSensorDevices.js +4 -2
  77. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +88 -73
  78. package/src/screens/AddNewGateway/PlugAndPlay/FirstWarning.js +4 -2
  79. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +155 -27
  80. package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +65 -0
  81. package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +26 -2
  82. package/src/screens/AddNewOneTap/index.js +32 -17
  83. package/src/screens/Automate/index.js +2 -2
  84. package/src/screens/Device/EditDevice/index.js +5 -3
  85. package/src/screens/Device/__test__/detail.test.js +0 -10
  86. package/src/screens/Device/components/SensorConnectStatusViewHeader.js +13 -2
  87. package/src/screens/Device/components/SensorDisplayItem.js +3 -0
  88. package/src/screens/Device/detail.js +119 -38
  89. package/src/screens/Device/hooks/useDisconnectedDevice.js +28 -16
  90. package/src/screens/GuestInfo/components/AccessScheduleItem.js +9 -2
  91. package/src/screens/GuestInfo/components/RecurringDetail.js +3 -2
  92. package/src/screens/GuestInfo/components/TemporaryDetail.js +3 -2
  93. package/src/screens/GuestInfo/styles/AccessScheduleItemStyles.js +3 -0
  94. package/src/screens/HanetCamera/CaptureFaceID.js +210 -0
  95. package/src/screens/HanetCamera/Detail.js +252 -0
  96. package/src/screens/HanetCamera/ManageAccess.js +173 -0
  97. package/src/screens/HanetCamera/MemberInfo.js +208 -0
  98. package/src/screens/HanetCamera/__test__/CaptureFaceID.test.js +133 -0
  99. package/src/screens/HanetCamera/__test__/Detail.test.js +185 -0
  100. package/src/screens/HanetCamera/__test__/ManageAccess.test.js +152 -0
  101. package/src/screens/HanetCamera/__test__/MemberInfo.test.js +178 -0
  102. package/src/screens/HanetCamera/components/CheckinHeader.js +37 -0
  103. package/src/screens/HanetCamera/hooks/__test__/useHanetCheckinData.test.js +151 -0
  104. package/src/screens/HanetCamera/hooks/__test__/useHanetPlaceMembers.test.js +71 -0
  105. package/src/screens/HanetCamera/hooks/index.js +5 -0
  106. package/src/screens/HanetCamera/hooks/useHanetCheckinData.js +116 -0
  107. package/src/screens/HanetCamera/hooks/useHanetPlaceMembers.js +86 -0
  108. package/src/screens/HanetCamera/hooks/useStateAlertAction.js +62 -0
  109. package/src/screens/HanetCamera/styles/captureFaceIDStyles.js +50 -0
  110. package/src/screens/HanetCamera/styles/checkinHeaderStyles.js +24 -0
  111. package/src/screens/HanetCamera/styles/detailStyles.js +107 -0
  112. package/src/screens/HanetCamera/styles/manageAccessStyles.js +49 -0
  113. package/src/screens/HanetCamera/styles/memberInfoStyles.js +73 -0
  114. package/src/screens/HanetCamera/utils/Monitor.js +52 -0
  115. package/src/screens/Notification/__test__/NotificationItem.test.js +16 -3
  116. package/src/screens/Notification/components/NotificationItem.js +68 -8
  117. package/src/screens/ScanChipQR/__test__/ScanChipQR.test.js +1 -0
  118. package/src/screens/ScanChipQR/hooks/index.js +90 -44
  119. package/src/screens/ScriptDetail/index.js +1 -6
  120. package/src/screens/SelectUnit/index.js +1 -0
  121. package/src/screens/SharedUnit/index.js +1 -1
  122. package/src/screens/SmartIr/__test__/ButtonsBottom.test.js +31 -0
  123. package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +80 -0
  124. package/src/screens/SmartIr/__test__/SelectBrand.test.js +65 -0
  125. package/src/screens/SmartIr/__test__/SelectDeviceType.test.js +57 -0
  126. package/src/screens/SmartIr/__test__/SmartIr.test.js +62 -0
  127. package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottom.js +45 -0
  128. package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottomStyles.js +31 -0
  129. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +208 -0
  130. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByTypeStyles.js +113 -0
  131. package/src/screens/SmartIr/components/SelectBrand.js +61 -0
  132. package/src/screens/SmartIr/components/SelectBrandStyles.js +14 -0
  133. package/src/screens/SmartIr/components/SelectDeviceType.js +96 -0
  134. package/src/screens/SmartIr/components/SelectDeviceTypeStyles.js +30 -0
  135. package/src/screens/SmartIr/index.js +28 -0
  136. package/src/screens/SmartIr/styles.js +14 -0
  137. package/src/screens/Unit/AddMenu.js +4 -1
  138. package/src/screens/Unit/Detail.js +8 -12
  139. package/src/screens/Unit/__test__/Detail.test.js +0 -10
  140. package/src/screens/Unit/components/MyUnitDevice/index.js +2 -4
  141. package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +38 -9
  142. package/src/screens/UnitSummary/components/PowerConsumeHistoryChart/__test__/index.test.js +32 -1
  143. package/src/screens/UnitSummary/components/PowerConsumeHistoryChart/index.js +1 -1
  144. package/src/utils/I18n/translations/en.json +59 -2
  145. package/src/utils/I18n/translations/vi.json +59 -2
  146. package/src/utils/Route/index.js +14 -0
  147. package/src/commons/ActionGroup/LightActionTemplate.js +0 -103
  148. package/src/commons/ActionGroup/__test__/LightActionTemplate.test.js +0 -59
@@ -0,0 +1,178 @@
1
+ import React from 'react';
2
+ import { TouchableOpacity } from 'react-native';
3
+ import { create, act } from 'react-test-renderer';
4
+ import axios from 'axios';
5
+ import { SCProvider } from '../../../context';
6
+ import { mockSCStore } from '../../../context/mockStore';
7
+ import HanetMemberInfo from '../MemberInfo';
8
+ import { AlertAction } from '../../../commons';
9
+ import TextInput from '../../../commons/Form/TextInput';
10
+ import BottomButtonView from '../../../commons/BottomButtonView';
11
+
12
+ const wrapComponent = (route) => (
13
+ <SCProvider initState={mockSCStore({})}>
14
+ <HanetMemberInfo route={route} />
15
+ </SCProvider>
16
+ );
17
+
18
+ jest.mock('react', () => {
19
+ return {
20
+ ...jest.requireActual('react'),
21
+ memo: (x) => x,
22
+ };
23
+ });
24
+
25
+ const mockedNavigate = jest.fn();
26
+ const mockedGoBack = jest.fn();
27
+ jest.mock('@react-navigation/native', () => {
28
+ return {
29
+ ...jest.requireActual('@react-navigation/native'),
30
+ useNavigation: () => ({
31
+ navigate: mockedNavigate,
32
+ goBack: mockedGoBack,
33
+ }),
34
+ useIsFocused: () => true,
35
+ };
36
+ });
37
+
38
+ jest.mock('axios');
39
+
40
+ describe('Test HanetMemberInfo', () => {
41
+ let tree, route;
42
+
43
+ beforeEach(() => {
44
+ mockedNavigate.mockClear();
45
+ mockedGoBack.mockClear();
46
+ axios.post.mockClear();
47
+ axios.patch.mockClear();
48
+ axios.delete.mockClear();
49
+ route = {
50
+ params: {
51
+ hanetPlace: {
52
+ place_id: 1,
53
+ },
54
+ hanetMember: {
55
+ id: 1,
56
+ alias_id: 1,
57
+ name: 'name',
58
+ avatar_uri: 'uri',
59
+ },
60
+ isAddNewMember: false,
61
+ },
62
+ };
63
+ });
64
+
65
+ test('Test rename member', async () => {
66
+ await act(async () => {
67
+ tree = await create(wrapComponent(route));
68
+ });
69
+ const instance = tree.root;
70
+ const touches = instance.findAllByType(TouchableOpacity);
71
+ expect(touches).toHaveLength(5);
72
+ const alertAction = instance.findByType(AlertAction);
73
+
74
+ // open alert action
75
+ await act(async () => {
76
+ await touches[2].props.onPress();
77
+ });
78
+ expect(alertAction.props.visible).toBe(true);
79
+
80
+ const textInput = instance.findByType(TextInput);
81
+
82
+ axios.patch.mockImplementationOnce(async () => ({ status: 200 }));
83
+
84
+ // change name and press rename
85
+ await act(async () => {
86
+ await textInput.props.onChange('new name');
87
+ await alertAction.props.rightButtonClick();
88
+ });
89
+ expect(axios.patch).toHaveBeenCalled();
90
+ });
91
+
92
+ test('Test remove member', async () => {
93
+ await act(async () => {
94
+ tree = await create(wrapComponent(route));
95
+ });
96
+ const instance = tree.root;
97
+ const touches = instance.findAllByType(TouchableOpacity);
98
+ expect(touches).toHaveLength(5);
99
+ const alertAction = instance.findByType(AlertAction);
100
+
101
+ // open alert action
102
+ await act(async () => {
103
+ await touches[3].props.onPress();
104
+ });
105
+ expect(alertAction.props.visible).toBe(true);
106
+
107
+ axios.delete.mockImplementationOnce(async () => ({ status: 200 }));
108
+
109
+ // press remove
110
+ await act(async () => {
111
+ await alertAction.props.rightButtonClick();
112
+ });
113
+
114
+ expect(axios.delete).toHaveBeenCalled();
115
+ expect(mockedGoBack).toHaveBeenCalled();
116
+ });
117
+
118
+ test('Test navigate CaptureFaceID', async () => {
119
+ await act(async () => {
120
+ tree = await create(wrapComponent(route));
121
+ });
122
+ const instance = tree.root;
123
+
124
+ const touches = instance.findAllByType(TouchableOpacity);
125
+ expect(touches).toHaveLength(5);
126
+
127
+ await act(async () => {
128
+ await touches[1].props.onPress();
129
+ });
130
+ expect(mockedNavigate).toBeCalled();
131
+ });
132
+
133
+ test('Test register new member', async () => {
134
+ route.params.hanetMember = {
135
+ alias_id: null,
136
+ name: null,
137
+ avatar_uri: 'avatar_uri',
138
+ };
139
+ route.params.isAddNewMember = true;
140
+ await act(async () => {
141
+ tree = await create(wrapComponent(route));
142
+ });
143
+ const instance = tree.root;
144
+
145
+ const touches = instance.findAllByType(TouchableOpacity);
146
+ expect(touches).toHaveLength(5);
147
+
148
+ // press set face id
149
+ await act(async () => {
150
+ await touches[1].props.onPress();
151
+ });
152
+ expect(mockedNavigate).toBeCalled();
153
+
154
+ // open alert action
155
+ const alertAction = instance.findByType(AlertAction);
156
+ await act(async () => {
157
+ await touches[2].props.onPress();
158
+ });
159
+ expect(alertAction.props.visible).toBe(true);
160
+
161
+ // change name and press rename
162
+ const textInput = instance.findByType(TextInput);
163
+ await act(async () => {
164
+ await textInput.props.onChange('new name');
165
+ await alertAction.props.rightButtonClick();
166
+ });
167
+ expect(axios.post).not.toBeCalled();
168
+
169
+ // finish
170
+ const bottomButton = instance.findByType(BottomButtonView);
171
+ axios.post.mockImplementationOnce(async () => ({ status: 200 }));
172
+ await act(async () => {
173
+ await bottomButton.props.onPressMain();
174
+ });
175
+ expect(axios.post).toBeCalled();
176
+ expect(mockedNavigate).toBeCalled();
177
+ });
178
+ });
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import { View, TouchableOpacity, Image } from 'react-native';
3
+ import Text from '../../../commons/Text';
4
+ import { Images, Colors } from '../../../configs';
5
+ import styles from '../styles/checkinHeaderStyles';
6
+ import CalendarSvg from '../../../../assets/images/Common/Calendar.svg';
7
+
8
+ const CheckinHeader = ({
9
+ date,
10
+ onPickPreviousDate,
11
+ onPickNextDate,
12
+ setShowCalendar,
13
+ }) => {
14
+ return (
15
+ <View style={styles.wrap}>
16
+ <Text type="H3" color={Colors.Gray9} bold>
17
+ {'Check in'}
18
+ </Text>
19
+ <View style={styles.row}>
20
+ <TouchableOpacity onPress={onPickPreviousDate}>
21
+ <Image source={Images.arrowLeft} />
22
+ </TouchableOpacity>
23
+ <TouchableOpacity onPress={setShowCalendar} style={styles.wrapDate}>
24
+ <Text color={Colors.Gray9} style={styles.marginRight10}>
25
+ {date.format('DD/MM/YYYY')}
26
+ </Text>
27
+ <CalendarSvg color={Colors.Primary} />
28
+ </TouchableOpacity>
29
+ <TouchableOpacity onPress={onPickNextDate}>
30
+ <Image source={Images.arrowLeft} style={styles.arrowRight} />
31
+ </TouchableOpacity>
32
+ </View>
33
+ </View>
34
+ );
35
+ };
36
+
37
+ export default CheckinHeader;
@@ -0,0 +1,151 @@
1
+ import { act, renderHook } from '@testing-library/react-hooks';
2
+ import { useHanetCheckinData } from '../index';
3
+ import axios from 'axios';
4
+ import moment from 'moment';
5
+
6
+ jest.mock('axios');
7
+
8
+ describe('Test useHanetCheckinData', () => {
9
+ let props, data;
10
+
11
+ beforeEach(() => {
12
+ Date.now = jest.fn(() => new Date('2021-09-09T10:00:00.000Z'));
13
+ axios.get.mockClear();
14
+ props = {
15
+ device_id: 1,
16
+ place: {
17
+ place_id: 2,
18
+ },
19
+ };
20
+ data = {
21
+ count: 2,
22
+ count_member: 1,
23
+ count_stranger: 1,
24
+ results: [
25
+ {
26
+ id: 1,
27
+ person_name: 'name 1',
28
+ person_type: 'EMPLOYEE',
29
+ detected_image_uri: 'uri',
30
+ detected_mask: 'MASK_OFF',
31
+ created_at: moment(),
32
+ },
33
+ {
34
+ id: 2,
35
+ person_name: 'name 2',
36
+ person_type: 'STRANGER',
37
+ detected_image_uri: 'uri',
38
+ detected_mask: 'MASK_ON',
39
+ created_at: moment(),
40
+ },
41
+ ],
42
+ };
43
+ });
44
+
45
+ test('Test onRefresh', async () => {
46
+ const { result } = renderHook(() => useHanetCheckinData(props));
47
+ axios.get.mockImplementationOnce(() => ({
48
+ status: 200,
49
+ data: data,
50
+ }));
51
+ await act(async () => {
52
+ await result.current.onRefresh();
53
+ });
54
+ expect(axios.get).toHaveBeenCalled();
55
+ });
56
+
57
+ test('Test onLoadMore', async () => {
58
+ const { result } = renderHook(() => useHanetCheckinData(props));
59
+ axios.get.mockImplementationOnce(() => ({
60
+ status: 200,
61
+ data: data,
62
+ }));
63
+ await act(async () => {
64
+ await result.current.onLoadMore();
65
+ });
66
+ expect(axios.get).toHaveBeenCalled();
67
+
68
+ axios.get.mockClear();
69
+
70
+ await act(async () => {
71
+ await result.current.onLoadMore();
72
+ });
73
+ expect(axios.get).toHaveBeenCalledTimes(0);
74
+ });
75
+
76
+ test('Test onMomentumScrollBegin', async () => {
77
+ const { result } = renderHook(() => useHanetCheckinData(props));
78
+ await act(async () => {
79
+ await result.current.onMomentumScrollBegin();
80
+ });
81
+ });
82
+
83
+ test('Test onReceiveNewCheckinData', async () => {
84
+ const { result } = renderHook(() => useHanetCheckinData(props));
85
+ expect(result.current.checkinData).toHaveLength(0);
86
+ const newData = {
87
+ id: 1,
88
+ person_name: 'name 1',
89
+ person_type: 'EMPLOYEE',
90
+ detected_image_uri: 'uri',
91
+ detected_mask: 'MASK_OFF',
92
+ created_at: moment(),
93
+ };
94
+ await act(async () => {
95
+ await result.current.onReceiveNewCheckinData(newData);
96
+ });
97
+ expect(result.current.checkinData).toHaveLength(1);
98
+ expect(result.current.countMember).toBe(1);
99
+ expect(result.current.countStranger).not.toBe(1);
100
+
101
+ const newData2 = {
102
+ id: 2,
103
+ person_name: 'name 2',
104
+ person_type: 'STRANGER',
105
+ detected_image_uri: 'uri',
106
+ detected_mask: 'MASK_ON',
107
+ created_at: moment(),
108
+ };
109
+ await act(async () => {
110
+ await result.current.onReceiveNewCheckinData(newData2);
111
+ });
112
+ expect(result.current.checkinData).toHaveLength(2);
113
+ expect(result.current.countMember).toBe(1);
114
+ expect(result.current.countStranger).toBe(1);
115
+
116
+ const newData3 = {
117
+ id: 3,
118
+ person_name: 'name 2',
119
+ person_type: 'STRANGER',
120
+ detected_image_uri: 'uri',
121
+ detected_mask: 'MASK_ON',
122
+ created_at: moment().add(-1, 'days'),
123
+ };
124
+ await act(async () => {
125
+ await result.current.onReceiveNewCheckinData(newData3);
126
+ });
127
+ // no change
128
+ expect(result.current.checkinData).toHaveLength(2);
129
+ expect(result.current.countMember).toBe(1);
130
+ expect(result.current.countStranger).toBe(1);
131
+
132
+ await act(async () => {
133
+ await result.current.onChangeDate(moment().add(-1, 'days'));
134
+ });
135
+ const newData4 = {
136
+ id: 4,
137
+ person_name: 'name 2',
138
+ person_type: 'STRANGER',
139
+ detected_image_uri: 'uri',
140
+ detected_mask: 'MASK_ON',
141
+ created_at: moment(),
142
+ };
143
+ await act(async () => {
144
+ await result.current.onReceiveNewCheckinData(newData4);
145
+ });
146
+ // no change
147
+ expect(result.current.checkinData).toHaveLength(2);
148
+ expect(result.current.countMember).toBe(1);
149
+ expect(result.current.countStranger).toBe(1);
150
+ });
151
+ });
@@ -0,0 +1,71 @@
1
+ import { act, renderHook } from '@testing-library/react-hooks';
2
+ import { useHanetPlaceMembers } from '../index';
3
+ import axios from 'axios';
4
+
5
+ jest.mock('axios');
6
+
7
+ describe('Test useHanetPlaceMembers', () => {
8
+ let props, data;
9
+
10
+ beforeEach(() => {
11
+ axios.get.mockClear();
12
+ props = {
13
+ place: {
14
+ place_id: 2,
15
+ },
16
+ };
17
+ data = {
18
+ count: 2,
19
+ results: [
20
+ {
21
+ id: 1,
22
+ name: 'name 1',
23
+ avatar_uri: 'uri 1',
24
+ },
25
+ {
26
+ id: 2,
27
+ name: 'name 2',
28
+ avatar_uri: 'uri 2',
29
+ },
30
+ ],
31
+ };
32
+ });
33
+
34
+ test('Test onRefresh', async () => {
35
+ const { result } = renderHook(() => useHanetPlaceMembers(props));
36
+ axios.get.mockImplementationOnce(() => ({
37
+ status: 200,
38
+ data: data,
39
+ }));
40
+ await act(async () => {
41
+ await result.current.onRefresh();
42
+ });
43
+ expect(axios.get).toHaveBeenCalled();
44
+ });
45
+
46
+ test('Test onLoadMore', async () => {
47
+ const { result } = renderHook(() => useHanetPlaceMembers(props));
48
+ axios.get.mockImplementationOnce(() => ({
49
+ status: 200,
50
+ data: data,
51
+ }));
52
+ await act(async () => {
53
+ await result.current.onLoadMore();
54
+ });
55
+ expect(axios.get).toHaveBeenCalled();
56
+
57
+ axios.get.mockClear();
58
+
59
+ await act(async () => {
60
+ await result.current.onLoadMore();
61
+ });
62
+ expect(axios.get).toHaveBeenCalledTimes(0);
63
+ });
64
+
65
+ test('Test onMomentumScrollBegin', async () => {
66
+ const { result } = renderHook(() => useHanetPlaceMembers(props));
67
+ await act(async () => {
68
+ await result.current.onMomentumScrollBegin();
69
+ });
70
+ });
71
+ });
@@ -0,0 +1,5 @@
1
+ import useHanetCheckinData from './useHanetCheckinData';
2
+ import useHanetPlaceMembers from './useHanetPlaceMembers';
3
+ import useStateAlertAction from './useStateAlertAction';
4
+
5
+ export { useHanetCheckinData, useHanetPlaceMembers, useStateAlertAction };
@@ -0,0 +1,116 @@
1
+ import { useState, useEffect } from 'react';
2
+ import moment from 'moment';
3
+ import { axiosGet } from '../../../utils/Apis/axios';
4
+ import { API } from '../../../configs';
5
+ import _ from 'lodash';
6
+
7
+ let onEndReachedCalledDuringMomentum = false;
8
+
9
+ const useHanetCheckinData = (hanetCamera) => {
10
+ const [checkinData, setCheckinData] = useState([]);
11
+ const [countMember, setCountMember] = useState(null);
12
+ const [countStranger, setCountStranger] = useState(null);
13
+ const [page, setPage] = useState(1);
14
+ const [date, setDate] = useState(moment());
15
+ const [refreshing, setRefreshing] = useState(false);
16
+ const [loadingMore, setLoadingMore] = useState(false);
17
+ const [canLoadMore, setCanLoadMore] = useState(true);
18
+
19
+ const fetchData = async (page, date) => {
20
+ if (!hanetCamera) {
21
+ return;
22
+ }
23
+ setPage(page);
24
+ setDate(date);
25
+ if (page === 1) {
26
+ setRefreshing(true);
27
+ } else {
28
+ if (!canLoadMore) {
29
+ return;
30
+ }
31
+ setLoadingMore(true);
32
+ }
33
+
34
+ const params = new URLSearchParams();
35
+ params.append('page', page);
36
+ params.append('date', date.format('YYYY-MM-DD'));
37
+ const { success, data } = await axiosGet(
38
+ API.CAMERA.HANET.CHECKIN(hanetCamera.device_id),
39
+ {
40
+ params,
41
+ }
42
+ );
43
+ if (success && data) {
44
+ setCountMember(data.count_member);
45
+ setCountStranger(data.count_stranger);
46
+ if (page === 1) {
47
+ setCheckinData(data.results || []);
48
+ } else {
49
+ setCanLoadMore(page < Math.ceil(data.count / 20));
50
+ setCheckinData((prevData) =>
51
+ _.uniqBy(prevData.concat(data.results || []))
52
+ );
53
+ }
54
+ }
55
+
56
+ if (page === 1) {
57
+ setRefreshing(false);
58
+ } else {
59
+ setLoadingMore(false);
60
+ }
61
+ };
62
+
63
+ const onLoadMore = () => {
64
+ if (!onEndReachedCalledDuringMomentum) {
65
+ onEndReachedCalledDuringMomentum = true;
66
+ fetchData(page + 1, date);
67
+ }
68
+ };
69
+
70
+ const onRefresh = () => {
71
+ setCanLoadMore(true);
72
+ fetchData(1, date);
73
+ };
74
+
75
+ const onMomentumScrollBegin = () =>
76
+ (onEndReachedCalledDuringMomentum = false);
77
+
78
+ const onChangeDate = (date) => {
79
+ fetchData(page, date);
80
+ };
81
+
82
+ const onReceiveNewCheckinData = (data) => {
83
+ if (!moment(data.created_at).isSame(date, 'date')) {
84
+ return;
85
+ }
86
+ setCheckinData((listData) => {
87
+ return _.uniqBy([data, ...listData], 'id');
88
+ });
89
+ if (['EMPLOYEE', 'CUSTOMER'].includes(data.person_type)) {
90
+ setCountMember((prevData) => prevData + 1);
91
+ } else {
92
+ setCountStranger((prevData) => prevData + 1);
93
+ }
94
+ };
95
+
96
+ useEffect(() => {
97
+ onRefresh();
98
+ // eslint-disable-next-line react-hooks/exhaustive-deps
99
+ }, [hanetCamera]);
100
+
101
+ return {
102
+ checkinData,
103
+ countMember,
104
+ countStranger,
105
+ refreshing,
106
+ loadingMore,
107
+ onRefresh,
108
+ onLoadMore,
109
+ date,
110
+ onChangeDate,
111
+ onMomentumScrollBegin,
112
+ onReceiveNewCheckinData,
113
+ };
114
+ };
115
+
116
+ export default useHanetCheckinData;
@@ -0,0 +1,86 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { useIsFocused } from '@react-navigation/native';
3
+ import { axiosGet } from '../../../utils/Apis/axios';
4
+ import { API } from '../../../configs';
5
+
6
+ let onEndReachedCalledDuringMomentum = false;
7
+
8
+ const useHanetPlaceMembers = (place) => {
9
+ const isFocused = useIsFocused();
10
+ const [data, setData] = useState([]);
11
+ const [page, setPage] = useState(1);
12
+ const [refreshing, setRefreshing] = useState(false);
13
+ const [loadingMore, setLoadingMore] = useState(false);
14
+ const [canLoadMore, setCanLoadMore] = useState(true);
15
+
16
+ const fetchData = async (page) => {
17
+ if (!place) {
18
+ return;
19
+ }
20
+ setPage(page);
21
+ if (page === 1) {
22
+ setRefreshing(true);
23
+ } else {
24
+ if (!canLoadMore) {
25
+ return;
26
+ }
27
+ setLoadingMore(true);
28
+ }
29
+
30
+ const params = new URLSearchParams();
31
+ params.append('page', page);
32
+ const { success, data } = await axiosGet(
33
+ API.CAMERA.HANET.PLACE_MEMBERS(place.place_id),
34
+ {
35
+ params,
36
+ }
37
+ );
38
+ if (success && data) {
39
+ if (page === 1) {
40
+ setData(data.results || []);
41
+ } else {
42
+ setCanLoadMore(page < Math.ceil(data.count / 20));
43
+ setData((prevData) => prevData.concat(data.results || []));
44
+ }
45
+ }
46
+
47
+ if (page === 1) {
48
+ setRefreshing(false);
49
+ } else {
50
+ setLoadingMore(false);
51
+ }
52
+ };
53
+
54
+ const onLoadMore = () => {
55
+ if (!onEndReachedCalledDuringMomentum) {
56
+ onEndReachedCalledDuringMomentum = true;
57
+ fetchData(page + 1);
58
+ }
59
+ };
60
+
61
+ const onRefresh = () => {
62
+ setCanLoadMore(true);
63
+ fetchData(1);
64
+ };
65
+
66
+ const onMomentumScrollBegin = () =>
67
+ (onEndReachedCalledDuringMomentum = false);
68
+
69
+ useEffect(() => {
70
+ if (isFocused) {
71
+ onRefresh();
72
+ }
73
+ // eslint-disable-next-line react-hooks/exhaustive-deps
74
+ }, [isFocused, place]);
75
+
76
+ return {
77
+ data,
78
+ refreshing,
79
+ loadingMore,
80
+ onRefresh,
81
+ onLoadMore,
82
+ onMomentumScrollBegin,
83
+ };
84
+ };
85
+
86
+ export default useHanetPlaceMembers;
@@ -0,0 +1,62 @@
1
+ import { useState, useCallback } from 'react';
2
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
3
+ import { Colors } from '../../../configs';
4
+
5
+ const useStateAlertAction = () => {
6
+ const t = useTranslations();
7
+ const [stateAlertAction, setStateAlertAction] = useState({
8
+ visible: false,
9
+ title: '',
10
+ message: '',
11
+ leftButton: t('cancel'),
12
+ rightButton: '',
13
+ rightColor: Colors.Primary,
14
+ isDelete: true,
15
+ });
16
+
17
+ const hideAlertAction = useCallback(() => {
18
+ setStateAlertAction({ ...stateAlertAction, visible: false });
19
+ }, [stateAlertAction]);
20
+
21
+ const showRename = useCallback(
22
+ (isAddNewMember) => {
23
+ setStateAlertAction((state) => {
24
+ return {
25
+ ...state,
26
+ visible: true,
27
+ title: isAddNewMember ? t('member_name') : t('rename_member'),
28
+ message: '',
29
+ leftButton: t('cancel'),
30
+ rightButton: isAddNewMember ? t('done') : t('rename'),
31
+ rightColor: Colors.Primary,
32
+ isDelete: false,
33
+ };
34
+ });
35
+ },
36
+ [t]
37
+ );
38
+
39
+ const showDelete = useCallback(() => {
40
+ setStateAlertAction((action) => {
41
+ return {
42
+ ...action,
43
+ visible: true,
44
+ title: t('remove_member'),
45
+ message: t('text_des_remove_hanet_member'),
46
+ leftButton: t('cancel'),
47
+ rightButton: t('remove'),
48
+ rightColor: Colors.Gray6,
49
+ isDelete: true,
50
+ };
51
+ });
52
+ }, [t]);
53
+
54
+ return {
55
+ stateAlertAction,
56
+ hideAlertAction,
57
+ showRename,
58
+ showDelete,
59
+ };
60
+ };
61
+
62
+ export default useStateAlertAction;