@eohjsc/react-native-smart-city 0.3.26 → 0.3.29
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.
- package/index.js +2 -0
- package/package.json +1 -1
- package/src/Images/Common/device_icon.png +0 -0
- package/src/Images/DevMode/gateway.png +0 -0
- package/src/Images/DevMode/gateway@2x.png +0 -0
- package/src/Images/DevMode/gateway@3x.png +0 -0
- package/src/Images/DevMode/menu.png +0 -0
- package/src/Images/DevMode/menu@2x.png +0 -0
- package/src/Images/DevMode/menu@3x.png +0 -0
- package/src/Images/DevMode/search.png +0 -0
- package/src/Images/DevMode/search@2x.png +0 -0
- package/src/Images/DevMode/search@3x.png +0 -0
- package/src/Images/DevMode/smart.png +0 -0
- package/src/Images/DevMode/smart@2x.png +0 -0
- package/src/Images/DevMode/smart@3x.png +0 -0
- package/src/Images/DevMode/template.png +0 -0
- package/src/Images/DevMode/template@2x.png +0 -0
- package/src/Images/DevMode/template@3x.png +0 -0
- package/src/commons/ActionGroup/CurtainButtonTemplate.js +1 -2
- package/src/commons/ActionGroup/OnOffTemplate/OnOffButtonTemplate.js +2 -0
- package/src/commons/ActionTemplate/CurtainAction.js +60 -0
- package/src/commons/ActionTemplate/CurtainActionStyles.js +11 -0
- package/src/commons/ActionTemplate/OnOffSmartLockAction.js +44 -0
- package/src/commons/ActionTemplate/OnOffSmartLockActionStyles.js +11 -0
- package/src/commons/ActionTemplate/index.js +18 -0
- package/src/commons/CameraDevice/index.js +1 -2
- package/src/commons/ConnectingProcess/DeviceItem/DeviceItem.js +20 -12
- package/src/commons/ConnectingProcess/DeviceItem/DeviceItemStyles.js +2 -0
- package/src/commons/ConnectingProcess/__test__/DeviceItem.test.js +1 -1
- package/src/commons/ConnectingProcess/index.js +11 -0
- package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +55 -5
- package/src/commons/Dashboard/MyUnit/index.js +59 -12
- package/src/commons/DevMode/Label.js +10 -0
- package/src/commons/DevMode/Search.js +20 -0
- package/src/commons/DevMode/Styles/LabelStyles.js +8 -0
- package/src/commons/DevMode/Styles/SearchStyles.js +21 -0
- package/src/commons/DevMode/index.js +3 -0
- package/src/commons/Device/ItemDevice.js +1 -0
- package/src/commons/Form/TextInput.js +4 -0
- package/src/commons/HeaderAni/index.js +1 -0
- package/src/commons/MediaPlayerDetail/index.js +0 -20
- package/src/commons/MenuActionMore/index.js +12 -4
- package/src/commons/Modal/index.js +1 -2
- package/src/commons/NavBar/index.js +12 -1
- package/src/commons/Popover/index.js +26 -0
- package/src/commons/SubUnit/ShortDetail.js +1 -0
- package/src/commons/SummaryItem/index.js +2 -1
- package/src/commons/Tabbar/Styles/indexStyles.js +51 -0
- package/src/commons/Tabbar/index.js +110 -0
- package/src/commons/Unit/HeaderUnit/index.js +2 -0
- package/src/commons/Unit/SharedUnit.js +1 -0
- package/src/commons/WrapParallaxScrollView/index.js +16 -2
- package/src/configs/Colors.js +4 -0
- package/src/configs/Constants.js +5 -0
- package/src/configs/Images.js +6 -0
- package/src/context/actionType.ts +2 -0
- package/src/context/reducer.ts +10 -0
- package/src/hooks/Common/useGGHomeDeviceConnected.js +9 -2
- package/src/hooks/Common/usePopover.js +0 -8
- package/src/hooks/IoT/useGGHomeConnection.js +0 -1
- package/src/navigations/GatewayStack.js +23 -0
- package/src/navigations/Main.js +144 -0
- package/src/navigations/SmartStack.js +23 -0
- package/src/navigations/TemplateStack.js +23 -0
- package/src/navigations/UnitStack.js +10 -2
- package/src/screens/AddNewAction/SelectAction.js +6 -1
- package/src/screens/AllCamera/__test__/index.test.js +1 -8
- package/src/screens/AllCamera/index.js +0 -13
- package/src/screens/Device/hooks/__test__/useEmergencyButton.test.js +37 -0
- package/src/screens/Drawer/Drawer.test.js +24 -0
- package/src/screens/Drawer/index.js +198 -0
- package/src/screens/Gateway/__test__/index.test.js +16 -0
- package/src/screens/Gateway/index.js +8 -0
- package/src/screens/Notification/__test__/NotificationItem.test.js +79 -85
- package/src/screens/Notification/components/NotificationItem.js +37 -220
- package/src/screens/ScriptDetail/__test__/index.test.js +39 -3
- package/src/screens/ScriptDetail/index.js +7 -10
- package/src/screens/Smart/__test__/index.test.js +16 -0
- package/src/screens/Smart/index.js +8 -0
- package/src/screens/SubUnit/AddSubUnit.js +1 -1
- package/src/screens/SubUnit/EditSubUnit.js +4 -1
- package/src/screens/Template/Styles/indexStyles.js +51 -0
- package/src/screens/Template/__test__/index.test.js +16 -0
- package/src/screens/Template/index.js +84 -0
- package/src/screens/Unit/Detail.js +10 -27
- package/src/screens/Unit/MoreMenu.js +16 -1
- package/src/screens/Unit/SmartAccount.js +7 -6
- package/src/screens/Unit/Station/__test__/index.test.js +41 -0
- package/src/screens/Unit/Station/index.js +0 -1
- package/src/screens/Unit/Summaries.js +14 -2
- package/src/screens/Unit/__test__/Detail.test.js +1 -5
- package/src/screens/Unit/components/Header/index.js +1 -1
- package/src/screens/Unit/components/MyUnitDevice/index.js +29 -12
- package/src/screens/Unit/components/__test__/Header.test.js +1 -1
- package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +2 -2
- package/src/screens/Unit/hook/useUnitConnectRemoteDevices.js +6 -5
- package/src/utils/Converter/__test__/timer.test.js +99 -0
- package/src/utils/Functions/Search.js +17 -0
- package/src/utils/Functions/ShortEmail.js +4 -0
- package/src/utils/Functions/__test__/Search.test.js +6 -0
- package/src/utils/Functions/__test__/ShortEmail.test.js +6 -0
- package/src/utils/I18n/translations/en.json +32 -42
- package/src/utils/I18n/translations/vi.json +32 -44
- package/src/utils/Route/index.js +6 -0
- package/src/commons/Modal/ModalFullVideo.js +0 -48
- package/src/commons/Modal/Styles/ModalFullVideoStyles.js +0 -26
- package/src/screens/Unit/components/MyUnit/index.js +0 -136
- package/src/screens/Unit/components/__test__/MyUnit.test.js +0 -35
package/index.js
CHANGED
|
@@ -19,6 +19,7 @@ import MyUnit from './src/commons/Dashboard/MyUnit';
|
|
|
19
19
|
import SharedUnit from './src/commons/Unit/SharedUnit';
|
|
20
20
|
import { Action } from './src/context/actionType';
|
|
21
21
|
import { withRemoteControl } from './src/hoc';
|
|
22
|
+
import DevModeStack from './src/navigations/Main';
|
|
22
23
|
|
|
23
24
|
export {
|
|
24
25
|
AddSubUnitStack,
|
|
@@ -44,4 +45,5 @@ export {
|
|
|
44
45
|
SCWrapper,
|
|
45
46
|
Action,
|
|
46
47
|
withRemoteControl,
|
|
48
|
+
DevModeStack,
|
|
47
49
|
};
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -16,7 +16,6 @@ const CurtainButtonTemplate = memo(({ actionGroup, doAction, sensor }) => {
|
|
|
16
16
|
action_on_data,
|
|
17
17
|
is_display_lock,
|
|
18
18
|
text1,
|
|
19
|
-
text2,
|
|
20
19
|
text3,
|
|
21
20
|
text_door_lock,
|
|
22
21
|
} = configuration || {};
|
|
@@ -56,7 +55,7 @@ const CurtainButtonTemplate = memo(({ actionGroup, doAction, sensor }) => {
|
|
|
56
55
|
{
|
|
57
56
|
style: styles.buttonActionCurtainCenter,
|
|
58
57
|
icon: Images.buttonPauseCurtain,
|
|
59
|
-
text:
|
|
58
|
+
text: '',
|
|
60
59
|
onPress: onButtonStopPress,
|
|
61
60
|
testID: TESTID.BUTTON_TEMPLATE_2,
|
|
62
61
|
},
|
|
@@ -18,6 +18,7 @@ const OnOffButtonTemplate = memo(
|
|
|
18
18
|
style={styles.bigCircle}
|
|
19
19
|
onPress={triggerAction}
|
|
20
20
|
testID={`${TESTID.ON_OFF_BUTTON}-${id}`}
|
|
21
|
+
accessibilityLabel={`${TESTID.ON_OFF_BUTTON}-${id}`}
|
|
21
22
|
>
|
|
22
23
|
<View style={styles.smallCircle}>
|
|
23
24
|
<Icon
|
|
@@ -31,6 +32,7 @@ const OnOffButtonTemplate = memo(
|
|
|
31
32
|
{ color: isOn ? Colors.Gray8 : Colors.Gray6 },
|
|
32
33
|
]}
|
|
33
34
|
testID={`${TESTID.SENSOR_STATUS}-${id}`}
|
|
35
|
+
accessibilityLabel={`${TESTID.SENSOR_STATUS}-${id}`}
|
|
34
36
|
>
|
|
35
37
|
{isOn ? configuration.text_on : configuration.text_off}
|
|
36
38
|
</Text>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React, { memo, useCallback } from 'react';
|
|
2
|
+
import { TouchableOpacity } from 'react-native';
|
|
3
|
+
import Text from '../Text';
|
|
4
|
+
import styles from './CurtainActionStyles';
|
|
5
|
+
|
|
6
|
+
const CurtainAction = ({ configuration, onPress, template }) => {
|
|
7
|
+
const { open_action, close_action, stop_action, text1, text2, text3 } =
|
|
8
|
+
configuration || {};
|
|
9
|
+
|
|
10
|
+
const onPressActionClose = useCallback(() => {
|
|
11
|
+
onPress &&
|
|
12
|
+
onPress({
|
|
13
|
+
name: text1,
|
|
14
|
+
action: close_action,
|
|
15
|
+
template,
|
|
16
|
+
});
|
|
17
|
+
}, [onPress, text1, close_action, template]);
|
|
18
|
+
|
|
19
|
+
const onPressActionStop = useCallback(() => {
|
|
20
|
+
onPress &&
|
|
21
|
+
onPress({
|
|
22
|
+
name: text2,
|
|
23
|
+
action: stop_action,
|
|
24
|
+
template,
|
|
25
|
+
});
|
|
26
|
+
}, [onPress, text2, stop_action, template]);
|
|
27
|
+
|
|
28
|
+
const onPressActionOpen = useCallback(() => {
|
|
29
|
+
onPress &&
|
|
30
|
+
onPress({
|
|
31
|
+
name: text3,
|
|
32
|
+
action: open_action,
|
|
33
|
+
template,
|
|
34
|
+
});
|
|
35
|
+
}, [onPress, text3, open_action, template]);
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<>
|
|
39
|
+
<TouchableOpacity onPress={onPressActionClose}>
|
|
40
|
+
<Text type="H4" style={styles.textwithline}>
|
|
41
|
+
{text1}
|
|
42
|
+
</Text>
|
|
43
|
+
</TouchableOpacity>
|
|
44
|
+
|
|
45
|
+
<TouchableOpacity onPress={onPressActionStop}>
|
|
46
|
+
<Text type="H4" style={styles.textwithline}>
|
|
47
|
+
{text2}
|
|
48
|
+
</Text>
|
|
49
|
+
</TouchableOpacity>
|
|
50
|
+
|
|
51
|
+
<TouchableOpacity onPress={onPressActionOpen}>
|
|
52
|
+
<Text type="H4" style={styles.textwithline}>
|
|
53
|
+
{text3}
|
|
54
|
+
</Text>
|
|
55
|
+
</TouchableOpacity>
|
|
56
|
+
</>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default memo(CurtainAction);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { memo, useCallback } from 'react';
|
|
2
|
+
import { TouchableOpacity } from 'react-native';
|
|
3
|
+
import Text from '../Text';
|
|
4
|
+
import styles from './OnOffSmartLockActionStyles';
|
|
5
|
+
|
|
6
|
+
const OnOffSmartLockAction = ({ configuration, onPress, template }) => {
|
|
7
|
+
const { action_off, action_on, text_off, text_on } = configuration || {};
|
|
8
|
+
|
|
9
|
+
const onPressActionClose = useCallback(() => {
|
|
10
|
+
onPress &&
|
|
11
|
+
onPress({
|
|
12
|
+
name: text_off,
|
|
13
|
+
action: action_off,
|
|
14
|
+
template,
|
|
15
|
+
});
|
|
16
|
+
}, [onPress, text_off, action_off, template]);
|
|
17
|
+
|
|
18
|
+
const onPressActionOpen = useCallback(() => {
|
|
19
|
+
onPress &&
|
|
20
|
+
onPress({
|
|
21
|
+
name: text_on,
|
|
22
|
+
action: action_on,
|
|
23
|
+
template,
|
|
24
|
+
});
|
|
25
|
+
}, [onPress, text_on, action_on, template]);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
<TouchableOpacity onPress={onPressActionClose}>
|
|
30
|
+
<Text type="H4" style={styles.textwithline}>
|
|
31
|
+
{text_off}
|
|
32
|
+
</Text>
|
|
33
|
+
</TouchableOpacity>
|
|
34
|
+
|
|
35
|
+
<TouchableOpacity onPress={onPressActionOpen}>
|
|
36
|
+
<Text type="H4" style={styles.textwithline}>
|
|
37
|
+
{text_on}
|
|
38
|
+
</Text>
|
|
39
|
+
</TouchableOpacity>
|
|
40
|
+
</>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default memo(OnOffSmartLockAction);
|
|
@@ -9,6 +9,8 @@ import ThreeButtonAction from './ThreeButtonAction';
|
|
|
9
9
|
import OnOffSimpleAction from './OnOffSimpleAction';
|
|
10
10
|
import SelectActionCard from '../SelectActionCard';
|
|
11
11
|
import { ModalCustom } from '../Modal';
|
|
12
|
+
import CurtainAction from './CurtainAction';
|
|
13
|
+
import OnOffSmartLockAction from './OnOffSmartLockAction';
|
|
12
14
|
|
|
13
15
|
const ActionTemplate = memo(({ data, onSelectAction }) => {
|
|
14
16
|
const t = useTranslations();
|
|
@@ -66,6 +68,22 @@ const ActionTemplate = memo(({ data, onSelectAction }) => {
|
|
|
66
68
|
key={index}
|
|
67
69
|
/>
|
|
68
70
|
);
|
|
71
|
+
case 'curtain_action_template':
|
|
72
|
+
return (
|
|
73
|
+
<CurtainAction
|
|
74
|
+
{...item}
|
|
75
|
+
onPress={onPressSelectAction}
|
|
76
|
+
key={index}
|
|
77
|
+
/>
|
|
78
|
+
);
|
|
79
|
+
case 'OnOffSmartLockActionTemplate':
|
|
80
|
+
return (
|
|
81
|
+
<OnOffSmartLockAction
|
|
82
|
+
{...item}
|
|
83
|
+
onPress={onPressSelectAction}
|
|
84
|
+
key={index}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
69
87
|
}
|
|
70
88
|
});
|
|
71
89
|
}, [data, onPressSelectAction]);
|
|
@@ -17,7 +17,7 @@ const { standardizeWidth, standardizeHeight } = standardizeCameraScreenSize(
|
|
|
17
17
|
Device.screenWidth - 32
|
|
18
18
|
);
|
|
19
19
|
|
|
20
|
-
const CameraDevice = ({ station,
|
|
20
|
+
const CameraDevice = ({ station, goToPlayBack }) => {
|
|
21
21
|
const t = useTranslations();
|
|
22
22
|
const { navigate } = useNavigation();
|
|
23
23
|
const { setAction } = useContext(SCContext);
|
|
@@ -62,7 +62,6 @@ const CameraDevice = ({ station, handleFullScreen, goToPlayBack }) => {
|
|
|
62
62
|
}}
|
|
63
63
|
key={`camera-device-${device.id}`}
|
|
64
64
|
cameraName={device.configuration.name}
|
|
65
|
-
handleFullScreen={handleFullScreen}
|
|
66
65
|
goToPlayBack={goToPlayBack(device, { uri: station?.background })}
|
|
67
66
|
width={standardizeWidth}
|
|
68
67
|
height={standardizeHeight}
|
|
@@ -3,18 +3,26 @@ import { View } from 'react-native';
|
|
|
3
3
|
import styles from './DeviceItemStyles';
|
|
4
4
|
import FImage from '../../FImage';
|
|
5
5
|
import _TextInput from '../../Form/TextInput';
|
|
6
|
+
import Images from '../../../configs/Images';
|
|
6
7
|
|
|
7
|
-
const DeviceItem = memo(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
8
|
+
const DeviceItem = memo(
|
|
9
|
+
({ icon, name, setNewName, handleSelectionChange, isSelection }) => {
|
|
10
|
+
return (
|
|
11
|
+
<View style={styles.container}>
|
|
12
|
+
<FImage
|
|
13
|
+
source={icon ? { uri: icon } : Images.deviceIcon}
|
|
14
|
+
style={styles.iconSensor}
|
|
15
|
+
/>
|
|
16
|
+
<_TextInput
|
|
17
|
+
value={name}
|
|
18
|
+
textInputStyle={styles.textItem}
|
|
19
|
+
onChange={setNewName}
|
|
20
|
+
selection={isSelection && { start: 0, end: 0 }}
|
|
21
|
+
onSelectionChange={handleSelectionChange}
|
|
22
|
+
/>
|
|
23
|
+
</View>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
);
|
|
19
27
|
|
|
20
28
|
export default DeviceItem;
|
|
@@ -13,7 +13,7 @@ describe('Test DeviceItem button', () => {
|
|
|
13
13
|
const instance = tree.root;
|
|
14
14
|
const image = instance.findAllByType(FImage);
|
|
15
15
|
const text = instance.findAllByType(_TextInput);
|
|
16
|
-
expect(image).toHaveLength(
|
|
16
|
+
expect(image).toHaveLength(1);
|
|
17
17
|
expect(text).toHaveLength(1);
|
|
18
18
|
});
|
|
19
19
|
});
|
|
@@ -20,6 +20,8 @@ const ConnectingSuccess = ({
|
|
|
20
20
|
unit_name,
|
|
21
21
|
newName,
|
|
22
22
|
setNewName,
|
|
23
|
+
isSelection,
|
|
24
|
+
handleSelectionChange,
|
|
23
25
|
}) => {
|
|
24
26
|
const t = useTranslations();
|
|
25
27
|
return (
|
|
@@ -37,6 +39,8 @@ const ConnectingSuccess = ({
|
|
|
37
39
|
icon={sensor?.icon_kit}
|
|
38
40
|
name={newName}
|
|
39
41
|
setNewName={setNewName}
|
|
42
|
+
handleSelectionChange={handleSelectionChange}
|
|
43
|
+
isSelection={isSelection}
|
|
40
44
|
/>
|
|
41
45
|
</View>
|
|
42
46
|
);
|
|
@@ -61,6 +65,7 @@ const ConnectingProcess = ({ route }) => {
|
|
|
61
65
|
const [sensor, setSensor] = useState(null);
|
|
62
66
|
const user = useSCContextSelector((state) => state?.auth?.account?.user);
|
|
63
67
|
const [newName, setNewName] = useState('');
|
|
68
|
+
const [isSelection, setIsSelection] = useState(true);
|
|
64
69
|
|
|
65
70
|
const connectingDevice = useCallback(async () => {
|
|
66
71
|
setIsLoading(true);
|
|
@@ -166,6 +171,10 @@ const ConnectingProcess = ({ route }) => {
|
|
|
166
171
|
unit_id,
|
|
167
172
|
]);
|
|
168
173
|
|
|
174
|
+
const handleSelectionChange = useCallback(() => {
|
|
175
|
+
setIsSelection(false);
|
|
176
|
+
}, []);
|
|
177
|
+
|
|
169
178
|
useEffect(() => {
|
|
170
179
|
connectingDevice();
|
|
171
180
|
}, [connectingDevice]);
|
|
@@ -185,6 +194,8 @@ const ConnectingProcess = ({ route }) => {
|
|
|
185
194
|
unit_name={unit_name}
|
|
186
195
|
newName={newName}
|
|
187
196
|
setNewName={setNewName}
|
|
197
|
+
isSelection={isSelection}
|
|
198
|
+
handleSelectionChange={handleSelectionChange}
|
|
188
199
|
/>
|
|
189
200
|
)}
|
|
190
201
|
</View>
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
3
4
|
import MyUnit from '..';
|
|
5
|
+
import MyUnitDevice from '../../../../screens/Unit/components/MyUnitDevice';
|
|
4
6
|
import { TESTID } from '../../../../configs/Constants';
|
|
5
7
|
import { SCProvider } from '../../../../context';
|
|
6
8
|
import { mockSCStore } from '../../../../context/mockStore';
|
|
9
|
+
import api from '../../../../utils/Apis/axios';
|
|
10
|
+
import { API } from '../../../../configs';
|
|
11
|
+
|
|
12
|
+
const mock = new MockAdapter(api.axiosInstance);
|
|
7
13
|
|
|
8
14
|
const mockedNavigate = jest.fn();
|
|
9
|
-
const mockUseIsFocused = jest.fn();
|
|
10
15
|
const mockedDispatch = jest.fn();
|
|
11
16
|
|
|
12
17
|
jest.mock('@react-navigation/native', () => {
|
|
@@ -15,9 +20,8 @@ jest.mock('@react-navigation/native', () => {
|
|
|
15
20
|
useNavigation: () => ({
|
|
16
21
|
navigate: mockedNavigate,
|
|
17
22
|
}),
|
|
18
|
-
useIsFocused: () =>
|
|
19
|
-
|
|
20
|
-
}),
|
|
23
|
+
useIsFocused: () => true,
|
|
24
|
+
useFocusEffect: jest.fn(),
|
|
21
25
|
};
|
|
22
26
|
});
|
|
23
27
|
|
|
@@ -34,6 +38,42 @@ const wrapComponent = () => (
|
|
|
34
38
|
|
|
35
39
|
describe('Test MyUnit', () => {
|
|
36
40
|
let tree;
|
|
41
|
+
let data = [
|
|
42
|
+
{
|
|
43
|
+
id: 1,
|
|
44
|
+
name: 'name',
|
|
45
|
+
background: 'background',
|
|
46
|
+
abstract_devices: [
|
|
47
|
+
{
|
|
48
|
+
id: 1,
|
|
49
|
+
name: 'device',
|
|
50
|
+
is_managed_by_backend: true,
|
|
51
|
+
device_type: 'GOOGLE_HOME',
|
|
52
|
+
station_name: 'name',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 2,
|
|
56
|
+
name: 'device',
|
|
57
|
+
is_managed_by_backend: true,
|
|
58
|
+
device_type: '',
|
|
59
|
+
station_name: 'name',
|
|
60
|
+
quick_action: {
|
|
61
|
+
config_id: 1,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 2,
|
|
68
|
+
name: 'name2',
|
|
69
|
+
background: 'background',
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
beforeEach(() => {
|
|
74
|
+
mock.resetHistory();
|
|
75
|
+
});
|
|
76
|
+
|
|
37
77
|
const getElement = (instance) => {
|
|
38
78
|
const goToDetail = instance.findAll(
|
|
39
79
|
(item) => item.props.testID === TESTID.MY_UNIT_GO_TO_DETAIL
|
|
@@ -44,7 +84,7 @@ describe('Test MyUnit', () => {
|
|
|
44
84
|
return { goToDetail, textNoUnit };
|
|
45
85
|
};
|
|
46
86
|
|
|
47
|
-
test('
|
|
87
|
+
test('MyUnit no Unit', async () => {
|
|
48
88
|
await act(async () => {
|
|
49
89
|
tree = await renderer.create(wrapComponent());
|
|
50
90
|
});
|
|
@@ -52,4 +92,14 @@ describe('Test MyUnit', () => {
|
|
|
52
92
|
const { textNoUnit } = getElement(instance);
|
|
53
93
|
expect(textNoUnit[0]).toBeDefined();
|
|
54
94
|
});
|
|
95
|
+
|
|
96
|
+
test('MyUnit with unit', async () => {
|
|
97
|
+
mock.onGet(API.UNIT.MY_UNITS()).replyOnce(200, data);
|
|
98
|
+
await act(async () => {
|
|
99
|
+
tree = await renderer.create(wrapComponent());
|
|
100
|
+
});
|
|
101
|
+
const instance = tree.root;
|
|
102
|
+
const devices = instance.findAllByType(MyUnitDevice);
|
|
103
|
+
expect(devices).toHaveLength(2);
|
|
104
|
+
});
|
|
55
105
|
});
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
memo,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useState,
|
|
6
|
+
useContext,
|
|
7
|
+
useMemo,
|
|
8
|
+
} from 'react';
|
|
2
9
|
import { View, Image, TouchableOpacity, Dimensions } from 'react-native';
|
|
10
|
+
import {
|
|
11
|
+
useNavigation,
|
|
12
|
+
useIsFocused,
|
|
13
|
+
useFocusEffect,
|
|
14
|
+
} from '@react-navigation/native';
|
|
15
|
+
import NetInfo from '@react-native-community/netinfo';
|
|
3
16
|
import { API, Colors, Images } from '../../../configs';
|
|
4
17
|
import Text from '../../Text';
|
|
5
18
|
import { fetchWithCache } from '../../../utils/Apis/axios';
|
|
@@ -7,10 +20,13 @@ import { fetchWithCache } from '../../../utils/Apis/axios';
|
|
|
7
20
|
import styles from './styles';
|
|
8
21
|
import { Section } from '../../Section';
|
|
9
22
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
10
|
-
import {
|
|
23
|
+
import { useUnitConnectRemoteDevices } from '../../../screens/Unit/hook/useUnitConnectRemoteDevices';
|
|
24
|
+
import { useWatchConfigs } from '../../../hooks/IoT';
|
|
25
|
+
import { SCContext } from '../../../context';
|
|
26
|
+
import { Action } from '../../../context/actionType';
|
|
11
27
|
|
|
12
28
|
import Carousel from 'react-native-snap-carousel';
|
|
13
|
-
import { TESTID } from '../../../configs/Constants';
|
|
29
|
+
import { TESTID, DEVICE_TYPE } from '../../../configs/Constants';
|
|
14
30
|
import Routes from '../../../utils/Route';
|
|
15
31
|
import MyUnitDevice from '../../../screens/Unit/components/MyUnitDevice';
|
|
16
32
|
|
|
@@ -20,21 +36,49 @@ const MyUnit = () => {
|
|
|
20
36
|
const isFocused = useIsFocused();
|
|
21
37
|
const navigation = useNavigation();
|
|
22
38
|
const [myUnits, setMyUnits] = useState([]);
|
|
39
|
+
const [slideIndex, setSlideIndex] = useState(0);
|
|
40
|
+
const { setAction } = useContext(SCContext);
|
|
23
41
|
|
|
24
42
|
const fetchMyUnitDashboard = useCallback(async () => {
|
|
25
43
|
await fetchWithCache(API.UNIT.MY_UNITS(), {}, (response) => {
|
|
26
44
|
const { success, data } = response;
|
|
27
|
-
|
|
28
|
-
setMyUnits(data);
|
|
29
|
-
}
|
|
45
|
+
success && setMyUnits(data);
|
|
30
46
|
});
|
|
31
47
|
}, [setMyUnits]);
|
|
32
48
|
|
|
33
49
|
useEffect(() => {
|
|
34
|
-
|
|
35
|
-
fetchMyUnitDashboard();
|
|
36
|
-
}
|
|
50
|
+
isFocused && fetchMyUnitDashboard();
|
|
37
51
|
}, [fetchMyUnitDashboard, isFocused]);
|
|
52
|
+
|
|
53
|
+
useFocusEffect(
|
|
54
|
+
useCallback(() => {
|
|
55
|
+
const unsubscribe = NetInfo.addEventListener((state) => {
|
|
56
|
+
setAction(Action.SET_NETWORK_CONNECTED, state.isConnected);
|
|
57
|
+
});
|
|
58
|
+
return () => unsubscribe();
|
|
59
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
60
|
+
}, [])
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
useUnitConnectRemoteDevices(myUnits[slideIndex]);
|
|
64
|
+
|
|
65
|
+
const configsNeedWatching = useMemo(() => {
|
|
66
|
+
const configIds = [];
|
|
67
|
+
myUnits.forEach((unit) => {
|
|
68
|
+
(unit?.abstract_devices || []).forEach((device) => {
|
|
69
|
+
if (
|
|
70
|
+
device?.quick_action?.config_id &&
|
|
71
|
+
device?.device_type !== DEVICE_TYPE.GOOGLE_HOME
|
|
72
|
+
) {
|
|
73
|
+
configIds.push(device.quick_action.config_id);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
return configIds;
|
|
78
|
+
}, [myUnits]);
|
|
79
|
+
|
|
80
|
+
useWatchConfigs(configsNeedWatching);
|
|
81
|
+
|
|
38
82
|
const goToDetail = useCallback(
|
|
39
83
|
(item) => {
|
|
40
84
|
navigation.navigate(Routes.UnitStack, {
|
|
@@ -47,6 +91,7 @@ const MyUnit = () => {
|
|
|
47
91
|
},
|
|
48
92
|
[navigation]
|
|
49
93
|
);
|
|
94
|
+
|
|
50
95
|
const _renderItem = useCallback(
|
|
51
96
|
({ item, index }) => {
|
|
52
97
|
const paddingLeft = index === 0 ? 0 : 8;
|
|
@@ -73,14 +118,15 @@ const MyUnit = () => {
|
|
|
73
118
|
/>
|
|
74
119
|
<Text style={styles.title}>{item.name}</Text>
|
|
75
120
|
</TouchableOpacity>
|
|
76
|
-
{item.
|
|
77
|
-
<MyUnitDevice key={
|
|
121
|
+
{(item?.abstract_devices || []).map((device, indexDevice) => (
|
|
122
|
+
<MyUnitDevice key={indexDevice} device={device} unit={item} />
|
|
78
123
|
))}
|
|
79
124
|
</View>
|
|
80
125
|
);
|
|
81
126
|
},
|
|
82
|
-
[myUnits
|
|
127
|
+
[myUnits, goToDetail]
|
|
83
128
|
);
|
|
129
|
+
|
|
84
130
|
return (
|
|
85
131
|
<>
|
|
86
132
|
<Section style={styles.boxTxtMyUnit}>
|
|
@@ -96,6 +142,7 @@ const MyUnit = () => {
|
|
|
96
142
|
itemWidth={screenWidth - 32}
|
|
97
143
|
renderItem={_renderItem}
|
|
98
144
|
inactiveSlideScale={1}
|
|
145
|
+
onSnapToItem={setSlideIndex}
|
|
99
146
|
/>
|
|
100
147
|
) : (
|
|
101
148
|
<View>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import Text from '../Text';
|
|
4
|
+
import styles from './Styles/LabelStyles';
|
|
5
|
+
|
|
6
|
+
const Label = ({ name = '', style }) => {
|
|
7
|
+
return <Text style={[styles.label, style]}>{name}</Text>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default memo(Label);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { View, Image, TextInput } from 'react-native';
|
|
3
|
+
import { Images } from '../../configs';
|
|
4
|
+
import t from '../../hooks/Common/useTranslations';
|
|
5
|
+
import styles from './Styles/SearchStyles';
|
|
6
|
+
|
|
7
|
+
const Search = ({ onSearch }) => {
|
|
8
|
+
return (
|
|
9
|
+
<View style={styles.wrap}>
|
|
10
|
+
<Image source={Images.search} style={styles.icon} />
|
|
11
|
+
<TextInput
|
|
12
|
+
style={styles.textInput}
|
|
13
|
+
placeholder={t('what_are_you_looking_for')}
|
|
14
|
+
onChangeText={onSearch}
|
|
15
|
+
/>
|
|
16
|
+
</View>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default memo(Search);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { Colors } from '../../../configs';
|
|
3
|
+
|
|
4
|
+
export default StyleSheet.create({
|
|
5
|
+
wrap: {
|
|
6
|
+
borderRadius: 6,
|
|
7
|
+
borderWidth: 1,
|
|
8
|
+
borderColor: Colors.Neutral.Neutral3,
|
|
9
|
+
width: '100%',
|
|
10
|
+
flexDirection: 'row',
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
paddingHorizontal: 10,
|
|
13
|
+
marginVertical: 16,
|
|
14
|
+
},
|
|
15
|
+
icon: {},
|
|
16
|
+
textInput: {
|
|
17
|
+
flex: 1,
|
|
18
|
+
height: 36,
|
|
19
|
+
marginLeft: 5,
|
|
20
|
+
},
|
|
21
|
+
});
|