@eohjsc/react-native-smart-city 0.7.12 → 0.7.14
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/package.json +5 -4
- package/src/commons/Header/Styles/HeaderCustomStyles.js +2 -1
- package/src/commons/Sharing/MemberList.js +28 -20
- package/src/commons/Sharing/RowMember.js +80 -135
- package/src/commons/Sharing/__test__/MemberList.test.js +7 -10
- package/src/commons/Sharing/__test__/RowMember.test.js +111 -14
- package/src/configs/AccessibilityLabel.js +6 -2
- package/src/hooks/Common/useIsOwnerOfUnit.js +0 -1
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +2 -1
- package/src/screens/Automate/AddNewAction/Styles/SetupScriptReceiverEmailStyles.js +7 -1
- package/src/screens/Automate/EditActionsList/Styles/UpdateReceiverEmailScriptStyles.js +6 -0
- package/src/screens/Automate/EditActionsList/Styles/indexStyles.js +6 -3
- package/src/screens/Automate/EditActionsList/UpdateNotifyScript.js +5 -3
- package/src/screens/Automate/EditActionsList/UpdateReceiverEmailScript.js +1 -0
- package/src/screens/Automate/EditActionsList/index.js +5 -2
- package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +4 -0
- package/src/screens/Automate/ScriptDetail/index.js +5 -2
- package/src/screens/Sharing/UnitMemberList.js +75 -52
- package/src/screens/Sharing/__test__/UnitMemberList.test.js +129 -32
- package/src/screens/Sharing/hooks/__test__/index.test.js +6 -5
- package/src/screens/Sharing/hooks/index.js +5 -4
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.7.
|
|
4
|
+
"version": "0.7.14",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
"pods": "cd example && pod-install --quiet",
|
|
43
43
|
"bootstrap": "yarn example && yarn && yarn pods",
|
|
44
44
|
"build": "syncdir ./src ../EohMobile/node_modules/@eohjsc/react-native-smart-city/src",
|
|
45
|
-
"watch": "syncdir ./src ../EohMobile/node_modules/@eohjsc/react-native-smart-city/src --watch"
|
|
45
|
+
"watch": "syncdir ./src ../EohMobile/node_modules/@eohjsc/react-native-smart-city/src --watch",
|
|
46
|
+
"copy-files": "cp -rfv ./assets/* ../EohMobile/node_modules/@eohjsc/react-native-smart-city/assets && cp -rfv ./src/* ../EohMobile/node_modules/@eohjsc/react-native-smart-city/src"
|
|
46
47
|
},
|
|
47
48
|
"repository": {
|
|
48
49
|
"type": "git",
|
|
@@ -87,7 +88,7 @@
|
|
|
87
88
|
"@react-navigation/drawer": "^6.6.15",
|
|
88
89
|
"@react-navigation/native": "^6.1.17",
|
|
89
90
|
"@react-navigation/native-stack": "^6.11.0",
|
|
90
|
-
"@sentry/react-native": "^
|
|
91
|
+
"@sentry/react-native": "^6.2.0",
|
|
91
92
|
"@testing-library/react-hooks": "^6.0.0",
|
|
92
93
|
"@types/jest": "^29.2.1",
|
|
93
94
|
"@types/react": "^17.0.0",
|
|
@@ -117,7 +118,7 @@
|
|
|
117
118
|
"jetifier": "^1.6.6",
|
|
118
119
|
"lint-staged": "^12.4.1",
|
|
119
120
|
"lodash": "^4.17.19",
|
|
120
|
-
"lottie-react-native": "^
|
|
121
|
+
"lottie-react-native": "^7.1.0",
|
|
121
122
|
"md5": "^2.3.0",
|
|
122
123
|
"metro-react-native-babel-preset": "0.73.9",
|
|
123
124
|
"moment": "^2.27.0",
|
|
@@ -41,7 +41,7 @@ export default StyleSheet.create({
|
|
|
41
41
|
height: 20,
|
|
42
42
|
},
|
|
43
43
|
title: {
|
|
44
|
-
|
|
44
|
+
alignSelf: 'center',
|
|
45
45
|
fontSize: 16,
|
|
46
46
|
lineHeight: 24,
|
|
47
47
|
fontWeight: 'bold',
|
|
@@ -55,5 +55,6 @@ export default StyleSheet.create({
|
|
|
55
55
|
},
|
|
56
56
|
wrapTitle: {
|
|
57
57
|
marginHorizontal: 12,
|
|
58
|
+
flex: 1,
|
|
58
59
|
},
|
|
59
60
|
});
|
|
@@ -1,49 +1,57 @@
|
|
|
1
1
|
import React, { memo } from 'react';
|
|
2
2
|
import { View, StyleSheet } from 'react-native';
|
|
3
3
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
4
|
-
import {
|
|
4
|
+
import { Constants } from '../../configs';
|
|
5
5
|
import Text from '../../commons/Text';
|
|
6
6
|
import RowMember from './RowMember';
|
|
7
|
+
import { RefreshControl, FlatList } from 'react-native';
|
|
8
|
+
import { getBottomSpace } from 'react-native-iphone-x-helper';
|
|
7
9
|
|
|
8
10
|
const MemberList = ({
|
|
9
11
|
dataMember,
|
|
10
12
|
ownerId,
|
|
11
13
|
unit,
|
|
12
14
|
currentUserId, //user is using app
|
|
15
|
+
isRefresh,
|
|
16
|
+
onRefresh,
|
|
13
17
|
}) => {
|
|
14
18
|
const t = useTranslations();
|
|
15
19
|
return (
|
|
16
|
-
<
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
<FlatList
|
|
21
|
+
contentContainerStyle={styles.contentContainer}
|
|
22
|
+
keyExtractor={(item) => `${item.id}`}
|
|
23
|
+
data={dataMember}
|
|
24
|
+
extraData={dataMember}
|
|
25
|
+
numColumns={1}
|
|
26
|
+
refreshControl={
|
|
27
|
+
<RefreshControl refreshing={isRefresh} onRefresh={onRefresh} />
|
|
28
|
+
}
|
|
29
|
+
renderItem={({ item, index }) => (
|
|
30
|
+
<RowMember
|
|
31
|
+
member={item}
|
|
32
|
+
unit={unit}
|
|
33
|
+
index={index}
|
|
34
|
+
ownerId={ownerId}
|
|
35
|
+
currentUserId={currentUserId}
|
|
36
|
+
/>
|
|
37
|
+
)}
|
|
38
|
+
ListEmptyComponent={() => (
|
|
29
39
|
<View style={styles.viewEmpty}>
|
|
30
|
-
<Text
|
|
40
|
+
<Text type="H4">{t('no_member')}</Text>
|
|
31
41
|
</View>
|
|
32
42
|
)}
|
|
33
|
-
|
|
43
|
+
/>
|
|
34
44
|
);
|
|
35
45
|
};
|
|
36
46
|
export default memo(MemberList);
|
|
37
47
|
|
|
38
48
|
const styles = StyleSheet.create({
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
paddingTop: 20,
|
|
49
|
+
contentContainer: {
|
|
50
|
+
paddingBottom: getBottomSpace() + 50,
|
|
42
51
|
},
|
|
43
52
|
viewEmpty: {
|
|
44
53
|
justifyContent: 'center',
|
|
45
54
|
alignItems: 'center',
|
|
46
55
|
height: Constants.height - 200,
|
|
47
|
-
backgroundColor: Colors.White,
|
|
48
56
|
},
|
|
49
57
|
});
|
|
@@ -18,160 +18,108 @@ const arrColor = [
|
|
|
18
18
|
Colors.Green3,
|
|
19
19
|
Colors.Cyan2,
|
|
20
20
|
];
|
|
21
|
-
const RowMember = memo(
|
|
22
|
-
(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
? [t('owner'), Colors.Primary]
|
|
39
|
-
: id === currentUserId
|
|
40
|
-
? [t('me'), Colors.Primary]
|
|
41
|
-
: [t('member'), Colors.Gray6],
|
|
42
|
-
[currentUserId, id, ownerId, t]
|
|
43
|
-
);
|
|
44
|
-
const firstWordsInName = useMemo(() => {
|
|
45
|
-
const wordTemp = name || shortEmailName(email) || '';
|
|
46
|
-
return wordTemp?.charAt();
|
|
47
|
-
}, [email, name]);
|
|
21
|
+
const RowMember = memo(({ member, index, ownerId, unit, currentUserId }) => {
|
|
22
|
+
const t = useTranslations();
|
|
23
|
+
const { navigate } = useNavigation();
|
|
24
|
+
const { id, name, phone_number, email, avatar } = member;
|
|
25
|
+
const [role, roleColor] = useMemo(
|
|
26
|
+
() =>
|
|
27
|
+
id === ownerId
|
|
28
|
+
? [t('owner'), Colors.Primary]
|
|
29
|
+
: id === currentUserId
|
|
30
|
+
? [t('me'), Colors.Primary]
|
|
31
|
+
: [t('member'), Colors.Gray6],
|
|
32
|
+
[currentUserId, id, ownerId, t]
|
|
33
|
+
);
|
|
34
|
+
const firstWordsInName = useMemo(() => {
|
|
35
|
+
const wordTemp = name || shortEmailName(email) || '';
|
|
36
|
+
return wordTemp?.charAt();
|
|
37
|
+
}, [email, name]);
|
|
48
38
|
|
|
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
|
-
{avatar ? (
|
|
79
|
-
<Image source={{ uri: avatar }} style={styles.avatar} />
|
|
80
|
-
) : (
|
|
81
|
-
<CircleView size={40} backgroundColor={circleColor} center>
|
|
82
|
-
<Text color={Colors.White}>{firstWordsInName}</Text>
|
|
83
|
-
</CircleView>
|
|
84
|
-
)}
|
|
85
|
-
</View>
|
|
86
|
-
)}
|
|
87
|
-
<View style={styles.columnFlex}>
|
|
88
|
-
<Text style={styles.titleName}>
|
|
89
|
-
{name || shortEmailName(email) || ''}
|
|
39
|
+
const onPressInfo = () => {
|
|
40
|
+
navigate(Routes.UnitMemberInformation, {
|
|
41
|
+
member,
|
|
42
|
+
ownerId,
|
|
43
|
+
unit,
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
return (
|
|
47
|
+
<TouchableOpacity
|
|
48
|
+
onPress={onPressInfo}
|
|
49
|
+
accessibilityLabel={`${AccessibilityLabel.SELECT_MEMBER_UNIT}-${member?.id}`}
|
|
50
|
+
>
|
|
51
|
+
<View style={styles.border}>
|
|
52
|
+
<View style={styles.paddingLeft16}>
|
|
53
|
+
{avatar ? (
|
|
54
|
+
<Image source={{ uri: avatar }} style={styles.avatar} />
|
|
55
|
+
) : (
|
|
56
|
+
<CircleView
|
|
57
|
+
size={40}
|
|
58
|
+
backgroundColor={arrColor[index % arrColor.length]}
|
|
59
|
+
center
|
|
60
|
+
>
|
|
61
|
+
<Text
|
|
62
|
+
color={Colors.White}
|
|
63
|
+
accessibilityLabel={
|
|
64
|
+
AccessibilityLabel.UNIT_MEMBER.ROW_TEXT_AVATAR
|
|
65
|
+
}
|
|
66
|
+
>
|
|
67
|
+
{firstWordsInName}
|
|
90
68
|
</Text>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
69
|
+
</CircleView>
|
|
70
|
+
)}
|
|
71
|
+
</View>
|
|
72
|
+
<View style={styles.columnFlex}>
|
|
73
|
+
<Text
|
|
74
|
+
style={styles.titleName}
|
|
75
|
+
accessibilityLabel={AccessibilityLabel.UNIT_MEMBER.ROW_TEXT_NAME}
|
|
76
|
+
>
|
|
77
|
+
{name || shortEmailName(email) || ''}
|
|
78
|
+
</Text>
|
|
79
|
+
{/* Can't write test for this case, use !! to avoid app crash when phone_number is '' */}
|
|
80
|
+
{!!phone_number && (
|
|
81
|
+
<Text
|
|
82
|
+
style={styles.status}
|
|
83
|
+
accessibilityLabel={AccessibilityLabel.UNIT_MEMBER.ROW_TEXT_PHONE}
|
|
84
|
+
>
|
|
85
|
+
{'******' + phone_number.slice(-4)}
|
|
86
|
+
</Text>
|
|
87
|
+
)}
|
|
88
|
+
</View>
|
|
89
|
+
<View style={styles.endFlex}>
|
|
90
|
+
{!!role && (
|
|
91
|
+
<Text
|
|
92
|
+
style={[styles.textRole, { color: roleColor }]}
|
|
93
|
+
accessibilityLabel={AccessibilityLabel.UNIT_MEMBER.ROW_TEXT_ROLE}
|
|
94
|
+
>
|
|
95
|
+
{role}
|
|
96
|
+
</Text>
|
|
97
|
+
)}
|
|
98
|
+
</View>
|
|
114
99
|
</View>
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
);
|
|
100
|
+
</TouchableOpacity>
|
|
101
|
+
);
|
|
102
|
+
});
|
|
118
103
|
|
|
119
104
|
export default RowMember;
|
|
120
105
|
|
|
121
106
|
const styles = StyleSheet.create({
|
|
122
|
-
rowContainer: {
|
|
123
|
-
flex: 1,
|
|
124
|
-
},
|
|
125
|
-
iconContainer: {
|
|
126
|
-
alignItems: 'center',
|
|
127
|
-
justifyContent: 'center',
|
|
128
|
-
marginRight: 16,
|
|
129
|
-
width: 40,
|
|
130
|
-
height: 40,
|
|
131
|
-
borderRadius: 20,
|
|
132
|
-
},
|
|
133
|
-
infoContainer: {
|
|
134
|
-
flex: 1,
|
|
135
|
-
paddingTop: 17,
|
|
136
|
-
borderBottomWidth: 1,
|
|
137
|
-
borderColor: Colors.Gray4,
|
|
138
|
-
},
|
|
139
|
-
textName: {
|
|
140
|
-
fontSize: 16,
|
|
141
|
-
lineHeight: 24,
|
|
142
|
-
color: Colors.Gray9,
|
|
143
|
-
marginBottom: 0,
|
|
144
|
-
},
|
|
145
107
|
textRole: {
|
|
146
108
|
fontSize: 12,
|
|
147
109
|
lineHeight: 20,
|
|
148
110
|
},
|
|
149
|
-
buttonRemove: {
|
|
150
|
-
position: 'absolute',
|
|
151
|
-
right: 0,
|
|
152
|
-
top: 10,
|
|
153
|
-
bottom: 10,
|
|
154
|
-
paddingHorizontal: 10,
|
|
155
|
-
justifyContent: 'center',
|
|
156
|
-
},
|
|
157
|
-
textCenter: {
|
|
158
|
-
alignSelf: 'center',
|
|
159
|
-
},
|
|
160
111
|
columnFlex: {
|
|
161
112
|
paddingLeft: 16,
|
|
162
113
|
justifyContent: 'center',
|
|
163
114
|
flexDirection: 'column',
|
|
164
115
|
},
|
|
165
|
-
rowFlex: {
|
|
166
|
-
flexDirection: 'row',
|
|
167
|
-
},
|
|
168
116
|
endFlex: {
|
|
169
117
|
flex: 1,
|
|
170
118
|
justifyContent: 'flex-start',
|
|
171
119
|
alignItems: 'flex-end',
|
|
172
120
|
paddingRight: 16,
|
|
173
121
|
},
|
|
174
|
-
|
|
122
|
+
border: {
|
|
175
123
|
display: 'flex',
|
|
176
124
|
width: '100%',
|
|
177
125
|
borderWidth: 0,
|
|
@@ -196,9 +144,6 @@ const styles = StyleSheet.create({
|
|
|
196
144
|
fontWeight: '400',
|
|
197
145
|
color: Colors.Gray7,
|
|
198
146
|
},
|
|
199
|
-
container: {
|
|
200
|
-
paddingTop: 0,
|
|
201
|
-
},
|
|
202
147
|
paddingLeft16: {
|
|
203
148
|
paddingLeft: 16,
|
|
204
149
|
},
|
|
@@ -1,31 +1,30 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import renderer, { act } from 'react-test-renderer';
|
|
2
|
+
|
|
3
3
|
import MemberList from '../MemberList';
|
|
4
|
+
import React from 'react';
|
|
4
5
|
import RowMember from '../RowMember';
|
|
5
|
-
import Text from '../../Text';
|
|
6
6
|
import { SCProvider } from '../../../context';
|
|
7
|
+
import Text from '../../Text';
|
|
7
8
|
import { mockSCStore } from '../../../context/mockStore';
|
|
8
9
|
import t from '../../../hooks/Common/useTranslations';
|
|
9
10
|
|
|
10
|
-
const wrapComponent = (dataMember, ownerId, currentUserId
|
|
11
|
+
const wrapComponent = (dataMember, ownerId, currentUserId) => (
|
|
11
12
|
<SCProvider initState={mockSCStore({})}>
|
|
12
13
|
<MemberList
|
|
13
14
|
dataMember={dataMember}
|
|
14
15
|
ownerId={ownerId}
|
|
15
16
|
currentUserId={currentUserId}
|
|
16
|
-
onPressRemove={mockFunc}
|
|
17
17
|
/>
|
|
18
18
|
</SCProvider>
|
|
19
19
|
);
|
|
20
20
|
|
|
21
21
|
describe('MemberList', () => {
|
|
22
22
|
let tree;
|
|
23
|
-
const mockFunc = jest.fn();
|
|
24
23
|
|
|
25
24
|
it('MemberList snapshot id dataMember === ownerId', async () => {
|
|
26
25
|
const dataMember = [{ id: 1, name: 'CEO' }];
|
|
27
26
|
await act(async () => {
|
|
28
|
-
tree = await renderer.create(wrapComponent(dataMember, 1, 2
|
|
27
|
+
tree = await renderer.create(wrapComponent(dataMember, 1, 2));
|
|
29
28
|
});
|
|
30
29
|
const instance = tree.root;
|
|
31
30
|
const rowMember = instance.findByType(RowMember);
|
|
@@ -38,9 +37,7 @@ describe('MemberList', () => {
|
|
|
38
37
|
it('MemberList snapshot id dataMember !== ownerId', async () => {
|
|
39
38
|
const dataMember = [{ id: 1, name: 'CEO' }];
|
|
40
39
|
await act(async () => {
|
|
41
|
-
tree = await renderer.create(
|
|
42
|
-
wrapComponent(dataMember, 2, null, mockFunc)
|
|
43
|
-
);
|
|
40
|
+
tree = await renderer.create(wrapComponent(dataMember, 2, null));
|
|
44
41
|
});
|
|
45
42
|
const instance = tree.root;
|
|
46
43
|
const rowMember = instance.findByType(RowMember);
|
|
@@ -53,7 +50,7 @@ describe('MemberList', () => {
|
|
|
53
50
|
it('MemberList snapshot id dataMember === currentUserId', async () => {
|
|
54
51
|
const dataMember = [{ id: 1, name: 'CEO' }];
|
|
55
52
|
await act(async () => {
|
|
56
|
-
tree = await renderer.create(wrapComponent(dataMember, 2, 1
|
|
53
|
+
tree = await renderer.create(wrapComponent(dataMember, 2, 1));
|
|
57
54
|
});
|
|
58
55
|
const instance = tree.root;
|
|
59
56
|
const rowMembers = instance.findAllByType(RowMember);
|
|
@@ -1,40 +1,137 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Image, TouchableOpacity } from 'react-native';
|
|
2
2
|
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
|
|
4
|
+
import AccessibilityLabel from '../../../configs/AccessibilityLabel';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import Routes from '../../../utils/Route';
|
|
3
7
|
import RowMember from '../RowMember';
|
|
4
|
-
import Text from '../../Text';
|
|
5
8
|
import { SCProvider } from '../../../context';
|
|
9
|
+
import Text from '../../Text';
|
|
6
10
|
import { mockSCStore } from '../../../context/mockStore';
|
|
11
|
+
import { useNavigation } from '@react-navigation/native';
|
|
7
12
|
|
|
8
|
-
const wrapComponent = (member, ownerId, currentUserId,
|
|
13
|
+
const wrapComponent = ({ member, ownerId, currentUserId, index = 0 }) => (
|
|
9
14
|
<SCProvider initState={mockSCStore({})}>
|
|
10
15
|
<RowMember
|
|
11
16
|
member={member}
|
|
12
17
|
ownerId={ownerId}
|
|
13
18
|
currentUserId={currentUserId}
|
|
14
|
-
|
|
19
|
+
index={index}
|
|
15
20
|
/>
|
|
16
21
|
</SCProvider>
|
|
17
22
|
);
|
|
18
23
|
|
|
19
24
|
describe('RowMember', () => {
|
|
20
25
|
let tree;
|
|
21
|
-
const
|
|
26
|
+
const mockedNavigate = useNavigation().navigate;
|
|
27
|
+
const assertTextItems = ({ instance, avatar, name, phone, role }) => {
|
|
28
|
+
const avatarText = instance.findAll(
|
|
29
|
+
(el) =>
|
|
30
|
+
el.props.accessibilityLabel ===
|
|
31
|
+
AccessibilityLabel.UNIT_MEMBER.ROW_TEXT_AVATAR && el.type === Text
|
|
32
|
+
);
|
|
33
|
+
const nameText = instance.findAll(
|
|
34
|
+
(el) =>
|
|
35
|
+
el.props.accessibilityLabel ===
|
|
36
|
+
AccessibilityLabel.UNIT_MEMBER.ROW_TEXT_NAME && el.type === Text
|
|
37
|
+
);
|
|
38
|
+
const phoneText = instance.findAll(
|
|
39
|
+
(el) =>
|
|
40
|
+
el.props.accessibilityLabel ===
|
|
41
|
+
AccessibilityLabel.UNIT_MEMBER.ROW_TEXT_PHONE && el.type === Text
|
|
42
|
+
);
|
|
43
|
+
const roleText = instance.findAll(
|
|
44
|
+
(el) =>
|
|
45
|
+
el.props.accessibilityLabel ===
|
|
46
|
+
AccessibilityLabel.UNIT_MEMBER.ROW_TEXT_ROLE && el.type === Text
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
avatar !== null
|
|
50
|
+
? expect(avatarText[0].props.children).toEqual(avatar)
|
|
51
|
+
: expect(avatarText.length).toEqual(0);
|
|
52
|
+
name !== null
|
|
53
|
+
? expect(nameText[0].props.children).toEqual(name)
|
|
54
|
+
: expect(nameText.length).toEqual(0);
|
|
55
|
+
phone !== null
|
|
56
|
+
? expect(phoneText[0].props.children).toEqual(phone)
|
|
57
|
+
: expect(phoneText.length).toEqual(0);
|
|
58
|
+
role !== null
|
|
59
|
+
? expect(roleText[0].props.children).toEqual(role)
|
|
60
|
+
: expect(roleText.length).toEqual(0);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
mockedNavigate.mockClear();
|
|
65
|
+
});
|
|
66
|
+
|
|
22
67
|
it('RowMember owner have name', async () => {
|
|
23
|
-
const dataMember = {
|
|
68
|
+
const dataMember = {
|
|
69
|
+
id: 1,
|
|
70
|
+
name: 'CEO',
|
|
71
|
+
avatar: 'https://image.jpg',
|
|
72
|
+
phone_number: '0123456789',
|
|
73
|
+
};
|
|
24
74
|
await act(async () => {
|
|
25
|
-
tree = await renderer.create(
|
|
75
|
+
tree = await renderer.create(
|
|
76
|
+
wrapComponent({ member: dataMember, ownerId: 1, currentUserId: 1 })
|
|
77
|
+
);
|
|
26
78
|
});
|
|
27
79
|
const instance = tree.root;
|
|
28
|
-
const
|
|
29
|
-
|
|
80
|
+
const image = instance.findByType(Image);
|
|
81
|
+
assertTextItems({
|
|
82
|
+
instance,
|
|
83
|
+
avatar: null,
|
|
84
|
+
name: 'CEO',
|
|
85
|
+
phone: '******6789',
|
|
86
|
+
role: 'Owner',
|
|
87
|
+
});
|
|
88
|
+
expect(image.props.source.uri).toEqual('https://image.jpg');
|
|
89
|
+
|
|
90
|
+
const touchable = instance.findByType(TouchableOpacity);
|
|
91
|
+
await act(async () => {
|
|
92
|
+
touchable.props.onPress();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
expect(global.mockedNavigate).toHaveBeenCalledWith(
|
|
96
|
+
Routes.UnitMemberInformation,
|
|
97
|
+
{
|
|
98
|
+
member: dataMember,
|
|
99
|
+
ownerId: 1,
|
|
100
|
+
unit: undefined,
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
it('render RowMember with null name', async () => {
|
|
105
|
+
const dataMember = { id: 2, name: '', email: 'abc@gmail.com' };
|
|
106
|
+
await act(async () => {
|
|
107
|
+
tree = await renderer.create(
|
|
108
|
+
wrapComponent({ member: dataMember, ownerId: 1, currentUserId: 2 })
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
const instance = tree.root;
|
|
112
|
+
|
|
113
|
+
assertTextItems({
|
|
114
|
+
instance,
|
|
115
|
+
avatar: 'a',
|
|
116
|
+
name: 'abc',
|
|
117
|
+
phone: null,
|
|
118
|
+
role: 'Me',
|
|
119
|
+
});
|
|
30
120
|
});
|
|
31
|
-
it('RowMember
|
|
32
|
-
const dataMember = { id:
|
|
121
|
+
it('render RowMember with null name and email', async () => {
|
|
122
|
+
const dataMember = { id: 3, name: null, email: null };
|
|
33
123
|
await act(async () => {
|
|
34
|
-
tree = await renderer.create(
|
|
124
|
+
tree = await renderer.create(
|
|
125
|
+
wrapComponent({ member: dataMember, ownerId: 1, currentUserId: 1 })
|
|
126
|
+
);
|
|
35
127
|
});
|
|
36
128
|
const instance = tree.root;
|
|
37
|
-
|
|
38
|
-
|
|
129
|
+
assertTextItems({
|
|
130
|
+
instance,
|
|
131
|
+
avatar: '',
|
|
132
|
+
name: '',
|
|
133
|
+
phone: null,
|
|
134
|
+
role: 'Member',
|
|
135
|
+
});
|
|
39
136
|
});
|
|
40
137
|
});
|
|
@@ -50,8 +50,12 @@ export default {
|
|
|
50
50
|
SHARING_MEMBER: 'SHARING_MEMBER',
|
|
51
51
|
REMOVE_MEMBER: 'REMOVE_MEMBER',
|
|
52
52
|
CHECK_BOX_CUSTOM: 'CHECK_BOX_CUSTOM',
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
UNIT_MEMBER: {
|
|
54
|
+
ROW_TEXT_AVATAR: 'ROW_TEXT_AVATAR',
|
|
55
|
+
ROW_TEXT_NAME: 'ROW_TEXT_NAME',
|
|
56
|
+
ROW_TEXT_PHONE: 'ROW_TEXT_PHONE',
|
|
57
|
+
ROW_TEXT_ROLE: 'ROW_TEXT_ROLE',
|
|
58
|
+
},
|
|
55
59
|
|
|
56
60
|
// SmartTiviTemplate
|
|
57
61
|
SMART_TIVI_TEMPLATE: {
|
|
@@ -104,12 +104,13 @@ const SetupScriptReceiverEmail = ({ route }) => {
|
|
|
104
104
|
|
|
105
105
|
return (
|
|
106
106
|
<View style={styles.rowContainer}>
|
|
107
|
-
<View style={styles.
|
|
107
|
+
<View style={styles.border}>
|
|
108
108
|
<CheckBox
|
|
109
109
|
disabled={!email}
|
|
110
110
|
lineWidth={4}
|
|
111
111
|
value={listUser.includes(id)}
|
|
112
112
|
onValueChange={onValueChange(id)}
|
|
113
|
+
style={styles.checkbox}
|
|
113
114
|
/>
|
|
114
115
|
<View style={styles.paddingLeft16}>
|
|
115
116
|
{avatar ? (
|
|
@@ -41,10 +41,12 @@ export default StyleSheet.create({
|
|
|
41
41
|
justifyContent: 'flex-start',
|
|
42
42
|
alignItems: 'flex-end',
|
|
43
43
|
},
|
|
44
|
-
|
|
44
|
+
border: {
|
|
45
45
|
flexDirection: 'row',
|
|
46
46
|
paddingBottom: 16,
|
|
47
47
|
paddingHorizontal: 16,
|
|
48
|
+
justifyContent: 'center',
|
|
49
|
+
alignItems: 'center',
|
|
48
50
|
},
|
|
49
51
|
titleName: {
|
|
50
52
|
fontSize: 16,
|
|
@@ -76,4 +78,8 @@ export default StyleSheet.create({
|
|
|
76
78
|
borderRadius: 40,
|
|
77
79
|
backgroundColor: Colors.Primary,
|
|
78
80
|
},
|
|
81
|
+
checkbox: {
|
|
82
|
+
width: 24,
|
|
83
|
+
height: 24,
|
|
84
|
+
},
|
|
79
85
|
});
|
|
@@ -36,6 +36,8 @@ export default StyleSheet.create({
|
|
|
36
36
|
flexDirection: 'row',
|
|
37
37
|
paddingBottom: 16,
|
|
38
38
|
paddingHorizontal: 16,
|
|
39
|
+
justifyContent: 'center',
|
|
40
|
+
alignItems: 'center',
|
|
39
41
|
},
|
|
40
42
|
paddingLeft16: {
|
|
41
43
|
paddingLeft: 16,
|
|
@@ -75,4 +77,8 @@ export default StyleSheet.create({
|
|
|
75
77
|
fontSize: 12,
|
|
76
78
|
lineHeight: 20,
|
|
77
79
|
},
|
|
80
|
+
checkbox: {
|
|
81
|
+
width: 24,
|
|
82
|
+
height: 24,
|
|
83
|
+
},
|
|
78
84
|
});
|
|
@@ -12,6 +12,7 @@ export default StyleSheet.create({
|
|
|
12
12
|
wrapContent: {
|
|
13
13
|
flex: 1,
|
|
14
14
|
paddingHorizontal: 20,
|
|
15
|
+
marginBottom: 100,
|
|
15
16
|
},
|
|
16
17
|
wrapItem: {
|
|
17
18
|
flexDirection: 'row',
|
|
@@ -50,12 +51,14 @@ export default StyleSheet.create({
|
|
|
50
51
|
noBorder: {
|
|
51
52
|
borderWidth: 0,
|
|
52
53
|
},
|
|
54
|
+
icon: {
|
|
55
|
+
alignItems: 'center',
|
|
56
|
+
justifyContent: 'center',
|
|
57
|
+
marginRight: 10,
|
|
58
|
+
},
|
|
53
59
|
iconItem: {
|
|
54
60
|
width: 35,
|
|
55
61
|
height: 35,
|
|
56
|
-
marginTop: 6,
|
|
57
|
-
marginRight: 15,
|
|
58
|
-
alignItems: 'center',
|
|
59
62
|
},
|
|
60
63
|
contentItem: {
|
|
61
64
|
flex: 1,
|
|
@@ -20,7 +20,7 @@ const UpdateNotifyScript = ({
|
|
|
20
20
|
updateIndex,
|
|
21
21
|
setNeedRefresh,
|
|
22
22
|
}) => {
|
|
23
|
-
const { title, message } = notify_script;
|
|
23
|
+
const { title, message, unit_id, unit_name } = notify_script;
|
|
24
24
|
const [newValue, setNewValue] = useState({
|
|
25
25
|
newTitle: title,
|
|
26
26
|
newMessage: message,
|
|
@@ -31,7 +31,7 @@ const UpdateNotifyScript = ({
|
|
|
31
31
|
API.AUTOMATE.UPDATE_SCRIPT_NOTIFY(automateId),
|
|
32
32
|
{
|
|
33
33
|
id: scriptItemId,
|
|
34
|
-
unit:
|
|
34
|
+
unit: unit_id,
|
|
35
35
|
title: newValue.newTitle,
|
|
36
36
|
message: newValue.newMessage,
|
|
37
37
|
}
|
|
@@ -40,6 +40,7 @@ const UpdateNotifyScript = ({
|
|
|
40
40
|
actionsList[updateIndex].notify_script = {
|
|
41
41
|
title: newValue.newTitle,
|
|
42
42
|
message: newValue.newMessage,
|
|
43
|
+
unit_name: unit_name,
|
|
43
44
|
};
|
|
44
45
|
setActionList(actionsList);
|
|
45
46
|
onClosePopup();
|
|
@@ -56,7 +57,8 @@ const UpdateNotifyScript = ({
|
|
|
56
57
|
setActionList,
|
|
57
58
|
setNeedRefresh,
|
|
58
59
|
t,
|
|
59
|
-
|
|
60
|
+
unit_id,
|
|
61
|
+
unit_name,
|
|
60
62
|
updateIndex,
|
|
61
63
|
]);
|
|
62
64
|
|
|
@@ -124,7 +124,7 @@ const EditActionsList = () => {
|
|
|
124
124
|
onLongPress={onPressUpdate}
|
|
125
125
|
accessibilityLabel={AccessibilityLabel.BUTTON_UPDATE}
|
|
126
126
|
>
|
|
127
|
-
{icon}
|
|
127
|
+
<View style={styles.icon}>{icon}</View>
|
|
128
128
|
<View style={styles.contentItem}>{content}</View>
|
|
129
129
|
<TouchableOpacity
|
|
130
130
|
accessibilityLabel={AccessibilityLabel.BUTTON_REMOVE_EDIT_ACTION_LIST}
|
|
@@ -183,7 +183,7 @@ const EditActionsList = () => {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
if (notify_script) {
|
|
186
|
-
const { title, message } = notify_script;
|
|
186
|
+
const { title, message, unit_name } = notify_script;
|
|
187
187
|
|
|
188
188
|
return (
|
|
189
189
|
<CommonItem
|
|
@@ -201,6 +201,9 @@ const EditActionsList = () => {
|
|
|
201
201
|
<Text numberOfLines={1} type="H4" color={Colors.Gray9}>
|
|
202
202
|
{message}
|
|
203
203
|
</Text>
|
|
204
|
+
<Text numberOfLines={1} type="H4" color={Colors.Gray9}>
|
|
205
|
+
{unit_name}
|
|
206
|
+
</Text>
|
|
204
207
|
</>
|
|
205
208
|
}
|
|
206
209
|
onPress={() => onPressRemove(item)}
|
|
@@ -89,6 +89,8 @@ export default StyleSheet.create({
|
|
|
89
89
|
paddingHorizontal: 16,
|
|
90
90
|
marginLeft: 4,
|
|
91
91
|
flexDirection: 'row',
|
|
92
|
+
justifyContent: 'center',
|
|
93
|
+
alignItems: 'center',
|
|
92
94
|
},
|
|
93
95
|
leftItem: {
|
|
94
96
|
width: 41,
|
|
@@ -179,5 +181,7 @@ export default StyleSheet.create({
|
|
|
179
181
|
height: 35,
|
|
180
182
|
marginTop: 6,
|
|
181
183
|
marginRight: 15,
|
|
184
|
+
justifyContent: 'center',
|
|
185
|
+
alignItems: 'center',
|
|
182
186
|
},
|
|
183
187
|
});
|
|
@@ -447,7 +447,7 @@ const Item = ({ item, index, enableScript, t }) => {
|
|
|
447
447
|
</View>
|
|
448
448
|
);
|
|
449
449
|
} else if (notify_script) {
|
|
450
|
-
const { title, message } = notify_script;
|
|
450
|
+
const { title, message, unit_name } = notify_script;
|
|
451
451
|
return (
|
|
452
452
|
<View style={styles.wrapItem}>
|
|
453
453
|
<View style={styles.leftItem}>
|
|
@@ -469,6 +469,9 @@ const Item = ({ item, index, enableScript, t }) => {
|
|
|
469
469
|
</Text>
|
|
470
470
|
</View>
|
|
471
471
|
</View>
|
|
472
|
+
<Text numberOfLines={1} type="H4" color={color}>
|
|
473
|
+
{unit_name}
|
|
474
|
+
</Text>
|
|
472
475
|
</View>
|
|
473
476
|
</View>
|
|
474
477
|
);
|
|
@@ -481,7 +484,7 @@ const Item = ({ item, index, enableScript, t }) => {
|
|
|
481
484
|
{paddedIndex}
|
|
482
485
|
</Text>
|
|
483
486
|
</View>
|
|
484
|
-
<View style={styles.
|
|
487
|
+
<View style={styles.rightItemAction}>
|
|
485
488
|
<View style={styles.iconEndDevice}>
|
|
486
489
|
<Delay />
|
|
487
490
|
</View>
|
|
@@ -1,33 +1,41 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
Fragment,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
5
8
|
import { StyleSheet, TouchableOpacity, View } from 'react-native';
|
|
6
|
-
import {
|
|
9
|
+
import { useDataMember, useStateAlertAction } from './hooks';
|
|
10
|
+
import { useIsFocused, useNavigation } from '@react-navigation/native';
|
|
7
11
|
|
|
12
|
+
import { AccessibilityLabel } from '../../configs/Constants';
|
|
13
|
+
import AlertAction from '../../commons/AlertAction';
|
|
8
14
|
import { Colors } from '../../configs';
|
|
9
|
-
import
|
|
15
|
+
import { HeaderCustom } from '../../commons';
|
|
16
|
+
import { IconOutline } from '@ant-design/icons-react-native';
|
|
17
|
+
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
|
10
18
|
import MemberList from '../../commons/Sharing/MemberList';
|
|
11
|
-
import
|
|
19
|
+
import Routes from '../../utils/Route';
|
|
20
|
+
import { Search } from '../../commons/DevMode';
|
|
21
|
+
import { ToastBottomHelper } from '../../utils/Utils';
|
|
22
|
+
import { convertToSlug } from '../../utils/Functions/Search';
|
|
23
|
+
import { useBackendPermission } from '../../utils/Permission/backend';
|
|
12
24
|
import { useIsOwnerOfUnit } from '../../hooks/Common';
|
|
13
|
-
import AlertAction from '../../commons/AlertAction';
|
|
14
|
-
|
|
15
|
-
import { useDataMember, useStateAlertAction } from './hooks';
|
|
16
|
-
import { AccessibilityLabel } from '../../configs/Constants';
|
|
17
25
|
import { useSCContextSelector } from '../../context';
|
|
18
|
-
import {
|
|
19
|
-
import { ToastBottomHelper } from '../../utils/Utils';
|
|
26
|
+
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
20
27
|
|
|
21
28
|
const UnitMemberList = ({ route }) => {
|
|
22
29
|
const t = useTranslations();
|
|
23
30
|
const { navigate } = useNavigation();
|
|
24
31
|
const isFocused = useIsFocused();
|
|
25
32
|
const account = useSCContextSelector((state) => state.auth.account);
|
|
26
|
-
const { unitId, unit } = route?.params
|
|
33
|
+
const { unitId, unit } = route?.params;
|
|
27
34
|
const { dataMembers, isRefresh, onRefresh, leaveUnit, loading } =
|
|
28
35
|
useDataMember(unitId, unit?.user_id);
|
|
29
36
|
const { isOwner } = useIsOwnerOfUnit(unit?.user_id);
|
|
30
37
|
const permissions = useBackendPermission();
|
|
38
|
+
const [searchText, setSearchText] = useState('');
|
|
31
39
|
|
|
32
40
|
const { stateAlertSharingMenu, hideStateAlertSharingMenu, stateLeaveUnit } =
|
|
33
41
|
useStateAlertAction();
|
|
@@ -71,45 +79,59 @@ const UnitMemberList = ({ route }) => {
|
|
|
71
79
|
}, [hideStateAlertSharingMenu, isOwner, leaveUnit, unit.name]);
|
|
72
80
|
|
|
73
81
|
useEffect(() => {
|
|
74
|
-
|
|
75
|
-
onRefresh();
|
|
76
|
-
}
|
|
82
|
+
isFocused && onRefresh();
|
|
77
83
|
}, [isFocused, onRefresh]);
|
|
78
84
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
const matchedMembers = useMemo(() => {
|
|
86
|
+
return dataMembers.filter((member) => {
|
|
87
|
+
const text = convertToSlug(searchText);
|
|
88
|
+
const isPhoneMatch = convertToSlug(member.phone_number ?? '').includes(
|
|
89
|
+
text
|
|
90
|
+
);
|
|
91
|
+
const isNameMatch = convertToSlug(member.name ?? '').includes(text);
|
|
92
|
+
return isPhoneMatch || isNameMatch;
|
|
93
|
+
});
|
|
94
|
+
}, [dataMembers, searchText]);
|
|
95
|
+
const rightComponent = useMemo(
|
|
96
|
+
() => (
|
|
97
|
+
<TouchableOpacity
|
|
98
|
+
accessibilityLabel={AccessibilityLabel.MEMBER_LIST_RIGHT_HEADER_TOUCH}
|
|
99
|
+
onPress={onPressRightHeader}
|
|
100
|
+
>
|
|
101
|
+
{isOwner ? (
|
|
102
|
+
<IconOutline name={'plus'} size={27} color={Colors.Black} />
|
|
103
|
+
) : (
|
|
104
|
+
<MaterialIcons name={'more-vert'} size={27} color={Colors.Black} />
|
|
105
|
+
)}
|
|
106
|
+
</TouchableOpacity>
|
|
107
|
+
),
|
|
108
|
+
[isOwner, onPressRightHeader]
|
|
91
109
|
);
|
|
92
110
|
|
|
93
111
|
return (
|
|
94
112
|
<View style={styles.container}>
|
|
95
|
-
<
|
|
113
|
+
<HeaderCustom
|
|
96
114
|
title={t('unit_member')}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
>
|
|
115
|
+
isShowSeparator
|
|
116
|
+
rightComponent={rightComponent}
|
|
117
|
+
titleStyles={styles.headerTitle}
|
|
118
|
+
/>
|
|
119
|
+
<View style={styles.content}>
|
|
103
120
|
{!loading && (
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
121
|
+
<Fragment>
|
|
122
|
+
<Search onSearch={setSearchText} />
|
|
123
|
+
<MemberList
|
|
124
|
+
accessibilityLabel={AccessibilityLabel.SHARING_MEMBER}
|
|
125
|
+
dataMember={matchedMembers}
|
|
126
|
+
unit={unit}
|
|
127
|
+
ownerId={unit.user_id}
|
|
128
|
+
currentUserId={account.user.id}
|
|
129
|
+
isRefresh={isRefresh}
|
|
130
|
+
onRefresh={onRefresh}
|
|
131
|
+
/>
|
|
132
|
+
</Fragment>
|
|
111
133
|
)}
|
|
112
|
-
</
|
|
134
|
+
</View>
|
|
113
135
|
<AlertAction
|
|
114
136
|
visible={stateAlertSharingMenu.visible}
|
|
115
137
|
hideModal={hideStateAlertSharingMenu}
|
|
@@ -130,18 +152,19 @@ export default UnitMemberList;
|
|
|
130
152
|
const styles = StyleSheet.create({
|
|
131
153
|
container: {
|
|
132
154
|
flex: 1,
|
|
133
|
-
backgroundColor: Colors.
|
|
155
|
+
backgroundColor: Colors.White,
|
|
134
156
|
},
|
|
135
|
-
|
|
136
|
-
alignItems: 'center',
|
|
137
|
-
width: 44,
|
|
138
|
-
justifyContent: 'center',
|
|
157
|
+
content: {
|
|
139
158
|
flex: 1,
|
|
140
|
-
|
|
141
|
-
headerAniStyle: {
|
|
142
|
-
borderBottomWidth: 0,
|
|
159
|
+
marginHorizontal: 16,
|
|
143
160
|
},
|
|
144
161
|
rightButtonStyle: {
|
|
145
162
|
color: Colors.Red,
|
|
146
163
|
},
|
|
164
|
+
headerTitle: {
|
|
165
|
+
alignSelf: 'flex-start',
|
|
166
|
+
marginLeft: 0,
|
|
167
|
+
fontSize: 20,
|
|
168
|
+
lineHeight: 28,
|
|
169
|
+
},
|
|
147
170
|
});
|
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { create, act } from 'react-test-renderer';
|
|
1
|
+
import { act, create } from 'react-test-renderer';
|
|
3
2
|
|
|
4
|
-
import
|
|
3
|
+
import { API } from '../../../configs';
|
|
4
|
+
import { AccessibilityLabel } from '../../../configs/Constants';
|
|
5
5
|
import { AlertAction } from '../../../commons';
|
|
6
|
+
import MemberList from '../../../commons/Sharing/MemberList';
|
|
7
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import Routes from '../../../utils/Route';
|
|
6
10
|
import { SCProvider } from '../../../context';
|
|
7
|
-
import {
|
|
11
|
+
import { Search } from '../../../commons/DevMode';
|
|
12
|
+
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
8
13
|
import { TouchableOpacity } from 'react-native';
|
|
9
|
-
import
|
|
10
|
-
import MockAdapter from 'axios-mock-adapter';
|
|
14
|
+
import UnitMemberList from '../UnitMemberList';
|
|
11
15
|
import api from '../../../utils/Apis/axios';
|
|
12
|
-
import { useNavigation } from '@react-navigation/native';
|
|
13
|
-
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
14
16
|
import { getTranslate } from '../../../utils/I18n';
|
|
17
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
18
|
+
import { useNavigation } from '@react-navigation/native';
|
|
15
19
|
|
|
16
|
-
new MockAdapter(api.axiosInstance);
|
|
17
|
-
|
|
18
|
-
jest.mock('../../../hooks/Common', () => {
|
|
19
|
-
return {
|
|
20
|
-
useIsOwnerOfUnit: () => ({ isOwner: true }),
|
|
21
|
-
};
|
|
22
|
-
});
|
|
20
|
+
const mockAxios = new MockAdapter(api.axiosInstance);
|
|
23
21
|
|
|
24
22
|
const wrapComponent = (route, state = {}) => (
|
|
25
23
|
<SCProvider initState={mockSCStore(state)}>
|
|
@@ -29,21 +27,17 @@ const wrapComponent = (route, state = {}) => (
|
|
|
29
27
|
|
|
30
28
|
describe('test MemberList', () => {
|
|
31
29
|
let route;
|
|
32
|
-
let localState
|
|
33
|
-
auth: {
|
|
34
|
-
account: {
|
|
35
|
-
user: {
|
|
36
|
-
id: 2,
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const mockedNavigate = useNavigation().navigate;
|
|
30
|
+
let localState;
|
|
43
31
|
|
|
32
|
+
const mockNavigate = useNavigation().navigate;
|
|
33
|
+
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
34
|
+
const spyToastSuccess = jest.spyOn(ToastBottomHelper, 'success');
|
|
44
35
|
beforeEach(() => {
|
|
45
|
-
|
|
46
|
-
|
|
36
|
+
mockNavigate.mockClear();
|
|
37
|
+
mockAxios.reset();
|
|
38
|
+
spyToastError.mockClear();
|
|
39
|
+
spyToastSuccess.mockClear();
|
|
40
|
+
jest.clearAllMocks();
|
|
47
41
|
route = {
|
|
48
42
|
params: {
|
|
49
43
|
unitId: 1,
|
|
@@ -54,6 +48,16 @@ describe('test MemberList', () => {
|
|
|
54
48
|
},
|
|
55
49
|
},
|
|
56
50
|
};
|
|
51
|
+
|
|
52
|
+
localState = {
|
|
53
|
+
auth: {
|
|
54
|
+
account: {
|
|
55
|
+
user: {
|
|
56
|
+
id: 2,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
57
61
|
});
|
|
58
62
|
|
|
59
63
|
it('AlertAction rightButtonClick', async () => {
|
|
@@ -70,7 +74,7 @@ describe('test MemberList', () => {
|
|
|
70
74
|
await act(async () => {
|
|
71
75
|
await memberListButtons[1].props.onPress();
|
|
72
76
|
});
|
|
73
|
-
expect(
|
|
77
|
+
expect(mockNavigate).toHaveBeenCalledWith(Routes.AddMemberStack, {
|
|
74
78
|
screen: Routes.SelectShareDevice,
|
|
75
79
|
params: { unit: { id: 1 } },
|
|
76
80
|
});
|
|
@@ -84,6 +88,7 @@ describe('test MemberList', () => {
|
|
|
84
88
|
auth: {
|
|
85
89
|
account: {
|
|
86
90
|
user: {
|
|
91
|
+
id: 2,
|
|
87
92
|
permissions: {
|
|
88
93
|
max_members_per_unit: 0,
|
|
89
94
|
},
|
|
@@ -94,16 +99,108 @@ describe('test MemberList', () => {
|
|
|
94
99
|
);
|
|
95
100
|
});
|
|
96
101
|
const instance = tree.root;
|
|
97
|
-
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
98
102
|
const memberListButtons = instance.findAllByType(TouchableOpacity);
|
|
99
103
|
await act(async () => {
|
|
100
104
|
await memberListButtons[1].props.onPress();
|
|
101
105
|
});
|
|
102
|
-
expect(
|
|
103
|
-
expect(spyToastError).
|
|
106
|
+
expect(mockNavigate).not.toHaveBeenCalled();
|
|
107
|
+
expect(spyToastError).toHaveBeenCalledWith(
|
|
104
108
|
getTranslate('en', 'reach_max_members_per_unit', { length: 0 }),
|
|
105
109
|
'',
|
|
106
110
|
7000
|
|
107
111
|
);
|
|
108
112
|
});
|
|
113
|
+
|
|
114
|
+
it('test member leaves unit', async () => {
|
|
115
|
+
mockAxios.onDelete(API.SHARE.UNITS_MEMBER_DETAIL(1, 'me')).reply(200);
|
|
116
|
+
|
|
117
|
+
localState = {
|
|
118
|
+
auth: {
|
|
119
|
+
account: {
|
|
120
|
+
user: {
|
|
121
|
+
id: 5,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
let tree;
|
|
128
|
+
await act(async () => {
|
|
129
|
+
tree = await create(wrapComponent(route, localState));
|
|
130
|
+
});
|
|
131
|
+
const instance = tree.root;
|
|
132
|
+
|
|
133
|
+
const alertAction = instance.findByType(AlertAction);
|
|
134
|
+
await act(async () => {
|
|
135
|
+
alertAction.props.rightButtonClick();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const rightHeaderButton = instance.find(
|
|
139
|
+
(el) =>
|
|
140
|
+
el.type === TouchableOpacity &&
|
|
141
|
+
el.props.accessibilityLabel ===
|
|
142
|
+
AccessibilityLabel.MEMBER_LIST_RIGHT_HEADER_TOUCH
|
|
143
|
+
);
|
|
144
|
+
await act(async () => {
|
|
145
|
+
await rightHeaderButton.props.onPress();
|
|
146
|
+
});
|
|
147
|
+
expect(mockNavigate).toHaveBeenCalledWith(Routes.Dashboard);
|
|
148
|
+
expect(spyToastSuccess).toHaveBeenCalledTimes(1);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('test search member by name and phone', async () => {
|
|
152
|
+
const dataMember = [
|
|
153
|
+
{
|
|
154
|
+
id: 1,
|
|
155
|
+
name: 'user 1',
|
|
156
|
+
avatar: 'https://image1.jpg',
|
|
157
|
+
phone_number: '0933123456',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: 2,
|
|
161
|
+
name: 'user 2',
|
|
162
|
+
avatar: 'https://image1.jpg',
|
|
163
|
+
phone_number: '0933777111',
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
id: 3,
|
|
167
|
+
name: null,
|
|
168
|
+
avatar: 'https://image1.jpg',
|
|
169
|
+
phone_number: null,
|
|
170
|
+
},
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
mockAxios.onGet(API.SHARE.UNITS_MEMBERS(1)).reply(200, dataMember);
|
|
174
|
+
|
|
175
|
+
let tree;
|
|
176
|
+
await act(async () => {
|
|
177
|
+
tree = await create(wrapComponent(route, localState));
|
|
178
|
+
});
|
|
179
|
+
const instance = tree.root;
|
|
180
|
+
|
|
181
|
+
const search = instance.findByType(Search);
|
|
182
|
+
const memberList = instance.findByType(MemberList);
|
|
183
|
+
await act(async () => {
|
|
184
|
+
search.props.onSearch('user 1');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
expect(memberList.props.dataMember).toEqual([dataMember[0]]);
|
|
188
|
+
|
|
189
|
+
await act(async () => {
|
|
190
|
+
search.props.onSearch('3777');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(memberList.props.dataMember).toEqual([dataMember[1]]);
|
|
194
|
+
|
|
195
|
+
await act(async () => {
|
|
196
|
+
search.props.onSearch('');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
//move owner to top
|
|
200
|
+
expect(memberList.props.dataMember).toEqual([
|
|
201
|
+
dataMember[1],
|
|
202
|
+
dataMember[0],
|
|
203
|
+
dataMember[2],
|
|
204
|
+
]);
|
|
205
|
+
});
|
|
109
206
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import { act, renderHook } from '@testing-library/react-hooks';
|
|
3
|
-
|
|
4
|
-
import { useDataMember } from '..';
|
|
2
|
+
|
|
5
3
|
import API from '../../../../configs/API';
|
|
6
|
-
import
|
|
4
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import Routes from '../../../../utils/Route';
|
|
7
7
|
import { SCProvider } from '../../../../context';
|
|
8
|
+
import api from '../../../../utils/Apis/axios';
|
|
8
9
|
import { mockSCStore } from '../../../../context/mockStore';
|
|
9
|
-
import
|
|
10
|
+
import { useDataMember } from '..';
|
|
10
11
|
|
|
11
12
|
const mock = new MockAdapter(api.axiosInstance);
|
|
12
13
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { axiosDelete, axiosGet } from '../../../utils/Apis/axios';
|
|
1
2
|
import { useCallback, useState } from 'react';
|
|
2
|
-
|
|
3
|
-
import { useNavigation } from '@react-navigation/native';
|
|
3
|
+
|
|
4
4
|
import { API } from '../../../configs';
|
|
5
5
|
import Routes from '../../../utils/Route';
|
|
6
|
-
import { axiosDelete, axiosGet } from '../../../utils/Apis/axios';
|
|
7
6
|
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
8
|
-
import { useSCContextSelector } from '../../../context';
|
|
9
7
|
import { useIsOwnerOfUnit } from '../../../hooks/Common';
|
|
8
|
+
import { useNavigation } from '@react-navigation/native';
|
|
9
|
+
import { useSCContextSelector } from '../../../context';
|
|
10
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
10
11
|
|
|
11
12
|
const useDataMember = (unitId, userUnitId = undefined) => {
|
|
12
13
|
const t = useTranslations();
|