@eohjsc/react-native-smart-city 0.4.44 → 0.4.46
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 +5 -1
- package/package.json +1 -2
- package/src/Images/Common/pushpin-full.svg +3 -0
- package/src/Images/Common/pushpin-outline.svg +3 -0
- package/src/Images/Common/star-full.svg +3 -0
- package/src/Images/Common/star-outline.svg +3 -0
- package/src/commons/Dashboard/MyPinnedSharedUnit/index.js +1 -6
- package/src/commons/Device/Hanet/ItemHanetDevice.js +5 -1
- package/src/commons/Device/ItemAddNew/index.js +6 -2
- package/src/commons/Device/ItemDevice.js +5 -1
- package/src/commons/SubUnit/OneTap/ItemOneTap.js +10 -2
- package/src/commons/Unit/HeaderUnit/index.js +5 -1
- package/src/commons/Unit/SharedUnit.js +58 -43
- package/src/commons/Unit/__test__/SharedUnit.test.js +60 -100
- package/src/commons/WrapParallaxScrollView/index.js +4 -0
- package/src/configs/AccessibilityLabel.js +3 -0
- package/src/navigations/AutomateStack.js +5 -2
- package/src/navigations/NotificationStack.js +28 -2
- package/src/navigations/SharedStack.js +8 -2
- package/src/screens/AddNewGateway/ConnectingDevice.js +0 -1
- package/src/screens/AddNewGateway/ShareWifiPassword.js +0 -1
- package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +1 -0
- package/src/screens/Automate/ScriptDetail/index.js +4 -7
- package/src/screens/Device/detail.js +4 -6
- package/src/screens/Notification/__test__/Notification.test.js +14 -8
- package/src/screens/Notification/components/NotificationItem.js +1 -0
- package/src/screens/Notification/index.js +42 -48
- package/src/screens/Notification/styles/indexStyles.js +6 -3
- package/src/screens/SharedUnit/index.js +1 -4
- package/src/screens/Unit/components/SharedUnit/index.js +6 -9
- package/src/screens/Unit/components/__test__/SharedUnit.test.js +19 -15
package/README.md
CHANGED
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
## Getting started
|
|
4
4
|
|
|
5
5
|
1. Install package dependencies:
|
|
6
|
-
|
|
6
|
+
- Using [react-native-get-random-values](https://www.npmjs.com/package/react-native-get-random-values): `yarn add react-native-get-random-values`
|
|
7
|
+
```
|
|
8
|
+
// Add this line to your 'index.js'
|
|
9
|
+
import 'react-native-get-random-values'
|
|
10
|
+
```
|
|
7
11
|
- Using [Yarn](https://yarnpkg.com/): `yarn add react-native-reanimated@^1.10.1`
|
|
8
12
|
|
|
9
13
|
2. Install:
|
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.4.
|
|
4
|
+
"version": "0.4.46",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -175,7 +175,6 @@
|
|
|
175
175
|
"react-native-geocoder": "^0.5.0",
|
|
176
176
|
"react-native-gesture-handler": "^2.10.0",
|
|
177
177
|
"react-native-get-location": "^2.0.0",
|
|
178
|
-
"react-native-get-random-values": "^1.8.0",
|
|
179
178
|
"react-native-image-crop-picker": "^0.37.2",
|
|
180
179
|
"react-native-image-resizer": "^1.4.5",
|
|
181
180
|
"react-native-input-credit-card": "^0.5.5",
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M20.5855 9.18984L14.8105 3.41484C14.6582 3.2625 14.4589 3.1875 14.2597 3.1875C14.0605 3.1875 13.8613 3.2625 13.7089 3.41484L9.93317 7.19297C9.64723 7.16016 9.35895 7.14609 9.07066 7.14609C7.35504 7.14609 5.63941 7.71094 4.23082 8.84063C3.86988 9.12891 3.84176 9.67031 4.16754 9.99844L8.42613 14.257L3.3777 19.3008C3.31583 19.3623 3.27765 19.4436 3.26988 19.5305L3.1902 20.4023C3.1691 20.6227 3.34488 20.8102 3.56285 20.8102C3.57457 20.8102 3.58629 20.8102 3.59801 20.8078L4.46988 20.7281C4.5566 20.7211 4.63863 20.6813 4.69957 20.6203L9.74801 15.5719L14.0066 19.8305C14.1589 19.9828 14.3582 20.0578 14.5574 20.0578C14.7847 20.0578 15.0097 19.9594 15.1644 19.7672C16.4839 18.1195 17.0324 16.057 16.8097 14.0625L20.5855 10.2867C20.8879 9.98672 20.8879 9.49453 20.5855 9.18984Z" fill="#1890FF"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M17.1236 7.6582L12.4395 2.8457C12.3159 2.71875 12.1543 2.65625 11.9927 2.65625C11.8311 2.65625 11.6695 2.71875 11.546 2.8457L8.48339 5.99414C8.25146 5.9668 8.01763 5.95508 7.7838 5.95508C6.39224 5.95508 5.00068 6.42578 3.85815 7.36719C3.78897 7.42426 3.73226 7.49567 3.69172 7.57677C3.65119 7.65786 3.62774 7.74682 3.62289 7.83784C3.61805 7.92887 3.63193 8.01992 3.66362 8.10507C3.69531 8.19021 3.7441 8.26755 3.80682 8.33203L7.26102 11.8809L3.16617 16.084C3.11599 16.1352 3.08503 16.203 3.07873 16.2754L3.01409 17.002C2.99698 17.1855 3.13956 17.3418 3.31636 17.3418C3.32586 17.3418 3.33537 17.3418 3.34487 17.3398L4.05206 17.2734C4.1224 17.2676 4.18893 17.2344 4.23836 17.1836L8.33321 12.9766L11.7874 16.5254C11.911 16.6523 12.0726 16.7148 12.2341 16.7148C12.4185 16.7148 12.601 16.6328 12.7265 16.4727C13.7968 15.0996 14.2416 13.3809 14.061 11.7188L17.1236 8.57227C17.3689 8.32227 17.3689 7.91211 17.1236 7.6582ZM13.0915 10.7285L12.6258 11.207L12.698 11.8789C12.8113 12.9181 12.6094 13.9679 12.1201 14.8848L5.4075 7.98438C5.65274 7.8457 5.90748 7.72852 6.17362 7.63477C6.6907 7.45117 7.2325 7.35938 7.7838 7.35938C7.9663 7.35938 8.1507 7.36914 8.33321 7.39063L8.98716 7.46484L9.45292 6.98633L11.9946 4.375L15.6351 8.11523L13.0915 10.7285Z" fill="#595959"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M21.2841 8.27559L15.3333 7.41075L12.6731 2.01778C12.6005 1.87013 12.4809 1.75059 12.3333 1.67794C11.963 1.49513 11.513 1.64747 11.3278 2.01778L8.66766 7.41075L2.71688 8.27559C2.55282 8.29903 2.40281 8.37638 2.28797 8.49356C2.14913 8.63627 2.07262 8.82825 2.07526 9.02733C2.0779 9.22642 2.15946 9.41631 2.30203 9.55528L6.6075 13.7529L5.59031 19.6803C5.56646 19.8182 5.58172 19.96 5.63436 20.0896C5.687 20.2193 5.77491 20.3316 5.88813 20.4138C6.00135 20.496 6.13535 20.5449 6.27492 20.5549C6.4145 20.5648 6.55407 20.5355 6.67781 20.4701L12.0005 17.6717L17.3231 20.4701C17.4684 20.5475 17.6372 20.5732 17.7989 20.5451C18.2067 20.4748 18.4809 20.0881 18.4106 19.6803L17.3934 13.7529L21.6989 9.55528C21.8161 9.44044 21.8934 9.29044 21.9169 9.12638C21.9802 8.71622 21.6942 8.33653 21.2841 8.27559Z" fill="#FADB14"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M22 9.24L14.81 8.62L12 2L9.19 8.63L2 9.24L7.46 13.97L5.82 21L12 17.27L18.18 21L16.55 13.97L22 9.24ZM12 15.4L8.24 17.67L9.24 13.39L5.92 10.51L10.3 10.13L12 6.1L13.71 10.14L18.09 10.52L14.77 13.4L15.77 17.68L12 15.4Z" fill="#262626"/>
|
|
3
|
+
</svg>
|
|
@@ -96,12 +96,7 @@ const MyPinnedSharedUnit = ({ refreshing }) => {
|
|
|
96
96
|
.filter((sharedUnit) => sharedUnit?.is_pin)
|
|
97
97
|
.map((item, index) => (
|
|
98
98
|
<View key={item.id}>
|
|
99
|
-
<SharedUnit
|
|
100
|
-
item={item}
|
|
101
|
-
index={index}
|
|
102
|
-
navigation={navigation}
|
|
103
|
-
isOptions={false}
|
|
104
|
-
/>
|
|
99
|
+
<SharedUnit item={item} index={index} isOptions={false} />
|
|
105
100
|
{index !== sharedUnits.length - 1 && (
|
|
106
101
|
<View style={styles.separator} />
|
|
107
102
|
)}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { memo } from 'react';
|
|
2
2
|
import {
|
|
3
|
+
Platform,
|
|
3
4
|
StyleSheet,
|
|
4
5
|
TouchableOpacity,
|
|
5
6
|
TouchableWithoutFeedback,
|
|
@@ -58,7 +59,10 @@ const ItemHanetDevice = memo(
|
|
|
58
59
|
{title}
|
|
59
60
|
</Text>
|
|
60
61
|
<View style={styles.row}>
|
|
61
|
-
<IconOutline
|
|
62
|
+
<IconOutline
|
|
63
|
+
name={Platform.OS === 'android' ? 'right-square' : 'right'}
|
|
64
|
+
size={12}
|
|
65
|
+
/>
|
|
62
66
|
</View>
|
|
63
67
|
</TouchableOpacity>
|
|
64
68
|
</View>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { memo } from 'react';
|
|
2
|
-
import { TouchableWithoutFeedback, View } from 'react-native';
|
|
2
|
+
import { Platform, TouchableWithoutFeedback, View } from 'react-native';
|
|
3
3
|
import { IconOutline } from '@ant-design/icons-react-native';
|
|
4
4
|
import Text from '../../Text';
|
|
5
5
|
|
|
@@ -16,7 +16,11 @@ const ItemAddNew = memo(({ title, onAddNew, wrapStyle }) => {
|
|
|
16
16
|
<View style={[styles.container, wrapStyle]}>
|
|
17
17
|
<View style={styles.boxIcon}>
|
|
18
18
|
<View style={styles.buttonPlus}>
|
|
19
|
-
<IconOutline
|
|
19
|
+
<IconOutline
|
|
20
|
+
name={Platform.OS === 'android' ? 'plus-square' : 'plus'}
|
|
21
|
+
size={22}
|
|
22
|
+
color={Colors.Gray8}
|
|
23
|
+
/>
|
|
20
24
|
</View>
|
|
21
25
|
</View>
|
|
22
26
|
<View>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { memo, useCallback } from 'react';
|
|
2
2
|
import {
|
|
3
|
+
Platform,
|
|
3
4
|
StyleSheet,
|
|
4
5
|
TouchableOpacity,
|
|
5
6
|
TouchableWithoutFeedback,
|
|
@@ -159,7 +160,10 @@ const ItemDevice = memo(
|
|
|
159
160
|
>
|
|
160
161
|
{description || textConnected}
|
|
161
162
|
</Text>
|
|
162
|
-
<IconOutline
|
|
163
|
+
<IconOutline
|
|
164
|
+
name={Platform.OS === 'android' ? 'right-square' : 'right'}
|
|
165
|
+
size={12}
|
|
166
|
+
/>
|
|
163
167
|
</View>
|
|
164
168
|
</TouchableOpacity>
|
|
165
169
|
</View>
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import React, { memo, useCallback } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Platform,
|
|
4
|
+
TouchableOpacity,
|
|
5
|
+
TouchableWithoutFeedback,
|
|
6
|
+
View,
|
|
7
|
+
} from 'react-native';
|
|
3
8
|
import { IconOutline } from '@ant-design/icons-react-native';
|
|
4
9
|
import moment from 'moment';
|
|
5
10
|
import Text from '../../Text';
|
|
@@ -106,7 +111,10 @@ const ItemOneTap = memo(({ automate = {}, wrapSyles, onPressItem }) => {
|
|
|
106
111
|
>
|
|
107
112
|
{activateAt && t('activated_time', { time: activateAt })}
|
|
108
113
|
</Text>
|
|
109
|
-
<IconOutline
|
|
114
|
+
<IconOutline
|
|
115
|
+
name={Platform.OS === 'android' ? 'right-square' : 'right'}
|
|
116
|
+
size={12}
|
|
117
|
+
/>
|
|
110
118
|
</View>
|
|
111
119
|
</TouchableOpacity>
|
|
112
120
|
</View>
|
|
@@ -22,6 +22,7 @@ const HeaderUnit = memo(
|
|
|
22
22
|
styleBoxTitle,
|
|
23
23
|
bottomBorder,
|
|
24
24
|
idButtonMore = AccessibilityLabel.HEADER_UNIT_BUTTON_MORE,
|
|
25
|
+
iconBackStyle,
|
|
25
26
|
}) => {
|
|
26
27
|
const { goBack } = useNavigation();
|
|
27
28
|
const buttonMoreRef = useRef(null);
|
|
@@ -49,7 +50,10 @@ const HeaderUnit = memo(
|
|
|
49
50
|
style={styles.btnLeft}
|
|
50
51
|
onPress={onPressBack}
|
|
51
52
|
>
|
|
52
|
-
<Image
|
|
53
|
+
<Image
|
|
54
|
+
source={Images.arrowLeft}
|
|
55
|
+
style={[styles.iconBack, iconBackStyle]}
|
|
56
|
+
/>
|
|
53
57
|
</TouchableOpacity>
|
|
54
58
|
<View style={[styles.boxTitle, styleBoxTitle]}>
|
|
55
59
|
{title && (
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import React, { Fragment, useCallback } from 'react';
|
|
2
2
|
import { View, Image, TouchableOpacity } from 'react-native';
|
|
3
3
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
4
|
-
import { IconOutline, IconFill } from '@ant-design/icons-react-native';
|
|
5
4
|
|
|
6
|
-
import { API,
|
|
5
|
+
import { API, Images } from '../../configs';
|
|
7
6
|
import Text from '../../commons/Text';
|
|
8
7
|
import Routes from '../../utils/Route';
|
|
9
8
|
import { axiosPost } from '../../utils/Apis/axios';
|
|
9
|
+
import StarFull from '../../Images/Common/star-full.svg';
|
|
10
|
+
import StarOutline from '../../Images/Common/star-outline.svg';
|
|
11
|
+
import PushPinFull from '../../Images/Common/pushpin-full.svg';
|
|
12
|
+
import PushPinOutline from '../../Images/Common/pushpin-outline.svg';
|
|
10
13
|
|
|
11
14
|
import styles from './styles';
|
|
12
15
|
import { AccessibilityLabel } from '../../configs/Constants';
|
|
16
|
+
import { useNavigation } from '@react-navigation/native';
|
|
13
17
|
|
|
14
|
-
const SharedUnit = ({
|
|
15
|
-
item,
|
|
16
|
-
navigation,
|
|
17
|
-
renewItem,
|
|
18
|
-
index,
|
|
19
|
-
isOptions = true,
|
|
20
|
-
}) => {
|
|
18
|
+
const SharedUnit = ({ item, renewItem, index, isOptions = true }) => {
|
|
21
19
|
const { unit } = item;
|
|
22
20
|
const t = useTranslations();
|
|
21
|
+
const { navigate } = useNavigation();
|
|
22
|
+
|
|
23
23
|
const goToDetail = useCallback(() => {
|
|
24
|
-
|
|
24
|
+
navigate(Routes.UnitStack, {
|
|
25
25
|
screen: Routes.UnitDetail,
|
|
26
26
|
params: {
|
|
27
27
|
unitId: unit.id,
|
|
28
28
|
unitData: unit,
|
|
29
29
|
},
|
|
30
30
|
});
|
|
31
|
-
}, [
|
|
31
|
+
}, [navigate, unit]);
|
|
32
32
|
|
|
33
33
|
const removePinSharedUnit = useCallback(async () => {
|
|
34
34
|
const { success } = await axiosPost(API.UNIT.UNPIN_UNIT(unit.id));
|
|
@@ -37,6 +37,7 @@ const SharedUnit = ({
|
|
|
37
37
|
renewItem(index);
|
|
38
38
|
}
|
|
39
39
|
}, [renewItem, index, unit, item]);
|
|
40
|
+
|
|
40
41
|
const addPinSharedUnit = useCallback(async () => {
|
|
41
42
|
const { success } = await axiosPost(API.UNIT.PIN_UNIT(unit.id));
|
|
42
43
|
|
|
@@ -45,6 +46,7 @@ const SharedUnit = ({
|
|
|
45
46
|
renewItem(index);
|
|
46
47
|
}
|
|
47
48
|
}, [renewItem, index, unit, item]);
|
|
49
|
+
|
|
48
50
|
const removeStarSharedUnit = useCallback(async () => {
|
|
49
51
|
const { success } = await axiosPost(API.UNIT.UNSTAR_UNIT(unit.id));
|
|
50
52
|
if (success) {
|
|
@@ -52,6 +54,15 @@ const SharedUnit = ({
|
|
|
52
54
|
renewItem(index);
|
|
53
55
|
}
|
|
54
56
|
}, [renewItem, index, unit, item]);
|
|
57
|
+
|
|
58
|
+
const onChangePin = useCallback(() => {
|
|
59
|
+
if (item.is_pin) {
|
|
60
|
+
removePinSharedUnit();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
addPinSharedUnit();
|
|
64
|
+
}, [addPinSharedUnit, item.is_pin, removePinSharedUnit]);
|
|
65
|
+
|
|
55
66
|
const addStarSharedUnit = useCallback(async () => {
|
|
56
67
|
const { success } = await axiosPost(API.UNIT.STAR_UNIT(unit.id));
|
|
57
68
|
if (success) {
|
|
@@ -60,6 +71,14 @@ const SharedUnit = ({
|
|
|
60
71
|
}
|
|
61
72
|
}, [renewItem, index, unit, item]);
|
|
62
73
|
|
|
74
|
+
const onChangeFavorite = useCallback(() => {
|
|
75
|
+
if (item.is_star) {
|
|
76
|
+
removeStarSharedUnit();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
addStarSharedUnit();
|
|
80
|
+
}, [addStarSharedUnit, item.is_star, removeStarSharedUnit]);
|
|
81
|
+
|
|
63
82
|
const justifyContent = isOptions ? 'space-around' : 'flex-end';
|
|
64
83
|
|
|
65
84
|
return (
|
|
@@ -90,38 +109,34 @@ const SharedUnit = ({
|
|
|
90
109
|
<View style={[styles.rowAction, { justifyContent: justifyContent }]}>
|
|
91
110
|
{isOptions && (
|
|
92
111
|
<Fragment>
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
onPress={addStarSharedUnit}
|
|
122
|
-
accessibilityLabel={`${AccessibilityLabel.ICON_ADD_STAR_SHARED_UNIT}-${item.id}`}
|
|
123
|
-
/>
|
|
124
|
-
)}
|
|
112
|
+
<TouchableOpacity
|
|
113
|
+
onPress={onChangePin}
|
|
114
|
+
accessibilityLabel={AccessibilityLabel.PIN_BUTTON}
|
|
115
|
+
>
|
|
116
|
+
{item.is_pin ? (
|
|
117
|
+
<PushPinFull
|
|
118
|
+
accessibilityLabel={`${AccessibilityLabel.ICON_REMOVE_PIN_SHARED_UNIT}-${item.id}`}
|
|
119
|
+
/>
|
|
120
|
+
) : (
|
|
121
|
+
<PushPinOutline
|
|
122
|
+
accessibilityLabel={`${AccessibilityLabel.ICON_ADD_PIN_SHARED_UNIT}-${item.id}`}
|
|
123
|
+
/>
|
|
124
|
+
)}
|
|
125
|
+
</TouchableOpacity>
|
|
126
|
+
<TouchableOpacity
|
|
127
|
+
onPress={onChangeFavorite}
|
|
128
|
+
accessibilityLabel={AccessibilityLabel.STAR_BUTTON}
|
|
129
|
+
>
|
|
130
|
+
{item.is_star ? (
|
|
131
|
+
<StarFull
|
|
132
|
+
accessibilityLabel={`${AccessibilityLabel.ICON_REMOVE_STAR_SHARED_UNIT}-${item.id}`}
|
|
133
|
+
/>
|
|
134
|
+
) : (
|
|
135
|
+
<StarOutline
|
|
136
|
+
accessibilityLabel={`${AccessibilityLabel.ICON_ADD_STAR_SHARED_UNIT}-${item.id}`}
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
139
|
+
</TouchableOpacity>
|
|
125
140
|
</Fragment>
|
|
126
141
|
)}
|
|
127
142
|
</View>
|
|
@@ -7,7 +7,6 @@ import MockAdapter from 'axios-mock-adapter';
|
|
|
7
7
|
import SharedUnit from '../SharedUnit';
|
|
8
8
|
import { AccessibilityLabel } from '../../../configs/Constants';
|
|
9
9
|
import { API } from '../../../configs';
|
|
10
|
-
import Routes from '../../../utils/Route';
|
|
11
10
|
import { SCProvider } from '../../../context';
|
|
12
11
|
import { mockSCStore } from '../../../context/mockStore';
|
|
13
12
|
import api from '../../../utils/Apis/axios';
|
|
@@ -24,14 +23,9 @@ jest.mock('@react-navigation/native', () => {
|
|
|
24
23
|
};
|
|
25
24
|
});
|
|
26
25
|
|
|
27
|
-
const wrapComponent = (item,
|
|
26
|
+
const wrapComponent = (item, isOptions, mockedRenewItem) => (
|
|
28
27
|
<SCProvider initState={mockSCStore({})}>
|
|
29
|
-
<SharedUnit
|
|
30
|
-
item={item}
|
|
31
|
-
navigation={navigation}
|
|
32
|
-
isOptions={isOptions}
|
|
33
|
-
renewItem={mockedRenewItem}
|
|
34
|
-
/>
|
|
28
|
+
<SharedUnit item={item} isOptions={isOptions} renewItem={mockedRenewItem} />
|
|
35
29
|
</SCProvider>
|
|
36
30
|
);
|
|
37
31
|
|
|
@@ -58,68 +52,6 @@ describe('Test SharedUnit', () => {
|
|
|
58
52
|
};
|
|
59
53
|
});
|
|
60
54
|
|
|
61
|
-
it('test create SharedUnit unit is not pin, not star', async () => {
|
|
62
|
-
const navigation = useNavigation();
|
|
63
|
-
const mockedRenewItem = jest.fn();
|
|
64
|
-
await act(async () => {
|
|
65
|
-
tree = await create(
|
|
66
|
-
wrapComponent(item, navigation, true, mockedRenewItem)
|
|
67
|
-
);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
await act(async () => {
|
|
71
|
-
tree = await create(wrapComponent(item, navigation));
|
|
72
|
-
});
|
|
73
|
-
const instance = tree.root;
|
|
74
|
-
const touchSharedUnit = instance.find(
|
|
75
|
-
(el) =>
|
|
76
|
-
el.props.accessibilityLabel ===
|
|
77
|
-
AccessibilityLabel.TOUCH_SHARED_UNIT + '-69'
|
|
78
|
-
);
|
|
79
|
-
await act(async () => {
|
|
80
|
-
touchSharedUnit.props.onPress();
|
|
81
|
-
});
|
|
82
|
-
const iconRemovePinSharedUnit = instance.findAll(
|
|
83
|
-
(el) =>
|
|
84
|
-
el.props.accessibilityLabel ===
|
|
85
|
-
AccessibilityLabel.ICON_REMOVE_PIN_SHARED_UNIT + '-69'
|
|
86
|
-
);
|
|
87
|
-
const iconAddPinSharedUnit = instance.find(
|
|
88
|
-
(el) =>
|
|
89
|
-
el.props.accessibilityLabel ===
|
|
90
|
-
AccessibilityLabel.ICON_ADD_PIN_SHARED_UNIT + '-69'
|
|
91
|
-
);
|
|
92
|
-
mock.onPost(API.UNIT.PIN_UNIT(3)).reply(200);
|
|
93
|
-
await act(async () => {
|
|
94
|
-
iconAddPinSharedUnit.props.onPress();
|
|
95
|
-
});
|
|
96
|
-
mock.onPost(API.UNIT.PIN_UNIT(3)).reply(400);
|
|
97
|
-
await act(async () => {
|
|
98
|
-
iconAddPinSharedUnit.props.onPress();
|
|
99
|
-
});
|
|
100
|
-
const iconAddStarSharedUnit = instance.find(
|
|
101
|
-
(el) =>
|
|
102
|
-
el.props.accessibilityLabel ===
|
|
103
|
-
AccessibilityLabel.ICON_ADD_STAR_SHARED_UNIT + '-69'
|
|
104
|
-
);
|
|
105
|
-
mock.onPost(API.UNIT.STAR_UNIT(3)).reply(200);
|
|
106
|
-
await act(async () => {
|
|
107
|
-
iconAddStarSharedUnit.props.onPress();
|
|
108
|
-
});
|
|
109
|
-
mock.onPost(API.UNIT.STAR_UNIT(3)).reply(400);
|
|
110
|
-
await act(async () => {
|
|
111
|
-
iconAddStarSharedUnit.props.onPress();
|
|
112
|
-
});
|
|
113
|
-
expect(iconRemovePinSharedUnit).toHaveLength(0);
|
|
114
|
-
expect(mockNavigate).toHaveBeenCalledWith(Routes.UnitStack, {
|
|
115
|
-
screen: Routes.UnitDetail,
|
|
116
|
-
params: {
|
|
117
|
-
unitId: 3,
|
|
118
|
-
unitData: unit,
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
55
|
it('test create SharedUnit unit without unit owner', async () => {
|
|
124
56
|
const navigation = useNavigation();
|
|
125
57
|
delete unit.owner_name;
|
|
@@ -155,50 +87,78 @@ describe('Test SharedUnit', () => {
|
|
|
155
87
|
AccessibilityLabel.ICON_ADD_STAR_SHARED_UNIT + '-69'
|
|
156
88
|
);
|
|
157
89
|
|
|
158
|
-
expect(iconAddPinSharedUnit).toHaveLength(
|
|
159
|
-
expect(iconStarUnit).toHaveLength(
|
|
90
|
+
expect(iconAddPinSharedUnit).toHaveLength(1);
|
|
91
|
+
expect(iconStarUnit).toHaveLength(1);
|
|
160
92
|
});
|
|
161
93
|
|
|
162
|
-
it('
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
94
|
+
it('Test go to detail', async () => {
|
|
95
|
+
await act(async () => {
|
|
96
|
+
tree = await create(wrapComponent(item, false));
|
|
97
|
+
});
|
|
98
|
+
const instance = tree.root;
|
|
99
|
+
const button = instance.findByProps({
|
|
100
|
+
accessibilityLabel: AccessibilityLabel.TOUCH_SHARED_UNIT + '-69',
|
|
101
|
+
});
|
|
102
|
+
await act(async () => {
|
|
103
|
+
await button.props.onPress();
|
|
104
|
+
});
|
|
105
|
+
expect(mockNavigate).toHaveBeenCalledWith('UnitStack', {
|
|
106
|
+
params: {
|
|
107
|
+
unitData: {
|
|
108
|
+
background: '',
|
|
109
|
+
icon: '',
|
|
110
|
+
id: 3,
|
|
111
|
+
name: 'name',
|
|
112
|
+
owner_name: 'owner_name',
|
|
113
|
+
short_summaries: [],
|
|
114
|
+
},
|
|
115
|
+
unitId: 3,
|
|
116
|
+
},
|
|
117
|
+
screen: 'UnitDetail',
|
|
118
|
+
});
|
|
119
|
+
});
|
|
166
120
|
|
|
121
|
+
it('Test pin then unpin unit', async () => {
|
|
122
|
+
const mockedRenewItem = jest.fn();
|
|
167
123
|
await act(async () => {
|
|
168
|
-
tree = await create(wrapComponent(item,
|
|
124
|
+
tree = await create(wrapComponent(item, true, mockedRenewItem));
|
|
169
125
|
});
|
|
170
126
|
const instance = tree.root;
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
)
|
|
127
|
+
const pinButton = instance.findByProps({
|
|
128
|
+
accessibilityLabel: AccessibilityLabel.PIN_BUTTON,
|
|
129
|
+
});
|
|
130
|
+
mock.onPost(API.UNIT.PIN_UNIT(3)).reply(200);
|
|
131
|
+
await act(async () => {
|
|
132
|
+
await pinButton.props.onPress();
|
|
133
|
+
});
|
|
134
|
+
expect(mockedRenewItem).toBeCalledTimes(1);
|
|
135
|
+
|
|
176
136
|
mock.onPost(API.UNIT.UNPIN_UNIT(3)).reply(200);
|
|
177
137
|
await act(async () => {
|
|
178
|
-
|
|
138
|
+
await pinButton.props.onPress();
|
|
179
139
|
});
|
|
180
|
-
|
|
140
|
+
expect(mockedRenewItem).toBeCalledTimes(2);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('Test add then remove favorite unit', async () => {
|
|
144
|
+
const mockedRenewItem = jest.fn();
|
|
181
145
|
await act(async () => {
|
|
182
|
-
|
|
146
|
+
tree = await create(wrapComponent(item, true, mockedRenewItem));
|
|
183
147
|
});
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
);
|
|
189
|
-
mock.onPost(API.UNIT.UNSTAR_UNIT(3)).reply(200);
|
|
148
|
+
const instance = tree.root;
|
|
149
|
+
const pinButton = instance.findByProps({
|
|
150
|
+
accessibilityLabel: AccessibilityLabel.STAR_BUTTON,
|
|
151
|
+
});
|
|
152
|
+
mock.onPost(API.UNIT.STAR_UNIT(3)).reply(200);
|
|
190
153
|
await act(async () => {
|
|
191
|
-
|
|
154
|
+
await pinButton.props.onPress();
|
|
192
155
|
});
|
|
193
|
-
|
|
156
|
+
expect(mockedRenewItem).toBeCalledTimes(1);
|
|
157
|
+
|
|
158
|
+
mock.onPost(API.UNIT.UNSTAR_UNIT(3)).reply(200);
|
|
194
159
|
await act(async () => {
|
|
195
|
-
|
|
160
|
+
await pinButton.props.onPress();
|
|
196
161
|
});
|
|
197
|
-
|
|
198
|
-
(el) =>
|
|
199
|
-
el.props.accessibilityLabel ===
|
|
200
|
-
AccessibilityLabel.ICON_REMOVE_STAR_SHARED_UNIT + '-69'
|
|
201
|
-
);
|
|
202
|
-
expect(iconRemoveStar).toHaveLength(3);
|
|
162
|
+
expect(mockedRenewItem).toBeCalledTimes(2);
|
|
203
163
|
});
|
|
204
164
|
});
|
|
@@ -88,6 +88,7 @@ const WrapParallaxScrollView = ({
|
|
|
88
88
|
hideRight={hideRight}
|
|
89
89
|
hideRightPlus={hideRightPlus}
|
|
90
90
|
idButtonMore={idButtonMore}
|
|
91
|
+
iconBackStyle={styles.iconBackStyle}
|
|
91
92
|
/>
|
|
92
93
|
</View>
|
|
93
94
|
),
|
|
@@ -136,4 +137,7 @@ const styles = StyleSheet.create({
|
|
|
136
137
|
position: 'absolute',
|
|
137
138
|
bottom: 40,
|
|
138
139
|
},
|
|
140
|
+
iconBackStyle: {
|
|
141
|
+
tintColor: Colors.Black,
|
|
142
|
+
},
|
|
139
143
|
});
|
|
@@ -126,6 +126,8 @@ export default {
|
|
|
126
126
|
HORIZONTAL_BAR_CHART: 'HORIZONTAL_BAR_CHART',
|
|
127
127
|
DEVICE_SHOW_REMOVE: 'DEVICE_SHOW_REMOVE',
|
|
128
128
|
DEVICE_SHOW_RENAME: 'DEVICE_SHOW_RENAME',
|
|
129
|
+
PIN_BUTTON: 'PIN_BUTTON',
|
|
130
|
+
STAR_BUTTON: 'STAR_BUTTON',
|
|
129
131
|
|
|
130
132
|
// common
|
|
131
133
|
COMMON_LOADING_ANIMATION: 'COMMON_LOADING_ANIMATION',
|
|
@@ -673,6 +675,7 @@ export default {
|
|
|
673
675
|
GATEWAY_CONNECTION_METHODS_TEXT: 'GATEWAY_CONNECTION_METHODS_TEXT',
|
|
674
676
|
//Notification
|
|
675
677
|
CUSTOM_TEXT: 'CUSTOM_TEXT',
|
|
678
|
+
NotificationItemText: 'NotificationItemText',
|
|
676
679
|
//ButtonWrapper
|
|
677
680
|
BUTTON_WRAPPER: 'BUTTON_WRAPPER',
|
|
678
681
|
//devmod
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { memo, useCallback, useEffect, useContext } from 'react';
|
|
2
|
-
import { TouchableOpacity } from 'react-native';
|
|
2
|
+
import { Platform, TouchableOpacity } from 'react-native';
|
|
3
3
|
import { createStackNavigator } from '@react-navigation/stack';
|
|
4
4
|
import { useNavigation } from '@react-navigation/core';
|
|
5
5
|
import { Icon } from '@ant-design/react-native';
|
|
@@ -44,7 +44,10 @@ const AutomateStack = memo(() => {
|
|
|
44
44
|
title: t('smart'),
|
|
45
45
|
headerLeft: () => (
|
|
46
46
|
<TouchableOpacity style={Theme.menuIcon} onPress={toggleDrawer}>
|
|
47
|
-
<Icon
|
|
47
|
+
<Icon
|
|
48
|
+
name={Platform.OS === 'android' ? 'menu-unfold' : 'menu'}
|
|
49
|
+
color={Colors.Black}
|
|
50
|
+
/>
|
|
48
51
|
</TouchableOpacity>
|
|
49
52
|
),
|
|
50
53
|
headerTitleAlign: 'left',
|
|
@@ -1,18 +1,44 @@
|
|
|
1
|
-
import React, { memo } from 'react';
|
|
1
|
+
import React, { memo, useCallback } from 'react';
|
|
2
2
|
import { createStackNavigator } from '@react-navigation/stack';
|
|
3
3
|
|
|
4
4
|
import Routes from '../utils/Route';
|
|
5
5
|
import Notification from '../screens/Notification';
|
|
6
6
|
import { screenOptions } from './utils';
|
|
7
|
+
import { TouchableOpacity } from 'react-native';
|
|
8
|
+
import { Colors, Theme } from '../configs';
|
|
9
|
+
import { useNavigation } from '@react-navigation/native';
|
|
10
|
+
import { Icon } from '@ant-design/react-native';
|
|
11
|
+
import { useTranslations } from '../hooks/Common/useTranslations';
|
|
12
|
+
import { Platform } from 'react-native';
|
|
7
13
|
|
|
8
14
|
const Stack = createStackNavigator();
|
|
9
15
|
|
|
10
16
|
const NotificationStack = memo(() => {
|
|
17
|
+
const navigation = useNavigation();
|
|
18
|
+
const t = useTranslations();
|
|
19
|
+
|
|
20
|
+
const toggleDrawer = useCallback(() => {
|
|
21
|
+
navigation.toggleDrawer();
|
|
22
|
+
}, [navigation]);
|
|
23
|
+
|
|
11
24
|
return (
|
|
12
25
|
<Stack.Navigator
|
|
13
26
|
screenOptions={{
|
|
14
27
|
...screenOptions,
|
|
15
|
-
headerShown:
|
|
28
|
+
headerShown: true,
|
|
29
|
+
title: t('notifications'),
|
|
30
|
+
headerLeft: () => (
|
|
31
|
+
<TouchableOpacity style={Theme.menuIcon} onPress={toggleDrawer}>
|
|
32
|
+
<Icon
|
|
33
|
+
name={Platform.OS === 'android' ? 'menu-unfold' : 'menu'}
|
|
34
|
+
color={Colors.Black}
|
|
35
|
+
/>
|
|
36
|
+
</TouchableOpacity>
|
|
37
|
+
),
|
|
38
|
+
headerTitleAlign: 'left',
|
|
39
|
+
headerStyle: {
|
|
40
|
+
backgroundColor: Colors.Gray2,
|
|
41
|
+
},
|
|
16
42
|
}}
|
|
17
43
|
>
|
|
18
44
|
<Stack.Screen name={Routes.Notification} component={Notification} />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { memo } from 'react';
|
|
2
2
|
import { createStackNavigator } from '@react-navigation/stack';
|
|
3
|
-
import { TouchableOpacity, StyleSheet } from 'react-native';
|
|
3
|
+
import { TouchableOpacity, StyleSheet, Platform } from 'react-native';
|
|
4
4
|
import { useNavigation, useRoute } from '@react-navigation/native';
|
|
5
5
|
import { Icon } from '@ant-design/react-native';
|
|
6
6
|
import { useTranslations } from '../hooks/Common/useTranslations';
|
|
@@ -29,7 +29,13 @@ const SharedStack = memo(() => {
|
|
|
29
29
|
onPress={() => (params?.isMainSource ? toggleDrawer() : goBack())}
|
|
30
30
|
>
|
|
31
31
|
<Icon
|
|
32
|
-
name={
|
|
32
|
+
name={
|
|
33
|
+
params?.isMainSource
|
|
34
|
+
? Platform.OS === 'android'
|
|
35
|
+
? 'menu-unfold'
|
|
36
|
+
: 'menu'
|
|
37
|
+
: 'arrow-left'
|
|
38
|
+
}
|
|
33
39
|
color={Colors.Black}
|
|
34
40
|
/>
|
|
35
41
|
</TouchableOpacity>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
|
2
2
|
import { useNavigation } from '@react-navigation/native';
|
|
3
3
|
import { Alert } from 'react-native';
|
|
4
|
-
import 'react-native-get-random-values';
|
|
5
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
6
5
|
|
|
7
6
|
import Processing from '../../commons/Processing';
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
import dgram from 'react-native-udp';
|
|
16
16
|
import { useNavigation, useIsFocused } from '@react-navigation/native';
|
|
17
17
|
import LottieView from 'lottie-react-native';
|
|
18
|
-
import 'react-native-get-random-values';
|
|
19
18
|
import { v4 as uuidv4 } from 'uuid';
|
|
20
19
|
|
|
21
20
|
import { ToastBottomHelper } from '../../utils/Utils';
|
|
@@ -7,7 +7,6 @@ import React, {
|
|
|
7
7
|
} from 'react';
|
|
8
8
|
import { Image, Platform, TouchableOpacity, View } from 'react-native';
|
|
9
9
|
import { PopoverMode } from 'react-native-popover-view';
|
|
10
|
-
import { IconFill, IconOutline } from '@ant-design/icons-react-native';
|
|
11
10
|
import { Icon } from '@ant-design/react-native';
|
|
12
11
|
|
|
13
12
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
@@ -31,6 +30,8 @@ import RenameScript from './Components/RenameScript';
|
|
|
31
30
|
import DeleteScript from './Components/DeleteScript';
|
|
32
31
|
import Images from '../../../configs/Images';
|
|
33
32
|
import { useBackendPermission } from '../../../utils/Permission/backend';
|
|
33
|
+
import StarFull from '../../../Images/Common/star-full.svg';
|
|
34
|
+
import StarOutline from '../../../Images/Common/star-outline.svg';
|
|
34
35
|
|
|
35
36
|
const PreventDoubleTouch = withPreventDoubleClick(TouchableOpacity);
|
|
36
37
|
|
|
@@ -160,7 +161,7 @@ const ScriptDetail = ({ route }) => {
|
|
|
160
161
|
style={[styles.headerButton, styles.moreButton]}
|
|
161
162
|
accessibilityLabel={AccessibilityLabel.ICON_MORE}
|
|
162
163
|
>
|
|
163
|
-
<Icon name={'
|
|
164
|
+
<Icon name={'ellipsis'} size={27} color={Colors.Black} />
|
|
164
165
|
</TouchableOpacity>
|
|
165
166
|
</View>
|
|
166
167
|
),
|
|
@@ -376,11 +377,7 @@ const ButtonStar = ({ automate }) => {
|
|
|
376
377
|
onPress={onPressStar}
|
|
377
378
|
accessibilityLabel={AccessibilityLabel.HEADER_SCRIPT_DETAIL_BUTTON_STAR}
|
|
378
379
|
>
|
|
379
|
-
{isStarred ?
|
|
380
|
-
<IconFill name="star" size={25} color={Colors.Yellow6} />
|
|
381
|
-
) : (
|
|
382
|
-
<IconOutline name="star" size={25} />
|
|
383
|
-
)}
|
|
380
|
+
{isStarred ? <StarFull /> : <StarOutline />}
|
|
384
381
|
</PreventDoubleTouch>
|
|
385
382
|
);
|
|
386
383
|
};
|
|
@@ -8,7 +8,7 @@ import React, {
|
|
|
8
8
|
} from 'react';
|
|
9
9
|
import { View, TouchableOpacity, Platform } from 'react-native';
|
|
10
10
|
import { useNavigation, useFocusEffect } from '@react-navigation/native';
|
|
11
|
-
import { IconFill
|
|
11
|
+
import { IconFill } from '@ant-design/icons-react-native';
|
|
12
12
|
import { Icon } from '@ant-design/react-native';
|
|
13
13
|
import moment from 'moment';
|
|
14
14
|
|
|
@@ -47,6 +47,8 @@ import { SensorDisplayItem } from './components/SensorDisplayItem';
|
|
|
47
47
|
import { EmergencyCountdown } from './components/EmergencyCountdown';
|
|
48
48
|
import { SensorConnectStatusViewHeader } from './components/SensorConnectStatusViewHeader';
|
|
49
49
|
import PreventAccess from '../../commons/PreventAccess';
|
|
50
|
+
import StarFull from '../../Images/Common/star-full.svg';
|
|
51
|
+
import StarOutline from '../../Images/Common/star-outline.svg';
|
|
50
52
|
|
|
51
53
|
import styles from './styles';
|
|
52
54
|
import Routes from '../../utils/Route';
|
|
@@ -676,11 +678,7 @@ const DeviceDetail = ({ route }) => {
|
|
|
676
678
|
onPress={isFavorite ? removeFromFavorites : addToFavorites}
|
|
677
679
|
accessibilityLabel={AccessibilityLabel.HEADER_DEVICE_BUTTON_STAR}
|
|
678
680
|
>
|
|
679
|
-
{isFavorite ?
|
|
680
|
-
<IconFill name="star" size={25} color={Colors.Yellow6} />
|
|
681
|
-
) : (
|
|
682
|
-
<IconOutline name="star" size={25} />
|
|
683
|
-
)}
|
|
681
|
+
{isFavorite ? <StarFull /> : <StarOutline />}
|
|
684
682
|
</TouchableOpacity>
|
|
685
683
|
|
|
686
684
|
{isShowSetupEmergencyContact && (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { act, create } from 'react-test-renderer';
|
|
3
3
|
import MockAdapter from 'axios-mock-adapter';
|
|
4
|
-
import {
|
|
4
|
+
import { FlatList, RefreshControl } from 'react-native';
|
|
5
5
|
import { NavigationContext } from '@react-navigation/native';
|
|
6
6
|
|
|
7
7
|
import { SCProvider } from '../../../context';
|
|
@@ -10,7 +10,8 @@ import Notification from '../index';
|
|
|
10
10
|
import NotificationItem from '../components/NotificationItem';
|
|
11
11
|
import { API } from '../../../configs';
|
|
12
12
|
import api from '../../../utils/Apis/axios';
|
|
13
|
-
import {
|
|
13
|
+
import { Text } from '../../../commons';
|
|
14
|
+
import AccessibilityLabel from '../../../configs/AccessibilityLabel';
|
|
14
15
|
|
|
15
16
|
const wrapComponent = () => (
|
|
16
17
|
<SCProvider initState={mockSCStore({})}>
|
|
@@ -105,17 +106,22 @@ describe('test Notification', () => {
|
|
|
105
106
|
tree = await create(wrapComponent());
|
|
106
107
|
});
|
|
107
108
|
const instance = tree.root;
|
|
108
|
-
const
|
|
109
|
-
expect(wrapHeaderScrollable.props.disableLoadMore).toEqual(false);
|
|
110
|
-
|
|
111
|
-
const scrollView = instance.findByType(Animated.ScrollView);
|
|
109
|
+
const flatlist = instance.findByType(FlatList);
|
|
112
110
|
mock
|
|
113
111
|
.onGet(API.NOTIFICATION.LIST_EOH_NOTIFICATIONS(2, ''))
|
|
114
112
|
.reply(200, response);
|
|
115
113
|
await act(async () => {
|
|
116
|
-
|
|
114
|
+
await flatlist.props.onMomentumScrollBegin();
|
|
115
|
+
await flatlist.props.onEndReached();
|
|
117
116
|
});
|
|
118
|
-
|
|
117
|
+
const notificationItemTexts = instance.findAll(
|
|
118
|
+
(el) =>
|
|
119
|
+
el.type === Text &&
|
|
120
|
+
el.props.accessibilityLabel === AccessibilityLabel.NotificationItemText
|
|
121
|
+
);
|
|
122
|
+
expect(notificationItemTexts[2].props.children).toBe(
|
|
123
|
+
' invited you to join '
|
|
124
|
+
);
|
|
119
125
|
});
|
|
120
126
|
|
|
121
127
|
it('test onRefresh', async () => {
|
|
@@ -1,55 +1,29 @@
|
|
|
1
|
-
import React, { memo,
|
|
2
|
-
import { View,
|
|
3
|
-
import { Icon } from '@ant-design/react-native';
|
|
1
|
+
import React, { memo, useState, useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import { View, FlatList, ActivityIndicator } from 'react-native';
|
|
4
3
|
import { useFocusEffect } from '@react-navigation/native';
|
|
5
4
|
|
|
6
5
|
import styles from './styles/indexStyles';
|
|
7
|
-
import { API
|
|
6
|
+
import { API } from '../../configs';
|
|
8
7
|
import { axiosGet } from '../../utils/Apis/axios';
|
|
9
|
-
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
10
8
|
import NotificationItem from './components/NotificationItem';
|
|
11
|
-
import WrapHeaderScrollable from '../../commons/Sharing/WrapHeaderScrollable';
|
|
12
9
|
import {
|
|
13
10
|
watchNotificationData,
|
|
14
11
|
unwatchNotificationData,
|
|
15
12
|
} from '../../utils/Monitor';
|
|
16
13
|
import { useSCContextSelector } from '../../context';
|
|
17
|
-
import { notImplemented } from '../../utils/Utils';
|
|
18
14
|
import { useReceiveNotifications } from '../../hooks';
|
|
19
15
|
|
|
20
16
|
const Notification = memo(() => {
|
|
21
|
-
const
|
|
22
|
-
const [page, setPage] = useState(1);
|
|
17
|
+
const onEndReachedCalledDuringMomentum = useRef(false);
|
|
23
18
|
const user = useSCContextSelector((state) => state?.auth?.account?.user);
|
|
19
|
+
const [page, setPage] = useState(1);
|
|
24
20
|
const [notifications, setNotifications] = useState([]);
|
|
25
21
|
const [maxPageNotification, setMaxPageNotification] = useState(1);
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
() => (
|
|
29
|
-
<View style={styles.rightComponent}>
|
|
30
|
-
<TouchableOpacity
|
|
31
|
-
style={styles.iconPlus}
|
|
32
|
-
onPress={() => {
|
|
33
|
-
notImplemented(t);
|
|
34
|
-
}}
|
|
35
|
-
>
|
|
36
|
-
<Icon name={'plus'} size={27} color={Colors.Black} />
|
|
37
|
-
</TouchableOpacity>
|
|
38
|
-
|
|
39
|
-
<TouchableOpacity
|
|
40
|
-
onPress={() => {
|
|
41
|
-
notImplemented(t);
|
|
42
|
-
}}
|
|
43
|
-
>
|
|
44
|
-
<Icon name={'search'} size={27} color={Colors.Black} />
|
|
45
|
-
</TouchableOpacity>
|
|
46
|
-
</View>
|
|
47
|
-
),
|
|
48
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
49
|
-
[]
|
|
50
|
-
);
|
|
22
|
+
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
23
|
+
const [isLoadMore, setIsLoadMore] = useState(false);
|
|
51
24
|
|
|
52
25
|
const fetchNotifications = useCallback(async (pageParam) => {
|
|
26
|
+
setIsLoadMore(true);
|
|
53
27
|
const { success, data } = await axiosGet(
|
|
54
28
|
API.NOTIFICATION.LIST_EOH_NOTIFICATIONS(pageParam, '')
|
|
55
29
|
);
|
|
@@ -57,16 +31,22 @@ const Notification = memo(() => {
|
|
|
57
31
|
setNotifications((preState) => preState.concat(data.results));
|
|
58
32
|
setMaxPageNotification(Math.ceil(data.count / 10));
|
|
59
33
|
}
|
|
34
|
+
setIsLoadMore(false);
|
|
35
|
+
onEndReachedCalledDuringMomentum.current = false;
|
|
60
36
|
}, []);
|
|
61
37
|
|
|
62
38
|
const handleOnLoadMore = useCallback(() => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
39
|
+
if (!onEndReachedCalledDuringMomentum.current) {
|
|
40
|
+
onEndReachedCalledDuringMomentum.current = true;
|
|
41
|
+
setPage((preState) => preState + 1);
|
|
42
|
+
if (page < maxPageNotification) {
|
|
43
|
+
fetchNotifications(page + 1);
|
|
44
|
+
}
|
|
66
45
|
}
|
|
67
46
|
}, [page, maxPageNotification, fetchNotifications]);
|
|
68
47
|
|
|
69
48
|
const onRefresh = useCallback(async () => {
|
|
49
|
+
setIsRefreshing(true);
|
|
70
50
|
setPage(1);
|
|
71
51
|
const { success, data } = await axiosGet(
|
|
72
52
|
API.NOTIFICATION.LIST_EOH_NOTIFICATIONS(1, '')
|
|
@@ -75,8 +55,20 @@ const Notification = memo(() => {
|
|
|
75
55
|
setNotifications(data.results);
|
|
76
56
|
setMaxPageNotification(Math.ceil(data.count / 10));
|
|
77
57
|
}
|
|
58
|
+
setIsRefreshing(false);
|
|
78
59
|
}, []);
|
|
79
60
|
|
|
61
|
+
const Footer = useCallback(() => {
|
|
62
|
+
if (!isLoadMore) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return (
|
|
66
|
+
<View style={styles.footer}>
|
|
67
|
+
<ActivityIndicator />
|
|
68
|
+
</View>
|
|
69
|
+
);
|
|
70
|
+
}, [isLoadMore]);
|
|
71
|
+
|
|
80
72
|
useReceiveNotifications(onRefresh);
|
|
81
73
|
|
|
82
74
|
useEffect(() => {
|
|
@@ -93,18 +85,20 @@ const Notification = memo(() => {
|
|
|
93
85
|
|
|
94
86
|
return (
|
|
95
87
|
<View style={styles.wrap}>
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
88
|
+
<FlatList
|
|
89
|
+
keyExtractor={(item) => item.id}
|
|
90
|
+
renderItem={({ item }) => <NotificationItem item={item} />}
|
|
91
|
+
data={notifications}
|
|
92
|
+
extraData={notifications}
|
|
100
93
|
onRefresh={onRefresh}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
{
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
94
|
+
onEndReachedThreshold={0.5}
|
|
95
|
+
onEndReached={handleOnLoadMore}
|
|
96
|
+
refreshing={isRefreshing}
|
|
97
|
+
onMomentumScrollBegin={() =>
|
|
98
|
+
(onEndReachedCalledDuringMomentum.current = false)
|
|
99
|
+
}
|
|
100
|
+
ListFooterComponent={<Footer />}
|
|
101
|
+
/>
|
|
108
102
|
</View>
|
|
109
103
|
);
|
|
110
104
|
});
|
|
@@ -13,10 +13,13 @@ export default StyleSheet.create({
|
|
|
13
13
|
marginRight: 18,
|
|
14
14
|
paddingRight: 10,
|
|
15
15
|
},
|
|
16
|
-
iconPlus: {
|
|
17
|
-
marginRight: 22,
|
|
18
|
-
},
|
|
19
16
|
styleScrollView: {
|
|
20
17
|
marginTop: -10,
|
|
21
18
|
},
|
|
19
|
+
footer: {
|
|
20
|
+
width: '100%',
|
|
21
|
+
height: 50,
|
|
22
|
+
justifyContent: 'center',
|
|
23
|
+
alignItems: 'center',
|
|
24
|
+
},
|
|
22
25
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import { FlatList, RefreshControl, TouchableOpacity, View } from 'react-native';
|
|
3
|
-
import { useIsFocused
|
|
3
|
+
import { useIsFocused } from '@react-navigation/native';
|
|
4
4
|
|
|
5
5
|
import { axiosGet } from '../../utils/Apis/axios';
|
|
6
6
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
@@ -20,7 +20,6 @@ const Shared = () => {
|
|
|
20
20
|
useBlockBackAndroid();
|
|
21
21
|
const t = useTranslations();
|
|
22
22
|
useTitleHeader(t('text_shared_with_me'));
|
|
23
|
-
const navigation = useNavigation();
|
|
24
23
|
const [tab, setTabActiveState] = useState(0);
|
|
25
24
|
const isFocused = useIsFocused();
|
|
26
25
|
const [sharedUnits, setSharedUnits] = useState([]);
|
|
@@ -133,7 +132,6 @@ const Shared = () => {
|
|
|
133
132
|
return (
|
|
134
133
|
<SharedUnit
|
|
135
134
|
key={`${item.id}-${item?.is_star}-${item?.is_pin}`}
|
|
136
|
-
navigation={navigation}
|
|
137
135
|
item={item}
|
|
138
136
|
index={index}
|
|
139
137
|
renewItem={renewItem}
|
|
@@ -157,7 +155,6 @@ const Shared = () => {
|
|
|
157
155
|
return (
|
|
158
156
|
<SharedUnit
|
|
159
157
|
key={`${item.id}-${item.is_star}-${item.is_pin}`}
|
|
160
|
-
navigation={navigation}
|
|
161
158
|
item={item}
|
|
162
159
|
index={index}
|
|
163
160
|
renewItem={renewItem}
|
|
@@ -2,6 +2,7 @@ import React, { Fragment, useCallback } from 'react';
|
|
|
2
2
|
import { View, Image, TouchableOpacity } from 'react-native';
|
|
3
3
|
import { useTranslations } from '../../../../hooks/Common/useTranslations';
|
|
4
4
|
import { IconOutline, IconFill } from '@ant-design/icons-react-native';
|
|
5
|
+
import { useNavigation } from '@react-navigation/native';
|
|
5
6
|
|
|
6
7
|
import { API, Colors, Images } from '../../../../configs';
|
|
7
8
|
import Text from '../../../../commons/Text';
|
|
@@ -11,24 +12,20 @@ import { axiosPost } from '../../../../utils/Apis/axios';
|
|
|
11
12
|
import styles from '../styles';
|
|
12
13
|
import { AccessibilityLabel } from '../../../../configs/Constants';
|
|
13
14
|
|
|
14
|
-
const SharedUnit = ({
|
|
15
|
-
item,
|
|
16
|
-
navigation,
|
|
17
|
-
renewItem,
|
|
18
|
-
index,
|
|
19
|
-
isOptions = true,
|
|
20
|
-
}) => {
|
|
15
|
+
const SharedUnit = ({ item, renewItem, index, isOptions = true }) => {
|
|
21
16
|
const t = useTranslations();
|
|
17
|
+
const { navigate } = useNavigation();
|
|
22
18
|
const { unit } = item;
|
|
19
|
+
|
|
23
20
|
const goToDetail = useCallback(() => {
|
|
24
|
-
|
|
21
|
+
navigate(Routes.UnitStack, {
|
|
25
22
|
screen: Routes.UnitDetail,
|
|
26
23
|
params: {
|
|
27
24
|
unitId: unit.id,
|
|
28
25
|
unitData: unit,
|
|
29
26
|
},
|
|
30
27
|
});
|
|
31
|
-
}, [
|
|
28
|
+
}, [navigate, unit]);
|
|
32
29
|
|
|
33
30
|
const removePinSharedUnit = useCallback(async () => {
|
|
34
31
|
const { success } = await axiosPost(API.UNIT.UNPIN_UNIT(unit.id));
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { create, act } from 'react-test-renderer';
|
|
3
3
|
import moment from 'moment';
|
|
4
|
-
import { useNavigation } from '@react-navigation/native';
|
|
5
4
|
import MockAdapter from 'axios-mock-adapter';
|
|
6
5
|
import SharedUnit from '../SharedUnit';
|
|
7
6
|
import { AccessibilityLabel } from '../../../../configs/Constants';
|
|
@@ -14,14 +13,9 @@ import api from '../../../../utils/Apis/axios';
|
|
|
14
13
|
const mock = new MockAdapter(api.axiosInstance);
|
|
15
14
|
|
|
16
15
|
const mockRenewItem = jest.fn();
|
|
17
|
-
const wrapComponent = (item
|
|
16
|
+
const wrapComponent = (item) => (
|
|
18
17
|
<SCProvider initState={mockSCStore({})}>
|
|
19
|
-
<SharedUnit
|
|
20
|
-
item={item}
|
|
21
|
-
navigation={navigation}
|
|
22
|
-
renewItem={mockRenewItem}
|
|
23
|
-
index={0}
|
|
24
|
-
/>
|
|
18
|
+
<SharedUnit item={item} renewItem={mockRenewItem} index={0} />
|
|
25
19
|
</SCProvider>
|
|
26
20
|
);
|
|
27
21
|
|
|
@@ -56,11 +50,10 @@ describe('Test SharedUnit', () => {
|
|
|
56
50
|
};
|
|
57
51
|
|
|
58
52
|
it('test create SharedUnit unit is not pin, not star', async () => {
|
|
59
|
-
const navigation = useNavigation();
|
|
60
53
|
mock.onPost(API.UNIT.PIN_UNIT(3)).reply(200);
|
|
61
54
|
mock.onPost(API.UNIT.STAR_UNIT(3)).reply(200);
|
|
62
55
|
await act(async () => {
|
|
63
|
-
tree = await create(wrapComponent(item
|
|
56
|
+
tree = await create(wrapComponent(item));
|
|
64
57
|
});
|
|
65
58
|
const instance = tree.root;
|
|
66
59
|
const touchSharedUnit = instance.find(
|
|
@@ -102,11 +95,10 @@ describe('Test SharedUnit', () => {
|
|
|
102
95
|
});
|
|
103
96
|
|
|
104
97
|
it('test create SharedUnit unit is pin, is star', async () => {
|
|
105
|
-
const navigation = useNavigation();
|
|
106
98
|
item.is_pin = true;
|
|
107
99
|
item.is_star = true;
|
|
108
100
|
await act(async () => {
|
|
109
|
-
tree = await create(wrapComponent(item
|
|
101
|
+
tree = await create(wrapComponent(item));
|
|
110
102
|
});
|
|
111
103
|
const instance = tree.root;
|
|
112
104
|
const iconRemovePinSharedUnit = instance.find(
|
|
@@ -128,11 +120,10 @@ describe('Test SharedUnit', () => {
|
|
|
128
120
|
});
|
|
129
121
|
|
|
130
122
|
it('test create SharedUnit unit is pin, is star with call api failure', async () => {
|
|
131
|
-
const navigation = useNavigation();
|
|
132
123
|
item.is_pin = true;
|
|
133
124
|
item.is_star = true;
|
|
134
125
|
await act(async () => {
|
|
135
|
-
tree = await create(wrapComponent(item
|
|
126
|
+
tree = await create(wrapComponent(item));
|
|
136
127
|
});
|
|
137
128
|
const instance = tree.root;
|
|
138
129
|
const iconRemovePinSharedUnit = instance.find(
|
|
@@ -150,6 +141,19 @@ describe('Test SharedUnit', () => {
|
|
|
150
141
|
);
|
|
151
142
|
mock.onPost(API.UNIT.UNSTAR_UNIT(3)).reply(200);
|
|
152
143
|
await iconRemoveStarSharedUnit.props.onPress();
|
|
153
|
-
expect(
|
|
144
|
+
expect(mockNavigate).toBeCalledWith('UnitStack', {
|
|
145
|
+
params: {
|
|
146
|
+
unitData: {
|
|
147
|
+
background: '',
|
|
148
|
+
icon: '',
|
|
149
|
+
id: 3,
|
|
150
|
+
name: 'name',
|
|
151
|
+
owner_name: 'owner_name',
|
|
152
|
+
short_summaries: [],
|
|
153
|
+
},
|
|
154
|
+
unitId: 3,
|
|
155
|
+
},
|
|
156
|
+
screen: 'UnitDetail',
|
|
157
|
+
});
|
|
154
158
|
});
|
|
155
159
|
});
|