@eohjsc/react-native-smart-city 0.4.59 → 0.4.61

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 (40) hide show
  1. package/package.json +1 -2
  2. package/src/commons/Action/ItemQuickAction.js +1 -1
  3. package/src/commons/Action/__test__/ItemQuickAction.test.js +22 -8
  4. package/src/commons/Automate/ItemAutomate.js +4 -9
  5. package/src/commons/Button/index.js +4 -2
  6. package/src/commons/Device/RainningSensor/CurrentRainSensor.js +49 -36
  7. package/src/commons/Grid/GridItem.js +20 -0
  8. package/src/commons/Grid/GridItemStyles.js +32 -0
  9. package/src/configs/API.js +0 -2
  10. package/src/configs/Constants.js +0 -1
  11. package/src/context/actionType.ts +1 -0
  12. package/src/context/reducer.ts +19 -1
  13. package/src/screens/Automate/AddNewAction/ChooseAction.js +0 -2
  14. package/src/screens/Automate/AddNewAction/ChooseConfig.js +46 -161
  15. package/src/screens/Automate/AddNewAction/Components/SelectDevices.js +2 -6
  16. package/src/screens/Automate/AddNewAction/NewActionWrapper.js +10 -6
  17. package/src/screens/Automate/AddNewAction/SelectMonitorDevices.js +1 -0
  18. package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +143 -173
  19. package/src/screens/Automate/AddNewAction/Styles/SelectActionStyles.js +8 -0
  20. package/src/screens/Automate/AddNewAction/Styles/SetupSensorStyles.js +29 -62
  21. package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +77 -9
  22. package/src/screens/Automate/AddNewAction/__test__/ChooseConfig.test.js +23 -83
  23. package/src/screens/Automate/AddNewAction/__test__/SelectControlDevices.test.js +2 -19
  24. package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +125 -94
  25. package/src/screens/Automate/AddNewAutoSmart/AddAutomationTypeSmart.js +0 -4
  26. package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +24 -27
  27. package/src/screens/Automate/AddNewAutoSmart/AddUnknownTypeSmart.js +0 -4
  28. package/src/screens/Automate/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +1 -21
  29. package/src/screens/Automate/ScriptDetail/utils.js +42 -19
  30. package/src/screens/Automate/index.js +2 -4
  31. package/src/screens/Device/__test__/sensorDisplayItem.test.js +9 -0
  32. package/src/screens/Device/components/SensorDisplayItem.js +3 -0
  33. package/src/screens/Device/hooks/__test__/useEvaluateValue.test.js +1 -1
  34. package/src/screens/Device/hooks/useEvaluateValue.js +10 -6
  35. package/src/screens/Notification/__test__/Notification.test.js +10 -0
  36. package/src/screens/Unit/__test__/AddMenu.test.js +76 -0
  37. package/src/screens/WaterQualityGuide/__test__/index.test.js +0 -5
  38. package/src/utils/I18n/translations/en.js +2 -0
  39. package/src/utils/I18n/translations/vi.js +2 -0
  40. package/src/utils/Route/index.js +5 -0
@@ -32,9 +32,43 @@ export const getAutomationData = (automate) => {
32
32
  return null;
33
33
  };
34
34
 
35
+ const generateAutomationConditionValueEvaluation = (
36
+ automateData,
37
+ valueEvaluations,
38
+ t
39
+ ) => {
40
+ const { action, end_device_name, config_name, value } = automateData;
41
+
42
+ const index = value[1];
43
+ const valueEvaluation = valueEvaluations?.find((v) => v.id === value[0]);
44
+
45
+ if (valueEvaluation) {
46
+ if (valueEvaluation.template === 'range') {
47
+ return `${config_name} ${t('is')} ${
48
+ valueEvaluation.configuration.ranges[index]?.evaluate.text
49
+ }`;
50
+ }
51
+ if (valueEvaluation.template === 'boolean') {
52
+ return `${config_name} ${t('is')} ${
53
+ index
54
+ ? valueEvaluation.configuration.on.text
55
+ : valueEvaluation.configuration.off.text
56
+ }`;
57
+ }
58
+ }
59
+ let textEvent = '';
60
+ if (config_name) {
61
+ const stateConditionData = null;
62
+ textEvent = `${config_name} - ${t(stateConditionData?.stateValue[value])}`;
63
+ } else {
64
+ textEvent = `${end_device_name} - ${action}`;
65
+ }
66
+ return textEvent;
67
+ };
68
+
35
69
  export const generateAutomationConditionText = (
36
70
  automate,
37
- valueEvaluation,
71
+ valueEvaluations,
38
72
  t
39
73
  ) => {
40
74
  const automateData = getAutomationData(automate);
@@ -44,6 +78,13 @@ export const generateAutomationConditionText = (
44
78
 
45
79
  if ([AUTOMATE_TYPE.VALUE_CHANGE].includes(automate?.type)) {
46
80
  const { condition, config_name, value } = automateData;
81
+ if (condition === 'value_evaluation') {
82
+ return generateAutomationConditionValueEvaluation(
83
+ automateData,
84
+ valueEvaluations,
85
+ t
86
+ );
87
+ }
47
88
 
48
89
  let text;
49
90
  if (condition === '>') {
@@ -90,24 +131,6 @@ export const generateAutomationConditionText = (
90
131
  const textWeekday = sortWeekday.map((item) => weekday[item]).join(', ');
91
132
  return `${textWeekday} ${t('at')} ${time}`;
92
133
  }
93
- } else if ([AUTOMATE_TYPE.EVENT].includes(automate?.type)) {
94
- const { action, end_device_name, config_name, value } = automateData;
95
-
96
- if (valueEvaluation) {
97
- return `${config_name} ${t('is')} ${
98
- valueEvaluation.configuration.ranges[value]?.evaluate.text
99
- }`;
100
- }
101
- let textEvent = '';
102
- if (config_name) {
103
- const stateConditionData = null;
104
- textEvent = `${config_name} - ${t(
105
- stateConditionData?.stateValue[value]
106
- )}`;
107
- } else {
108
- textEvent = `${end_device_name} - ${action}`;
109
- }
110
- return textEvent;
111
134
  }
112
135
  return null;
113
136
  };
@@ -60,10 +60,7 @@ const Automate = () => {
60
60
  if (success && data && data.length) {
61
61
  setAutomatesData(data);
62
62
  }
63
- const timeout = setTimeout(() => {
64
- setIsLoading(false);
65
- clearTimeout(timeout);
66
- }, 1000);
63
+ setIsLoading(false);
67
64
  }, []);
68
65
 
69
66
  const onPressItem = useCallback(
@@ -197,6 +194,7 @@ const Automate = () => {
197
194
 
198
195
  useLayoutEffect(() => {
199
196
  setOptions({
197
+ /* istanbul ignore next */
200
198
  headerRight: () => (
201
199
  <TouchableOpacity style={styles.buttonAdd}>
202
200
  <IconFill name={'plus-circle'} size={28} color={Colors.Orange} />
@@ -360,6 +360,9 @@ describe('Test SensorDisplayItem', () => {
360
360
  },
361
361
  ],
362
362
  isWidgetOrder: undefined,
363
+ size: 120,
364
+ iconSize: 25,
365
+ textType: 'H4',
363
366
  });
364
367
  });
365
368
 
@@ -392,6 +395,9 @@ describe('Test SensorDisplayItem', () => {
392
395
  evaluate: null,
393
396
  },
394
397
  ],
398
+ size: 120,
399
+ iconSize: 25,
400
+ textType: 'H4',
395
401
  isWidgetOrder: undefined,
396
402
  });
397
403
  });
@@ -410,6 +416,9 @@ describe('Test SensorDisplayItem', () => {
410
416
 
411
417
  await _testCircleMini(item, {
412
418
  data: undefined,
419
+ size: 120,
420
+ iconSize: 25,
421
+ textType: 'H4',
413
422
  isWidgetOrder: undefined,
414
423
  });
415
424
  });
@@ -194,6 +194,9 @@ export const SensorDisplayItem = ({
194
194
  case 'circle_mini':
195
195
  return (
196
196
  <CurrentRainSensor
197
+ size={120}
198
+ textType="H4"
199
+ iconSize={25}
197
200
  data={getDataCircleMini(item)}
198
201
  isWidgetOrder={isWidgetOrder}
199
202
  />
@@ -177,7 +177,7 @@ describe('useEvaluateValue', () => {
177
177
 
178
178
  it('test evaluate fetch from server if not exists', async () => {
179
179
  const mock = new MockAdapter(api.axiosInstance);
180
- mock.onGet(API.FETCH_VALUE_EVALUATION(111)).reply(200, {
180
+ mock.onGet(API.VALUE_EVALUATIONS()).reply(200, {
181
181
  unit_id: 1,
182
182
  configs: [111],
183
183
  });
@@ -87,7 +87,7 @@ export const useEvaluateValue = () => {
87
87
  return evaluateValue;
88
88
  };
89
89
 
90
- export const useGetEvaluateValue = (configId) => {
90
+ export const useGetEvaluateValue = (configId, unitId) => {
91
91
  const valueEvaluations = useSCContextSelector((state) => {
92
92
  return state.valueEvaluations;
93
93
  });
@@ -95,13 +95,17 @@ export const useGetEvaluateValue = (configId) => {
95
95
 
96
96
  if (configId && valueEvaluations[configId] === undefined) {
97
97
  (async () => {
98
- const { success, data } = await axiosGet(
99
- API.FETCH_VALUE_EVALUATION(configId)
100
- );
98
+ const { success, data } = await axiosGet(API.VALUE_EVALUATIONS(), {
99
+ configs__id: configId,
100
+ });
101
101
  if (success) {
102
+ setAction(Action.INIT_VALUE_EVALUATIONS, {
103
+ configId: configId,
104
+ });
105
+
102
106
  setAction(Action.UPDATE_VALUE_EVALUATIONS, {
103
- unitId: data.unit_id,
104
- data: [data],
107
+ unitId: unitId,
108
+ data: data.results,
105
109
  });
106
110
  }
107
111
  })();
@@ -12,6 +12,8 @@ import { API } from '../../../configs';
12
12
  import api from '../../../utils/Apis/axios';
13
13
  import { WrapHeaderScrollable } from '../../../commons';
14
14
 
15
+ import { getPusher } from '../../../utils/Pusher';
16
+
15
17
  const wrapComponent = () => (
16
18
  <SCProvider initState={mockSCStore({})}>
17
19
  <NavigationContext.Provider
@@ -154,4 +156,12 @@ describe('test Notification', () => {
154
156
  });
155
157
  expect(refreshControl).toBeDefined();
156
158
  });
159
+
160
+ it('should call unwatchNotificationData when unmounting', async () => {
161
+ await act(async () => {
162
+ tree = await create(wrapComponent());
163
+ await tree.unmount();
164
+ });
165
+ expect(getPusher().unsubscribe).toBeCalledWith('private-user-1');
166
+ });
157
167
  });
@@ -8,6 +8,7 @@ import AddMenu from '../AddMenu';
8
8
  import { useNavigation } from '@react-navigation/native';
9
9
  import { ToastBottomHelper } from '../../../utils/Utils';
10
10
  import { getTranslate } from '../../../utils/I18n';
11
+ import Routes from '../../../utils/Route';
11
12
 
12
13
  const mockedAfterItemClick = jest.fn();
13
14
  const mockedHideAddModal = jest.fn();
@@ -130,4 +131,79 @@ describe('Test AddMenu Unit', () => {
130
131
  });
131
132
  expect(spyToastError).not.toBeCalled();
132
133
  });
134
+
135
+ it('add sub_unit but has not permission', async () => {
136
+ let unit = {
137
+ id: 1,
138
+ name: 'Unit 1',
139
+ stations: [
140
+ { name: 'station name 1' },
141
+ { name: 'station name 2' },
142
+ { name: 'station name 3' },
143
+ ],
144
+ };
145
+ await act(async () => {
146
+ tree = await create(
147
+ wrapComponent(unit, {
148
+ auth: {
149
+ account: {
150
+ user: {
151
+ permissions: {
152
+ max_stations_per_unit: 1,
153
+ },
154
+ },
155
+ },
156
+ },
157
+ })
158
+ );
159
+ });
160
+
161
+ const instance = tree.root;
162
+ const menuActionAddnew = instance.findByType(MenuActionAddnew);
163
+ await act(async () => {
164
+ menuActionAddnew.props.onItemClick(menuActionAddnew.props.dataActions[0]);
165
+ });
166
+ expect(spyToastError).toBeCalledWith(
167
+ getTranslate('en', 'reach_max_stations_per_unit'),
168
+ '',
169
+ 7000
170
+ );
171
+ });
172
+
173
+ it('add smart account', async () => {
174
+ let unit = {
175
+ id: 1,
176
+ name: 'Unit 1',
177
+ stations: [
178
+ { name: 'station name 1' },
179
+ { name: 'station name 2' },
180
+ { name: 'station name 3' },
181
+ ],
182
+ };
183
+ await act(async () => {
184
+ tree = await create(
185
+ wrapComponent(unit, {
186
+ auth: {
187
+ account: {
188
+ user: {
189
+ permissions: {
190
+ max_stations_per_unit: 1,
191
+ },
192
+ },
193
+ },
194
+ },
195
+ })
196
+ );
197
+ });
198
+
199
+ const instance = tree.root;
200
+ const menuActionAddnew = instance.findByType(MenuActionAddnew);
201
+ await act(async () => {
202
+ menuActionAddnew.props.onItemClick(menuActionAddnew.props.dataActions[3]);
203
+ });
204
+ expect(mockedNavigate).toBeCalledWith(Routes.SmartAccountStack, {
205
+ params: { unitId: 1, unitName: 'Unit 1' },
206
+ screen: 'SmartAccount',
207
+ });
208
+ });
133
209
  });
@@ -6,11 +6,6 @@ import Text from '../../../commons/Text';
6
6
  import { SCProvider } from '../../../context';
7
7
  import { mockSCStore } from '../../../context/mockStore';
8
8
 
9
- jest.mock('react', () => ({
10
- ...jest.requireActual('react'),
11
- useLayoutEffect: jest.fn(),
12
- }));
13
-
14
9
  const wrapComponent = (route) => (
15
10
  <SCProvider initState={mockSCStore({})}>
16
11
  <WaterQualityGuide route={route} />
@@ -1444,4 +1444,6 @@ export default {
1444
1444
  end_devices_added: 'end devices added',
1445
1445
  bellow_widget_is_not_configured: 'Bellow widget is not configured',
1446
1446
  bellow_widget_is_wrongly_configured: 'Bellow widget is wrongly configured',
1447
+ 'customize...': 'Customize...',
1448
+ when_value_is: 'When value is',
1447
1449
  };
@@ -1455,4 +1455,6 @@ export default {
1455
1455
  end_devices_added: 'thiết bị được thêm vào',
1456
1456
  bellow_widget_is_not_configured: 'Tiện ích bên dưới chưa được cấu hình',
1457
1457
  bellow_widget_is_wrongly_configured: 'Tiện ích bên dưới được cấu hình sai',
1458
+ 'customize...': 'Tùy chỉnh...',
1459
+ when_value_is: 'Khi giá trị là',
1458
1460
  };
@@ -114,11 +114,16 @@ const Routes = {
114
114
  Browser: 'Browser',
115
115
  ManageAccess: 'ManageAccess',
116
116
  MoveToAnotherSubUnit: 'MoveToAnotherSubUnit',
117
+
118
+ // start automate
117
119
  SelectMonitorDevices: 'SelectMonitorDevices',
118
120
  SelectControlDevices: 'SelectControlDevices',
119
121
  ChooseEvent: 'ChooseEvent',
120
122
  ChooseAction: 'ChooseAction',
121
123
  ChooseConfig: 'ChooseConfig',
124
+ PreviewAutomate: 'PreviewAutomate',
125
+ // end automate
126
+
122
127
  GuestInfo: 'GuestInfo',
123
128
  AddLGDevice: 'AddLGDevice',
124
129
  AddLGDeviceStack: 'AddLGDeviceStack',