@eohjsc/react-native-smart-city 0.2.59 → 0.2.63
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/README.md +115 -68
- package/assets/images/Map/MarkerGeolocation.svg +4 -0
- package/package.json +3 -3
- package/src/commons/ActionGroup/CurtainButtonTemplate.js +10 -2
- package/src/commons/ActionGroup/__test__/CurtainButtonTemplate.test.js +1 -1
- package/src/commons/ActionGroup/__test__/MenuActionAddSchedule.test.js +71 -0
- package/src/commons/ActionGroup/hooks/AccessScheduleDetailStyles.js +41 -0
- package/src/commons/ActionGroup/hooks/MenuActionAddSchedule.js +110 -0
- package/src/commons/ActionGroup/hooks/MenuActionAddScheduleStyle.js +69 -0
- package/src/commons/ActionGroup/hooks/RecurringDetail.js +97 -0
- package/src/commons/DateTimeRangeChange/DateTimeButton.js +7 -2
- package/src/commons/Device/HistoryChart.js +80 -81
- package/src/commons/Device/HorizontalBarChart.js +48 -31
- package/src/commons/Device/LinearChart.js +28 -1
- package/src/commons/Form/CurrencyInput.js +1 -0
- package/src/commons/FourButtonFilterHistory/__test__/FourButtonFilterHistory.test.js +48 -0
- package/src/commons/FourButtonFilterHistory/index.js +72 -0
- package/src/commons/FourButtonFilterHistory/styles.js +22 -0
- package/src/commons/ImagePicker/index.js +27 -33
- package/src/commons/MediaPlayerDetail/Styles/MediaPlayerDetailStyles.js +11 -1
- package/src/commons/MediaPlayerDetail/index.js +14 -5
- package/src/commons/SubUnit/OneTap/OneTapStyles.js +20 -1
- package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +151 -40
- package/src/commons/SubUnit/OneTap/index.js +64 -12
- package/src/commons/UnitSummary/AirQuality/index.js +9 -7
- package/src/commons/UnitSummary/ConfigHistoryChart.js +2 -1
- package/src/configs/API.js +3 -0
- package/src/configs/Constants.js +15 -0
- package/src/iot/RemoteControl/Bluetooth.js +6 -3
- package/src/iot/RemoteControl/GoogleHome.js +6 -3
- package/src/iot/RemoteControl/Internet.js +1 -0
- package/src/iot/RemoteControl/LG.js +2 -1
- package/src/iot/RemoteControl/index.js +13 -6
- package/src/navigations/SharedStack.js +11 -9
- package/src/navigations/UnitStack.js +26 -2
- package/src/screens/ActivityLog/ItemLog.js +3 -3
- package/src/screens/ActivityLog/__test__/ItemLog.test.js +5 -2
- package/src/screens/ActivityLog/hooks/index.js +2 -1
- package/src/screens/ActivityLog/index.js +0 -1
- package/src/screens/AddLocationMaps/index.js +4 -2
- package/src/screens/AddNewAction/SelectSensorDevices.js +18 -11
- package/src/screens/AddNewAction/Styles/SelectSensorDevicesStyles.js +5 -1
- package/src/screens/AddNewAction/__test__/SelectSensorDevices.test.js +6 -1
- package/src/screens/Automate/MultiUnits.js +7 -4
- package/src/screens/Automate/__test__/MultiUnits.test.js +1 -1
- package/src/screens/Automate/__test__/index.test.js +12 -0
- package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +61 -0
- package/src/screens/ConfirmUnitDeletion/index.js +64 -0
- package/src/screens/ConfirmUnitDeletion/styles.js +37 -0
- package/src/screens/Device/__test__/detail.test.js +3 -2
- package/src/screens/Device/detail.js +48 -15
- package/src/screens/Device/hooks/useDisconnectedDevice.js +2 -1
- package/src/screens/Device/styles.js +3 -3
- package/src/screens/EmergencySetting/__test__/DropDownItem.test.js +59 -0
- package/src/screens/EmergencySetting/__test__/index.test.js +27 -0
- package/src/screens/EmergencySetting/components/DropDownItem.js +54 -0
- package/src/screens/EmergencySetting/index.js +92 -0
- package/src/screens/EmergencySetting/styles/DropDownItem.js +38 -0
- package/src/screens/EmergencySetting/styles.js +25 -0
- package/src/screens/MoveToAnotherSubUnit/__test__/index.test.js +126 -0
- package/src/screens/MoveToAnotherSubUnit/index.js +88 -0
- package/src/screens/MoveToAnotherSubUnit/styles/MoveToAnotherSubUnitStyles.js +50 -0
- package/src/screens/ScriptDetail/Styles/indexStyles.js +0 -1
- package/src/screens/ScriptDetail/index.js +1 -0
- package/src/screens/SubUnit/AddSubUnit.js +3 -3
- package/src/screens/SubUnit/AddSubUnitStyles.js +0 -2
- package/src/screens/SubUnit/EditSubUnit.js +16 -7
- package/src/screens/SubUnit/EditSubUnitStyles.js +2 -3
- package/src/screens/SubUnit/__test__/EditSubUnit.test.js +2 -2
- package/src/screens/TDSGuide/index.js +1 -1
- package/src/screens/Unit/ChooseLocation.js +3 -7
- package/src/screens/Unit/ChooseLocationStyles.js +5 -8
- package/src/screens/Unit/Detail.js +16 -6
- package/src/screens/Unit/ManageUnit.js +20 -26
- package/src/screens/Unit/SmartAccount.js +25 -41
- package/src/screens/Unit/SmartAccountItem.js +2 -1
- package/src/screens/Unit/SmartAccountStyles.js +0 -1
- package/src/screens/Unit/__test__/ManageUnit.test.js +0 -6
- package/src/screens/Unit/__test__/SmartAccount.test.js +24 -0
- package/src/screens/Unit/__test__/SmartAccountItem.test.js +72 -0
- package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +58 -59
- package/src/screens/UnitSummary/components/PowerConsumption/index.js +26 -22
- package/src/screens/UnitSummary/components/Temperature/ItemTemperature/index.js +2 -2
- package/src/screens/UnitSummary/components/Temperature/index.js +15 -14
- package/src/screens/UnitSummary/components/UvIndex/index.js +6 -5
- package/src/screens/UnitSummary/components/WaterQuality/index.js +9 -7
- package/src/screens/UnitSummary/index.js +11 -7
- package/src/screens/WaterQualityGuide/index.js +1 -0
- package/src/utils/Apis/axios.js +4 -4
- package/src/utils/I18n/translations/en.json +20 -2
- package/src/utils/I18n/translations/vi.json +21 -2
- package/src/utils/Route/index.js +3 -0
- package/src/utils/Utils.js +4 -0
- package/src/commons/ThreeButtonHistory/CalendarHeader.js +0 -35
- package/src/commons/ThreeButtonHistory/CalendarHeaderStyles.js +0 -17
- package/src/commons/ThreeButtonHistory/SelectMonth.js +0 -53
- package/src/commons/ThreeButtonHistory/SelectMonthStyles.js +0 -29
- package/src/commons/ThreeButtonHistory/__test__/SelectMonth.test.js +0 -37
- package/src/commons/ThreeButtonHistory/__test__/ThreeButtonHistory.test.js +0 -240
- package/src/commons/ThreeButtonHistory/index.js +0 -310
- package/src/commons/ThreeButtonHistory/styles.js +0 -65
package/README.md
CHANGED
|
@@ -1,101 +1,148 @@
|
|
|
1
|
-
|
|
1
|
+
## react-native-smart-city
|
|
2
2
|
|
|
3
3
|
## Getting started
|
|
4
|
+
1. Install package dependencies:
|
|
5
|
+
- Using [Yarn](https://yarnpkg.com/): `yarn add react-native-reanimated@^1.10.1`
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
2. Install:
|
|
8
|
+
- Using [npm](https://www.npmjs.com/#getting-started): `npm install @eohjsc/react-native-smart-city --save`
|
|
9
|
+
- Using [Yarn](https://yarnpkg.com/): `yarn add @eohjsc/react-native-smart-city`
|
|
6
10
|
|
|
11
|
+
3. Compile application using react-native run-android
|
|
7
12
|
### Mostly automatic installation
|
|
8
|
-
|
|
9
13
|
`$ react-native link @eohjsc/react-native-smart-city`
|
|
10
14
|
|
|
11
15
|
## Usage
|
|
12
|
-
|
|
13
|
-
Make sure that SmartCity
|
|
14
|
-
Example:
|
|
15
|
-
|
|
16
|
+
1. StackNavigator
|
|
16
17
|
```javascript
|
|
17
|
-
import
|
|
18
|
-
|
|
19
|
-
EmergencyContactsStack,
|
|
18
|
+
import {
|
|
19
|
+
UnitStack,
|
|
20
20
|
AddMemberStack,
|
|
21
|
-
|
|
21
|
+
AddSubUnitStack,
|
|
22
22
|
AddDeviceStack,
|
|
23
|
-
|
|
24
|
-
AddUnitStack,
|
|
25
|
-
SharedStack,
|
|
26
|
-
Explore,
|
|
27
|
-
SCProvider,
|
|
23
|
+
AddGatewayStack,
|
|
28
24
|
SCContext,
|
|
29
25
|
AddLGDeviceStack,
|
|
30
26
|
initSCConfig,
|
|
27
|
+
AddUnitStack,
|
|
31
28
|
AutomateStack,
|
|
32
29
|
NotificationStack,
|
|
33
|
-
MyPinnedSharedUnit,
|
|
34
|
-
SharedUnit,
|
|
35
|
-
MyUnit,
|
|
36
30
|
} from '@eohjsc/react-native-smart-city';
|
|
37
31
|
import { createStackNavigator } from '@react-navigation/stack';
|
|
38
32
|
|
|
39
33
|
// TODO: What to do with the module?
|
|
40
|
-
const Stack =
|
|
34
|
+
const Stack = createStackNavigator();
|
|
41
35
|
|
|
42
36
|
const YourStack = () => {
|
|
43
37
|
// Declare yourAuthObject and params
|
|
44
38
|
return (
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
/>
|
|
83
|
-
<Stack.Screen
|
|
84
|
-
name={'EmergencyContactsStack'}
|
|
85
|
-
component={EmergencyContactsStack}
|
|
86
|
-
options={{ headerShown: false }}
|
|
87
|
-
/>
|
|
88
|
-
</Stack.Navigator>
|
|
89
|
-
</NavigationContainer>
|
|
90
|
-
</SmartCity>
|
|
39
|
+
<Stack.Navigator>
|
|
40
|
+
<Stack.Screen
|
|
41
|
+
name={'MainTab'}
|
|
42
|
+
component={MainTab}
|
|
43
|
+
options={{
|
|
44
|
+
headerShown: false,
|
|
45
|
+
}}
|
|
46
|
+
/>
|
|
47
|
+
<Stack.Screen
|
|
48
|
+
name={'UnitStack'}
|
|
49
|
+
component={UnitStack}
|
|
50
|
+
initialParams={params}
|
|
51
|
+
options={{
|
|
52
|
+
headerShown: false,
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
<Stack.Screen
|
|
56
|
+
name={'AddGatewayStack'}
|
|
57
|
+
component={AddGatewayStack}
|
|
58
|
+
options={{ headerShown: false }}
|
|
59
|
+
/>
|
|
60
|
+
<Stack.Screen
|
|
61
|
+
name={'AddDeviceStack'}
|
|
62
|
+
component={AddDeviceStack}
|
|
63
|
+
options={{ headerShown: false }}
|
|
64
|
+
/>
|
|
65
|
+
<Stack.Screen
|
|
66
|
+
name={'AddMemberStack'}
|
|
67
|
+
component={AddMemberStack}
|
|
68
|
+
options={{ headerShown: false }}
|
|
69
|
+
/>
|
|
70
|
+
<Stack.Screen
|
|
71
|
+
name={'AddSubUnitStack'}
|
|
72
|
+
component={AddSubUnitStack}
|
|
73
|
+
options={{ headerShown: false }}
|
|
74
|
+
/>
|
|
75
|
+
</Stack.Navigator>
|
|
91
76
|
);
|
|
92
77
|
};
|
|
93
78
|
const MainTab = () => {
|
|
94
79
|
return (
|
|
95
80
|
<Tab.Navigator>
|
|
96
|
-
<Tab.Screen name={'
|
|
97
|
-
<Tab.Screen name={'
|
|
81
|
+
<Tab.Screen name={'AutomateStack'} component={AutomateStack} />
|
|
82
|
+
<Tab.Screen name={'NotificationStack'} component={NotificationStack} />
|
|
98
83
|
</Tab.Navigator>
|
|
99
84
|
);
|
|
100
85
|
};
|
|
101
86
|
```
|
|
87
|
+
2. Use components
|
|
88
|
+
```javascript
|
|
89
|
+
import React from 'react';
|
|
90
|
+
import { View } from 'react-native';
|
|
91
|
+
import { MyPinnedSharedUnit, MyUnit } from '@eohjsc/react-native-smart-city';
|
|
92
|
+
|
|
93
|
+
const MyScreen = () => {
|
|
94
|
+
return (
|
|
95
|
+
<View>
|
|
96
|
+
<MyUnit />
|
|
97
|
+
<MyPinnedSharedUnit />
|
|
98
|
+
</View>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
```
|
|
102
|
+
3. Trigger quick action
|
|
103
|
+
```javascript
|
|
104
|
+
import React from 'react';
|
|
105
|
+
import { View, Button } from 'react-native';
|
|
106
|
+
import { sendRemoteCommand } from '@eohjsc/react-native-smart-city/src/iot/RemoteControl';
|
|
107
|
+
|
|
108
|
+
export const MyFunctionalComponent = () => {
|
|
109
|
+
const sensor = {
|
|
110
|
+
id: 1,
|
|
111
|
+
remote_control_options: {
|
|
112
|
+
internet: {},
|
|
113
|
+
bluetooth: {},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
const action = {
|
|
117
|
+
color: '#00979D',
|
|
118
|
+
command_prefer_over_bluetooth: true,
|
|
119
|
+
command_prefer_over_googlehome: false,
|
|
120
|
+
command_prefer_over_internet: false,
|
|
121
|
+
googlehome_actions: [],
|
|
122
|
+
icon: 'caret-up',
|
|
123
|
+
icon_kit: null,
|
|
124
|
+
id: 1,
|
|
125
|
+
key: '24240de0-5c8e-11ec-bf63-0242ac130002',
|
|
126
|
+
lg_actions: [],
|
|
127
|
+
name: 'Garage Up',
|
|
128
|
+
};
|
|
129
|
+
const handleQuickAction = async() => {
|
|
130
|
+
const result = await sendRemoteCommand(sensor, action); // Action Garage Up
|
|
131
|
+
if (result){
|
|
132
|
+
console.log('Successful control')
|
|
133
|
+
}else {
|
|
134
|
+
console.log('Control failed')
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
return (
|
|
138
|
+
<View>
|
|
139
|
+
<Button onPress={handleQuickAction} title="Example trigger quick action control Garage Up" />
|
|
140
|
+
</View>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
```
|
|
144
|
+
- sendRemoteCommand user needs to `have permission to control the device`, you pass in the `sensor and action` to it and it will run after calling render.
|
|
145
|
+
- `sensor` is a device in your Unit and action is the `action` key of the device..
|
|
146
|
+
- You can take out the sensor and action from your Unit when calling the `API.UNIT.UNIT_DETAIL(unitId)` it will return all devices in 1 unit.
|
|
147
|
+
- Or get sensor from `API.SENSOR.DISPLAY(sensor.id)` returns all actions of 1 device.
|
|
148
|
+
- Refer YourProjectPath /node_modules/@eohjsc/react-native-smart-city/src/screens/Unit/Detail.js
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg width="24" height="39" viewBox="0 0 24 39" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M12 8.21875C11.0656 8.21875 10.1875 8.58125 9.525 9.24375C9.19945 9.56837 8.94129 9.95415 8.76538 10.3789C8.58947 10.8037 8.49928 11.259 8.5 11.7188C8.5 12.6531 8.86562 13.5312 9.525 14.1938C9.84962 14.5193 10.2354 14.7775 10.6602 14.9534C11.0849 15.1293 11.5403 15.2195 12 15.2188C12.9344 15.2188 13.8125 14.8531 14.475 14.1938C15.1375 13.5312 15.5 12.6531 15.5 11.7188C15.5 10.7844 15.1375 9.90625 14.475 9.24375C13.8125 8.58125 12.9344 8.21875 12 8.21875ZM22.7062 7.03438C22.1179 5.67775 21.2697 4.44944 20.2094 3.41875C19.1456 2.37875 17.8915 1.55331 16.5156 0.9875C15.0844 0.39375 13.5656 0.09375 12 0.09375C10.4344 0.09375 8.91562 0.39375 7.48438 0.984375C6.1 1.55625 4.85938 2.375 3.79063 3.41563C2.73101 4.44689 1.88286 5.67506 1.29375 7.03125C0.684375 8.4375 0.375 9.93125 0.375 11.4688C0.375 13.675 0.903125 15.8719 1.94063 17.9906C2.775 19.6938 3.94063 21.3531 5.40938 22.9312C7.91875 25.625 10.55 27.2719 11.2969 27.7125C11.5089 27.8377 11.7507 27.9036 11.9969 27.9031C12.2406 27.9031 12.4812 27.8406 12.6969 27.7125C13.4437 27.2719 16.075 25.625 18.5844 22.9312C20.0531 21.3562 21.2188 19.6938 22.0531 17.9906C23.0969 15.875 23.625 13.6812 23.625 11.4719C23.625 9.93437 23.3156 8.44063 22.7062 7.03438ZM12 17.2188C8.9625 17.2188 6.5 14.7563 6.5 11.7188C6.5 8.68125 8.9625 6.21875 12 6.21875C15.0375 6.21875 17.5 8.68125 17.5 11.7188C17.5 14.7563 15.0375 17.2188 12 17.2188Z" fill="#1890FF"/>
|
|
3
|
+
<path d="M16.6666 30.2735L15.7266 29.3335L12 33.0602L8.27331 29.3335L7.33331 30.2735L11.06 34.0002L7.33331 37.7268L8.27331 38.6668L12 34.9402L15.7266 38.6668L16.6666 37.7268L12.94 34.0002L16.6666 30.2735Z" fill="#262626"/>
|
|
4
|
+
</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.
|
|
4
|
+
"version": "0.2.63",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"@react-native-community/async-storage": "^1.12.1",
|
|
107
107
|
"@react-native-community/cameraroll": "^4.0.0",
|
|
108
108
|
"@react-native-community/checkbox": "^0.5.5",
|
|
109
|
-
"@react-native-community/datetimepicker": "
|
|
109
|
+
"@react-native-community/datetimepicker": "https://github.com/hinh-eoh/datepicker",
|
|
110
110
|
"@react-native-community/geolocation": "^2.0.2",
|
|
111
111
|
"@react-native-community/masked-view": "^0.1.10",
|
|
112
112
|
"@react-native-community/netinfo": "^6.0.0",
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
"react-native-geocoder": "^0.5.0",
|
|
158
158
|
"react-native-gesture-handler": "^1.7.0",
|
|
159
159
|
"react-native-get-location": "^2.0.0",
|
|
160
|
-
"react-native-image-picker": "^
|
|
160
|
+
"react-native-image-crop-picker": "^0.37.2",
|
|
161
161
|
"react-native-image-resizer": "^1.4.5",
|
|
162
162
|
"react-native-input-credit-card": "^0.5.5",
|
|
163
163
|
"react-native-iphone-x-helper": "^1.2.1",
|
|
@@ -8,11 +8,14 @@ import { TESTID } from '../../configs/Constants';
|
|
|
8
8
|
import { Colors, Images } from '../../configs';
|
|
9
9
|
import { Section } from '../../commons/Section';
|
|
10
10
|
import { IconOutline } from '@ant-design/icons-react-native';
|
|
11
|
+
import MenuActionAddSchedule from './hooks/MenuActionAddSchedule';
|
|
12
|
+
import { useBoolean } from '../../hooks/Common';
|
|
11
13
|
|
|
12
14
|
const CurtainButtonTemplate = memo(({ actionGroup, doAction }) => {
|
|
13
15
|
const t = useTranslations();
|
|
14
16
|
const { configuration } = actionGroup;
|
|
15
17
|
const [lock, setLock] = useState(false);
|
|
18
|
+
const [isShowModal, setShowModal, setHideModal] = useBoolean(false);
|
|
16
19
|
|
|
17
20
|
const onButtonOpenPress = useCallback(
|
|
18
21
|
() => doAction(configuration.open_action_data),
|
|
@@ -120,17 +123,22 @@ const CurtainButtonTemplate = memo(({ actionGroup, doAction }) => {
|
|
|
120
123
|
<Text type="H4" color={Colors.Gray8}>
|
|
121
124
|
{t('schedule')}
|
|
122
125
|
</Text>
|
|
123
|
-
<TouchableOpacity>
|
|
126
|
+
<TouchableOpacity onPress={setShowModal}>
|
|
124
127
|
<IconOutline name="plus" size={20} />
|
|
125
128
|
</TouchableOpacity>
|
|
126
129
|
</View>
|
|
127
130
|
<View>
|
|
128
|
-
<TouchableOpacity
|
|
131
|
+
<TouchableOpacity
|
|
132
|
+
onPress={setShowModal}
|
|
133
|
+
style={styles.tapToAddSchedule}
|
|
134
|
+
>
|
|
129
135
|
<Text type="Body" color={Colors.Gray6} center>
|
|
130
136
|
{t('tap_to_add_new_schedule')}
|
|
131
137
|
</Text>
|
|
132
138
|
</TouchableOpacity>
|
|
133
139
|
</View>
|
|
140
|
+
|
|
141
|
+
<MenuActionAddSchedule visible={isShowModal} hideModal={setHideModal} />
|
|
134
142
|
</Section>
|
|
135
143
|
</>
|
|
136
144
|
);
|
|
@@ -67,6 +67,6 @@ describe('Test CurtainButtonTemplate', () => {
|
|
|
67
67
|
});
|
|
68
68
|
const instance = wrapper.root;
|
|
69
69
|
const touchableOpacities = instance.findAllByType(TouchableOpacity);
|
|
70
|
-
expect(touchableOpacities.length).toEqual(
|
|
70
|
+
expect(touchableOpacities.length).toEqual(18);
|
|
71
71
|
});
|
|
72
72
|
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
|
|
4
|
+
import MenuActionAddSchedule from '../hooks/MenuActionAddSchedule';
|
|
5
|
+
import { SCProvider } from '../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
7
|
+
import RecurringDetail from '../hooks/RecurringDetail';
|
|
8
|
+
import WheelDateTimePicker from '../../WheelDateTimePicker';
|
|
9
|
+
|
|
10
|
+
const mockSetState = jest.fn();
|
|
11
|
+
jest.mock('react', () => {
|
|
12
|
+
return {
|
|
13
|
+
...jest.requireActual('react'),
|
|
14
|
+
memo: (x) => x,
|
|
15
|
+
useState: jest.fn((init) => [init, mockSetState]),
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const wrapComponent = (actionGroup) => (
|
|
20
|
+
<SCProvider initState={mockSCStore({})}>
|
|
21
|
+
<MenuActionAddSchedule />
|
|
22
|
+
</SCProvider>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const mockedNavigate = jest.fn();
|
|
26
|
+
|
|
27
|
+
jest.mock('@react-navigation/native', () => {
|
|
28
|
+
return {
|
|
29
|
+
...jest.requireActual('@react-navigation/native'),
|
|
30
|
+
useNavigation: () => ({
|
|
31
|
+
goBack: mockedNavigate,
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
jest.mock('react', () => {
|
|
37
|
+
return {
|
|
38
|
+
...jest.requireActual('react'),
|
|
39
|
+
memo: (x) => x,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
jest.mock('axios');
|
|
44
|
+
|
|
45
|
+
describe('Test MenuActionAddSchedule', () => {
|
|
46
|
+
let tree;
|
|
47
|
+
|
|
48
|
+
test('test render MenuActionAddSchedule', async () => {
|
|
49
|
+
await act(async () => {
|
|
50
|
+
tree = await renderer.create(wrapComponent());
|
|
51
|
+
});
|
|
52
|
+
const instance = tree.root;
|
|
53
|
+
|
|
54
|
+
const recurringDetail = instance.findByType(RecurringDetail);
|
|
55
|
+
await act(async () => {
|
|
56
|
+
recurringDetail.props.onShowSetDateTime();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const wheelDateTimePicker = instance.findByType(WheelDateTimePicker);
|
|
60
|
+
|
|
61
|
+
await act(async () => {
|
|
62
|
+
wheelDateTimePicker.props.onPicked();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await act(async () => {
|
|
66
|
+
wheelDateTimePicker.props.onCancel();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(wheelDateTimePicker.props.isVisible).toEqual(false);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { Colors } from '../../../configs';
|
|
3
|
+
|
|
4
|
+
export default StyleSheet.create({
|
|
5
|
+
title: {
|
|
6
|
+
marginTop: 16,
|
|
7
|
+
},
|
|
8
|
+
value: {
|
|
9
|
+
marginTop: 8,
|
|
10
|
+
marginBottom: 12,
|
|
11
|
+
},
|
|
12
|
+
repeatWrap: {
|
|
13
|
+
flexDirection: 'row',
|
|
14
|
+
justifyContent: 'space-around',
|
|
15
|
+
marginTop: 16,
|
|
16
|
+
},
|
|
17
|
+
repeatItem: {
|
|
18
|
+
width: 24,
|
|
19
|
+
height: 24,
|
|
20
|
+
justifyContent: 'center',
|
|
21
|
+
alignItems: 'center',
|
|
22
|
+
borderRadius: 12,
|
|
23
|
+
borderWidth: 0,
|
|
24
|
+
borderColor: Colors.Orange,
|
|
25
|
+
},
|
|
26
|
+
repeatItemSelected: {
|
|
27
|
+
borderWidth: 1,
|
|
28
|
+
},
|
|
29
|
+
repeatText: {
|
|
30
|
+
lineHeight: 16,
|
|
31
|
+
},
|
|
32
|
+
curtainText: {
|
|
33
|
+
fontSize: 17,
|
|
34
|
+
marginTop: 12,
|
|
35
|
+
color: Colors.Gray9,
|
|
36
|
+
},
|
|
37
|
+
boder: {
|
|
38
|
+
borderBottomWidth: 1,
|
|
39
|
+
borderColor: Colors.Gray4,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import React, { memo, useCallback, useState } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
4
|
+
|
|
5
|
+
import Text from '../../Text';
|
|
6
|
+
import { ModalCustom } from '../../Modal';
|
|
7
|
+
import ViewButtonBottom from '../../ViewButtonBottom';
|
|
8
|
+
import WheelDateTimePicker from '../../WheelDateTimePicker';
|
|
9
|
+
import moment from 'moment';
|
|
10
|
+
import { useBoolean } from '../../../hooks/Common';
|
|
11
|
+
import RecurringDetail from './RecurringDetail';
|
|
12
|
+
import _TextInput from '../../../commons/Form/TextInput';
|
|
13
|
+
import styles from './MenuActionAddScheduleStyle';
|
|
14
|
+
|
|
15
|
+
const MenuActionAddSchedule = memo(({ visible, hideModal, onItemClick }) => {
|
|
16
|
+
const t = useTranslations();
|
|
17
|
+
|
|
18
|
+
const [stateDateTimePicker, setStateDateTimePicker] = useState({
|
|
19
|
+
isVisible: false,
|
|
20
|
+
mode: 'time',
|
|
21
|
+
defaultValue: moment().valueOf(),
|
|
22
|
+
setter: null,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const [lockShowing, releaseLockShowing, acquireLockShowing] =
|
|
26
|
+
useBoolean(true);
|
|
27
|
+
const [recurringTimeStart, setRecurringTimeStart] = useState('');
|
|
28
|
+
const [recurringTimeEnd, setRecurringTimeEnd] = useState('');
|
|
29
|
+
const [recurringTimeRepeat, setRecurringTimeRepeat] = useState('');
|
|
30
|
+
|
|
31
|
+
const onShowSetDateTime = useCallback(
|
|
32
|
+
(currentValue, setter, mode) => {
|
|
33
|
+
acquireLockShowing();
|
|
34
|
+
setStateDateTimePicker((state) => ({
|
|
35
|
+
...state,
|
|
36
|
+
isVisible: true,
|
|
37
|
+
mode: mode,
|
|
38
|
+
defaultValue: currentValue,
|
|
39
|
+
setter: setter,
|
|
40
|
+
}));
|
|
41
|
+
},
|
|
42
|
+
[setStateDateTimePicker, acquireLockShowing]
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const onDateTimePicked = useCallback(
|
|
46
|
+
(timeData) => {
|
|
47
|
+
const setter = stateDateTimePicker.setter;
|
|
48
|
+
setter && setter(moment(timeData));
|
|
49
|
+
},
|
|
50
|
+
[stateDateTimePicker]
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const onHideSetDateTime = useCallback(() => {
|
|
54
|
+
acquireLockShowing();
|
|
55
|
+
setStateDateTimePicker((state) => ({
|
|
56
|
+
...state,
|
|
57
|
+
isVisible: false,
|
|
58
|
+
}));
|
|
59
|
+
}, [setStateDateTimePicker, acquireLockShowing]);
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<ModalCustom
|
|
63
|
+
isVisible={visible}
|
|
64
|
+
onBackButtonPress={hideModal}
|
|
65
|
+
onBackdropPress={hideModal}
|
|
66
|
+
style={styles.container}
|
|
67
|
+
>
|
|
68
|
+
<View style={styles.popoverStyle}>
|
|
69
|
+
<View style={styles.modalWrapper}>
|
|
70
|
+
<View style={styles.modalHeader}>
|
|
71
|
+
<Text style={styles.modalHeaderText}>{t('add_schedule')}</Text>
|
|
72
|
+
<View style={styles.boder} />
|
|
73
|
+
<RecurringDetail
|
|
74
|
+
onShowSetDateTime={onShowSetDateTime}
|
|
75
|
+
recurringTimeStart={recurringTimeStart}
|
|
76
|
+
recurringTimeEnd={recurringTimeEnd}
|
|
77
|
+
recurringTimeRepeat={recurringTimeRepeat}
|
|
78
|
+
setRecurringTimeStart={setRecurringTimeStart}
|
|
79
|
+
setRecurringTimeEnd={setRecurringTimeEnd}
|
|
80
|
+
setRecurringTimeRepeat={setRecurringTimeRepeat}
|
|
81
|
+
/>
|
|
82
|
+
|
|
83
|
+
<Text style={styles.subName}>{t('schedule_name')}</Text>
|
|
84
|
+
<_TextInput
|
|
85
|
+
placeholder={t('enter_name')}
|
|
86
|
+
wrapStyle={styles.noMarginTop}
|
|
87
|
+
textInputStyle={styles.textInput}
|
|
88
|
+
/>
|
|
89
|
+
<View style={styles.ViewButtonBottom}>
|
|
90
|
+
<ViewButtonBottom
|
|
91
|
+
leftTitle={t('cancel')}
|
|
92
|
+
onLeftClick={hideModal}
|
|
93
|
+
rightTitle={t('done')}
|
|
94
|
+
/>
|
|
95
|
+
</View>
|
|
96
|
+
<WheelDateTimePicker
|
|
97
|
+
mode={stateDateTimePicker.mode}
|
|
98
|
+
isVisible={stateDateTimePicker.isVisible && lockShowing}
|
|
99
|
+
defaultValue={stateDateTimePicker.defaultValue}
|
|
100
|
+
onPicked={onDateTimePicked}
|
|
101
|
+
onCancel={onHideSetDateTime}
|
|
102
|
+
onHide={releaseLockShowing}
|
|
103
|
+
/>
|
|
104
|
+
</View>
|
|
105
|
+
</View>
|
|
106
|
+
</View>
|
|
107
|
+
</ModalCustom>
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
export default MenuActionAddSchedule;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Colors } from '../../../configs';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export default StyleSheet.create({
|
|
5
|
+
container: {
|
|
6
|
+
flex: 1,
|
|
7
|
+
margin: 0,
|
|
8
|
+
},
|
|
9
|
+
popoverStyle: {
|
|
10
|
+
width: '100%',
|
|
11
|
+
backgroundColor: Colors.White,
|
|
12
|
+
bottom: 0,
|
|
13
|
+
left: 0,
|
|
14
|
+
position: 'absolute',
|
|
15
|
+
borderRadius: 10,
|
|
16
|
+
},
|
|
17
|
+
modalWrapper: {
|
|
18
|
+
flex: 1,
|
|
19
|
+
flexDirection: 'column',
|
|
20
|
+
backgroundColor: Colors.White,
|
|
21
|
+
borderRadius: 10,
|
|
22
|
+
},
|
|
23
|
+
modalHeader: {
|
|
24
|
+
padding: 16,
|
|
25
|
+
backgroundColor: Colors.White,
|
|
26
|
+
justifyContent: 'flex-start',
|
|
27
|
+
},
|
|
28
|
+
modalHeaderText: {
|
|
29
|
+
fontSize: 17,
|
|
30
|
+
lineHeight: 24,
|
|
31
|
+
color: Colors.Gray9,
|
|
32
|
+
fontWeight: 'bold',
|
|
33
|
+
borderTopLeftRadius: 20,
|
|
34
|
+
borderTopRightRadius: 20,
|
|
35
|
+
marginVertical: 20,
|
|
36
|
+
},
|
|
37
|
+
boder: {
|
|
38
|
+
borderBottomWidth: 1,
|
|
39
|
+
borderColor: Colors.Gray4,
|
|
40
|
+
},
|
|
41
|
+
subName: {
|
|
42
|
+
color: Colors.Gray8,
|
|
43
|
+
marginTop: 12,
|
|
44
|
+
},
|
|
45
|
+
ViewButtonBottom: {
|
|
46
|
+
borderTopWidth: 1,
|
|
47
|
+
borderTopColor: Colors.Gray4,
|
|
48
|
+
},
|
|
49
|
+
scheduleName: {
|
|
50
|
+
fontSize: 17,
|
|
51
|
+
marginTop: 12,
|
|
52
|
+
color: Colors.Gray9,
|
|
53
|
+
marginBottom: 12,
|
|
54
|
+
},
|
|
55
|
+
noMarginTop: {
|
|
56
|
+
marginTop: 0,
|
|
57
|
+
backgroundColor: Colors.White,
|
|
58
|
+
},
|
|
59
|
+
textInput: {
|
|
60
|
+
marginTop: 0,
|
|
61
|
+
borderWidth: 0,
|
|
62
|
+
borderBottomWidth: 1,
|
|
63
|
+
borderBottomColor: Colors.Gray4,
|
|
64
|
+
paddingLeft: 0,
|
|
65
|
+
backgroundColor: Colors.White,
|
|
66
|
+
fontSize: 17,
|
|
67
|
+
color: Colors.Gray9,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { View, TouchableOpacity } from 'react-native';
|
|
3
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
4
|
+
|
|
5
|
+
import Text from '../../../commons/Text';
|
|
6
|
+
import { Colors } from '../../../configs';
|
|
7
|
+
import { REPEAT_ITEMS } from '../../../screens/GuestInfo/constant';
|
|
8
|
+
import styles from './AccessScheduleDetailStyles';
|
|
9
|
+
|
|
10
|
+
const RecurringDetail = ({
|
|
11
|
+
onShowSetDateTime,
|
|
12
|
+
recurringTimeStart,
|
|
13
|
+
recurringTimeEnd,
|
|
14
|
+
recurringTimeRepeat,
|
|
15
|
+
setRecurringTimeStart,
|
|
16
|
+
setRecurringTimeEnd,
|
|
17
|
+
setRecurringTimeRepeat,
|
|
18
|
+
}) => {
|
|
19
|
+
const t = useTranslations();
|
|
20
|
+
const onSetTimeStart = useCallback(() => {
|
|
21
|
+
onShowSetDateTime();
|
|
22
|
+
}, [onShowSetDateTime]);
|
|
23
|
+
|
|
24
|
+
const onSetTimeEnd = useCallback(() => {
|
|
25
|
+
onShowSetDateTime();
|
|
26
|
+
}, [onShowSetDateTime]);
|
|
27
|
+
|
|
28
|
+
const onSetRepeat = useCallback(
|
|
29
|
+
(item) => {
|
|
30
|
+
const index = recurringTimeRepeat.indexOf(item.value);
|
|
31
|
+
if (index !== -1) {
|
|
32
|
+
setRecurringTimeRepeat([
|
|
33
|
+
...recurringTimeRepeat.slice(0, index),
|
|
34
|
+
...recurringTimeRepeat.slice(index + 1),
|
|
35
|
+
]);
|
|
36
|
+
} else {
|
|
37
|
+
setRecurringTimeRepeat([...recurringTimeRepeat, item.value]);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
[recurringTimeRepeat, setRecurringTimeRepeat]
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const renderRepeatItem = useCallback(
|
|
44
|
+
(item, index, isSelected) => {
|
|
45
|
+
return (
|
|
46
|
+
<TouchableOpacity
|
|
47
|
+
key={index}
|
|
48
|
+
style={[styles.repeatItem, isSelected && styles.repeatItemSelected]}
|
|
49
|
+
onPress={() => onSetRepeat(item)}
|
|
50
|
+
>
|
|
51
|
+
<Text
|
|
52
|
+
type="Body"
|
|
53
|
+
lineHeight={16}
|
|
54
|
+
color={isSelected ? Colors.Orange : item.color}
|
|
55
|
+
style={styles.repeatText}
|
|
56
|
+
>
|
|
57
|
+
{item.text}
|
|
58
|
+
</Text>
|
|
59
|
+
</TouchableOpacity>
|
|
60
|
+
);
|
|
61
|
+
},
|
|
62
|
+
[onSetRepeat]
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<View>
|
|
67
|
+
<Text style={styles.curtainText}>{t('curtain_opens')}</Text>
|
|
68
|
+
<TouchableOpacity onPress={onSetTimeStart}>
|
|
69
|
+
<Text type="Body" color={Colors.Orange} style={styles.value}>
|
|
70
|
+
07:00 AM
|
|
71
|
+
</Text>
|
|
72
|
+
</TouchableOpacity>
|
|
73
|
+
<View style={styles.boder} />
|
|
74
|
+
<Text style={styles.curtainText}>{t('curtain_closes')}</Text>
|
|
75
|
+
<TouchableOpacity onPress={onSetTimeEnd}>
|
|
76
|
+
<Text type="Body" color={Colors.Orange} style={styles.value}>
|
|
77
|
+
12:00 AM
|
|
78
|
+
</Text>
|
|
79
|
+
</TouchableOpacity>
|
|
80
|
+
<View style={styles.boder} />
|
|
81
|
+
<Text type="Body" color={Colors.Gray8} style={styles.title}>
|
|
82
|
+
{t('repeat')}
|
|
83
|
+
</Text>
|
|
84
|
+
<View style={styles.repeatWrap}>
|
|
85
|
+
{REPEAT_ITEMS.map((item, index) =>
|
|
86
|
+
renderRepeatItem(
|
|
87
|
+
item,
|
|
88
|
+
index,
|
|
89
|
+
recurringTimeRepeat.includes(item.value)
|
|
90
|
+
)
|
|
91
|
+
)}
|
|
92
|
+
</View>
|
|
93
|
+
</View>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export default RecurringDetail;
|