dhre-ui-kit 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +104 -0
- package/src/App.tsx +146 -0
- package/src/assets/images/calenderDots.svg +1 -0
- package/src/assets/index.ts +2 -0
- package/src/components/autoOtpReader/AutoOtpReader.test.tsx +56 -0
- package/src/components/autoOtpReader/AutoOtpReader.tsx +79 -0
- package/src/components/autoOtpReader/index.ts +1 -0
- package/src/components/badge/Badge.styles.ts +20 -0
- package/src/components/badge/Badge.test.tsx +45 -0
- package/src/components/badge/Badge.tsx +47 -0
- package/src/components/badge/index.ts +1 -0
- package/src/components/bottomDrawer/BottomDrawer.interface.ts +12 -0
- package/src/components/bottomDrawer/BottomDrawer.styles.ts +31 -0
- package/src/components/bottomDrawer/BottomDrawer.test.tsx +19 -0
- package/src/components/bottomDrawer/BottomDrawer.tsx +43 -0
- package/src/components/bottomDrawer/index.ts +1 -0
- package/src/components/button/Button.interface.ts +18 -0
- package/src/components/button/Button.styles.ts +78 -0
- package/src/components/button/Button.test.tsx +43 -0
- package/src/components/button/Button.tsx +53 -0
- package/src/components/button/index.ts +1 -0
- package/src/components/cards/Cards.interface.ts +13 -0
- package/src/components/cards/Cards.styles.ts +59 -0
- package/src/components/cards/Cards.test.tsx +41 -0
- package/src/components/cards/Cards.tsx +69 -0
- package/src/components/cards/index.ts +1 -0
- package/src/components/checkBox/CheckBox.interface.ts +10 -0
- package/src/components/checkBox/CheckBox.styles.ts +36 -0
- package/src/components/checkBox/CheckBox.test.tsx +46 -0
- package/src/components/checkBox/CheckBox.tsx +42 -0
- package/src/components/checkBox/index.ts +1 -0
- package/src/components/customDropdown/CustomDropdown.interface.ts +15 -0
- package/src/components/customDropdown/CustomDropdown.styles.tsx +46 -0
- package/src/components/customDropdown/CustomDropdown.test.tsx +30 -0
- package/src/components/customDropdown/CustomDropdown.tsx +106 -0
- package/src/components/customDropdown/index.ts +1 -0
- package/src/components/customInputText/CustomInputText.interface.ts +20 -0
- package/src/components/customInputText/CustomInputText.styles.ts +56 -0
- package/src/components/customInputText/CustomInputText.test.tsx +37 -0
- package/src/components/customInputText/CustomInputText.tsx +120 -0
- package/src/components/customInputText/index.ts +1 -0
- package/src/components/customText/CustomText.tsx +31 -0
- package/src/components/customText/index.ts +1 -0
- package/src/components/customTooltip/CustomTooltip.interface.ts +14 -0
- package/src/components/customTooltip/CustomTooltip.styles.ts +23 -0
- package/src/components/customTooltip/CustomTooltip.test.tsx +18 -0
- package/src/components/customTooltip/CustomTooltip.tsx +46 -0
- package/src/components/customTooltip/index.ts +1 -0
- package/src/components/customTypography/CustomTypography.tsx +25 -0
- package/src/components/fileUpload/FileUpload.styles.ts +41 -0
- package/src/components/fileUpload/FileUpload.test.tsx +39 -0
- package/src/components/fileUpload/FileUpload.tsx +65 -0
- package/src/components/fileUpload/index.ts +1 -0
- package/src/components/notification/Notification.interface.ts +61 -0
- package/src/components/notification/Notification.styles.ts +33 -0
- package/src/components/notification/Notification.test.tsx +116 -0
- package/src/components/notification/Notification.tsx +156 -0
- package/src/components/pdfView/PdfView.test.tsx +10 -0
- package/src/components/pdfView/PdfView.tsx +18 -0
- package/src/components/pdfView/index.ts +1 -0
- package/src/components/popup/PopUp.interface.ts +9 -0
- package/src/components/popup/PopUp.styles.ts +52 -0
- package/src/components/popup/PopUp.test.tsx +35 -0
- package/src/components/popup/PopUp.tsx +60 -0
- package/src/components/popup/index.ts +1 -0
- package/src/components/progressBar/ProgressBar.test.tsx +78 -0
- package/src/components/progressBar/ProgressBar.tsx +93 -0
- package/src/components/progressBar/index.ts +1 -0
- package/src/components/property360View/Property360View.test.tsx +24 -0
- package/src/components/property360View/Property360View.tsx +19 -0
- package/src/components/property360View/index.ts +1 -0
- package/src/components/rating/Rating.styles.ts +13 -0
- package/src/components/rating/Rating.test.tsx +61 -0
- package/src/components/rating/Rating.tsx +96 -0
- package/src/components/rating/index.ts +1 -0
- package/src/components/tabs/Tabs.interface.ts +13 -0
- package/src/components/tabs/Tabs.styles.ts +36 -0
- package/src/components/tabs/Tabs.test.tsx +20 -0
- package/src/components/tabs/Tabs.tsx +65 -0
- package/src/components/tabs/index.ts +1 -0
- package/src/components/tags/Tags.interface.ts +12 -0
- package/src/components/tags/Tags.styles.ts +36 -0
- package/src/components/tags/Tags.test.tsx +22 -0
- package/src/components/tags/Tags.tsx +76 -0
- package/src/components/tags/index.ts +1 -0
- package/src/components/toggleButton/ToggleButton.styles.ts +40 -0
- package/src/components/toggleButton/ToggleButton.test.tsx +33 -0
- package/src/components/toggleButton/ToggleButton.tsx +78 -0
- package/src/components/toggleButton/index.ts +1 -0
- package/src/index.ts +19 -0
- package/src/theme/ThemeContext.tsx +32 -0
- package/src/theme/colors.ts +156 -0
- package/src/theme/fonts.ts +303 -0
- package/src/theme/themes.ts +20 -0
- package/src/theme/withThemeProvider.tsx +14 -0
- package/src/utils/appEnum.ts +17 -0
- package/src/utils/commonStyles.ts +17 -0
- package/src/utils/constants.ts +17 -0
- package/src/utils/deviceUtils.ts +9 -0
- package/src/utils/regex.ts +1 -0
- package/src/utils/stylehelper.ts +13 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
## Component library for mobile
|
package/package.json
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dhre-ui-kit",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"main": "src/index.ts",
|
|
5
|
+
"files": [
|
|
6
|
+
"src",
|
|
7
|
+
"README.md"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"android": "react-native run-android",
|
|
11
|
+
"ios": "react-native run-ios",
|
|
12
|
+
"start": "react-native start",
|
|
13
|
+
"test": "jest",
|
|
14
|
+
"tsc": "tsc",
|
|
15
|
+
"lint": "npx eslint ./src",
|
|
16
|
+
"lint:fix": "npm run lint -- --fix",
|
|
17
|
+
"lint:report": "eslint . --format=json --output-file=eslint-report.json",
|
|
18
|
+
"prettier": "npx prettier ./src --check",
|
|
19
|
+
"prettier:fix": "npm run prettier ./src -- --write",
|
|
20
|
+
"build": "bob build",
|
|
21
|
+
"prepublishOnly": "npm run build",
|
|
22
|
+
"prepare": "husky"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@testing-library/react-native": "^12.5.1",
|
|
26
|
+
"lint-staged": "^15.2.7",
|
|
27
|
+
"react": "18.2.0",
|
|
28
|
+
"react-native": "0.74.3",
|
|
29
|
+
"react-native-otp-verify": "^1.1.8",
|
|
30
|
+
"react-native-pdf": "^6.7.1",
|
|
31
|
+
"react-native-gesture-handler": "2.17.0",
|
|
32
|
+
"react-native-progress": "^5.0.1",
|
|
33
|
+
"react-native-svg": "^15.4.0",
|
|
34
|
+
"react-native-svg-transformer": "^1.5.0",
|
|
35
|
+
"react-native-webview": "^13.12.0",
|
|
36
|
+
"react-redux": "^9.1.2",
|
|
37
|
+
"rn-tooltip": "^3.0.3"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@babel/core": "^7.20.0",
|
|
41
|
+
"@babel/preset-env": "^7.25.3",
|
|
42
|
+
"@babel/runtime": "^7.20.0",
|
|
43
|
+
"@eslint/js": "^9.7.0",
|
|
44
|
+
"@react-native/babel-preset": "0.74.85",
|
|
45
|
+
"@react-native/eslint-config": "0.74.85",
|
|
46
|
+
"@react-native/metro-config": "0.74.85",
|
|
47
|
+
"@react-native/typescript-config": "0.74.85",
|
|
48
|
+
"@types/jest": "^29.5.12",
|
|
49
|
+
"@types/react": "^18.2.6",
|
|
50
|
+
"@types/react-native": "^0.73.0",
|
|
51
|
+
"@types/react-test-renderer": "^18.0.0",
|
|
52
|
+
"@typescript-eslint/eslint-plugin": "^7.17.0",
|
|
53
|
+
"@typescript-eslint/parser": "^7.17.0",
|
|
54
|
+
"babel-jest": "^29.7.0",
|
|
55
|
+
"babel-plugin-module-resolver": "^5.0.2",
|
|
56
|
+
"eslint": "^8.57.0",
|
|
57
|
+
"eslint-config-prettier": "9.1.0",
|
|
58
|
+
"eslint-plugin-react": "^7.35.0",
|
|
59
|
+
"globals": "^15.8.0",
|
|
60
|
+
"husky": "^9.1.1",
|
|
61
|
+
"jest": "^29.7.0",
|
|
62
|
+
"metro-runtime": "^0.80.10",
|
|
63
|
+
"prettier": "2.8.8",
|
|
64
|
+
"react-native-builder-bob": "^0.30.0",
|
|
65
|
+
"react-native-typescript-transformer": "^1.2.13",
|
|
66
|
+
"react-test-renderer": "18.2.0",
|
|
67
|
+
"typescript": "^5.0.4",
|
|
68
|
+
"typescript-eslint": "^7.17.0"
|
|
69
|
+
},
|
|
70
|
+
"lint-staged": {
|
|
71
|
+
"*.{ts,tsx}": [
|
|
72
|
+
"eslint ./src --fix",
|
|
73
|
+
"prettier ./src --write"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
"engines": {
|
|
77
|
+
"node": ">=18"
|
|
78
|
+
},
|
|
79
|
+
"packageManager": "yarn@3.6.4",
|
|
80
|
+
"react-native-builder-bob": {
|
|
81
|
+
"source": "src",
|
|
82
|
+
"output": "dist",
|
|
83
|
+
"targets": [
|
|
84
|
+
[
|
|
85
|
+
"commonjs",
|
|
86
|
+
{
|
|
87
|
+
"esm": true
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
[
|
|
91
|
+
"module",
|
|
92
|
+
{
|
|
93
|
+
"esm": true
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
[
|
|
97
|
+
"typescript",
|
|
98
|
+
{
|
|
99
|
+
"esm": true
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
}
|
package/src/App.tsx
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {ThemeProvider} from './theme/ThemeContext';
|
|
3
|
+
import {
|
|
4
|
+
Badge,
|
|
5
|
+
Button,
|
|
6
|
+
CustomDropdown,
|
|
7
|
+
CustomTextInput,
|
|
8
|
+
FileUpload,
|
|
9
|
+
StarRating,
|
|
10
|
+
Tabs,
|
|
11
|
+
Tags,
|
|
12
|
+
} from './index';
|
|
13
|
+
import {CalenderDots} from './assets';
|
|
14
|
+
import {View} from 'react-native';
|
|
15
|
+
import {BUTTON_TYPES} from './utils/constants';
|
|
16
|
+
import Checkbox from './components/checkBox';
|
|
17
|
+
import {Text} from 'react-native-svg';
|
|
18
|
+
|
|
19
|
+
import {DHRE_COLORS_PRIMARY, DHRE_COLORS_TEXT} from './theme/colors';
|
|
20
|
+
import {moderateScale} from './utils/stylehelper';
|
|
21
|
+
import CustomTooltip from './components/customTooltip';
|
|
22
|
+
const App = () => {
|
|
23
|
+
const options = [
|
|
24
|
+
{id: '1', value: 'user1', label: 'User 1'},
|
|
25
|
+
{id: '2', value: 'user2', label: 'User 2'},
|
|
26
|
+
{id: '3', value: 'user3', label: 'User 3'},
|
|
27
|
+
];
|
|
28
|
+
const handleTabPress = (index: number) => {
|
|
29
|
+
console.log('Tab pressed:', index);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const handleSetSelectedTagsOptions = (tags: string[]) => {
|
|
33
|
+
console.log('Selected tags:', tags);
|
|
34
|
+
};
|
|
35
|
+
const handleTagsChange = (tag: string) => {
|
|
36
|
+
console.log('Tag removed:', tag);
|
|
37
|
+
};
|
|
38
|
+
const handleSelect = (option: {id: string; value: string; label: string}) => {
|
|
39
|
+
console.log('Selected:', option);
|
|
40
|
+
};
|
|
41
|
+
return (
|
|
42
|
+
<ThemeProvider>
|
|
43
|
+
<View style={{marginTop: 50}}>
|
|
44
|
+
<Badge
|
|
45
|
+
handleIconPress={function (): void {}}
|
|
46
|
+
text="gggsdfghjhgf"
|
|
47
|
+
style={{margin: 20}}
|
|
48
|
+
iconName={<CalenderDots width={20} height={20} />}
|
|
49
|
+
textStyle={{color: 'black'}}
|
|
50
|
+
iconStyle={{}}
|
|
51
|
+
/>
|
|
52
|
+
|
|
53
|
+
<Button
|
|
54
|
+
onPress={function (): void {
|
|
55
|
+
throw new Error('Function not implemented.');
|
|
56
|
+
}}
|
|
57
|
+
title={'dfghj'}
|
|
58
|
+
buttonType={BUTTON_TYPES.PRIMARY}
|
|
59
|
+
variant={'H6bold'}
|
|
60
|
+
iconShown={true}
|
|
61
|
+
iconName={<CalenderDots width={20} height={20} />}
|
|
62
|
+
/>
|
|
63
|
+
|
|
64
|
+
<Checkbox
|
|
65
|
+
isChecked={false}
|
|
66
|
+
labelName={'circle'}
|
|
67
|
+
checkedIcon={<CalenderDots width={20} height={20} />}
|
|
68
|
+
uncheckedIcon={<CalenderDots width={20} height={20} />}
|
|
69
|
+
/>
|
|
70
|
+
<CustomDropdown
|
|
71
|
+
label="Select User"
|
|
72
|
+
placeholder="Choose Option"
|
|
73
|
+
options={options}
|
|
74
|
+
oneSelect={handleSelect}
|
|
75
|
+
selectedValue={options[0]} // Initially selected value
|
|
76
|
+
iconName={<CalenderDots />} // Dynamic icon for the dropdown
|
|
77
|
+
upArrowIcon={<CalenderDots />} // Up arrow icon
|
|
78
|
+
downArrowIcon={<CalenderDots />} // Down arrow icon
|
|
79
|
+
testId="CUSTOM-DROPDOWN"
|
|
80
|
+
iconStyle={{marginRight: 10}}
|
|
81
|
+
/>
|
|
82
|
+
<CustomTextInput
|
|
83
|
+
label="Search"
|
|
84
|
+
placeholder="Type here"
|
|
85
|
+
isSearchBar={true}
|
|
86
|
+
searchIcon={<CalenderDots />}
|
|
87
|
+
rightIcon1={<CalenderDots />}
|
|
88
|
+
rightIcon2={<CalenderDots />}
|
|
89
|
+
secureTextEntry={true}
|
|
90
|
+
errorMessage="This field is required."
|
|
91
|
+
handleOnChangeText={text => console.log(text)}
|
|
92
|
+
/>
|
|
93
|
+
<FileUpload
|
|
94
|
+
onUpload={() => console.log('Upload clicked')}
|
|
95
|
+
title="Upload Files"
|
|
96
|
+
btnText="Browse"
|
|
97
|
+
containerStyle={{width: 200}}
|
|
98
|
+
uploadImageStyling={{width: 10, height: 10}} // Example styling
|
|
99
|
+
icon={<CalenderDots />} // Pass your icon here
|
|
100
|
+
iconStyle={{}} // Optional styling for the icon
|
|
101
|
+
/>
|
|
102
|
+
<Tags
|
|
103
|
+
tags={['Tag1', 'Tag2', 'Tag3']}
|
|
104
|
+
handleSetSelectedTagsOptions={handleSetSelectedTagsOptions}
|
|
105
|
+
handleTagsChange={handleTagsChange}
|
|
106
|
+
testID="tags-component"
|
|
107
|
+
icon={<CalenderDots />} // Pass your icon here
|
|
108
|
+
iconStyle={{backgroundColor: DHRE_COLORS_TEXT.DH_WHITE}} // Optional styling for the icon
|
|
109
|
+
/>
|
|
110
|
+
|
|
111
|
+
<Tabs
|
|
112
|
+
tabs={[{label: 'Tab 1'}, {label: 'Tab 2'}, {label: 'Tab 3'}]}
|
|
113
|
+
onTabPress={handleTabPress}
|
|
114
|
+
testID="tabs-component"
|
|
115
|
+
icon={<CalenderDots />}
|
|
116
|
+
iconStyle={{width: 24, height: 24}}
|
|
117
|
+
/>
|
|
118
|
+
<StarRating
|
|
119
|
+
rating={3.5}
|
|
120
|
+
count={5}
|
|
121
|
+
size={24}
|
|
122
|
+
fullStarIcon={<CalenderDots />}
|
|
123
|
+
halfStarIcon={<CalenderDots />}
|
|
124
|
+
fullStarColor="gold"
|
|
125
|
+
emptyStarColor="gray"
|
|
126
|
+
starStyle={{marginHorizontal: 2}}
|
|
127
|
+
/>
|
|
128
|
+
<CustomTooltip
|
|
129
|
+
message="This is a tooltip"
|
|
130
|
+
icon={
|
|
131
|
+
<CalenderDots
|
|
132
|
+
width={moderateScale(16)}
|
|
133
|
+
height={moderateScale(16)}
|
|
134
|
+
/>
|
|
135
|
+
}
|
|
136
|
+
iconStyle={{width: moderateScale(16), height: moderateScale(16)}} // Optional styling for the icon
|
|
137
|
+
iconColor={DHRE_COLORS_PRIMARY.DH_RED_100} // Example icon color
|
|
138
|
+
>
|
|
139
|
+
<Text>Hover over me</Text>
|
|
140
|
+
</CustomTooltip>
|
|
141
|
+
</View>
|
|
142
|
+
</ThemeProvider>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export default App;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256"><path d="M208,34H182V24a6,6,0,0,0-12,0V34H86V24a6,6,0,0,0-12,0V34H48A14,14,0,0,0,34,48V208a14,14,0,0,0,14,14H208a14,14,0,0,0,14-14V48A14,14,0,0,0,208,34ZM48,46H74V56a6,6,0,0,0,12,0V46h84V56a6,6,0,0,0,12,0V46h26a2,2,0,0,1,2,2V82H46V48A2,2,0,0,1,48,46ZM208,210H48a2,2,0,0,1-2-2V94H210V208A2,2,0,0,1,208,210Zm-70-78a10,10,0,1,1-10-10A10,10,0,0,1,138,132Zm44,0a10,10,0,1,1-10-10A10,10,0,0,1,182,132ZM94,172a10,10,0,1,1-10-10A10,10,0,0,1,94,172Zm44,0a10,10,0,1,1-10-10A10,10,0,0,1,138,172Zm44,0a10,10,0,1,1-10-10A10,10,0,0,1,182,172Z"></path></svg>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {render} from '@testing-library/react-native';
|
|
3
|
+
import AutoOtpReader from './AutoOtpReader';
|
|
4
|
+
import RNOtpVerify from 'react-native-otp-verify';
|
|
5
|
+
import {isAndroid} from '../../utils/deviceUtils';
|
|
6
|
+
|
|
7
|
+
jest.mock('../../utils/deviceUtils', () => ({
|
|
8
|
+
isAndroid: jest.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const mockOnOtpDetected = jest.fn();
|
|
12
|
+
const mockOnHashGenerated = jest.fn();
|
|
13
|
+
|
|
14
|
+
describe('AutoOtpReader', () => {
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
jest.clearAllMocks();
|
|
17
|
+
(isAndroid as jest.Mock).mockReturnValue(true);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should start listening for OTP on mount and generate hash', async () => {
|
|
21
|
+
const otpMessage = 'Your OTP is 123456. Hash: xyz123';
|
|
22
|
+
const generatedHash = 'hash123';
|
|
23
|
+
|
|
24
|
+
(RNOtpVerify.getOtp as jest.Mock).mockResolvedValueOnce(undefined);
|
|
25
|
+
(RNOtpVerify.getHash as jest.Mock).mockResolvedValueOnce(generatedHash);
|
|
26
|
+
(RNOtpVerify.addListener as jest.Mock).mockImplementation(callback => {
|
|
27
|
+
callback(otpMessage);
|
|
28
|
+
});
|
|
29
|
+
render(
|
|
30
|
+
<AutoOtpReader
|
|
31
|
+
onOtpDetected={mockOnOtpDetected}
|
|
32
|
+
onHashGenerated={mockOnHashGenerated}
|
|
33
|
+
/>,
|
|
34
|
+
);
|
|
35
|
+
await new Promise(r => setTimeout(r, 0));
|
|
36
|
+
expect(RNOtpVerify.getOtp).toHaveBeenCalled();
|
|
37
|
+
expect(RNOtpVerify.addListener).toHaveBeenCalled();
|
|
38
|
+
expect(mockOnOtpDetected).toHaveBeenCalledWith('123456');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should not call onHashGenerated if hash generation fails', async () => {
|
|
42
|
+
(RNOtpVerify.getOtp as jest.Mock).mockResolvedValueOnce(undefined);
|
|
43
|
+
(RNOtpVerify.getHash as jest.Mock).mockRejectedValueOnce(
|
|
44
|
+
new Error('Hash generation error'),
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
render(
|
|
48
|
+
<AutoOtpReader
|
|
49
|
+
onOtpDetected={mockOnOtpDetected}
|
|
50
|
+
onHashGenerated={mockOnHashGenerated}
|
|
51
|
+
/>,
|
|
52
|
+
);
|
|
53
|
+
await new Promise(r => setTimeout(r, 0));
|
|
54
|
+
expect(mockOnHashGenerated).not.toHaveBeenCalled();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React, {useCallback, useEffect} from 'react';
|
|
2
|
+
import {Keyboard} from 'react-native';
|
|
3
|
+
import RNOtpVerify from 'react-native-otp-verify';
|
|
4
|
+
import {isAndroid} from '../../utils/deviceUtils';
|
|
5
|
+
import {stringLengthRegex} from '../../utils/regex';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Interface for the props of the AutoOtpReader component.
|
|
9
|
+
*/
|
|
10
|
+
interface AutoOtpReaderProps {
|
|
11
|
+
onOtpDetected: (otp: string) => void;
|
|
12
|
+
onHashGenerated?: (hash: string) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* AutoOtpReader component to automatically fetch OTP from the message for Android devices.
|
|
17
|
+
*
|
|
18
|
+
* - Generates a Hash using RNOtpVerify.getHash().
|
|
19
|
+
* - Shares this Hash using an API request with OTP API.
|
|
20
|
+
* - Appends this hash to the OTP message.
|
|
21
|
+
* - Once the OTP message is received on the device, based on the matching hash, contents of the message will be copied to the OTP boxes.
|
|
22
|
+
*
|
|
23
|
+
* In iOS, use textContentType="oneTimeCode" for OTP autofill.
|
|
24
|
+
*
|
|
25
|
+
* @param props The props for the component.
|
|
26
|
+
* @returns A null component as it only handles side effects.
|
|
27
|
+
*/
|
|
28
|
+
const AutoOtpReader: React.FC<AutoOtpReaderProps> = ({
|
|
29
|
+
onOtpDetected,
|
|
30
|
+
onHashGenerated,
|
|
31
|
+
}) => {
|
|
32
|
+
const otpHandler = useCallback(
|
|
33
|
+
(message: string) => {
|
|
34
|
+
if (message) {
|
|
35
|
+
try {
|
|
36
|
+
const code = message.match(stringLengthRegex);
|
|
37
|
+
if (code) {
|
|
38
|
+
onOtpDetected(code[0]);
|
|
39
|
+
}
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.log('ERROR::', error);
|
|
42
|
+
} finally {
|
|
43
|
+
RNOtpVerify.removeListener();
|
|
44
|
+
Keyboard.dismiss();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
[onOtpDetected],
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const startListeningForOtp = useCallback(() => {
|
|
52
|
+
RNOtpVerify.getOtp()
|
|
53
|
+
.then(() => RNOtpVerify.addListener(otpHandler))
|
|
54
|
+
.catch(error => console.log(error));
|
|
55
|
+
}, [otpHandler]);
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (isAndroid()) {
|
|
59
|
+
startListeningForOtp();
|
|
60
|
+
}
|
|
61
|
+
return () => RNOtpVerify.removeListener();
|
|
62
|
+
}, [startListeningForOtp]);
|
|
63
|
+
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (isAndroid()) {
|
|
66
|
+
RNOtpVerify.getHash()
|
|
67
|
+
.then(hash => {
|
|
68
|
+
if (hash && hash.length > 0 && onHashGenerated) {
|
|
69
|
+
onHashGenerated(hash[0]);
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
.catch(error => console.log(error));
|
|
73
|
+
}
|
|
74
|
+
}, [onHashGenerated]);
|
|
75
|
+
|
|
76
|
+
return null;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export default AutoOtpReader;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {default} from './AutoOtpReader';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {StyleSheet} from 'react-native';
|
|
2
|
+
import {horizontalScale, verticalScale} from '../../utils/stylehelper';
|
|
3
|
+
import {DHRE_COLORS_ALERT, DHRE_COLORS_TEXT} from '../../theme/colors';
|
|
4
|
+
const styles = StyleSheet.create({
|
|
5
|
+
badge: {
|
|
6
|
+
backgroundColor: DHRE_COLORS_ALERT.DH_SUCCESS_GREEN,
|
|
7
|
+
borderRadius: 15,
|
|
8
|
+
padding: verticalScale(4),
|
|
9
|
+
},
|
|
10
|
+
icon: {
|
|
11
|
+
marginHorizontal: horizontalScale(4),
|
|
12
|
+
height: verticalScale(16),
|
|
13
|
+
width: horizontalScale(16),
|
|
14
|
+
},
|
|
15
|
+
text: {
|
|
16
|
+
color: DHRE_COLORS_TEXT.DH_WHITE,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export default styles;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {render, screen} from '@testing-library/react-native';
|
|
3
|
+
import Badge from './Badge';
|
|
4
|
+
|
|
5
|
+
describe('Badge component', () => {
|
|
6
|
+
it('renders text correctly', () => {
|
|
7
|
+
const text = 'Test Badge';
|
|
8
|
+
render(
|
|
9
|
+
<Badge
|
|
10
|
+
text={text}
|
|
11
|
+
handleIconPress={function (): void {
|
|
12
|
+
throw new Error('Function not implemented.');
|
|
13
|
+
}}
|
|
14
|
+
/>,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const badgeText = screen.getByText(text);
|
|
18
|
+
expect(badgeText).toBeDefined();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('renders icon correctly', () => {
|
|
22
|
+
render(
|
|
23
|
+
<Badge
|
|
24
|
+
handleIconPress={function (): void {
|
|
25
|
+
throw new Error('Function not implemented.');
|
|
26
|
+
}}
|
|
27
|
+
/>,
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('renders with custom style', () => {
|
|
32
|
+
const customStyle = {backgroundColor: 'red'};
|
|
33
|
+
render(
|
|
34
|
+
<Badge
|
|
35
|
+
style={customStyle}
|
|
36
|
+
handleIconPress={function (): void {
|
|
37
|
+
throw new Error('Function not implemented.');
|
|
38
|
+
}}
|
|
39
|
+
/>,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const badge = screen.getByTestId('BADGE');
|
|
43
|
+
expect(badge).toBeDefined();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React, {ReactElement} from 'react';
|
|
2
|
+
import {View, ViewStyle, TextStyle, Pressable} from 'react-native';
|
|
3
|
+
import commonStyles from '../../utils/commonStyles';
|
|
4
|
+
import styles from './Badge.styles';
|
|
5
|
+
import {SvgProps} from 'react-native-svg';
|
|
6
|
+
import CustomTypography from '../customTypography/CustomTypography';
|
|
7
|
+
|
|
8
|
+
interface BadgeProps {
|
|
9
|
+
text?: string;
|
|
10
|
+
style?: ViewStyle;
|
|
11
|
+
iconName?: ReactElement<SvgProps>;
|
|
12
|
+
textStyle?: TextStyle;
|
|
13
|
+
iconStyle?: ViewStyle;
|
|
14
|
+
handleIconPress: () => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const Badge: React.FC<BadgeProps> = ({
|
|
18
|
+
text,
|
|
19
|
+
style,
|
|
20
|
+
iconName,
|
|
21
|
+
textStyle,
|
|
22
|
+
iconStyle,
|
|
23
|
+
handleIconPress,
|
|
24
|
+
}) => {
|
|
25
|
+
return (
|
|
26
|
+
<Pressable
|
|
27
|
+
style={[styles.badge, commonStyles.centerRow, style]}
|
|
28
|
+
testID="BADGE"
|
|
29
|
+
onPress={handleIconPress}>
|
|
30
|
+
{iconName && (
|
|
31
|
+
<View style={[styles.icon, iconStyle]}>
|
|
32
|
+
{React.cloneElement(iconName)}
|
|
33
|
+
</View>
|
|
34
|
+
)}
|
|
35
|
+
|
|
36
|
+
{text && (
|
|
37
|
+
<CustomTypography
|
|
38
|
+
variant="B3semiBold"
|
|
39
|
+
style={[styles.text, textStyle]}
|
|
40
|
+
text={text}
|
|
41
|
+
/>
|
|
42
|
+
)}
|
|
43
|
+
</Pressable>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default Badge;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {default} from './Badge';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {ViewStyle} from 'react-native';
|
|
2
|
+
|
|
3
|
+
export interface BottomDrawerProps {
|
|
4
|
+
isModalVisible: boolean;
|
|
5
|
+
toggleModal: () => void;
|
|
6
|
+
isFullScreen?: boolean;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
title: string;
|
|
9
|
+
testID?: string;
|
|
10
|
+
style?: ViewStyle;
|
|
11
|
+
modalContainerStyle?: ViewStyle;
|
|
12
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {DHRE_COLORS_TEXT, DHRE_COLORS_BG} from '../../theme/colors';
|
|
2
|
+
import {
|
|
3
|
+
horizontalScale,
|
|
4
|
+
moderateScale,
|
|
5
|
+
verticalScale,
|
|
6
|
+
} from '../../utils/stylehelper';
|
|
7
|
+
import {StyleSheet} from 'react-native';
|
|
8
|
+
|
|
9
|
+
const styles = StyleSheet.create({
|
|
10
|
+
mainContainer: {
|
|
11
|
+
flex: 1,
|
|
12
|
+
backgroundColor: DHRE_COLORS_TEXT.DH_BLACK,
|
|
13
|
+
justifyContent: 'flex-end',
|
|
14
|
+
},
|
|
15
|
+
modalContainer: {padding: moderateScale(16)},
|
|
16
|
+
separator: {
|
|
17
|
+
height: verticalScale(2),
|
|
18
|
+
width: horizontalScale(40),
|
|
19
|
+
alignSelf: 'center',
|
|
20
|
+
backgroundColor: DHRE_COLORS_BG.DH_GREY1,
|
|
21
|
+
marginBottom: verticalScale(16),
|
|
22
|
+
borderRadius: moderateScale(25),
|
|
23
|
+
},
|
|
24
|
+
headderContainer: {
|
|
25
|
+
flexDirection: 'row',
|
|
26
|
+
justifyContent: 'center',
|
|
27
|
+
marginVertical: verticalScale(4),
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export default styles;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {Text} from 'react-native';
|
|
3
|
+
import {it} from '@jest/globals';
|
|
4
|
+
import {render} from '@testing-library/react-native';
|
|
5
|
+
import BottomDrawer from './BottomDrawer';
|
|
6
|
+
|
|
7
|
+
const mockProps = {
|
|
8
|
+
isModalVisible: true,
|
|
9
|
+
toggleModal: jest.fn(),
|
|
10
|
+
children: <Text>Mock Child</Text>,
|
|
11
|
+
title: 'Test Title',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
describe('Bottom Drawer Component', () => {
|
|
15
|
+
it('Component renders correctly', () => {
|
|
16
|
+
const {getByTestId} = render(<BottomDrawer {...mockProps} />);
|
|
17
|
+
expect(getByTestId('BOTTOM-DRAWER')).toBeTruthy();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {View, Modal} from 'react-native';
|
|
3
|
+
import {BottomDrawerProps} from './BottomDrawer.interface';
|
|
4
|
+
import styles from './BottomDrawer.styles';
|
|
5
|
+
import CustomTypography from '../customTypography/CustomTypography';
|
|
6
|
+
|
|
7
|
+
const BottomDrawer: React.FC<BottomDrawerProps> = ({
|
|
8
|
+
isModalVisible,
|
|
9
|
+
toggleModal,
|
|
10
|
+
isFullScreen = true,
|
|
11
|
+
children,
|
|
12
|
+
title,
|
|
13
|
+
testID = 'BOTTOM-DRAWER',
|
|
14
|
+
style,
|
|
15
|
+
modalContainerStyle,
|
|
16
|
+
}) => {
|
|
17
|
+
return (
|
|
18
|
+
<Modal
|
|
19
|
+
animationType="slide"
|
|
20
|
+
transparent={true}
|
|
21
|
+
visible={isModalVisible}
|
|
22
|
+
onRequestClose={toggleModal}>
|
|
23
|
+
<View style={[styles.mainContainer, style]} testID={testID}>
|
|
24
|
+
<View
|
|
25
|
+
style={[
|
|
26
|
+
{
|
|
27
|
+
flex: isFullScreen ? 1 : 0.5,
|
|
28
|
+
},
|
|
29
|
+
styles.modalContainer,
|
|
30
|
+
modalContainerStyle,
|
|
31
|
+
]}>
|
|
32
|
+
<View style={styles.separator} />
|
|
33
|
+
<View style={styles.headderContainer}>
|
|
34
|
+
<CustomTypography variant="H7bold" text={title} />
|
|
35
|
+
</View>
|
|
36
|
+
<View>{children}</View>
|
|
37
|
+
</View>
|
|
38
|
+
</View>
|
|
39
|
+
</Modal>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default BottomDrawer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {default} from './BottomDrawer';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {ReactElement} from 'react';
|
|
2
|
+
import {FONT_STYLES} from '../../theme/fonts';
|
|
3
|
+
import {ViewStyle} from 'react-native';
|
|
4
|
+
import {SvgProps} from 'react-native-svg';
|
|
5
|
+
|
|
6
|
+
export interface ButtonProps {
|
|
7
|
+
onPress: () => void;
|
|
8
|
+
title: string;
|
|
9
|
+
buttonType: string;
|
|
10
|
+
buttonStyle?: ViewStyle;
|
|
11
|
+
titleStyle?: ViewStyle;
|
|
12
|
+
iconShown?: boolean;
|
|
13
|
+
iconStyles?: ViewStyle;
|
|
14
|
+
testID?: string;
|
|
15
|
+
titleShown?: boolean;
|
|
16
|
+
variant: keyof typeof FONT_STYLES | string;
|
|
17
|
+
iconName?: ReactElement<SvgProps>;
|
|
18
|
+
}
|