@eohjsc/react-native-smart-city 0.7.27 → 0.7.31

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 (71) hide show
  1. package/index.js +2 -0
  2. package/package.json +2 -1
  3. package/src/commons/Dashboard/MyDashboardDevice/__test__/index.test.js +68 -0
  4. package/src/commons/Dashboard/MyDashboardDevice/index.js +46 -11
  5. package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +43 -11
  6. package/src/commons/Dashboard/MyUnit/index.js +40 -32
  7. package/src/commons/ModalAlert/index.js +51 -0
  8. package/src/commons/ModalAlert/styles.js +54 -0
  9. package/src/commons/SubUnit/ShortDetail.js +20 -4
  10. package/src/commons/SubUnit/__test__/ShortDetail.test.js +46 -1
  11. package/src/configs/API.js +8 -0
  12. package/src/configs/AccessibilityLabel.js +3 -0
  13. package/src/configs/Constants.js +7 -0
  14. package/src/configs/SCConfig.js +6 -0
  15. package/src/context/SCContext.tsx +12 -1
  16. package/src/context/SCStore.ts +14 -0
  17. package/src/context/actionType.ts +10 -0
  18. package/src/context/mockStore.ts +30 -1
  19. package/src/context/reducer.ts +35 -0
  20. package/src/hooks/IoT/useRemoteControl.js +4 -1
  21. package/src/hooks/IoT/useWatchSharedChips.js +130 -0
  22. package/src/hooks/Review/__test__/useInAppReview.test.js +99 -0
  23. package/src/hooks/Review/useInAppReview.js +70 -0
  24. package/src/hooks/useMqtt.js +78 -27
  25. package/src/iot/Monitor.js +149 -26
  26. package/src/iot/UpdateStates.js +60 -0
  27. package/src/iot/mqtt.js +177 -22
  28. package/src/navigations/UnitStack.js +16 -0
  29. package/src/screens/ActivityLog/ItemLog.js +1 -0
  30. package/src/screens/AddNewGateway/RenameNewDevices.js +5 -0
  31. package/src/screens/AddNewGateway/__test__/RenameNewDevices.test.js +18 -0
  32. package/src/screens/Automate/AddNewAction/ReceiverSelect.js +210 -0
  33. package/src/screens/Automate/AddNewAction/SetupScriptEmail.js +1 -1
  34. package/src/screens/Automate/AddNewAction/SetupScriptNotify.js +18 -28
  35. package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +22 -129
  36. package/src/screens/Automate/AddNewAction/SetupScriptReceiverNotify.js +59 -0
  37. package/src/screens/Automate/AddNewAction/SetupScriptReceiverSms.js +22 -129
  38. package/src/screens/Automate/AddNewAction/SetupScriptSms.js +1 -1
  39. package/src/screens/Automate/AddNewAction/Styles/{SetupScriptReceiverEmailStyles.js → ReceiverSelectStyles.js} +18 -1
  40. package/src/screens/Automate/AddNewAction/__test__/SetupScriptNotify.test.js +16 -33
  41. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverEmail.test.js +10 -8
  42. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverNotify.test.js +217 -0
  43. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverSms.test.js +10 -8
  44. package/src/screens/Automate/Components/InputName.js +5 -1
  45. package/src/screens/Automate/EditActionsList/UpdateReceiverEmailScript.js +4 -3
  46. package/src/screens/Automate/EditActionsList/UpdateReceiverSmsScript.js +5 -4
  47. package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +18 -0
  48. package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +1 -1
  49. package/src/screens/Automate/ScriptDetail/__test__/index.test.js +116 -2
  50. package/src/screens/Automate/ScriptDetail/index.js +47 -9
  51. package/src/screens/CreatePassword/__test__/index.test.js +133 -0
  52. package/src/screens/CreatePassword/index.js +134 -0
  53. package/src/screens/CreatePassword/styles.js +45 -0
  54. package/src/screens/Device/__test__/DeviceDetail-3rdparty.test.js +447 -0
  55. package/src/screens/Device/__test__/DeviceDetail-arduino.test.js +344 -0
  56. package/src/screens/Device/__test__/{mqttDetail.test.js → DeviceDetail-modbus.test.js} +287 -320
  57. package/src/screens/Device/__test__/DeviceDetail-zigbee.test.js +451 -0
  58. package/src/screens/Device/__test__/DeviceDetail.test.js +502 -0
  59. package/src/screens/Device/__test__/detail.test.js +61 -3
  60. package/src/screens/Device/__test__/sensorDisplayItem.test.js +28 -3
  61. package/src/screens/Device/detail.js +14 -6
  62. package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +3 -2
  63. package/src/screens/EnterPassword/__test__/EnterPassword.test.js +76 -1
  64. package/src/screens/EnterPassword/index.js +34 -4
  65. package/src/screens/EnterPassword/styles.js +1 -1
  66. package/src/utils/FactoryGateway.js +597 -0
  67. package/src/utils/I18n/translations/en.js +11 -0
  68. package/src/utils/I18n/translations/vi.js +11 -0
  69. package/src/utils/Route/index.js +3 -1
  70. package/src/utils/Validation.js +5 -0
  71. package/src/utils/store.js +5 -0
@@ -0,0 +1,133 @@
1
+ import MockAdapter from 'axios-mock-adapter';
2
+ import React from 'react';
3
+ import { TouchableOpacity } from 'react-native';
4
+ import { act, create } from 'react-test-renderer';
5
+
6
+ import { useNavigation } from '@react-navigation/native';
7
+ import { API } from '../../../configs';
8
+ import { AccessibilityLabel } from '../../../configs/Constants';
9
+ import _TextInputPassword from '../../../commons/Form/TextInputPassword';
10
+ import { SCProvider } from '../../../context';
11
+ import { mockSCStore } from '../../../context/mockStore';
12
+ import api from '../../../utils/Apis/axios';
13
+ import t from '../../../hooks/Common/useTranslations';
14
+ import { ToastBottomHelper } from '../../../utils/Utils';
15
+ import Routes from '../../../utils/Route';
16
+ import CreatePassword from '..';
17
+
18
+ const mock = new MockAdapter(api.axiosInstance);
19
+
20
+ const wrapComponent = () => (
21
+ <SCProvider initState={mockSCStore({})}>
22
+ <CreatePassword />
23
+ </SCProvider>
24
+ );
25
+
26
+ describe('test CreatePassword', () => {
27
+ let tree;
28
+ const { navigate } = useNavigation();
29
+ const spyToastSuccess = jest.spyOn(ToastBottomHelper, 'success');
30
+
31
+ beforeEach(() => {
32
+ spyToastSuccess.mockClear();
33
+ });
34
+
35
+ const onChangePasswords = async (component, text1, text2) => {
36
+ await act(async () => {
37
+ await component[0].props.onChange(text1);
38
+ });
39
+ await act(async () => {
40
+ await component[1].props.onChange(text2);
41
+ });
42
+ };
43
+
44
+ const buttonDone = (instance) => {
45
+ return instance.find(
46
+ (el) =>
47
+ el.props.accessibilityLabel ===
48
+ AccessibilityLabel.CREATE_PASSWORD_BUTTON_DONE &&
49
+ el.type === TouchableOpacity
50
+ );
51
+ };
52
+
53
+ it('validate and create password success', async () => {
54
+ mock.onPatch(API.AUTH.CREATE_PASSWORD).reply(200);
55
+ await act(async () => {
56
+ tree = await create(wrapComponent());
57
+ });
58
+ const instance = tree.root;
59
+ const button = buttonDone(instance);
60
+ const texts = instance.findAllByType(_TextInputPassword);
61
+
62
+ await onChangePasswords(texts, '', '');
63
+ expect(texts[0].props.errorText).toEqual(t('please_enter_new_password'));
64
+ expect(texts[1].props.errorText).toEqual(
65
+ t('please_enter_your_confirm_password')
66
+ );
67
+ expect(button.props.disabled).toBeTruthy();
68
+
69
+ await onChangePasswords(texts, '123', '123');
70
+ expect(texts[0].props.errorText).toEqual(t('password_must_be_strong'));
71
+ expect(texts[1].props.errorText).toEqual('');
72
+ expect(button.props.disabled).toBeTruthy();
73
+
74
+ await onChangePasswords(texts, 'Password1', 'Password2');
75
+ expect(texts[0].props.errorText).toEqual('');
76
+ expect(texts[1].props.errorText).toEqual(t('confirm_password_not_match'));
77
+ expect(button.props.disabled).toBeTruthy();
78
+
79
+ await act(async () => {
80
+ await texts[1].props.onChange('Password1');
81
+ });
82
+ expect(texts[0].props.errorText).toEqual('');
83
+ expect(texts[1].props.errorText).toEqual('');
84
+ expect(button.props.disabled).toBeFalsy();
85
+
86
+ await act(async () => {
87
+ await texts[0].props.onChange('Password2');
88
+ });
89
+ expect(texts[0].props.errorText).toEqual('');
90
+ expect(texts[1].props.errorText).toEqual(t('confirm_password_not_match'));
91
+ expect(button.props.disabled).toBeTruthy();
92
+
93
+ await act(async () => {
94
+ await texts[0].props.onChange('Password1');
95
+ });
96
+ expect(texts[0].props.errorText).toEqual('');
97
+ expect(texts[1].props.errorText).toEqual('');
98
+ expect(button.props.disabled).toBeFalsy();
99
+
100
+ await act(async () => {
101
+ await button.props.onPress();
102
+ });
103
+
104
+ expect(spyToastSuccess).toHaveBeenCalledWith(
105
+ t('create_password_successfully')
106
+ );
107
+ expect(navigate).toHaveBeenCalledWith(Routes.Dashboard, {
108
+ needLogout: true,
109
+ });
110
+ });
111
+
112
+ it('create password fail', async () => {
113
+ mock.onPatch(API.AUTH.CREATE_PASSWORD).reply(400);
114
+ await act(async () => {
115
+ tree = await create(wrapComponent());
116
+ });
117
+ const instance = tree.root;
118
+ const button = buttonDone(instance);
119
+ const texts = instance.findAllByType(_TextInputPassword);
120
+
121
+ await onChangePasswords(texts, 'Password1', 'Password1');
122
+ expect(texts[0].props.errorText).toEqual('');
123
+ expect(texts[1].props.errorText).toEqual('');
124
+ expect(button.props.disabled).toBeFalsy();
125
+
126
+ await act(async () => {
127
+ await button.props.onPress();
128
+ });
129
+
130
+ expect(spyToastSuccess).not.toHaveBeenCalled();
131
+ expect(navigate).not.toHaveBeenCalled();
132
+ });
133
+ });
@@ -0,0 +1,134 @@
1
+ import React, { useMemo, useState, useCallback } from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+
5
+ import { Colors, API } from '../../configs';
6
+ import { AccessibilityLabel } from '../../configs/Constants';
7
+ import { HeaderCustom } from '../../commons/Header';
8
+ import _TextInputPassword from '../../commons/Form/TextInputPassword';
9
+ import { Section } from '../../commons/Section';
10
+ import Text from '../../commons/Text';
11
+ import { useTranslations } from '../../hooks/Common/useTranslations';
12
+ import { axiosPatch } from '../../utils/Apis/axios';
13
+ import { isValidPassword } from '../../utils/Validation';
14
+ import { ToastBottomHelper } from '../../utils/Utils';
15
+ import Routes from '../../utils/Route';
16
+
17
+ import styles from './styles';
18
+
19
+ const CreatePassword = ({ route }) => {
20
+ const t = useTranslations();
21
+ const { navigate } = useNavigation();
22
+ const [newPassword, setNewPassword] = useState('');
23
+ const [confirmPassword, setConfirmPassword] = useState('');
24
+ const [newPasswordError, setNewPasswordError] = useState('');
25
+ const [confirmPasswordError, setConfirmPasswordError] = useState('');
26
+
27
+ const onChangeNewPassword = useCallback(
28
+ (value) => {
29
+ setNewPassword(value);
30
+ setNewPasswordError(
31
+ !value
32
+ ? t('please_enter_new_password')
33
+ : !isValidPassword(value)
34
+ ? t('password_must_be_strong')
35
+ : ''
36
+ );
37
+ setConfirmPasswordError((prev) =>
38
+ confirmPassword && value !== confirmPassword
39
+ ? t('confirm_password_not_match')
40
+ : value === confirmPassword
41
+ ? ''
42
+ : prev
43
+ );
44
+ },
45
+ [confirmPassword, t]
46
+ );
47
+
48
+ const onChangeConfirmPassword = useCallback(
49
+ (value) => {
50
+ setConfirmPassword(value);
51
+ setConfirmPasswordError(
52
+ !value
53
+ ? t('please_enter_your_confirm_password')
54
+ : value !== newPassword
55
+ ? t('confirm_password_not_match')
56
+ : ''
57
+ );
58
+ },
59
+ [newPassword, t]
60
+ );
61
+
62
+ const canDone = useMemo(() => {
63
+ return (
64
+ newPassword &&
65
+ confirmPassword &&
66
+ !newPasswordError &&
67
+ !confirmPasswordError
68
+ );
69
+ }, [newPassword, confirmPassword, newPasswordError, confirmPasswordError]);
70
+
71
+ const onCreatePassword = useCallback(async () => {
72
+ const { success } = await axiosPatch(API.AUTH.CREATE_PASSWORD, {
73
+ new_password: newPassword,
74
+ confirm_password: confirmPassword,
75
+ });
76
+
77
+ if (success) {
78
+ ToastBottomHelper.success(t('create_password_successfully'));
79
+ navigate(Routes.Dashboard, { needLogout: true });
80
+ }
81
+ }, [newPassword, confirmPassword, navigate, t]);
82
+
83
+ return (
84
+ <View style={styles.container}>
85
+ <HeaderCustom
86
+ title={t('password')}
87
+ isShowSeparator
88
+ titleStyle={{ color: Colors.Gray9 }}
89
+ />
90
+ <Text style={styles.boardTitle} color={Colors.Black} bold>
91
+ {t('create_password')}
92
+ </Text>
93
+ <Section type={'border'}>
94
+ <_TextInputPassword
95
+ secureTextEntry
96
+ label={t('new_password')}
97
+ labelStyle={styles.labelStyle}
98
+ wrapStyle={styles.wrapStyle}
99
+ onChange={onChangeNewPassword}
100
+ value={newPassword}
101
+ textInputStyle={styles.passwordInput}
102
+ selectionColor={Colors.Primary}
103
+ errorText={newPasswordError}
104
+ />
105
+ <_TextInputPassword
106
+ secureTextEntry
107
+ label={t('confirm_password')}
108
+ labelStyle={styles.labelStyle}
109
+ wrapStyle={styles.wrapStyle}
110
+ onChange={onChangeConfirmPassword}
111
+ value={confirmPassword}
112
+ textInputStyle={styles.passwordInput}
113
+ selectionColor={Colors.Primary}
114
+ errorText={confirmPasswordError}
115
+ />
116
+ </Section>
117
+ <TouchableOpacity
118
+ style={[styles.buttonDone, !canDone && styles.buttonDoneDisable]}
119
+ onPress={onCreatePassword}
120
+ accessibilityLabel={AccessibilityLabel.CREATE_PASSWORD_BUTTON_DONE}
121
+ disabled={!canDone}
122
+ >
123
+ <Text
124
+ type="H4"
125
+ style={canDone ? styles.textDone : styles.textDoneDisable}
126
+ >
127
+ {t('done')}
128
+ </Text>
129
+ </TouchableOpacity>
130
+ </View>
131
+ );
132
+ };
133
+
134
+ export default CreatePassword;
@@ -0,0 +1,45 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors } from '../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ container: {
6
+ flex: 1,
7
+ backgroundColor: Colors.Gray2,
8
+ },
9
+ boardTitle: {
10
+ marginBottom: 8,
11
+ marginTop: 12,
12
+ marginLeft: 16,
13
+ },
14
+ labelStyle: {
15
+ color: Colors.Primary,
16
+ },
17
+ wrapStyle: {
18
+ marginTop: 12,
19
+ width: '100%',
20
+ },
21
+ passwordInput: {
22
+ paddingTop: 8,
23
+ paddingBottom: 8,
24
+ },
25
+ buttonDone: {
26
+ justifyContent: 'center',
27
+ alignItems: 'center',
28
+ paddingVertical: 12,
29
+ borderRadius: 30,
30
+ backgroundColor: Colors.Primary,
31
+ width: '90%',
32
+ alignSelf: 'center',
33
+ },
34
+ buttonDoneDisable: {
35
+ backgroundColor: Colors.White,
36
+ borderWidth: 1,
37
+ borderColor: Colors.Neutral.Neutral3,
38
+ },
39
+ textDone: {
40
+ color: Colors.White,
41
+ },
42
+ textDoneDisable: {
43
+ color: Colors.Gray6,
44
+ },
45
+ });