@eohjsc/react-native-smart-city 0.2.73 → 0.2.74

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 (45) hide show
  1. package/package.json +2 -2
  2. package/src/Images/Common/disney.svg +20 -0
  3. package/src/Images/Common/home.svg +3 -0
  4. package/src/Images/Common/input.svg +3 -0
  5. package/src/Images/Common/keyboard_arrow_down.svg +3 -0
  6. package/src/Images/Common/keyboard_arrow_up.svg +3 -0
  7. package/src/Images/Common/keyboard_return.svg +3 -0
  8. package/src/Images/Common/netflix.svg +9 -0
  9. package/src/Images/Common/pause.svg +3 -0
  10. package/src/Images/Common/shadowButton.png +0 -0
  11. package/src/Images/Common/spotify.svg +5 -0
  12. package/src/Images/Common/volume_up.svg +3 -0
  13. package/src/Images/Common/youtube.svg +13 -0
  14. package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +214 -0
  15. package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplateStyles.js +69 -0
  16. package/src/commons/ActionGroup/SmartTiviActionTemplate/__test__/CircleButton.test.js +129 -0
  17. package/src/commons/ActionGroup/SmartTiviActionTemplate/__test__/ControlPlay.test.js +138 -0
  18. package/src/commons/ActionGroup/SmartTiviActionTemplate/__test__/RectangleButton.test.js +110 -0
  19. package/src/commons/ActionGroup/SmartTiviActionTemplate/__test__/SmartTiviActionTemplate.test.js +144 -0
  20. package/src/commons/ActionGroup/SmartTiviActionTemplate/component/CircleButton.js +91 -0
  21. package/src/commons/ActionGroup/SmartTiviActionTemplate/component/CircleButtonStyles.js +79 -0
  22. package/src/commons/ActionGroup/SmartTiviActionTemplate/component/ControlPlay.js +51 -0
  23. package/src/commons/ActionGroup/SmartTiviActionTemplate/component/ControlPlayStyles.js +28 -0
  24. package/src/commons/ActionGroup/SmartTiviActionTemplate/component/Icon.js +25 -0
  25. package/src/commons/ActionGroup/SmartTiviActionTemplate/component/RectangleButton.js +49 -0
  26. package/src/commons/ActionGroup/SmartTiviActionTemplate/component/RectangleButtonStyles.js +47 -0
  27. package/src/commons/ActionGroup/index.js +3 -0
  28. package/src/commons/Device/HistoryChart.js +11 -7
  29. package/src/commons/Device/WaterQualitySensor/QualityIndicatorsItem.js +1 -1
  30. package/src/configs/API.js +3 -0
  31. package/src/configs/Constants.js +23 -0
  32. package/src/configs/Images.js +1 -0
  33. package/src/navigations/UnitStack.js +1 -3
  34. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +37 -50
  35. package/src/screens/ConfirmUnitDeletion/index.js +1 -1
  36. package/src/screens/Device/EditDevice/index.js +1 -1
  37. package/src/screens/Device/EditDevice/styles/EditDeviceStyles.js +2 -0
  38. package/src/screens/Notification/Monitor.js +12 -0
  39. package/src/screens/Notification/components/NotificationItem.js +11 -0
  40. package/src/screens/Notification/index.js +8 -0
  41. package/src/screens/Unit/ManageUnit.js +9 -6
  42. package/src/screens/Unit/components/MyUnitDevice/index.js +4 -1
  43. package/src/utils/I18n/translations/en.json +1 -0
  44. package/src/utils/I18n/translations/vi.json +1 -0
  45. package/src/utils/Pusher/index.js +36 -0
@@ -0,0 +1,49 @@
1
+ import React, { memo } from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
+
4
+ import styles from './RectangleButtonStyles';
5
+ import { KeyboardArrowUp, KeyboardArrowDown } from './Icon';
6
+ import { TESTID } from '../../../../configs/Constants';
7
+
8
+ const RectangleButton = memo(
9
+ ({ icon, onPressUp, onPressDown, wrapStyle, type, onPress }) => {
10
+ switch (type) {
11
+ case 'row':
12
+ return (
13
+ <View style={[styles.wrapRowRectangle, wrapStyle]}>
14
+ <TouchableOpacity style={[styles.rectangleRow]} onPress={onPress}>
15
+ {!!icon && icon}
16
+ </TouchableOpacity>
17
+ </View>
18
+ );
19
+ case 'column':
20
+ return (
21
+ <View style={[styles.wrapColumnRectangle, wrapStyle]}>
22
+ <TouchableOpacity
23
+ style={[styles.rectangleColumn]}
24
+ onPress={onPressUp}
25
+ testID={TESTID.SMART_TIVI_TEMPLATE.CH_VOLUME_UP_BUTTON}
26
+ >
27
+ <KeyboardArrowUp size={24} name={'up'} style={styles.padding8} />
28
+ </TouchableOpacity>
29
+ <View style={styles.iconKeyboardRetangle}>{!!icon && icon}</View>
30
+ <TouchableOpacity
31
+ style={[styles.rectangleColumn]}
32
+ onPress={onPressDown}
33
+ testID={TESTID.SMART_TIVI_TEMPLATE.CH_VOLUME_DOWN_BUTTON}
34
+ >
35
+ <KeyboardArrowDown
36
+ size={24}
37
+ name={'down'}
38
+ style={styles.padding8}
39
+ />
40
+ </TouchableOpacity>
41
+ </View>
42
+ );
43
+ default:
44
+ return <></>;
45
+ }
46
+ }
47
+ );
48
+
49
+ export default RectangleButton;
@@ -0,0 +1,47 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors, Device } from '../../../../configs';
3
+ const widthMonitor = Device.screenWidth;
4
+
5
+ const centerRowItem = {
6
+ justifyContent: 'center',
7
+ alignItems: 'center',
8
+ };
9
+ const centerColumnItem = {
10
+ flexDirection: 'column',
11
+ justifyContent: 'space-between',
12
+ };
13
+ const borderItem = {
14
+ borderWidth: 1,
15
+ borderColor: Colors.Gray4,
16
+ borderRadius: 10,
17
+ };
18
+ export default StyleSheet.create({
19
+ rectangleColumn: {
20
+ padding: 16,
21
+ ...centerRowItem,
22
+ },
23
+ rectangleRow: {
24
+ ...centerRowItem,
25
+ },
26
+ wrapRowRectangle: {
27
+ flexWrap: 'nowrap',
28
+ ...centerColumnItem,
29
+ width: widthMonitor / 2 - 37,
30
+ ...borderItem,
31
+ margin: 12,
32
+ padding: 10,
33
+ },
34
+ wrapColumnRectangle: {
35
+ width: 63,
36
+ height: 186,
37
+ ...centerColumnItem,
38
+ backgroundColor: Colors.White,
39
+ ...borderItem,
40
+ },
41
+ iconKeyboardRetangle: {
42
+ ...centerRowItem,
43
+ },
44
+ padding8: {
45
+ padding: 8,
46
+ },
47
+ });
@@ -9,6 +9,7 @@ import OptionsDropdownActionTemplate from './OptionsDropdownActionTemplate';
9
9
  import OnOffTemplate from './OnOffTemplate';
10
10
  import TimerActionTemplate from './TimerActionTemplate';
11
11
  import CurtainButtonTemplate from './CurtainButtonTemplate';
12
+ import SmartTiviActionTemplate from './SmartTiviActionTemplate/SmartTiviActionTemplate';
12
13
 
13
14
  export const getActionComponent = (template) => {
14
15
  switch (template) {
@@ -32,6 +33,8 @@ export const getActionComponent = (template) => {
32
33
  return TimerActionTemplate;
33
34
  case 'curtain_action_template':
34
35
  return CurtainButtonTemplate;
36
+ case 'SmartTiviActionTemplate':
37
+ return SmartTiviActionTemplate;
35
38
  default:
36
39
  return null;
37
40
  }
@@ -190,13 +190,17 @@ const HistoryChart = memo(
190
190
  />
191
191
  )}
192
192
  </View>
193
- <DateTimeRangeChange
194
- startTime={eventPicker.startTime}
195
- onStart={onStart}
196
- onEnd={onEnd}
197
- endTime={eventPicker.endTime}
198
- formatType={formatType}
199
- />
193
+ {!(
194
+ configuration.type === 'horizontal_bar_chart' && groupBy !== 'date'
195
+ ) && (
196
+ <DateTimeRangeChange
197
+ startTime={eventPicker.startTime}
198
+ onStart={onStart}
199
+ onEnd={onEnd}
200
+ endTime={eventPicker.endTime}
201
+ formatType={formatType}
202
+ />
203
+ )}
200
204
  </View>
201
205
  {configuration.config === 'power_consumption' && (
202
206
  <View style={styles.wrapCalculateCost}>
@@ -68,7 +68,7 @@ const styles = StyleSheet.create({
68
68
  borderWidth: 1,
69
69
  borderColor: Colors.Gray4,
70
70
  marginRight: 8,
71
- width: (width / 375) * 112,
71
+ width: (width / 375) * 120,
72
72
  },
73
73
  rowFlex: {
74
74
  flexDirection: 'row',
@@ -204,6 +204,9 @@ const API = {
204
204
  REMOVE_SMART_ACCOUNT: (id) =>
205
205
  SCConfig.apiRoot + `/smart_account/smart_accounts/${id}/`,
206
206
  },
207
+ PUSHER: {
208
+ AUTH: () => SCConfig.apiRoot + '/smart_parking/pusher/auth/',
209
+ },
207
210
  };
208
211
 
209
212
  export default API;
@@ -178,6 +178,28 @@ export const TESTID = {
178
178
  MY_UNIT_NO_UNIT: 'MY_UNIT_NO_UNIT',
179
179
  ITEM_UNIT: 'ITEM_UNIT',
180
180
 
181
+ // SmartTiviTemplate
182
+ SMART_TIVI_TEMPLATE: {
183
+ BIG_BUTTON: 'BIG_BUTTON',
184
+ ONOFF_BUTTON: 'ONOFF_BUTTON',
185
+ EXIT_BUTTON: 'EXIT_BUTTON',
186
+ CH_VOLUME_UP_BUTTON: 'CH_VOLUME_UP_BUTTON',
187
+ CH_VOLUME_DOWN_BUTTON: 'CH_VOLUME_DOWN_BUTTON',
188
+ PREV_BUTTON: 'PREV_BUTTON',
189
+ STOP_BUTTON: 'STOP_BUTTON',
190
+ NEXT_BUTTON: 'NEXT_BUTTON',
191
+ UP_BUTTON: 'UP_BUTTON',
192
+ DOWN_BUTTON: 'DOWN_BUTTON',
193
+ LEFT_BUTTON: 'LEFT_BUTTON',
194
+ RIGHT_BUTTON: 'RIGHT_BUTTON',
195
+ OK_BUTTON: 'OK_BUTTON',
196
+ HOME_BUTTON: 'HOME_BUTTON',
197
+ BACK_BUTTON: 'BACK_BUTTON',
198
+ VOLUME_BUTTON: 'VOLUME_BUTTON',
199
+ CH_BUTTON: 'CH_BUTTON',
200
+ CONTROL_BUTTON: 'CONTROL_BUTTON',
201
+ },
202
+
181
203
  // sub unit
182
204
  SUB_UNIT_FULL_CAMERA: 'SUB_UNIT_FULL_CAMERA',
183
205
  SUB_UNIT_CAMERA_VIEW: 'SUB_UNIT_CAMERA_VIEW',
@@ -612,6 +634,7 @@ export const NOTIFICATION_TYPES = {
612
634
  REMINDER: 'REMINDER',
613
635
  NOTIFY_REMOVE_UNIT: 'NOTIFY_REMOVE_UNIT',
614
636
  NOTIFY_REMOVE_MEMBER: 'NOTIFY_REMOVE_MEMBER',
637
+ NOTIFY_MEMBER_LEAVE_UNIT: 'NOTIFY_MEMBER_LEAVE_UNIT',
615
638
  };
616
639
 
617
640
  export const ACTIVITY_LOG_TYPES = {
@@ -10,4 +10,5 @@ export default {
10
10
  buttonPauseCurtain: require('../Images/Common/buttonPauseCurtain.png'),
11
11
  buttonLeftCurtain: require('../Images/Common/buttonLeftCurtain.png'),
12
12
  buttonRightCurtain: require('../Images/Common/buttonRightCurtain.png'),
13
+ shadowButton: require('../Images/Common/shadowButton.png'),
13
14
  };
@@ -1,5 +1,5 @@
1
1
  import React, { memo } from 'react';
2
- import { View, StyleSheet, Platform } from 'react-native';
2
+ import { View, StyleSheet } from 'react-native';
3
3
  import { IconOutline } from '@ant-design/icons-react-native';
4
4
  import { createStackNavigator } from '@react-navigation/stack';
5
5
  import { get } from 'lodash';
@@ -134,7 +134,6 @@ export const UnitStack = memo((props) => {
134
134
  component={UnitSummary}
135
135
  options={{
136
136
  headerShown: false,
137
- animationEnabled: Platform.OS === 'ios',
138
137
  }}
139
138
  />
140
139
  <Stack.Screen
@@ -161,7 +160,6 @@ export const UnitStack = memo((props) => {
161
160
  component={DeviceDetail}
162
161
  options={{
163
162
  headerShown: false,
164
- animationEnabled: Platform.OS === 'ios',
165
163
  }}
166
164
  />
167
165
  <Stack.Screen
@@ -20,45 +20,12 @@ import { Colors, API } from '../../../configs';
20
20
  import { axiosPost } from '../../../utils/Apis/axios';
21
21
  import Routes from '../../../utils/Route';
22
22
 
23
- const socket = dgram.createSocket({ type: 'udp4' });
24
-
25
- socket.once('listening', function () {
26
- socket.send(
27
- JSON.stringify({ type: 'scan', data: { wifi: '' } }),
28
- undefined,
29
- undefined,
30
- 54321,
31
- '192.168.27.1',
32
- undefined
33
- );
34
- });
35
-
36
23
  const ConnectWifiWarning = memo(({ route }) => {
37
24
  const { wifi_ssid, wifi_pass, unit_id, chip_id } = route.params;
38
25
  const t = useTranslations();
39
- const { navigate } = useNavigation();
26
+ const { navigate, goBack } = useNavigation();
40
27
  const [isLoading, setIsLoading] = useState(false);
41
28
 
42
- socket.on('message', function (msg, rinfo) {
43
- const data = JSON.parse(msg.toString());
44
- if (data.hasOwnProperty('wifi')) {
45
- navigate(Routes.GatewayWifiList, {
46
- list_wifi: data.wifi,
47
- unit_id: unit_id,
48
- chip_id: chip_id,
49
- socket: socket,
50
- });
51
- }
52
- if (data.hasOwnProperty('gateway')) {
53
- navigate(Routes.Dashboard);
54
- ToastBottomHelper.success(t('completed'));
55
- }
56
- });
57
-
58
- socket.on('error', () => {
59
- ToastBottomHelper.error(t('server_error'));
60
- });
61
-
62
29
  const getPermissionWifiAndroid = useCallback(async () => {
63
30
  const granted = await PermissionsAndroid.request(
64
31
  PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
@@ -78,26 +45,45 @@ const ConnectWifiWarning = memo(({ route }) => {
78
45
 
79
46
  useEffect(() => {
80
47
  Platform.OS === 'android' && getPermissionWifiAndroid();
81
- socket.bind(54321);
82
48
  }, [getPermissionWifiAndroid]);
83
49
 
84
- const handleSend = async () => {
85
- await socket.send(
86
- JSON.stringify({ type: 'scan', data: { wifi: '' } }),
87
- undefined,
88
- undefined,
89
- 54321,
90
- '192.168.27.1',
91
- undefined
92
- );
50
+ const handleSend = () => {
51
+ const socket = dgram.createSocket({ type: 'udp4' });
52
+ socket.bind(54321);
53
+ socket.once('listening', function () {
54
+ socket.send(
55
+ JSON.stringify({ type: 'scan', data: { wifi: '' } }),
56
+ undefined,
57
+ undefined,
58
+ 54321,
59
+ '192.168.27.1',
60
+ undefined
61
+ );
62
+ });
63
+ socket.on('message', function (msg, rinfo) {
64
+ const data = JSON.parse(msg.toString());
65
+ if (data.hasOwnProperty('wifi')) {
66
+ navigate(Routes.GatewayWifiList, {
67
+ list_wifi: data.wifi,
68
+ unit_id: unit_id,
69
+ chip_id: chip_id,
70
+ socket: socket,
71
+ });
72
+ }
73
+ if (data.hasOwnProperty('gateway')) {
74
+ navigate(Routes.Dashboard);
75
+ ToastBottomHelper.success(t('completed'));
76
+ }
77
+ });
78
+ socket.on('error', () => {
79
+ ToastBottomHelper.error(t('server_error'));
80
+ goBack();
81
+ });
82
+ return () => {
83
+ socket.close();
84
+ };
93
85
  };
94
86
 
95
- useEffect(() => {
96
- if (isLoading) {
97
- handleSend();
98
- }
99
- }, [isLoading]);
100
-
101
87
  const handleConnectWifiGateway = async () => {
102
88
  setIsLoading(true);
103
89
  const { success } = await axiosPost(API.UNIT.ADD_GATEWAY(unit_id), {
@@ -113,6 +99,7 @@ const ConnectWifiWarning = memo(({ route }) => {
113
99
  },
114
100
  (e) => {
115
101
  ToastBottomHelper.error('Connection failed!');
102
+ goBack();
116
103
  }
117
104
  );
118
105
  };
@@ -28,8 +28,8 @@ const ConfirmUnitDeletion = ({ route }) => {
28
28
  if (confirm === 'YES') {
29
29
  const { success } = await axiosDelete(API.UNIT.MANAGE_UNIT(unit.id));
30
30
  if (success) {
31
- navigation.navigate(Routes.Dashboard);
32
31
  ToastBottomHelper.success(t('unit_deleted_successfully'));
32
+ navigation.navigate(Routes.Dashboard);
33
33
  }
34
34
  } else {
35
35
  setErrorText(t('please_enter_correct'));
@@ -96,7 +96,7 @@ const EditDevice = memo(() => {
96
96
  </Text>
97
97
  <IconOutline
98
98
  name="right"
99
- size={20}
99
+ size={18}
100
100
  color={Colors.Gray7}
101
101
  style={styles.iconRight}
102
102
  />
@@ -25,6 +25,8 @@ export default StyleSheet.create({
25
25
  DeviceButtonRight: {
26
26
  flexDirection: 'row',
27
27
  paddingRight: 16,
28
+ marginTop: 1,
29
+ marginLeft: 5,
28
30
  },
29
31
  iconRight: {
30
32
  paddingLeft: 16,
@@ -0,0 +1,12 @@
1
+ import { getPusher, destroyPusher } from '../../utils/Pusher';
2
+
3
+ // eslint-disable-next-line promise/prefer-await-to-callbacks
4
+ export const watchNotificationData = (user, callback) => {
5
+ const channel = getPusher().subscribe(`private-user-${user.id}`);
6
+ channel.bind('new-notification', callback);
7
+ };
8
+
9
+ export const unwatchNotificationData = (user) => {
10
+ getPusher().unsubscribe(`private-user-${user.id}`);
11
+ destroyPusher();
12
+ };
@@ -243,6 +243,17 @@ const NotificationItem = memo(({ item }) => {
243
243
  <IconComponent icon={'home'} style={styles.backgroundSummer} />
244
244
  ),
245
245
  };
246
+ case NOTIFICATION_TYPES.NOTIFY_MEMBER_LEAVE_UNIT:
247
+ return {
248
+ content: customColorText(
249
+ t('text_notification_content_member_leave_unit'),
250
+ arrParams
251
+ ),
252
+ redirect: () => null,
253
+ iconContent: (
254
+ <IconComponent icon={'home'} style={styles.backgroundSummer} />
255
+ ),
256
+ };
246
257
  default:
247
258
  return {
248
259
  content: customColorText(t('this_notification_will_be_updated_soon')),
@@ -8,11 +8,14 @@ import { axiosGet } from '../../utils/Apis/axios';
8
8
  import { useTranslations } from '../../hooks/Common/useTranslations';
9
9
  import NotificationItem from './components/NotificationItem';
10
10
  import WrapHeaderScrollable from '../../commons/Sharing/WrapHeaderScrollable';
11
+ import { watchNotificationData, unwatchNotificationData } from './Monitor';
12
+ import { useSCContextSelector } from '../../context';
11
13
 
12
14
  let page = 1;
13
15
 
14
16
  const Notification = memo(() => {
15
17
  const t = useTranslations();
18
+ const user = useSCContextSelector((state) => state?.auth?.account?.user);
16
19
  const [notifications, setNotifications] = useState([]);
17
20
  const [maxPageNotification, setMaxPageNotification] = useState(1);
18
21
  const rightComponent = useMemo(
@@ -66,6 +69,11 @@ const Notification = memo(() => {
66
69
  }
67
70
  }, []);
68
71
 
72
+ useEffect(() => {
73
+ watchNotificationData(user, onRefresh);
74
+ return () => unwatchNotificationData(user);
75
+ }, [user, onRefresh]);
76
+
69
77
  return (
70
78
  <View style={styles.wrap}>
71
79
  <WrapHeaderScrollable
@@ -73,8 +73,8 @@ const ManageUnit = ({ route }) => {
73
73
  const [showImagePicker, setShowImagePicker] = useState(false);
74
74
 
75
75
  const updateUnit = useCallback(
76
- async (headers) => {
77
- const formData = createFormData({ background: imageUrl }, ['background']);
76
+ async (bodyData, headers) => {
77
+ const formData = createFormData(bodyData, ['background']);
78
78
 
79
79
  const { success, data } = await axiosPatch(
80
80
  API.UNIT.MANAGE_UNIT(unit.id),
@@ -86,7 +86,7 @@ const ManageUnit = ({ route }) => {
86
86
  ToastBottomHelper.success(t('unit_updated_successfully'));
87
87
  }
88
88
  },
89
- [unit.id, t, imageUrl]
89
+ [unit.id, t]
90
90
  );
91
91
 
92
92
  const updateLocation = useCallback(
@@ -116,9 +116,12 @@ const ManageUnit = ({ route }) => {
116
116
 
117
117
  useEffect(() => {
118
118
  if (imageUrl) {
119
- updateUnit({
120
- headers: { 'Content-Type': 'multipart/form-data' },
121
- });
119
+ updateUnit(
120
+ { background: imageUrl },
121
+ {
122
+ headers: { 'Content-Type': 'multipart/form-data' },
123
+ }
124
+ );
122
125
  }
123
126
  }, [imageUrl, updateUnit]);
124
127
 
@@ -51,12 +51,14 @@ const MyUnitDevice = ({ sensor, unit }) => {
51
51
 
52
52
  const styles = StyleSheet.create({
53
53
  item: {
54
- height: 46,
54
+ height: 'auto',
55
55
  flexDirection: 'row',
56
56
  justifyContent: 'space-between',
57
57
  alignItems: 'center',
58
58
  borderBottomColor: Colors.Gray4,
59
59
  borderBottomWidth: 1,
60
+ paddingTop: 5,
61
+ paddingBottom: 5,
60
62
  },
61
63
  iconCircle: {
62
64
  width: 32,
@@ -89,6 +91,7 @@ const styles = StyleSheet.create({
89
91
  height: 32,
90
92
  },
91
93
  marginTop3: {
94
+ flex: 1,
92
95
  marginTop: 3,
93
96
  },
94
97
  });
@@ -671,6 +671,7 @@
671
671
  "text_notification_content_remove_unit_to_owner": "Unit **%{unit_name}** has been removed successfully.",
672
672
  "text_notification_content_remove_unit_to_member": "Unit **%{unit_name}** has been removed by **%{unit_owner_name}**. You cannot access to this unit anymore.",
673
673
  "text_notification_content_remove_member": "You were remove from **%{unit_name}** by **%{unit_owner_name}**. You cannot access to this unit anymore.",
674
+ "text_notification_content_member_leave_unit": "**%{member_name}** has left **%{unit_name}**.",
674
675
  "this_spot_does_not_exsit": "This spot does not exist",
675
676
  "please_scan_again_or_contact_the_parking_manager": "Please scan again or contact the parking manager",
676
677
  "this_spot_does_not_support_to_scan": "This spot does not support to scan",
@@ -679,6 +679,7 @@
679
679
  "text_notification_content_remove_unit_to_owner": "Địa điểm **%{unit_name}** vừa được xoá thành công.",
680
680
  "text_notification_content_remove_unit_to_member": "Địa điểm **%{unit_name}** vừa được xoá bởi **%{unit_owner_name}**. Bạn không thể truy cập vào địa điểm này được nữa.",
681
681
  "text_notification_content_remove_member": "Bạn vừa được xoá khỏi **%{unit_name}** bởi **%{unit_owner_name}**. Bạn không thể truy cập vào địa điểm này được nữa.",
682
+ "text_notification_content_member_leave_unit": "**%{member_name}** vừa rời khỏi **%{unit_name}**.",
682
683
  "this_spot_does_not_exsit": "Vị trí đỗ này không tồn tại",
683
684
  "please_scan_again_or_contact_the_parking_manager": "Vui lòng quét lại hoặc liên hệ với người quản lý bãi đậu xe",
684
685
  "this_spot_does_not_support_to_scan": "Vị trí đỗ này không hỗ trợ quét",
@@ -0,0 +1,36 @@
1
+ import { API } from '../../configs';
2
+ import Pusher from 'pusher-js/react-native';
3
+ import { SCConfig } from '../../configs/SCConfig';
4
+ import { axiosPost } from '../../utils/Apis/axios';
5
+
6
+ Pusher.logToConsole = true;
7
+ let pusher = null;
8
+
9
+ export const getPusher = () => {
10
+ if (!pusher) {
11
+ pusher = new Pusher(SCConfig.pusherAppKey, {
12
+ cluster: SCConfig.pusherAppCluste,
13
+ authorizer: function (channel, option) {
14
+ return {
15
+ // eslint-disable-next-line promise/prefer-await-to-callbacks
16
+ authorize: async function (socketId, callback) {
17
+ const { success, data } = await axiosPost(API.PUSHER.AUTH(), {
18
+ channel_name: channel.name,
19
+ socket_id: socketId,
20
+ });
21
+ if (success) {
22
+ // eslint-disable-next-line promise/prefer-await-to-callbacks
23
+ callback(null, data);
24
+ }
25
+ },
26
+ };
27
+ },
28
+ });
29
+ }
30
+ return pusher;
31
+ };
32
+
33
+ export const destroyPusher = () => {
34
+ pusher.disconnect();
35
+ pusher = null;
36
+ };