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

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 (197) hide show
  1. package/README.md +35 -14
  2. package/package.json +4 -2
  3. package/src/commons/Action/ItemQuickAction.js +5 -2
  4. package/src/commons/ActionGroup/ColorPickerTemplate.js +1 -1
  5. package/src/commons/ActionGroup/CurtainButtonTemplate.js +10 -5
  6. package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +12 -4
  7. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/__test__/index.test.js +4 -0
  8. package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +7 -4
  9. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscode.js +1 -1
  10. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/__test__/ItemPasscode.test.js +24 -0
  11. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/__test__/index.test.js +14 -0
  12. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/index.js +1 -0
  13. package/src/commons/ActionGroup/OnOffTemplate/OnOffSimpleTemplate.js +10 -10
  14. package/src/commons/ActionGroup/OnOffTemplate/index.js +18 -15
  15. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +9 -3
  16. package/src/commons/ActionGroup/SliderRangeTemplate.js +1 -1
  17. package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +4 -1
  18. package/src/commons/ActionGroup/StatesGridActionTemplate.js +22 -8
  19. package/src/commons/ActionGroup/TimerActionTemplate.js +11 -3
  20. package/src/commons/ActionGroup/TwoButtonTemplate/index.js +13 -9
  21. package/src/commons/ActionGroup/__test__/CurtainButtonTemplate.test.js +53 -4
  22. package/src/commons/ActionGroup/__test__/OnOffButtonTemplate.test.js +14 -14
  23. package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +53 -78
  24. package/src/commons/ActionGroup/__test__/OneBigButtonTemplate.test.js +36 -20
  25. package/src/commons/ActionGroup/__test__/StatesGridActionTemplate.test.js +77 -0
  26. package/src/commons/ActionGroup/__test__/TimerActionTemplate.test.js +58 -6
  27. package/src/commons/ActionGroup/__test__/TwoButtonTemplate.test.js +49 -1
  28. package/src/commons/ActionGroup/__test__/index.test.js +135 -0
  29. package/src/commons/Auth/AccountList.js +1 -1
  30. package/src/commons/Automate/ItemAutomate.js +1 -3
  31. package/src/commons/Calendar/__test__/Calendar.test.js +33 -0
  32. package/src/commons/Connecting/__test__/Connecting.test.js +19 -2
  33. package/src/commons/ConnectingProcess/__test__/Connecting.test.js +136 -3
  34. package/src/commons/ConnectingProcess/index.js +1 -1
  35. package/src/commons/Dashboard/MyPinnedSharedUnit/__test__/MyPinnedSharedUnit.test.js +16 -13
  36. package/src/commons/Dashboard/MyPinnedSharedUnit/index.js +1 -1
  37. package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +0 -5
  38. package/src/commons/Device/Hanet/ItemHanetDevice.test.js +58 -0
  39. package/src/commons/Device/HistoryChart.js +4 -0
  40. package/src/commons/Device/LinearChart.js +15 -0
  41. package/src/commons/Device/PMSensor/PMSensorIndicatior.js +16 -12
  42. package/src/commons/Device/PMSensor/PMSensorIndicatorStyles.js +3 -0
  43. package/src/commons/Device/WaterQualitySensor/ListQualityIndicator.js +1 -0
  44. package/src/commons/Explore/__test__/CityItem.test.js +33 -54
  45. package/src/commons/FieldTemplate/ChooseUserField/ChooseFieldStyles.js +25 -0
  46. package/src/commons/FieldTemplate/ChooseUserField/ChoosePopup.js +96 -0
  47. package/src/commons/FieldTemplate/ChooseUserField/ChoosePopupStyles.js +39 -0
  48. package/src/commons/FieldTemplate/ChooseUserField/__test__/index.test.js +118 -0
  49. package/src/commons/FieldTemplate/ChooseUserField/index.js +62 -0
  50. package/src/commons/FieldTemplate/PasscodeField/PasscodeFieldStyles.js +30 -0
  51. package/src/commons/FieldTemplate/PasscodeField/__test__/index.test.js +90 -0
  52. package/src/commons/FieldTemplate/PasscodeField/index.js +43 -0
  53. package/src/commons/FieldTemplate/ScheduleField/ScheduleFieldStyles.js +13 -0
  54. package/src/commons/FieldTemplate/ScheduleField/__test__/index.test.js +179 -0
  55. package/src/commons/FieldTemplate/ScheduleField/index.js +176 -0
  56. package/src/commons/FullLoading/index.js +2 -1
  57. package/src/commons/MenuActionAddnew/index.js +1 -0
  58. package/src/commons/MenuActionList/index.js +1 -0
  59. package/src/commons/MenuActionMore/index.js +1 -1
  60. package/src/commons/PreventAccess/__test__/PreventAccess.test.js +62 -0
  61. package/src/commons/PreventAccess/index.js +9 -1
  62. package/src/commons/Sharing/__test__/DevicePermissionsCheckbox.test.js +0 -1
  63. package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +8 -35
  64. package/src/commons/SubUnit/OneTap/index.js +1 -2
  65. package/src/commons/Unit/SharedUnit.js +1 -0
  66. package/src/commons/Unit/__test__/SharedUnit.test.js +38 -183
  67. package/src/commons/WheelDateTimePicker/index.js +2 -1
  68. package/src/configs/API.js +87 -138
  69. package/src/configs/Constants.js +27 -1
  70. package/src/configs/SCConfig.js +2 -0
  71. package/src/iot/RemoteControl/__test__/GoogleHome.test.js +8 -30
  72. package/src/iot/RemoteControl/__test__/Internet.test.js +18 -7
  73. package/src/iot/RemoteControl/__test__/LgThinq.test.js +36 -177
  74. package/src/navigations/UnitStack.js +8 -0
  75. package/src/screens/AQIGuide/index.js +1 -1
  76. package/src/screens/ActivityLog/FilterPopup.js +2 -0
  77. package/src/screens/ActivityLog/__test__/index.test.js +38 -23
  78. package/src/screens/ActivityLog/hooks/__test__/index.test.js +51 -90
  79. package/src/screens/ActivityLog/index.js +2 -2
  80. package/src/screens/AddCommon/SelectSubUnit.js +1 -0
  81. package/src/screens/AddCommon/SelectUnit.js +1 -0
  82. package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +13 -24
  83. package/src/screens/AddCommon/__test__/SelectUnit.test.js +9 -33
  84. package/src/screens/AddLocationMaps/index.js +4 -1
  85. package/src/screens/AddNewAction/SelectSensorDevices.js +8 -2
  86. package/src/screens/AddNewAction/__test__/SelectAction.test.js +10 -91
  87. package/src/screens/AddNewAction/__test__/SelectSensorDevices.test.js +40 -26
  88. package/src/screens/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +3 -1
  89. package/src/screens/AddNewAutoSmart/index.js +5 -2
  90. package/src/screens/AddNewDevice/ConnectingDevices.js +3 -3
  91. package/src/screens/AddNewDevice/__test__/AddNewDevice.test.js +34 -33
  92. package/src/screens/AddNewDevice/__test__/ConnectDevices.test.js +0 -4
  93. package/src/screens/AddNewDevice/__test__/ConnectingDevices.test.js +21 -21
  94. package/src/screens/AddNewDevice/index.js +1 -0
  95. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +4 -1
  96. package/src/screens/AddNewGateway/SelectGateway.js +1 -0
  97. package/src/screens/AddNewGateway/SetupGatewayWifi.js +1 -0
  98. package/src/screens/AddNewGateway/__test__/AddNewGateway.test.js +4 -6
  99. package/src/screens/AddNewGateway/__test__/ConnectedGateway.test.js +0 -4
  100. package/src/screens/AddNewGateway/__test__/ConnectingGateway.test.js +5 -29
  101. package/src/screens/AddNewGateway/__test__/SelectGateway.test.js +0 -4
  102. package/src/screens/AddNewGateway/__test__/SetupGateway.test.js +0 -4
  103. package/src/screens/AddNewGateway/index.js +1 -0
  104. package/src/screens/AddNewOneTap/__test__/AddNewOneTap.test.js +10 -24
  105. package/src/screens/AddNewOneTap/index.js +3 -2
  106. package/src/screens/Automate/__test__/MultiUnits.test.js +6 -9
  107. package/src/screens/Automate/__test__/index.test.js +7 -12
  108. package/src/screens/Automate/index.js +2 -0
  109. package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +36 -8
  110. package/src/screens/ConfirmUnitDeletion/index.js +7 -1
  111. package/src/screens/Device/EditDevice/__test__/EditDevice.test.js +71 -22
  112. package/src/screens/Device/__test__/detail.test.js +23 -84
  113. package/src/screens/Device/detail.js +31 -8
  114. package/src/screens/Device/hooks/useFavoriteDevice.js +5 -9
  115. package/src/screens/DeviceInfo/__test__/index.test.js +0 -2
  116. package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +6 -3
  117. package/src/screens/EmergencyContacts/__test__/EmergencyContactAddNew.test.js +7 -19
  118. package/src/screens/EmergencyContacts/__test__/EmergencyContactList.test.js +20 -2
  119. package/src/screens/EmergencyContacts/__test__/EmergencyContactsSelectContacts.test.js +40 -23
  120. package/src/screens/EmergencySetting/index.js +4 -1
  121. package/src/screens/EnterPassword/__test__/EnterPassword.test.js +41 -25
  122. package/src/screens/Explore/index.js +2 -0
  123. package/src/screens/GuestInfo/__test__/index.test.js +14 -41
  124. package/src/screens/GuestInfo/components/RecurringDetail.js +1 -0
  125. package/src/screens/GuestInfo/components/TemporaryDetail.js +2 -2
  126. package/src/screens/HanetCamera/__test__/CaptureFaceID.test.js +8 -12
  127. package/src/screens/HanetCamera/__test__/Detail.test.js +27 -42
  128. package/src/screens/HanetCamera/__test__/ManageAccess.test.js +8 -5
  129. package/src/screens/HanetCamera/__test__/MemberInfo.test.js +10 -32
  130. package/src/screens/HanetCamera/hooks/__test__/useHanetCheckinData.test.js +43 -35
  131. package/src/screens/HanetCamera/hooks/__test__/useHanetPlaceMembers.test.js +10 -21
  132. package/src/screens/ManageAccess/__test__/ManageAccess.test.js +33 -22
  133. package/src/screens/ManageAccess/hooks/__test__/useManageAccess.test.js +44 -45
  134. package/src/screens/ManageAccess/index.js +2 -1
  135. package/src/screens/MoveToAnotherSubUnit/__test__/index.test.js +35 -12
  136. package/src/screens/MoveToAnotherSubUnit/index.js +5 -5
  137. package/src/screens/Notification/__test__/Notification.test.js +14 -25
  138. package/src/screens/Notification/__test__/NotificationItem.test.js +4 -3
  139. package/src/screens/PlayBackCamera/__test__/index.test.js +87 -2
  140. package/src/screens/PlayBackCamera/index.js +19 -3
  141. package/src/screens/ScanChipQR/__test__/ScanChipQR.test.js +7 -20
  142. package/src/screens/ScanChipQR/components/QRScan/index.js +1 -0
  143. package/src/screens/ScanSensorQR/__test__/ScanSensorQR.test.js +8 -24
  144. package/src/screens/ScriptDetail/__test__/index.test.js +17 -86
  145. package/src/screens/ScriptDetail/index.js +5 -4
  146. package/src/screens/SelectUnit/__test__/index.test.js +12 -55
  147. package/src/screens/SelectUnit/index.js +5 -2
  148. package/src/screens/SetSchedule/index.js +6 -2
  149. package/src/screens/SharedUnit/__test__/TabHeader.test.js +0 -2
  150. package/src/screens/SharedUnit/index.js +2 -0
  151. package/src/screens/Sharing/InfoMemberUnit.js +1 -1
  152. package/src/screens/Sharing/MemberList.js +12 -11
  153. package/src/screens/Sharing/SelectPermission.js +107 -70
  154. package/src/screens/Sharing/__test__/InfoMemberUnit.test.js +47 -29
  155. package/src/screens/Sharing/__test__/MemberList.test.js +13 -127
  156. package/src/screens/Sharing/__test__/MemberList2.test.js +80 -0
  157. package/src/screens/Sharing/__test__/SelectPermission.test.js +28 -38
  158. package/src/screens/Sharing/__test__/SelectUser.test.js +17 -38
  159. package/src/screens/Sharing/hooks/index.js +3 -0
  160. package/src/screens/SideMenuDetail/SideMenuDetailStyles.js +28 -0
  161. package/src/screens/SideMenuDetail/__test__/index.test.js +154 -0
  162. package/src/screens/SideMenuDetail/index.js +149 -0
  163. package/src/screens/SmartIr/components/SelectBrand.js +1 -1
  164. package/src/screens/SubUnit/ManageSubUnit.js +1 -0
  165. package/src/screens/SubUnit/__test__/AddSubUnit.test.js +21 -67
  166. package/src/screens/SubUnit/__test__/Detail.test.js +31 -8
  167. package/src/screens/SubUnit/__test__/EditSubUnit.test.js +21 -89
  168. package/src/screens/SubUnit/hooks/__test__/useManageSubUnit.test.js +47 -44
  169. package/src/screens/SyncLGDevice/AddLGDevice.js +1 -0
  170. package/src/screens/SyncLGDevice/__test__/AddLGDevice.test.js +14 -90
  171. package/src/screens/TDSGuide/index.js +4 -1
  172. package/src/screens/UVIndexGuide/index.js +1 -1
  173. package/src/screens/Unit/ChooseLocation.js +1 -1
  174. package/src/screens/Unit/ManageUnit.js +1 -0
  175. package/src/screens/Unit/SelectAddress.js +4 -1
  176. package/src/screens/Unit/Station/index.js +1 -0
  177. package/src/screens/Unit/Summaries.js +1 -1
  178. package/src/screens/Unit/__test__/CheckSendEmail.test.js +15 -28
  179. package/src/screens/Unit/__test__/ChooseLocation.test.js +27 -14
  180. package/src/screens/Unit/__test__/Detail.test.js +83 -185
  181. package/src/screens/Unit/__test__/ManageUnit.test.js +18 -42
  182. package/src/screens/Unit/__test__/SelectAddress.test.js +13 -39
  183. package/src/screens/Unit/__test__/SmartAccount.test.js +17 -9
  184. package/src/screens/Unit/__test__/SmartAccountItem.test.js +0 -1
  185. package/src/screens/Unit/components/MyAllUnit/__test__/MyAllUnit.test.js +36 -0
  186. package/src/screens/Unit/components/MyAllUnit/__test__/index.test.js +54 -0
  187. package/src/screens/Unit/components/SharedUnit/index.js +1 -0
  188. package/src/screens/Unit/components/__test__/SharedUnit.test.js +31 -34
  189. package/src/screens/UnitSummary/__test__/index.test.js +38 -31
  190. package/src/screens/UnitSummary/components/PowerConsumeHistoryChart/__test__/index.test.js +7 -4
  191. package/src/screens/UnitSummary/components/PowerConsumption/__test__/PowerConsumption.test.js +14 -16
  192. package/src/screens/WaterQualityGuide/index.js +1 -1
  193. package/src/utils/Apis/axios.js +37 -13
  194. package/src/utils/I18n/translations/en.json +1 -0
  195. package/src/utils/I18n/translations/vi.json +1 -0
  196. package/src/utils/Route/index.js +1 -0
  197. package/src/utils/Utils.js +6 -6
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import { TouchableWithoutFeedback } from 'react-native';
3
+ import renderer, { act } from 'react-test-renderer';
4
+ import ItemHanetDevice from './ItemHanetDevice';
5
+ import { SCProvider } from '../../../context';
6
+ import { mockSCStore } from '../../../context/mockStore';
7
+
8
+ const wrapComponent = (props) => (
9
+ <SCProvider initState={mockSCStore({})}>
10
+ <ItemHanetDevice {...props} />
11
+ </SCProvider>
12
+ );
13
+
14
+ const mockNavigate = jest.fn();
15
+ jest.mock('@react-navigation/native', () => {
16
+ return {
17
+ ...jest.requireActual('@react-navigation/native'),
18
+ useNavigation: () => ({
19
+ navigate: mockNavigate,
20
+ }),
21
+ };
22
+ });
23
+
24
+ describe('Test ItemHanetDevice', () => {
25
+ let tree, props;
26
+
27
+ beforeEach(() => {
28
+ props = {
29
+ svgMain: 'icon',
30
+ title: 'title',
31
+ sensor: {},
32
+ unit: {},
33
+ station: {},
34
+ };
35
+ });
36
+
37
+ test('render ItemHanetDevice', () => {
38
+ act(() => {
39
+ tree = renderer.create(wrapComponent(props));
40
+ });
41
+ const instance = tree.root;
42
+ const touches = instance.findAllByType(TouchableWithoutFeedback);
43
+ act(() => {
44
+ tree = touches[0].props.onPress();
45
+ });
46
+ expect(mockNavigate).toBeCalled();
47
+ });
48
+
49
+ test('render ItemHanetDevice sensor has icon', () => {
50
+ props.sensor.icon_kit = 'icon';
51
+ act(() => {
52
+ tree = renderer.create(wrapComponent(props));
53
+ });
54
+ const instance = tree.root;
55
+ const touches = instance.findAllByType(TouchableWithoutFeedback);
56
+ expect(touches.length).toBeGreaterThan(0);
57
+ });
58
+ });
@@ -239,6 +239,8 @@ const HistoryChart = memo(
239
239
  onConfirm={onConfirmStart}
240
240
  onCancel={onCancel}
241
241
  display="spinner"
242
+ cancelTextIOS={t('cancel')}
243
+ confirmTextIOS={t('confirm')}
242
244
  />
243
245
  <DateTimePickerModal
244
246
  isVisible={eventPicker.showModalEnd}
@@ -247,6 +249,8 @@ const HistoryChart = memo(
247
249
  onConfirm={onConfirmEnd}
248
250
  onCancel={onCancel}
249
251
  display="spinner"
252
+ cancelTextIOS={t('cancel')}
253
+ confirmTextIOS={t('confirm')}
250
254
  />
251
255
  </View>
252
256
  );
@@ -52,6 +52,21 @@ const chartOptions = {
52
52
  format: '{value:%d.%m %H:%M}',
53
53
  },
54
54
  },
55
+ legend: {
56
+ useHTML: true,
57
+ labelFormatter: function () {
58
+ if (this.visible) {
59
+ return (
60
+ '<span style="color:#333333;font-weight:bold">' +
61
+ this.name +
62
+ '</span>'
63
+ );
64
+ }
65
+ return (
66
+ '<span style="color:#cccccc;font-weight:bold">' + this.name + '</span>'
67
+ );
68
+ },
69
+ },
55
70
  };
56
71
 
57
72
  function LinearChart({ datas }) {
@@ -1,4 +1,5 @@
1
1
  import React, { memo, useCallback } from 'react';
2
+ import { View } from 'react-native';
2
3
  import { FlatList } from 'react-native';
3
4
  import QualityIndicatorItem from '../WaterQualitySensor/QualityIndicatorsItem';
4
5
  import styles from './PMSensorIndicatorStyles';
@@ -26,18 +27,21 @@ const PMSensorIndicatior = memo(({ data, style }) => {
26
27
  const isScrollMode = data.length > 3;
27
28
 
28
29
  return (
29
- <FlatList
30
- bounces={false}
31
- numColumns={1}
32
- horizontal={true}
33
- contentContainerStyle={[
34
- styles.standard,
35
- !isScrollMode && styles.centerItem,
36
- ]}
37
- data={data}
38
- keyExtractor={keyExtractor}
39
- renderItem={renderItem}
40
- />
30
+ <View style={styles.wrap}>
31
+ <FlatList
32
+ bounces={false}
33
+ numColumns={1}
34
+ horizontal={true}
35
+ contentContainerStyle={[
36
+ styles.standard,
37
+ !isScrollMode && styles.centerItem,
38
+ ]}
39
+ data={data}
40
+ keyExtractor={keyExtractor}
41
+ renderItem={renderItem}
42
+ scrollIndicatorInsets={{ right: 1 }}
43
+ />
44
+ </View>
41
45
  );
42
46
  });
43
47
 
@@ -10,4 +10,7 @@ export default StyleSheet.create({
10
10
  flex: 1,
11
11
  justifyContent: 'center',
12
12
  },
13
+ wrap: {
14
+ marginVertical: 16,
15
+ },
13
16
  });
@@ -27,6 +27,7 @@ const ListQualityIndicator = ({ data, style }) => {
27
27
  showsHorizontalScrollIndicator={false}
28
28
  nestedScrollEnabled
29
29
  contentContainerStyle={[styles.flatlistContent, style]}
30
+ scrollIndicatorInsets={{ right: 1 }}
30
31
  />
31
32
  </View>
32
33
  );
@@ -2,12 +2,15 @@ import React from 'react';
2
2
  import renderer, { act } from 'react-test-renderer';
3
3
  import CityItem from '../CityItem';
4
4
  import { TouchableOpacity } from 'react-native';
5
- import axios from 'axios';
6
5
  import { API } from '../../../configs';
7
6
  import Pin from '../../../../assets/images/Explore/Pin.svg';
8
7
  import PinOutline from '../../../../assets/images/Explore/PinOutline.svg';
9
8
  import { SCProvider } from '../../../context';
10
9
  import { mockSCStore } from '../../../context/mockStore';
10
+ import MockAdapter from 'axios-mock-adapter';
11
+ import api from '../../../utils/Apis/axios';
12
+
13
+ const mock = new MockAdapter(api.axiosInstance);
11
14
 
12
15
  const mockedDispatch = jest.fn();
13
16
 
@@ -17,7 +20,6 @@ const wrapComponent = (item, mockeSelect) => (
17
20
  </SCProvider>
18
21
  );
19
22
 
20
- jest.mock('axios');
21
23
  jest.mock('react-redux', () => ({
22
24
  ...jest.requireActual('react-redux'),
23
25
  useDispatch: () => mockedDispatch,
@@ -25,9 +27,6 @@ jest.mock('react-redux', () => ({
25
27
 
26
28
  describe('Test CityItem', () => {
27
29
  let tree;
28
- afterEach(() => {
29
- axios.post.mockClear();
30
- });
31
30
 
32
31
  test('render CityItem is_pin: true', async () => {
33
32
  const item = {
@@ -38,37 +37,23 @@ describe('Test CityItem', () => {
38
37
  count_pin: 1,
39
38
  };
40
39
  const mockeSelect = jest.fn();
41
- const response = {
42
- status: 200,
43
- };
44
-
45
- axios.post.mockImplementation(async () => {
46
- return response;
47
- });
40
+ mock.onPost(API.UNIT.PIN_UNIT()).reply(200);
48
41
  await act(async () => {
49
42
  tree = await renderer.create(wrapComponent(item, mockeSelect));
50
43
  });
51
44
  const instance = tree.root;
52
45
  const buttons = instance.findAllByType(TouchableOpacity);
53
46
  expect(buttons.length).toBe(2);
54
- await act(async () => {
55
- await buttons[0].props.onPress();
56
- });
47
+ await buttons[0].props.onPress();
57
48
  expect(mockeSelect).toHaveBeenCalledTimes(1);
58
-
59
49
  const pin = instance.findAllByType(Pin);
60
50
  expect(pin.length).toBe(2);
61
- await act(async () => {
62
- await pin[1].props.onPress();
63
- });
64
- expect(axios.post).toHaveBeenCalledWith(API.UNIT.UNPIN_UNIT(1));
65
-
51
+ mock.onPost(API.UNIT.PIN_UNIT()).reply(200);
52
+ await pin[1].props.onPress();
66
53
  const unpin = instance.findAllByType(PinOutline);
54
+ mock.onPost(API.UNIT.UNPIN_UNIT(1)).reply(200);
55
+ await unpin[1].props.onPress();
67
56
  expect(unpin.length).toBe(2);
68
- await act(async () => {
69
- await unpin[1].props.onPress();
70
- });
71
- expect(axios.post).toHaveBeenCalledWith(API.UNIT.UNPIN_UNIT(1));
72
57
  });
73
58
 
74
59
  test('render CityItem is_pin: false', async () => {
@@ -80,24 +65,33 @@ describe('Test CityItem', () => {
80
65
  count_pin: 1,
81
66
  };
82
67
  const mockeSelect = jest.fn();
83
- const response = {
84
- status: 200,
85
- };
86
-
87
- axios.post.mockImplementation(async () => {
88
- return response;
89
- });
90
68
  await act(async () => {
91
69
  tree = await renderer.create(wrapComponent(item, mockeSelect));
92
70
  });
93
71
  const instance = tree.root;
94
-
95
72
  const unpin = instance.findAllByType(PinOutline);
73
+ mock.onPost(API.UNIT.PIN_UNIT(1)).reply(200);
74
+ await unpin[1].props.onPress();
96
75
  expect(unpin.length).toBe(2);
76
+ });
77
+
78
+ test('render CityItem is_pin: false and call api false', async () => {
79
+ const item = {
80
+ id: 1,
81
+ name: 'name',
82
+ icon: 'icon',
83
+ is_pin: false,
84
+ count_pin: 1,
85
+ };
86
+ const mockeSelect = jest.fn();
97
87
  await act(async () => {
98
- await unpin[1].props.onPress();
88
+ tree = await renderer.create(wrapComponent(item, mockeSelect));
99
89
  });
100
- expect(axios.post).toHaveBeenCalledWith(API.UNIT.PIN_UNIT(1));
90
+ const instance = tree.root;
91
+ const unpin = instance.findAllByType(PinOutline);
92
+ mock.onPost(API.UNIT.PIN_UNIT(1)).reply(400);
93
+ await unpin[1].props.onPress();
94
+ expect(unpin.length).toBe(2);
101
95
  });
102
96
 
103
97
  test('render CityItem PinOutline axios.post response false', async () => {
@@ -109,22 +103,14 @@ describe('Test CityItem', () => {
109
103
  count_pin: 1,
110
104
  };
111
105
  const mockeSelect = jest.fn();
112
- const response = {};
113
-
114
- axios.post.mockImplementation(async () => {
115
- return response;
116
- });
106
+ mock.onPost(API.UNIT.PIN_UNIT()).reply(200, {});
117
107
  await act(async () => {
118
108
  tree = await renderer.create(wrapComponent(item, mockeSelect));
119
109
  });
120
110
  const instance = tree.root;
121
-
122
111
  const unpin = instance.findAllByType(PinOutline);
112
+ await unpin[1].props.onPress();
123
113
  expect(unpin.length).toBe(2);
124
- await act(async () => {
125
- await unpin[1].props.onPress();
126
- });
127
- expect(axios.post).not.toHaveBeenCalledWith(API.UNIT.UNPIN_UNIT(1));
128
114
  });
129
115
 
130
116
  test('render CityItem Pin axios.post response false', async () => {
@@ -136,21 +122,14 @@ describe('Test CityItem', () => {
136
122
  count_pin: 1,
137
123
  };
138
124
  const mockeSelect = jest.fn();
139
- const response = {};
140
-
141
- axios.post.mockImplementation(async () => {
142
- return response;
143
- });
125
+ mock.onPost(API.UNIT.UNPIN_UNIT(1)).reply(400, {});
144
126
  await act(async () => {
145
127
  tree = await renderer.create(wrapComponent(item, mockeSelect));
146
128
  });
147
129
  const instance = tree.root;
148
130
  const pin = instance.findAllByType(Pin);
131
+ await pin[1].props.onPress();
149
132
  expect(pin.length).toBe(2);
150
- await act(async () => {
151
- await pin[1].props.onPress();
152
- });
153
- expect(axios.post).toHaveBeenCalledWith(API.UNIT.UNPIN_UNIT(1));
154
133
  });
155
134
 
156
135
  test('render CityItem icon null', async () => {
@@ -0,0 +1,25 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors } from '../../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ wrapper: {
6
+ flexDirection: 'row',
7
+ paddingTop: 30,
8
+ },
9
+ textHeadLine: {
10
+ fontSize: 16,
11
+ color: Colors.Gray9,
12
+ fontWeight: 'bold',
13
+ },
14
+ buttonValue: {
15
+ flex: 1,
16
+ flexDirection: 'row',
17
+ justifyContent: 'flex-end',
18
+ alignItems: 'center',
19
+ },
20
+ value: {
21
+ marginRight: 20,
22
+ fontSize: 14,
23
+ color: Colors.Gray8,
24
+ },
25
+ });
@@ -0,0 +1,96 @@
1
+ import React, { useState, useCallback } from 'react';
2
+ import { View, ScrollView, TouchableOpacity } from 'react-native';
3
+ import { Colors } from '../../../configs';
4
+ import { TESTID } from '../../../configs/Constants';
5
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
6
+ import BottomButtonView from '../../BottomButtonView';
7
+ import { ModalCustom } from '../../Modal';
8
+ import RadioCircle from '../../RadioCircle';
9
+ import Text from '../../Text';
10
+
11
+ import styles from './ChoosePopupStyles';
12
+
13
+ const RowMember = ({ member, isSelected, onSelect }) => {
14
+ const handleOnPress = useCallback(() => {
15
+ onSelect(member);
16
+ }, [onSelect, member]);
17
+ return (
18
+ <TouchableOpacity
19
+ style={styles.row}
20
+ onPress={handleOnPress}
21
+ testID={TESTID.CHOOSE_ITEM}
22
+ >
23
+ <RadioCircle active={isSelected} />
24
+ <View style={styles.wrapText}>
25
+ <Text type="H4" color={Colors.Gray9}>
26
+ {member.name
27
+ ? member.name
28
+ : member.phone_number
29
+ ? member.phone_number
30
+ : member.email}
31
+ </Text>
32
+ </View>
33
+ </TouchableOpacity>
34
+ );
35
+ };
36
+
37
+ const ChoosePopup = ({ isVisible, title, onHide, members, onApply }) => {
38
+ const t = useTranslations();
39
+ const [selectedUsers, setSelectedUsers] = useState({});
40
+
41
+ const handleOnSelectUser = useCallback((user) => {
42
+ setSelectedUsers(user);
43
+ }, []);
44
+
45
+ const handleOnApply = useCallback(() => {
46
+ onApply(selectedUsers);
47
+ onHide();
48
+ }, [selectedUsers, onApply, onHide]);
49
+
50
+ const handleOnCancel = useCallback(() => {
51
+ onHide();
52
+ }, [onHide]);
53
+
54
+ return (
55
+ <ModalCustom
56
+ testID={TESTID.CHOOSE_POPUP}
57
+ isVisible={isVisible}
58
+ onBackButtonPress={handleOnCancel}
59
+ onBackdropPress={handleOnCancel}
60
+ useNativeDriver={true}
61
+ useNativeDriverForBackdrop={true}
62
+ animationIn={'zoomIn'}
63
+ animationOut={'zoomOut'}
64
+ style={styles.wrapPopup}
65
+ >
66
+ <View style={[styles.popup, styles.heigh50percent]}>
67
+ <Text type="H4" style={styles.title} bold>
68
+ {title}
69
+ </Text>
70
+ <View style={styles.separator} />
71
+ <ScrollView>
72
+ {members.map((member, index) => (
73
+ <RowMember
74
+ key={index}
75
+ member={member}
76
+ isSelected={selectedUsers.id === member.id}
77
+ onSelect={handleOnSelectUser}
78
+ />
79
+ ))}
80
+ </ScrollView>
81
+ <View style={styles.separator} />
82
+ <BottomButtonView
83
+ rowButton={true}
84
+ testIDPrefix={TESTID.CHOOSE_POPUP}
85
+ style={styles.bottomButtonView}
86
+ secondaryTitle={t('cancel')}
87
+ mainTitle={t('apply')}
88
+ onPressSecondary={handleOnCancel}
89
+ onPressMain={handleOnApply}
90
+ />
91
+ </View>
92
+ </ModalCustom>
93
+ );
94
+ };
95
+
96
+ export default ChoosePopup;
@@ -0,0 +1,39 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors, Constants } from '../../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ wrapPopup: {
6
+ marginHorizontal: 16,
7
+ },
8
+ popup: {
9
+ backgroundColor: Colors.White,
10
+ width: '100%',
11
+ height: (Constants.height * 80) / 100,
12
+ padding: 24,
13
+ paddingBottom: 100,
14
+ borderRadius: 10,
15
+ },
16
+ heigh50percent: {
17
+ height: (Constants.height * 50) / 100,
18
+ },
19
+ title: {
20
+ marginBottom: 16,
21
+ },
22
+ bottomButtonView: {
23
+ marginBottom: 24,
24
+ },
25
+ separator: {
26
+ height: 0.5,
27
+ backgroundColor: Colors.Gray4,
28
+ },
29
+ row: {
30
+ flexDirection: 'row',
31
+ alignItems: 'center',
32
+ },
33
+ wrapText: {
34
+ flex: 1,
35
+ paddingVertical: 8,
36
+ marginRight: 24,
37
+ marginLeft: 16,
38
+ },
39
+ });
@@ -0,0 +1,118 @@
1
+ import React from 'react';
2
+ import MockAdapter from 'axios-mock-adapter';
3
+ import { act, create } from 'react-test-renderer';
4
+ import { TESTID } from '../../../../configs/Constants';
5
+ import { mockSCStore } from '../../../../context/mockStore';
6
+ import { SCProvider } from '../../../../context';
7
+ import ChooseUserField from '../index';
8
+ import { TouchableOpacity } from 'react-native';
9
+ import { ModalCustom } from '../../../Modal';
10
+ import api from '../../../../utils/Apis/axios';
11
+ import { API } from '../../../../configs';
12
+
13
+ const mock = new MockAdapter(api.axiosInstance);
14
+
15
+ const wrapComponent = (
16
+ unit = { id: 1 },
17
+ dataItem = {
18
+ type: 'choose_user',
19
+ key: 'user_id',
20
+ action: {
21
+ type: 'action_zigbee',
22
+ id: 1,
23
+ },
24
+ },
25
+ index = 0,
26
+ setDataForm,
27
+ dataForm = [
28
+ {
29
+ type: 'choose_user',
30
+ key: 'user_id',
31
+ action: {
32
+ type: 'action_zigbee',
33
+ id: 1,
34
+ },
35
+ },
36
+ ]
37
+ ) => (
38
+ <SCProvider initState={mockSCStore({})}>
39
+ <ChooseUserField
40
+ unit={unit}
41
+ dataItem={dataItem}
42
+ index={index}
43
+ setDataForm={jest.fn()}
44
+ dataForm={dataForm}
45
+ />
46
+ </SCProvider>
47
+ );
48
+
49
+ describe('Test ChooseUserField', () => {
50
+ let tree;
51
+
52
+ const onPressCancel = async (instance, popup) => {
53
+ const buttonCancel = instance.find(
54
+ (el) =>
55
+ el.props.testID ===
56
+ TESTID.CHOOSE_POPUP + TESTID.BOTTOM_VIEW_SECONDARY &&
57
+ el.type === TouchableOpacity
58
+ );
59
+
60
+ await act(async () => {
61
+ await buttonCancel.props.onPress();
62
+ });
63
+ expect(popup.props.isVisible).toBeFalsy();
64
+ };
65
+
66
+ const onPressApply = async (instance, popup) => {
67
+ const buttonApply = instance.find(
68
+ (el) =>
69
+ el.props.testID === TESTID.CHOOSE_POPUP + TESTID.BOTTOM_VIEW_MAIN &&
70
+ el.type === TouchableOpacity
71
+ );
72
+
73
+ await act(async () => {
74
+ await buttonApply.props.onPress();
75
+ });
76
+ expect(popup.props.isVisible).toBeFalsy();
77
+ };
78
+
79
+ test('render ChooseUserField handleOnApply', async () => {
80
+ mock.onGet(API.SHARE.UNITS_MEMBERS(1)).reply(200, [{ id: 1, name: 'Ken' }]);
81
+ await act(async () => {
82
+ tree = create(wrapComponent());
83
+ });
84
+
85
+ const instance = tree.root;
86
+
87
+ const ChooseField = instance.find(
88
+ (item) =>
89
+ item.props.testID === TESTID.CHOOSE_FIELD &&
90
+ item.type === TouchableOpacity
91
+ );
92
+ await act(async () => {
93
+ await ChooseField.props.onPress();
94
+ });
95
+
96
+ const popup = instance.find(
97
+ (item) =>
98
+ item.props.testID === TESTID.CHOOSE_POPUP && item.type === ModalCustom
99
+ );
100
+ expect(popup.props.isVisible).toBeTruthy();
101
+ await onPressCancel(instance, popup);
102
+ await onPressApply(instance, popup);
103
+ });
104
+
105
+ test('fetch unit_members error', async () => {
106
+ mock.onGet(API.SHARE.UNITS_MEMBERS(1)).reply(new Error('Network Error'));
107
+ await act(async () => {
108
+ tree = create(wrapComponent());
109
+ });
110
+ const instance = tree.root;
111
+ const ChooseField = instance.findAll(
112
+ (item) =>
113
+ item.props.testID === TESTID.CHOOSE_ITEM &&
114
+ item.type === TouchableOpacity
115
+ );
116
+ expect(ChooseField).toHaveLength(0);
117
+ });
118
+ });
@@ -0,0 +1,62 @@
1
+ import React, { memo, useEffect, useState } from 'react';
2
+ import { IconOutline } from '@ant-design/icons-react-native';
3
+ import { TouchableOpacity, View } from 'react-native';
4
+
5
+ import styles from './ChooseFieldStyles';
6
+ import ChoosePopup from './ChoosePopup';
7
+ import { useBoolean } from '../../../hooks/Common';
8
+ import { axiosGet } from '../../../utils/Apis/axios';
9
+ import { API, Colors } from '../../../configs';
10
+ import { TESTID } from '../../../configs/Constants';
11
+ import Text from '../../Text';
12
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
13
+
14
+ const ChooseUserField = ({ unit, dataItem, index, setDataForm, dataForm }) => {
15
+ const [showFilterPopup, setShowFilterPopup, setHideFilterPopup] =
16
+ useBoolean();
17
+ const [choose, setChoose] = useState({});
18
+ const [members, setMembers] = useState([]);
19
+ const t = useTranslations();
20
+ const fetchMembers = async () => {
21
+ const { success, data } = await axiosGet(API.SHARE.UNITS_MEMBERS(unit.id));
22
+ if (success) {
23
+ setMembers(data);
24
+ }
25
+ };
26
+
27
+ useEffect(() => {
28
+ if (!members.length) {
29
+ fetchMembers();
30
+ return;
31
+ }
32
+
33
+ dataItem.data = choose.id;
34
+ dataItem.valid = true;
35
+ dataItem[dataItem.action.type] = dataItem.action.id;
36
+ dataForm[index] = dataItem;
37
+ setDataForm([...dataForm]);
38
+ // eslint-disable-next-line react-hooks/exhaustive-deps
39
+ }, [choose]);
40
+
41
+ return (
42
+ <View style={styles.wrapper}>
43
+ <Text style={styles.textHeadLine}>{t('choose_user')}</Text>
44
+ <TouchableOpacity
45
+ testID={TESTID.CHOOSE_FIELD}
46
+ style={styles.buttonValue}
47
+ onPress={setShowFilterPopup}
48
+ >
49
+ <Text style={styles.value}>{choose.name}</Text>
50
+ <IconOutline name="right" size={20} color={Colors.Gray8} />
51
+ </TouchableOpacity>
52
+ <ChoosePopup
53
+ isVisible={showFilterPopup}
54
+ onHide={setHideFilterPopup}
55
+ members={members}
56
+ title={t('choose_user')}
57
+ onApply={setChoose}
58
+ />
59
+ </View>
60
+ );
61
+ };
62
+ export default memo(ChooseUserField);