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

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 (42) hide show
  1. package/assets/images/Device/button-lock.svg +3 -0
  2. package/assets/images/Device/button-unlock.svg +3 -0
  3. package/package.json +1 -1
  4. package/src/commons/ActionGroup/OnOffSmartLock.js +48 -0
  5. package/src/commons/ActionGroup/OnOffSmartLockStyle.js +51 -0
  6. package/src/commons/ActionGroup/index.js +3 -0
  7. package/src/commons/ConnectingProcess/index.js +5 -2
  8. package/src/commons/Device/ItemDevice.js +8 -3
  9. package/src/commons/MediaPlayer/__test__/index.test.js +45 -0
  10. package/src/commons/SubUnit/ShortDetail.js +10 -22
  11. package/src/commons/SubUnit/__test__/ShortDetail.test.js +57 -48
  12. package/src/configs/API.js +2 -2
  13. package/src/configs/Constants.js +13 -0
  14. package/src/screens/ActivityLog/hooks/index.js +18 -4
  15. package/src/screens/ActivityLog/index.js +3 -0
  16. package/src/screens/AddCommon/SelectSubUnit.js +1 -0
  17. package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +1 -1
  18. package/src/screens/AddNewAction/SelectSensorDevices.js +4 -2
  19. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +10 -2
  20. package/src/screens/AddNewGateway/PlugAndPlay/FirstWarning.js +4 -2
  21. package/src/screens/AddNewOneTap/index.js +32 -17
  22. package/src/screens/Automate/index.js +2 -2
  23. package/src/screens/Device/EditDevice/index.js +5 -3
  24. package/src/screens/Device/components/SensorDisplayItem.js +3 -0
  25. package/src/screens/Device/detail.js +1 -0
  26. package/src/screens/Notification/__test__/NotificationItem.test.js +15 -3
  27. package/src/screens/Notification/components/NotificationItem.js +52 -8
  28. package/src/screens/ScanChipQR/__test__/ScanChipQR.test.js +1 -0
  29. package/src/screens/ScanChipQR/hooks/index.js +90 -44
  30. package/src/screens/ScriptDetail/index.js +1 -6
  31. package/src/screens/SelectUnit/index.js +1 -0
  32. package/src/screens/SharedUnit/index.js +1 -1
  33. package/src/screens/SmartIr/__test__/SmartIr.test.js +61 -0
  34. package/src/screens/SmartIr/index.js +23 -0
  35. package/src/screens/SmartIr/styles.js +14 -0
  36. package/src/screens/Unit/AddMenu.js +4 -1
  37. package/src/screens/Unit/Detail.js +1 -1
  38. package/src/screens/UnitSummary/components/PowerConsumeHistoryChart/__test__/index.test.js +32 -1
  39. package/src/screens/UnitSummary/components/PowerConsumeHistoryChart/index.js +1 -1
  40. package/src/utils/I18n/translations/en.json +9 -2
  41. package/src/utils/I18n/translations/vi.json +9 -2
  42. package/src/utils/Route/index.js +1 -0
@@ -0,0 +1,3 @@
1
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M22.0495 3.90313C22.0112 3.88385 21.9687 3.87473 21.9259 3.87662C21.8831 3.87852 21.8415 3.89138 21.8051 3.91397C21.7687 3.93656 21.7388 3.96811 21.7181 4.00561C21.6974 4.04311 21.6867 4.0853 21.687 4.12813V6.13438C21.687 6.30625 21.7776 6.46562 21.9213 6.55937C22.626 7.00293 23.2781 7.52502 23.8651 8.11563C24.887 9.14063 25.6901 10.3313 26.2495 11.6563C26.828 13.0279 27.1245 14.502 27.1213 15.9906C27.1213 17.4938 26.8276 18.9531 26.2495 20.325C25.6907 21.6481 24.881 22.8504 23.8651 23.8656C22.8525 24.8841 21.6509 25.6951 20.3276 26.2531C18.9588 26.8344 17.4995 27.1281 15.9995 27.1281C14.4995 27.1281 13.0401 26.8344 11.6713 26.2531C10.348 25.6951 9.14638 24.8841 8.13384 23.8656C7.11791 22.8504 6.3082 21.6481 5.74946 20.325C5.17097 18.9533 4.87446 17.4793 4.87759 15.9906C4.87759 14.4875 5.17134 13.0281 5.74946 11.6562C6.30884 10.3313 7.11196 9.14063 8.13384 8.11563C8.72759 7.52188 9.37759 7.00312 10.0776 6.55937C10.2245 6.46875 10.312 6.30625 10.312 6.13438V4.125C10.312 3.9375 10.1151 3.81875 9.94946 3.9C5.57759 6.1 2.56196 10.6031 2.49946 15.8219C2.41196 23.2844 8.51509 29.4844 15.9745 29.5C23.4432 29.5156 29.4995 23.4594 29.4995 15.9875C29.4995 10.7 26.4682 6.12188 22.0495 3.90313ZM14.9995 17.5H16.9995C17.137 17.5 17.2495 17.3875 17.2495 17.25V2.75C17.2495 2.6125 17.137 2.5 16.9995 2.5H14.9995C14.862 2.5 14.7495 2.6125 14.7495 2.75L14.7495 17.25C14.7495 17.3875 14.862 17.5 14.9995 17.5Z" fill="#00979D"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M22.0495 3.90313C22.0112 3.88385 21.9687 3.87473 21.9259 3.87662C21.8831 3.87852 21.8415 3.89138 21.8051 3.91397C21.7687 3.93656 21.7388 3.96811 21.7181 4.00561C21.6974 4.04311 21.6867 4.0853 21.687 4.12813V6.13438C21.687 6.30625 21.7776 6.46562 21.9213 6.55937C22.626 7.00293 23.2781 7.52502 23.8651 8.11563C24.887 9.14063 25.6901 10.3313 26.2495 11.6563C26.828 13.0279 27.1245 14.502 27.1213 15.9906C27.1213 17.4938 26.8276 18.9531 26.2495 20.325C25.6907 21.6481 24.881 22.8504 23.8651 23.8656C22.8525 24.8841 21.6509 25.6951 20.3276 26.2531C18.9588 26.8344 17.4995 27.1281 15.9995 27.1281C14.4995 27.1281 13.0401 26.8344 11.6713 26.2531C10.348 25.6951 9.14638 24.8841 8.13384 23.8656C7.11791 22.8504 6.3082 21.6481 5.74946 20.325C5.17097 18.9533 4.87446 17.4793 4.87759 15.9906C4.87759 14.4875 5.17134 13.0281 5.74946 11.6562C6.30884 10.3313 7.11196 9.14063 8.13384 8.11563C8.72759 7.52188 9.37759 7.00312 10.0776 6.55937C10.2245 6.46875 10.312 6.30625 10.312 6.13438V4.125C10.312 3.9375 10.1151 3.81875 9.94946 3.9C5.57759 6.1 2.56196 10.6031 2.49946 15.8219C2.41196 23.2844 8.51509 29.4844 15.9745 29.5C23.4432 29.5156 29.4995 23.4594 29.4995 15.9875C29.4995 10.7 26.4682 6.12188 22.0495 3.90313ZM14.9995 17.5H16.9995C17.137 17.5 17.2495 17.3875 17.2495 17.25V2.75C17.2495 2.6125 17.137 2.5 16.9995 2.5H14.9995C14.862 2.5 14.7495 2.6125 14.7495 2.75L14.7495 17.25C14.7495 17.3875 14.862 17.5 14.9995 17.5Z" fill="#F5222D"/>
3
+ </svg>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eohjsc/react-native-smart-city",
3
3
  "title": "React Native Smart Home",
4
- "version": "0.2.85",
4
+ "version": "0.2.86",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -0,0 +1,48 @@
1
+ import React, { memo, useCallback, useState } from 'react';
2
+ import { SafeAreaView, TouchableOpacity, View } from 'react-native';
3
+ import { useTranslations } from '../../hooks/Common/useTranslations';
4
+ import { Section } from '../Section';
5
+ import Text from '../Text';
6
+ import styles from './OnOffSmartLockStyle';
7
+ import ButtonLock from '../../../assets/images/Device/button-lock.svg';
8
+ import ButtonUnLock from '../../../assets/images/Device/button-unlock.svg';
9
+
10
+ const OnOffSmartLock = memo(({ actionGroup, doAction, sensor }) => {
11
+ const t = useTranslations();
12
+ const [active, setActive] = useState(true);
13
+
14
+ const handleClickButton = useCallback(() => {
15
+ setActive(!active);
16
+ }, [active]);
17
+
18
+ return (
19
+ <SafeAreaView style={styles.container}>
20
+ <View style={styles.wrap}>
21
+ <Section style={styles.section}>
22
+ <View style={styles.wrapController}>
23
+ <Text style={styles.textController}>{t('controller')}</Text>
24
+ </View>
25
+ <View style={styles.wrapButtonSmartLock}>
26
+ <TouchableOpacity onPress={handleClickButton}>
27
+ {active ? (
28
+ <ButtonLock style={styles.buttonSmartLock} />
29
+ ) : (
30
+ <ButtonUnLock style={styles.buttonSmartLock} />
31
+ )}
32
+ </TouchableOpacity>
33
+ <Text style={styles.textSmartLock}>
34
+ {active ? t('lock') : t('unlock')}
35
+ </Text>
36
+ </View>
37
+ <View style={styles.wrapStatus}>
38
+ <Text style={styles.textStatus}>
39
+ {active ? t('door_is_open') : t('door_is_close')}
40
+ </Text>
41
+ </View>
42
+ </Section>
43
+ </View>
44
+ </SafeAreaView>
45
+ );
46
+ });
47
+
48
+ export default OnOffSmartLock;
@@ -0,0 +1,51 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors } from '../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ container: {
6
+ flex: 1,
7
+ },
8
+ wrap: {
9
+ paddingHorizontal: 16,
10
+ },
11
+ section: {
12
+ borderRadius: 10,
13
+ },
14
+ wrapController: {
15
+ flexDirection: 'row',
16
+ justifyContent: 'flex-start',
17
+ },
18
+ textController: {
19
+ color: Colors.Gray8,
20
+ fontSize: 16,
21
+ marginBottom: 16,
22
+ },
23
+ wrapButtonSmartLock: {
24
+ flexDirection: 'column',
25
+ justifyContent: 'center',
26
+ alignItems: 'center',
27
+ backgroundColor: Colors.Gray2,
28
+ borderRadius: 10,
29
+ borderColor: Colors.Gray4,
30
+ borderWidth: 1,
31
+ },
32
+ buttonSmartLock: {
33
+ marginTop: 14,
34
+ },
35
+ textSmartLock: {
36
+ color: Colors.Gray9,
37
+ fontSize: 14,
38
+ marginTop: 8,
39
+ marginBottom: 18,
40
+ },
41
+ wrapStatus: {
42
+ flexDirection: 'row',
43
+ justifyContent: 'center',
44
+ alignItems: 'center',
45
+ },
46
+ textStatus: {
47
+ color: Colors.Gray8,
48
+ fontSize: 14,
49
+ marginTop: 16,
50
+ },
51
+ });
@@ -11,6 +11,7 @@ import TimerActionTemplate from './TimerActionTemplate';
11
11
  import CurtainButtonTemplate from './CurtainButtonTemplate';
12
12
  import SmartTiviActionTemplate from './SmartTiviActionTemplate/SmartTiviActionTemplate';
13
13
  import LightActionTemplate from './LightActionTemplate';
14
+ import OnOffSmartLock from './OnOffSmartLock';
14
15
 
15
16
  export const getActionComponent = (template) => {
16
17
  switch (template) {
@@ -21,6 +22,8 @@ export const getActionComponent = (template) => {
21
22
  case 'OnOffButtonActionTemplate':
22
23
  case 'OnOffSimpleActionTemplate':
23
24
  return OnOffTemplate;
25
+ case 'OnOffButtonActionSmartLock':
26
+ return OnOffSmartLock;
24
27
  case 'one_button_action_template': // todo refactor later with backend
25
28
  case 'OneBigButtonActionTemplate':
26
29
  return OneBigButtonTemplate;
@@ -23,6 +23,7 @@ const ConnectingProcess = ({ route }) => {
23
23
  station,
24
24
  unit,
25
25
  unit_id,
26
+ unit_name,
26
27
  devicePrefixName,
27
28
  wifi_ssid,
28
29
  wifi_pass,
@@ -156,12 +157,14 @@ const ConnectingProcess = ({ route }) => {
156
157
  {t('successfully_connected')}
157
158
  </Text>
158
159
  <Text size={14} style={styles.textHome}>
159
- Home - {station?.name}
160
+ {`${unit?.name || unit_name} ${
161
+ station?.name !== undefined ? '- ' + station?.name : ''
162
+ }`}
160
163
  </Text>
161
164
  <DeviceItem icon={sensor?.icon_kit} name={sensor?.name} />
162
165
  </View>
163
166
  );
164
- }, [sensor?.icon_kit, sensor?.name, station?.name, t]);
167
+ }, [sensor?.icon_kit, sensor?.name, station?.name, t, unit?.name, unit_name]);
165
168
 
166
169
  const handleDone = useCallback(() => {
167
170
  navigate(Routes.UnitStack, {
@@ -14,7 +14,7 @@ import Text from '../../commons/Text';
14
14
  import { isDeviceConnected } from '../../iot/RemoteControl/Bluetooth';
15
15
 
16
16
  import { Colors, Constants } from '../../configs';
17
- import { TESTID } from '../../configs/Constants';
17
+ import { TESTID, DEVICE_TYPE } from '../../configs/Constants';
18
18
  import FImage from '../../commons/FImage';
19
19
 
20
20
  const marginItem = 12;
@@ -61,11 +61,16 @@ const ItemDevice = memo(
61
61
  status === undefined
62
62
  ? isNetworkConnected && sensor.is_connected
63
63
  : isNetworkConnected && status.is_connected;
64
- const isBLEConnected = isDeviceConnected(
64
+ const isConnectedViaBLE = isDeviceConnected(
65
65
  sensor?.remote_control_options?.bluetooth?.address
66
66
  );
67
+ const isConnectedViaGGHome =
68
+ !!sensor &&
69
+ sensor?.is_other_device &&
70
+ !sensor?.device_type !== DEVICE_TYPE.LG_THINQ &&
71
+ isGGHomeConnected;
67
72
  const isConnected =
68
- isConnectedViaInternet || isGGHomeConnected || isBLEConnected;
73
+ isConnectedViaInternet || isConnectedViaGGHome || isConnectedViaBLE;
69
74
  const borderColor = isConnected ? Colors.Gray4 : Colors.Red6;
70
75
  const textConnected = isConnected ? t('connected') : t('disconnected');
71
76
 
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { act, create } from 'react-test-renderer';
3
+ import { SCProvider } from '../../../context';
4
+ import { mockSCStore } from '../../../context/mockStore';
5
+ import { TouchableOpacity } from 'react-native';
6
+ import MediaPlay from '../index';
7
+
8
+ jest.mock('react', () => {
9
+ return {
10
+ ...jest.requireActual('react'),
11
+ memo: (x) => x,
12
+ };
13
+ });
14
+
15
+ const wrapComponent = (props) => (
16
+ <SCProvider initState={mockSCStore({})}>
17
+ <MediaPlay {...props} />
18
+ </SCProvider>
19
+ );
20
+
21
+ describe('Test MediaPlayer', () => {
22
+ let tree, props;
23
+
24
+ beforeAll(() => {
25
+ jest.useFakeTimers();
26
+ props = {
27
+ uri: 'uri',
28
+ previewUri: 'previewUri',
29
+ thumbnail: 'thumbnail',
30
+ background: 'background',
31
+ };
32
+ });
33
+
34
+ it('Test render', async () => {
35
+ await act(async () => {
36
+ tree = await create(wrapComponent(props));
37
+ });
38
+ const instance = tree.root;
39
+ const pauseButton = instance.findByType(TouchableOpacity);
40
+ await act(async () => {
41
+ await pauseButton.props.onPress();
42
+ });
43
+ jest.runAllTimers();
44
+ });
45
+ });
@@ -4,7 +4,7 @@ import { useNavigation, useIsFocused } from '@react-navigation/native';
4
4
  import { useTranslations } from '../../hooks/Common/useTranslations';
5
5
 
6
6
  import { Images, Device, API } from '../../configs';
7
- import { SubUnitName, TESTID } from '../../configs/Constants';
7
+ import { TESTID } from '../../configs/Constants';
8
8
  import { Section } from '../Section';
9
9
  import Text from '../Text';
10
10
  import ItemDevice from '../Device/ItemDevice';
@@ -104,28 +104,16 @@ const ShortDetailSubUnit = ({
104
104
  };
105
105
 
106
106
  const handleOnAddNew = () => {
107
- if (!station.isFavorites) {
108
- navigate(Routes.AddDeviceStack, {
109
- screen: Routes.ScanSensorQR,
110
- params: {
111
- station_id: station.id,
112
- unit_id: unit.id,
113
- unit_name: unit.name,
114
- },
115
- });
116
- } else {
117
- alert(t('feature_under_development'));
118
- }
107
+ navigate(Routes.AddDeviceStack, {
108
+ screen: Routes.ScanSensorQR,
109
+ params: {
110
+ station_id: station?.id,
111
+ unit_id: unit.id,
112
+ unit_name: unit.name,
113
+ },
114
+ });
119
115
  };
120
116
 
121
- const itemAddNewTitle = t(
122
- station?.isFavorites
123
- ? 'add_to_favorites'
124
- : station?.name === SubUnitName.smart
125
- ? 'add_script'
126
- : 'add_new'
127
- );
128
-
129
117
  return (
130
118
  <Section style={styles.noShadow}>
131
119
  {renderCamera()}
@@ -156,7 +144,7 @@ const ShortDetailSubUnit = ({
156
144
  status={sensorsStatus.find((s) => s.id === sensor.id)}
157
145
  />
158
146
  ))}
159
- <ItemAddNew title={itemAddNewTitle} onAddNew={handleOnAddNew} />
147
+ <ItemAddNew title={t('add_new_device')} onAddNew={handleOnAddNew} />
160
148
  </View>
161
149
  </Section>
162
150
  );
@@ -1,21 +1,27 @@
1
1
  import React from 'react';
2
- import { Image, View, TouchableWithoutFeedback } from 'react-native';
2
+ import { Image, View } from 'react-native';
3
3
  import { act, create } from 'react-test-renderer';
4
4
  import { TESTID } from '../../../configs/Constants';
5
5
  import { SCProvider } from '../../../context';
6
6
  import { mockSCStore } from '../../../context/mockStore';
7
+ import ShortDetailSubUnit from '../ShortDetail';
8
+ import ItemAddNew from '../../Device/ItemAddNew';
7
9
  import Routes from '../../../utils/Route';
8
10
 
9
- const wrapComponent = (unit, station) => (
11
+ const wrapComponent = (props) => (
10
12
  <SCProvider initState={mockSCStore({})}>
11
- <ShortDetailSubUnit unit={unit} station={station} />
13
+ <ShortDetailSubUnit {...props} />
12
14
  </SCProvider>
13
15
  );
14
16
 
15
- import ShortDetailSubUnit from '../ShortDetail';
17
+ jest.mock('react', () => {
18
+ return {
19
+ ...jest.requireActual('react'),
20
+ memo: (x) => x,
21
+ };
22
+ });
16
23
 
17
24
  const mockedNavigate = jest.fn();
18
-
19
25
  jest.mock('@react-navigation/native', () => {
20
26
  return {
21
27
  ...jest.requireActual('@react-navigation/native'),
@@ -27,43 +33,46 @@ jest.mock('@react-navigation/native', () => {
27
33
  });
28
34
 
29
35
  describe('test ShortDetail Subunit', () => {
30
- let tree, unit, station;
36
+ let tree, props;
31
37
  beforeEach(() => {
32
- unit = {
33
- address: null,
34
- background:
35
- 'https://cdn-staging.eoh.io/image-90a42c0a-96ad-42e5-b736-b2b8a2e7fb20.jpg',
36
- can_add: true,
37
- icon: 'https://cdn-staging.eoh.io/baelen.jpg',
38
- id: 21,
39
- main_config_count: 0,
40
- name: 'Gia Cat Unit',
41
- remote_control_options: { bluetooth: [], googlehome: [] },
42
- stations: [
43
- {
44
- background:
45
- 'https://cdn-staging.eoh.io/image-cc9ea441-e113-46b5-bff3-23d924723733.jpg',
46
- camera: null,
47
- id: 71,
48
- name: 'Station 1',
49
- sensors: [],
50
- },
51
- ],
52
- user_id: 64,
53
- };
54
-
55
- station = {
56
- background:
57
- 'https://cdn-staging.eoh.io/image-cc9ea441-e113-46b5-bff3-23d924723733.jpg',
58
- camera: null,
59
- id: 71,
60
- name: 'Station 1',
38
+ props = {
39
+ unit: {
40
+ address: null,
41
+ background:
42
+ 'https://cdn-staging.eoh.io/image-90a42c0a-96ad-42e5-b736-b2b8a2e7fb20.jpg',
43
+ can_add: true,
44
+ icon: 'https://cdn-staging.eoh.io/baelen.jpg',
45
+ id: 21,
46
+ main_config_count: 0,
47
+ name: 'Gia Cat Unit',
48
+ remote_control_options: { bluetooth: [], googlehome: [] },
49
+ stations: [
50
+ {
51
+ background:
52
+ 'https://cdn-staging.eoh.io/image-cc9ea441-e113-46b5-bff3-23d924723733.jpg',
53
+ camera: null,
54
+ id: 71,
55
+ name: 'Station 1',
56
+ sensors: [],
57
+ },
58
+ ],
59
+ user_id: 64,
60
+ },
61
+ station: {
62
+ background:
63
+ 'https://cdn-staging.eoh.io/image-cc9ea441-e113-46b5-bff3-23d924723733.jpg',
64
+ camera: null,
65
+ id: 71,
66
+ name: 'Station 1',
67
+ },
68
+ isNetworkConnected: true,
69
+ isGGHomeConnected: true,
61
70
  };
62
71
  });
63
72
 
64
73
  test('render ShortDetail', () => {
65
74
  act(() => {
66
- tree = create(wrapComponent(unit, station));
75
+ tree = create(wrapComponent(props));
67
76
  });
68
77
  const instance = tree.root;
69
78
  const image = instance.findAllByType(Image);
@@ -74,9 +83,9 @@ describe('test ShortDetail Subunit', () => {
74
83
  });
75
84
 
76
85
  test('render ShortDetail without background', () => {
77
- station.background = '';
86
+ props.station.background = '';
78
87
  act(() => {
79
- tree = create(wrapComponent(unit, station));
88
+ tree = create(wrapComponent(props));
80
89
  });
81
90
  const instance = tree.root;
82
91
  const image = instance.findAllByType(Image);
@@ -87,7 +96,7 @@ describe('test ShortDetail Subunit', () => {
87
96
  });
88
97
 
89
98
  test('render ShortDetail with camera', () => {
90
- station.camera = {
99
+ props.station.camera = {
91
100
  id: 2,
92
101
  name: 'EoH Gate',
93
102
  preview_uri: '',
@@ -95,7 +104,7 @@ describe('test ShortDetail Subunit', () => {
95
104
  };
96
105
 
97
106
  act(() => {
98
- tree = create(wrapComponent(unit, station));
107
+ tree = create(wrapComponent(props));
99
108
  });
100
109
  const instance = tree.root;
101
110
  const view = instance.findAllByType(View);
@@ -106,7 +115,7 @@ describe('test ShortDetail Subunit', () => {
106
115
  });
107
116
 
108
117
  test('render ShortDetail with device', () => {
109
- station.sensors = [
118
+ props.station.sensors = [
110
119
  {
111
120
  action: {
112
121
  color: '#00979D',
@@ -129,7 +138,7 @@ describe('test ShortDetail Subunit', () => {
129
138
  ];
130
139
 
131
140
  act(() => {
132
- tree = create(wrapComponent(unit, station));
141
+ tree = create(wrapComponent(props));
133
142
  });
134
143
  const instance = tree.root;
135
144
  const itemDevice = instance.findAll(
@@ -141,19 +150,19 @@ describe('test ShortDetail Subunit', () => {
141
150
 
142
151
  test('render ShortDetail add new device', () => {
143
152
  act(() => {
144
- tree = create(wrapComponent(unit, station));
153
+ tree = create(wrapComponent(props));
145
154
  });
146
155
  const instance = tree.root;
147
- const buttonAddNew = instance.findAllByType(TouchableWithoutFeedback);
156
+ const buttonAddNew = instance.findByType(ItemAddNew);
148
157
  act(() => {
149
- buttonAddNew[0].props.onPress();
158
+ buttonAddNew.props.onAddNew();
150
159
  });
151
160
  expect(mockedNavigate).toHaveBeenCalledWith(Routes.AddDeviceStack, {
152
161
  screen: Routes.ScanSensorQR,
153
162
  params: {
154
- station_id: station.id,
155
- unit_id: unit.id,
156
- unit_name: unit.name,
163
+ station_id: props.station.id,
164
+ unit_id: props.unit.id,
165
+ unit_name: props.unit.name,
157
166
  },
158
167
  });
159
168
  });
@@ -182,9 +182,9 @@ const API = {
182
182
  `/connection_manager/lg_thinq/device_status/${sensorId}/`,
183
183
  },
184
184
  VCONNEX: {
185
- AUTHORIZE: (client_id, redirect_uri, user_id, station_id) =>
185
+ AUTHORIZE: (client_id, redirect_uri, user_id, unit_id, station_id) =>
186
186
  // eslint-disable-next-line max-len
187
- `https://partner-api-stg.vconnex.vn/oauth/authorize?client_id=${client_id}&redirect_uri=${redirect_uri}&response_type=code&scope=SYNCH&scope=CONTROL&scope=QUERY&state=${user_id}@${station_id}`,
187
+ `https://partner-api-stg.vconnex.vn/oauth/authorize?client_id=${client_id}&redirect_uri=${redirect_uri}&response_type=code&scope=SYNCH&scope=CONTROL&scope=QUERY&state=${user_id}@${unit_id}@${station_id}`,
188
188
  },
189
189
  },
190
190
  NOTIFICATION: {
@@ -663,6 +663,8 @@ export const NOTIFICATION_TYPES = {
663
663
  NOTIFY_DEVICE_DISCONNECT: 'NOTIFY_DEVICE_DISCONNECT',
664
664
  NOTIFY_RENAME_SUB_UNIT: 'NOTIFY_RENAME_SUB_UNIT',
665
665
  NOTIFY_UPDATE_ADDRESS: 'NOTIFY_UPDATE_ADDRESS',
666
+ NOTIFY_REMOVE_SUB_UNIT: 'NOTIFY_REMOVE_SUB_UNIT',
667
+ NOTIFY_REMOVE_DEVICE: 'NOTIFY_REMOVE_DEVICE',
666
668
  };
667
669
 
668
670
  export const ACTIVITY_LOG_TYPES = {
@@ -670,3 +672,14 @@ export const ACTIVITY_LOG_TYPES = {
670
672
  ACTIVATED_BY: 'ACTIVATED_BY',
671
673
  SCRIPT_UPDATED_BY: 'SCRIPT_UPDATED_BY',
672
674
  };
675
+
676
+ export const SENSOR_TYPE = {
677
+ AIR_QUALITY: 'air_quality',
678
+ TURBIDITY: 'turbidity',
679
+ PH: 'ph',
680
+ CLO: 'clo',
681
+ UV: 'uv',
682
+ SMOKE: 'smoke',
683
+ FIRE: 'fire',
684
+ SOS: 'sos',
685
+ };
@@ -37,6 +37,7 @@ String.prototype.capitalize = function () {
37
37
  return this.charAt(0).toUpperCase() + this.slice(1);
38
38
  };
39
39
 
40
+ let onEndReachedCalledDuringMomentum = false;
40
41
  let dataTemp = [];
41
42
 
42
43
  export default ({ id, type, share, filterEnabled }) => {
@@ -59,7 +60,7 @@ export default ({ id, type, share, filterEnabled }) => {
59
60
  if (page === 1) {
60
61
  setIsRefreshing(true);
61
62
  } else {
62
- if (!isCanLoadMore || isLoading) {
63
+ if (!isCanLoadMore) {
63
64
  return;
64
65
  }
65
66
  setIsLoading(true);
@@ -81,6 +82,7 @@ export default ({ id, type, share, filterEnabled }) => {
81
82
  params.append(key, value);
82
83
  }
83
84
  params.append('page', page);
85
+
84
86
  const { success, data } = await axiosGet(api.url(id), {
85
87
  params: params,
86
88
  });
@@ -91,9 +93,9 @@ export default ({ id, type, share, filterEnabled }) => {
91
93
  setData(api.standardizeData(results));
92
94
  } else {
93
95
  dataTemp = dataTemp.concat(results);
96
+ setIsCanLoadMore(page < Math.ceil(data.count / 20));
94
97
  setData(api.standardizeData(dataTemp));
95
98
  }
96
- setIsCanLoadMore(page < Math.ceil(data.count / 20));
97
99
  }
98
100
  page === 1 ? setIsRefreshing(false) : setIsLoading(false);
99
101
  };
@@ -110,9 +112,20 @@ export default ({ id, type, share, filterEnabled }) => {
110
112
  }
111
113
  };
112
114
 
113
- const onRefresh = () => fetchData({ ...filters, page: 1 });
115
+ const onRefresh = () => {
116
+ setIsCanLoadMore(true);
117
+ fetchData({ ...filters, page: 1 });
118
+ };
119
+
120
+ const onLoadMore = () => {
121
+ if (!onEndReachedCalledDuringMomentum) {
122
+ onEndReachedCalledDuringMomentum = true;
123
+ fetchData({ ...filters, page: page + 1 });
124
+ }
125
+ };
114
126
 
115
- const onLoadMore = () => fetchData({ ...filters, page: page + 1 });
127
+ const onMomentumScrollBegin = () =>
128
+ (onEndReachedCalledDuringMomentum = false);
116
129
 
117
130
  return {
118
131
  data,
@@ -124,5 +137,6 @@ export default ({ id, type, share, filterEnabled }) => {
124
137
  fetchMembers,
125
138
  filters,
126
139
  setFilters,
140
+ onMomentumScrollBegin,
127
141
  };
128
142
  };
@@ -34,7 +34,9 @@ const ActivityLogScreen = ({ route }) => {
34
34
  fetchMembers,
35
35
  filters,
36
36
  setFilters,
37
+ onMomentumScrollBegin,
37
38
  } = useActivityLog({ id, type, share, filterEnabled });
39
+
38
40
  const [showFilterPopup, setShowFilterPopup, setHideFilterPopup] =
39
41
  useBoolean();
40
42
 
@@ -113,6 +115,7 @@ const ActivityLogScreen = ({ route }) => {
113
115
  removeClippedSubviews={true}
114
116
  maxToRenderPerBatch={20}
115
117
  contentContainerStyle={styles.contentContainerStyle}
118
+ onMomentumScrollBegin={onMomentumScrollBegin}
116
119
  />
117
120
  </View>
118
121
  {(filterEnabled.user || filterEnabled.date) && (
@@ -107,6 +107,7 @@ const AddCommonSelectSubUnit = ({ route }) => {
107
107
  SCConfig.VCONNEX_CLIENT_ID,
108
108
  SCConfig.VCONNEX_REDIRECT_URI_APP,
109
109
  unit.user_id,
110
+ unit_id,
110
111
  subUnits[selectedIndex]?.id
111
112
  ),
112
113
  });
@@ -152,7 +152,7 @@ describe('Test SelectSubUnit container', () => {
152
152
  case 'AddVconnexDevice':
153
153
  expect(mockedNavigate).toBeCalledWith('Browser', {
154
154
  // eslint-disable-next-line max-len
155
- link: 'https://partner-api-stg.vconnex.vn/oauth/authorize?client_id=&redirect_uri=&response_type=code&scope=SYNCH&scope=CONTROL&scope=QUERY&state=undefined@undefined',
155
+ link: 'https://partner-api-stg.vconnex.vn/oauth/authorize?client_id=&redirect_uri=&response_type=code&scope=SYNCH&scope=CONTROL&scope=QUERY&state=undefined@undefined@undefined',
156
156
  });
157
157
  break;
158
158
  case 'AddDeviceNewFlow':
@@ -175,7 +175,7 @@ const SelectSensorDevices = memo(({ route }) => {
175
175
  {t(title)}
176
176
  </Text>
177
177
 
178
- {!!listStation.length > 0 ? (
178
+ {listStation ? (
179
179
  <NavBar
180
180
  listStation={listStation}
181
181
  listMenuItem={listMenuItem}
@@ -185,7 +185,9 @@ const SelectSensorDevices = memo(({ route }) => {
185
185
  />
186
186
  ) : (
187
187
  <View style={styles.noneData}>
188
- <Text center>{t('text_sub_unit_not_have_device')}</Text>
188
+ <Text center>
189
+ {t('you_do_not_have_the_device_or_have_share_control_device')}
190
+ </Text>
189
191
  </View>
190
192
  )}
191
193
 
@@ -28,8 +28,15 @@ import { SCContext } from '../../../context';
28
28
  import { Action } from '../../../context/actionType';
29
29
 
30
30
  const ConnectWifiWarning = memo(({ route }) => {
31
- const { wifi_ssid, wifi_pass, unit_id, chip_id, devicePrefixName, body } =
32
- route.params;
31
+ const {
32
+ wifi_ssid,
33
+ wifi_pass,
34
+ unit_id,
35
+ chip_id,
36
+ devicePrefixName,
37
+ body,
38
+ unit_name,
39
+ } = route.params;
33
40
  const t = useTranslations();
34
41
  const { navigate, goBack } = useNavigation();
35
42
  const [isLoading, setIsLoading] = useState(false);
@@ -109,6 +116,7 @@ const ConnectWifiWarning = memo(({ route }) => {
109
116
  screen: Routes.ConnectingProcess,
110
117
  params: {
111
118
  unit_id: unit_id,
119
+ unit_name: unit_name,
112
120
  scan_sensor_data: { ...body },
113
121
  gateway: data?.gateway,
114
122
  devicePrefixName: devicePrefixName,