@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.
Files changed (31) hide show
  1. package/README.md +5 -1
  2. package/package.json +1 -2
  3. package/src/Images/Common/pushpin-full.svg +3 -0
  4. package/src/Images/Common/pushpin-outline.svg +3 -0
  5. package/src/Images/Common/star-full.svg +3 -0
  6. package/src/Images/Common/star-outline.svg +3 -0
  7. package/src/commons/Dashboard/MyPinnedSharedUnit/index.js +1 -6
  8. package/src/commons/Device/Hanet/ItemHanetDevice.js +5 -1
  9. package/src/commons/Device/ItemAddNew/index.js +6 -2
  10. package/src/commons/Device/ItemDevice.js +5 -1
  11. package/src/commons/SubUnit/OneTap/ItemOneTap.js +10 -2
  12. package/src/commons/Unit/HeaderUnit/index.js +5 -1
  13. package/src/commons/Unit/SharedUnit.js +58 -43
  14. package/src/commons/Unit/__test__/SharedUnit.test.js +60 -100
  15. package/src/commons/WrapParallaxScrollView/index.js +4 -0
  16. package/src/configs/AccessibilityLabel.js +3 -0
  17. package/src/navigations/AutomateStack.js +5 -2
  18. package/src/navigations/NotificationStack.js +28 -2
  19. package/src/navigations/SharedStack.js +8 -2
  20. package/src/screens/AddNewGateway/ConnectingDevice.js +0 -1
  21. package/src/screens/AddNewGateway/ShareWifiPassword.js +0 -1
  22. package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +1 -0
  23. package/src/screens/Automate/ScriptDetail/index.js +4 -7
  24. package/src/screens/Device/detail.js +4 -6
  25. package/src/screens/Notification/__test__/Notification.test.js +14 -8
  26. package/src/screens/Notification/components/NotificationItem.js +1 -0
  27. package/src/screens/Notification/index.js +42 -48
  28. package/src/screens/Notification/styles/indexStyles.js +6 -3
  29. package/src/screens/SharedUnit/index.js +1 -4
  30. package/src/screens/Unit/components/SharedUnit/index.js +6 -9
  31. 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.44",
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 name="right" size={12} />
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 name="plus" size={22} color={Colors.Gray8} />
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 name="right" size={12} />
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 { TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native';
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 name="right" size={12} />
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 source={Images.arrowLeft} style={styles.iconBack} />
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, Colors, Images } from '../../configs';
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
- navigation.navigate(Routes.UnitStack, {
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
- }, [navigation, unit]);
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
- {item.is_pin ? (
94
- <IconFill
95
- name="pushpin"
96
- size={20}
97
- color={Colors.Blue10}
98
- onPress={removePinSharedUnit}
99
- accessibilityLabel={`${AccessibilityLabel.ICON_REMOVE_PIN_SHARED_UNIT}-${item.id}`}
100
- />
101
- ) : (
102
- <IconOutline
103
- name="pushpin"
104
- size={20}
105
- onPress={addPinSharedUnit}
106
- accessibilityLabel={`${AccessibilityLabel.ICON_ADD_PIN_SHARED_UNIT}-${item.id}`}
107
- />
108
- )}
109
- {item.is_star ? (
110
- <IconFill
111
- name="star"
112
- size={20}
113
- color={Colors.Yellow6}
114
- onPress={removeStarSharedUnit}
115
- accessibilityLabel={`${AccessibilityLabel.ICON_REMOVE_STAR_SHARED_UNIT}-${item.id}`}
116
- />
117
- ) : (
118
- <IconOutline
119
- name="star"
120
- size={20}
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, navigation, isOptions, mockedRenewItem) => (
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(0);
159
- expect(iconStarUnit).toHaveLength(0);
90
+ expect(iconAddPinSharedUnit).toHaveLength(1);
91
+ expect(iconStarUnit).toHaveLength(1);
160
92
  });
161
93
 
162
- it('test create SharedUnit unit is pin, is star', async () => {
163
- const navigation = useNavigation();
164
- item.is_pin = true;
165
- item.is_star = true;
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, navigation));
124
+ tree = await create(wrapComponent(item, true, mockedRenewItem));
169
125
  });
170
126
  const instance = tree.root;
171
- const iconRemovePinSharedUnit = instance.find(
172
- (el) =>
173
- el.props.accessibilityLabel ===
174
- AccessibilityLabel.ICON_REMOVE_PIN_SHARED_UNIT + '-69'
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
- iconRemovePinSharedUnit.props.onPress();
138
+ await pinButton.props.onPress();
179
139
  });
180
- mock.onPost(API.UNIT.UNPIN_UNIT(3)).reply(400);
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
- iconRemovePinSharedUnit.props.onPress();
146
+ tree = await create(wrapComponent(item, true, mockedRenewItem));
183
147
  });
184
- const iconRemoveStarSharedUnit = instance.find(
185
- (el) =>
186
- el.props.accessibilityLabel ===
187
- AccessibilityLabel.ICON_REMOVE_STAR_SHARED_UNIT + '-69'
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
- iconRemoveStarSharedUnit.props.onPress();
154
+ await pinButton.props.onPress();
192
155
  });
193
- mock.onPost(API.UNIT.UNSTAR_UNIT(3)).reply(400);
156
+ expect(mockedRenewItem).toBeCalledTimes(1);
157
+
158
+ mock.onPost(API.UNIT.UNSTAR_UNIT(3)).reply(200);
194
159
  await act(async () => {
195
- iconRemoveStarSharedUnit.props.onPress();
160
+ await pinButton.props.onPress();
196
161
  });
197
- const iconRemoveStar = instance.findAll(
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 name={'menu'} color={Colors.Black} />
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: false,
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={params?.isMainSource ? 'menu' : 'arrow-left'}
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';
@@ -63,6 +63,7 @@ export default StyleSheet.create({
63
63
  },
64
64
  moreButton: {
65
65
  marginLeft: -5,
66
+ transform: [{ rotate: '90deg' }],
66
67
  },
67
68
  wrapStyle: {
68
69
  borderRadius: 8,
@@ -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={'more'} size={27} color={Colors.Black} />
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, IconOutline } from '@ant-design/icons-react-native';
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 { Animated, RefreshControl } from 'react-native';
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 { WrapHeaderScrollable } from '../../../commons';
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 wrapHeaderScrollable = instance.findByType(WrapHeaderScrollable);
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
- scrollView.props.onMomentumScrollEnd();
114
+ await flatlist.props.onMomentumScrollBegin();
115
+ await flatlist.props.onEndReached();
117
116
  });
118
- expect(wrapHeaderScrollable.props.disableLoadMore).toEqual(true);
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 () => {
@@ -30,6 +30,7 @@ const NotificationItem = memo(({ item }) => {
30
30
  bold={i % 2 !== 0}
31
31
  key={i}
32
32
  style={styles.textNotification}
33
+ accessibilityLabel={AccessibilityLabel.NotificationItemText}
33
34
  >
34
35
  {i % 2 === 0 ? str : params[str]}
35
36
  </Text>
@@ -1,55 +1,29 @@
1
- import React, { memo, useMemo, useState, useCallback, useEffect } from 'react';
2
- import { View, TouchableOpacity } from 'react-native';
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, Colors } from '../../configs';
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 t = useTranslations();
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 rightComponent = useMemo(
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
- setPage((preState) => preState + 1);
64
- if (page < maxPageNotification) {
65
- fetchNotifications(page + 1);
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
- <WrapHeaderScrollable
97
- title={t('notifications')}
98
- rightComponent={rightComponent}
99
- onLoadMore={handleOnLoadMore}
88
+ <FlatList
89
+ keyExtractor={(item) => item.id}
90
+ renderItem={({ item }) => <NotificationItem item={item} />}
91
+ data={notifications}
92
+ extraData={notifications}
100
93
  onRefresh={onRefresh}
101
- disableLoadMore={page >= maxPageNotification}
102
- styleScrollView={styles.styleScrollView}
103
- >
104
- {notifications.map((item, index) => (
105
- <NotificationItem item={item} key={index} />
106
- ))}
107
- </WrapHeaderScrollable>
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, useNavigation } from '@react-navigation/native';
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
- navigation.navigate(Routes.UnitStack, {
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
- }, [navigation, unit]);
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, navigation) => (
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, navigation));
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, navigation));
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, navigation));
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(mockRenewItem).toBeCalled();
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
  });