@truworth/twc-auth 1.2.4 → 1.2.5
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 -4
- package/build/src/api/axiosClient/index.js +1 -1
- package/build/src/api/axiosClient/index.native.js +1 -1
- package/build/src/components/VerifyMobileOTP/index.js +8 -6
- package/build/src/components/VerifyMobileOTP/index.native.js +6 -11
- package/build/src/constants/base-url/index.js +5 -0
- package/build/src/constants/base-url/index.native.js +1 -0
- package/build/src/constants/cdn-url/index.js +2 -1
- package/build/src/contexts/AuthContext.js +3 -1
- package/build/src/enums/loginMethod.enum.js +1 -1
- package/build/src/navigator/index.native.js +5 -1
- package/build/src/screens/EnterEmail/hooks/internal/useEnterEmail.js +50 -40
- package/build/src/screens/EnterEmail/index.js +8 -10
- package/build/src/screens/EnterEmail/index.native.js +6 -9
- package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/hooks/internal/useExistingAccountsSheet.js +36 -0
- package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/index.js +33 -0
- package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/index.native.js +73 -0
- package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/types.js +1 -0
- package/build/src/screens/EnterMobile/hooks/internal/useEnterMobile.js +67 -0
- package/build/src/screens/EnterMobile/index.js +82 -0
- package/build/src/screens/EnterMobile/index.native.js +56 -0
- package/build/src/screens/EnterMobile/types.js +1 -0
- package/build/src/screens/EnterPassword/hooks/internal/useEnterPassword.js +42 -31
- package/build/src/screens/EnterPassword/index.js +6 -6
- package/build/src/screens/EnterPassword/index.native.js +5 -10
- package/build/src/screens/Login/components/LoginWebComponent/index.js +4 -1
- package/build/src/screens/LoginWithEmailOTP/hooks/internal/useLoginWithEmailOTP.js +8 -5
- package/build/src/screens/LoginWithMobileOTP/hooks/internal/useLoginWithMobileOTP.js +71 -0
- package/build/src/screens/LoginWithMobileOTP/index.js +8 -0
- package/build/src/screens/LoginWithMobileOTP/index.native.js +10 -0
- package/build/src/screens/SSOLogin/AuthenticationMethods/index.js +9 -8
- package/build/src/screens/SSOLogin/AuthenticationMethods/index.native.js +2 -6
- package/build/src/screens/SignUp/components/SignUpForm/index.js +20 -5
- package/build/src/screens/SignUp/components/SignUpWebComponent/index.js +1 -1
- package/build/src/screens/SignUp/index.native.js +14 -13
- package/build/src/screens/UserConsent/index.js +1 -1
- package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/hooks/internal/useVerifyLinkPrimaryAccountEmailOTP.js +73 -0
- package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/index.js +8 -0
- package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/index.native.js +14 -0
- package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/types.js +1 -0
- package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/hooks/internal/useVerifyLinkPrimaryAccountMobileOTP.js +82 -0
- package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/index.js +8 -0
- package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/index.native.js +10 -0
- package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/types.js +1 -0
- package/build/src/screens/Welcome/index.js +3 -2
- package/build/types/components/VerifyMobileOTP/index.d.ts +1 -1
- package/build/types/components/VerifyMobileOTP/types.d.ts +0 -1
- package/build/types/constants/base-url/index.d.ts +1 -0
- package/build/types/constants/base-url/index.native.d.ts +1 -0
- package/build/types/constants/cdn-url/index.d.ts +2 -1
- package/build/types/contexts/AuthContext.d.ts +2 -1
- package/build/types/contexts/type.d.ts +3 -0
- package/build/types/enums/loginMethod.enum.d.ts +1 -1
- package/build/types/navigator/index.native.d.ts +14 -0
- package/build/types/screens/EnterEmail/hooks/internal/useEnterEmail.d.ts +11 -14
- package/build/types/screens/EnterEmail/types.d.ts +6 -1
- package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/hooks/internal/useExistingAccountsSheet.d.ts +13 -0
- package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/index.d.ts +3 -0
- package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/index.native.d.ts +3 -0
- package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/types.d.ts +28 -0
- package/build/types/screens/EnterMobile/hooks/internal/useEnterMobile.d.ts +15 -0
- package/build/types/screens/EnterMobile/index.d.ts +4 -0
- package/build/types/screens/EnterMobile/index.native.d.ts +4 -0
- package/build/types/screens/EnterMobile/types.d.ts +44 -0
- package/build/types/screens/EnterPassword/hooks/internal/useEnterPassword.d.ts +8 -8
- package/build/types/screens/LoginWithEmailOTP/hooks/internal/useLoginWithEmailOTP.d.ts +1 -1
- package/build/types/screens/LoginWithMobileOTP/hooks/internal/useLoginWithMobileOTP.d.ts +11 -0
- package/build/types/screens/LoginWithMobileOTP/index.d.ts +5 -0
- package/build/types/screens/LoginWithMobileOTP/index.native.d.ts +4 -0
- package/build/types/screens/SSOLogin/AuthenticationMethods/index.d.ts +1 -1
- package/build/types/screens/SSOLogin/AuthenticationMethods/types.d.ts +1 -0
- package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/hooks/internal/useVerifyLinkPrimaryAccountEmailOTP.d.ts +15 -0
- package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/index.d.ts +3 -0
- package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/index.native.d.ts +4 -0
- package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/types.d.ts +14 -0
- package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/hooks/internal/useVerifyLinkPrimaryAccountMobileOTP.d.ts +17 -0
- package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/index.d.ts +3 -0
- package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/index.native.d.ts +4 -0
- package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/types.d.ts +5 -0
- package/package.json +1 -5
package/README.md
CHANGED
|
@@ -70,7 +70,6 @@ Truworth Auth Module - A comprehensive authentication solution for React Native
|
|
|
70
70
|
| react | >=18.2.0 |
|
|
71
71
|
| react-native | >=0.74.5 |
|
|
72
72
|
| react-native-fast-image | >=8.6.3 |
|
|
73
|
-
| react-native-freshchat-sdk | >=4.6.6 |
|
|
74
73
|
| react-native-gesture-handler | >=2.16.0 |
|
|
75
74
|
| react-native-linear-gradient | >=2.8.3 |
|
|
76
75
|
| react-native-modalize | >=2.1.1 |
|
|
@@ -80,13 +79,12 @@ Truworth Auth Module - A comprehensive authentication solution for React Native
|
|
|
80
79
|
| react-native-svg | >=15.8.0 |
|
|
81
80
|
| react-native-vector-icons | >=9.2.0 |
|
|
82
81
|
|
|
83
|
-
> Note: lottie-react-native, react-native-fast-image
|
|
82
|
+
> Note: lottie-react-native, react-native-fast-image are optional and only needed if your app uses features that depend on them.
|
|
84
83
|
|
|
85
84
|
#### Web Dependencies
|
|
86
85
|
|
|
87
86
|
| Package | Version |
|
|
88
87
|
| ------------------------ | -------- |
|
|
89
|
-
| @truworth/twc-web-common | ^1.0.11 |
|
|
90
88
|
| @truworth/twc-web-design | ^1.9.0 |
|
|
91
89
|
| antd | ^5.6.3 |
|
|
92
90
|
| framer-motion | ^12.6.2 |
|
|
@@ -108,7 +106,6 @@ Truworth Auth Module - A comprehensive authentication solution for React Native
|
|
|
108
106
|
```bash
|
|
109
107
|
npm install \
|
|
110
108
|
next@^15.0.4 \
|
|
111
|
-
@truworth/twc-web-common@^1.0.11 \
|
|
112
109
|
@truworth/twc-web-design@^1.9.0 \
|
|
113
110
|
antd@^5.6.3 \
|
|
114
111
|
framer-motion@^12.6.2 \
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useEffect } from "react";
|
|
3
3
|
import { Button, Flex, OTPInput, Typography } from "@truworth/twc-web-design";
|
|
4
|
-
const VerifyMobileOTP = ({ validateOTP, timer, resendOTP, phone, status
|
|
4
|
+
const VerifyMobileOTP = ({ validateOTP, timer, resendOTP, phone, status }) => {
|
|
5
5
|
const [otp, setOtp] = useState('');
|
|
6
6
|
const [otpError, setOtpError] = useState(false);
|
|
7
7
|
useEffect(() => {
|
|
@@ -10,14 +10,16 @@ const VerifyMobileOTP = ({ validateOTP, timer, resendOTP, phone, status, resendT
|
|
|
10
10
|
setOtp('');
|
|
11
11
|
}
|
|
12
12
|
}, [status]);
|
|
13
|
-
|
|
14
|
-
return (_jsxs(_Fragment, { children: [defaultPhoneDisplayText, _jsx(OTPInput, { value: otp, onChange: (code) => {
|
|
13
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Typography, { type: 'body', size: 'large', className: 'mb-6 text-gray-400 text-center', children: ["OTP sent to", _jsx("span", { className: 'pl-2 text-secondary-dark', children: phone ? `XXXXXXX${phone.slice(-3)}` : 'your registered mobile number' })] }), _jsx(OTPInput, { value: otp, onChange: (code) => {
|
|
15
14
|
setOtp(code);
|
|
16
15
|
setOtpError(false);
|
|
17
16
|
}, error: otpError, maxLength: 6, className: `!w-auto ${otpError ? '!border-destructive' : ''}` }), otpError &&
|
|
18
|
-
_jsx(Typography, { type: "utility", size: "medium", className: "mt-4", color: "text-utility-danger-main", children: "Please enter the correct OTP." }),
|
|
19
|
-
_jsxs(Flex, { justify: 'between', align: 'center', className: 'mt-4', children: [_jsx(Typography, { type: 'utility', size: 'medium',
|
|
17
|
+
_jsx(Typography, { type: "utility", size: "medium", className: "mt-4", color: "text-utility-danger-main", children: "Please enter the correct OTP." }), timer <= 0 ?
|
|
18
|
+
_jsxs(Flex, { justify: 'between', align: 'center', className: 'mt-4', children: [_jsx(Typography, { type: 'utility', size: 'medium', children: "Didn't receive OTP?" }), _jsx(Button, { label: 'Re-send OTP', size: 'small', variant: 'link', onClick: () => {
|
|
19
|
+
setOtp('');
|
|
20
|
+
resendOTP();
|
|
21
|
+
} })] })
|
|
20
22
|
:
|
|
21
|
-
_jsxs(Typography, { type: 'utility', size: 'medium', className:
|
|
23
|
+
_jsxs(Typography, { type: 'utility', size: 'medium', className: 'mt-3', children: ["Resend Code in ", timer, " seconds"] }), _jsx(Button, { label: "Continue", isFullWidth: true, onClick: () => validateOTP?.(otp), disabled: otp ? otp?.length < 6 : true, className: "mt-6" })] }));
|
|
22
24
|
};
|
|
23
25
|
export { VerifyMobileOTP };
|
|
@@ -8,30 +8,25 @@ import { OTPStatusLabel } from '../OTPStatusLabel/index.native';
|
|
|
8
8
|
import OTPInputView from '@twotalltotems/react-native-otp-input';
|
|
9
9
|
const { gray } = Colors;
|
|
10
10
|
const VerifyMobileOTP = ({ validateOTP, timer, status, resendOTP, phone }) => {
|
|
11
|
-
const [otp,
|
|
11
|
+
const [otp, setOtp] = useState('');
|
|
12
12
|
const { otpValue } = useAuthPackageContext();
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
if (otp?.length === 6) {
|
|
15
|
-
validateOTP(otp);
|
|
16
|
-
}
|
|
17
|
-
}, [otp]);
|
|
18
13
|
useEffect(() => {
|
|
19
14
|
if (otpValue && otpValue.length == 6) {
|
|
20
|
-
|
|
15
|
+
setOtp(otpValue);
|
|
21
16
|
}
|
|
22
17
|
}, [otpValue]);
|
|
23
18
|
return (_jsxs(Layout, { style: { flex: 1, backgroundColor: '#FFFFFF' }, children: [_jsx(Header, {}), _jsxs(CustomKeyboardAvoidingView, { behavior: Platform.OS === 'ios' ? 'padding' : undefined, keyboardVerticalOffset: 0, children: [_jsxs(ScrollView, { style: { paddingHorizontal: 20, paddingTop: 32, flex: 1 }, children: [_jsxs(Text, { textBreakStrategy: 'simple', style: {
|
|
24
19
|
fontSize: 20, fontWeight: '600', color: gray.gray_900,
|
|
25
20
|
lineHeight: 32, marginBottom: 32,
|
|
26
|
-
}, children: ["OTP sent to ", '\n', phone ? phone.replace(/\d(?=\d{4})/g, 'x') : ''] }), _jsx(View, { style: { justifyContent: 'center', flexDirection: 'row', marginBottom: 30, position: 'relative' }, children: _jsx(OTPInputView, { pinCount: 6, autoFocusOnLoad: false, onCodeChanged: text =>
|
|
21
|
+
}, children: ["OTP sent to ", '\n', phone ? phone.replace(/\d(?=\d{4})/g, 'x') : ''] }), _jsx(View, { style: { justifyContent: 'center', flexDirection: 'row', marginBottom: 30, position: 'relative' }, children: _jsx(OTPInputView, { pinCount: 6, autoFocusOnLoad: false, onCodeChanged: text => setOtp(text), codeInputFieldStyle: {
|
|
27
22
|
fontSize: 20, color: 'black', width: 30,
|
|
28
23
|
height: 45, borderWidth: 0, borderBottomWidth: 1,
|
|
29
24
|
}, codeInputHighlightStyle: { borderColor: '#03DAC6' }, style: {
|
|
30
25
|
height: 50,
|
|
31
26
|
width: Dimensions.get('window').width - 100,
|
|
32
|
-
}, code: otp ?? '', onCodeFilled: code =>
|
|
33
|
-
_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center' }, children: [
|
|
34
|
-
|
|
27
|
+
}, code: otp ?? '', onCodeFilled: code => validateOTP(code) }) }), timer <= 0 &&
|
|
28
|
+
_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center' }, children: [_jsx(Text, { style: { fontSize: 12, color: '#000', fontWeight: '400', opacity: 0.5 }, children: "Did not receive OTP?" }), _jsx(TouchableOpacity, { disabled: timer > 0, onPress: () => {
|
|
29
|
+
setOtp('');
|
|
35
30
|
resendOTP();
|
|
36
31
|
}, children: _jsx(Text, { style: { fontSize: 14, color: '#2cbaa4', fontWeight: '400', opacity: 1 }, children: "Re-send OTP" }) })] })] }), _jsx(View, { style: { width: '100%' }, children: _jsx(OTPStatusLabel, { status: status, timer: timer }) })] })] }));
|
|
37
32
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const BASE_URL = process.env.BASE_URL;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export const MEMBER_IMAGES_URL = process.env.NEXT_PUBLIC_MEMBER_IMAGES_URL;
|
|
2
|
+
export const CDN_IMAGES_URL = process.env.NEXT_PUBLIC_CDN_IMAGES_URL;
|
|
@@ -31,8 +31,9 @@ const AuthPackageContext = React.createContext(null);
|
|
|
31
31
|
* @param onLogout - Optional callback after successful logout
|
|
32
32
|
* @param onLaunchAuthSession - Optional callback after successfully launching the auth session. For example, it can be used to set the Firebase notification token or request Android permissions.
|
|
33
33
|
* @param onRefreshSession - Optional handler for refreshing user session
|
|
34
|
+
* @param openChatSupport - Optional callback to open chat support
|
|
34
35
|
*/
|
|
35
|
-
const AuthProvider = ({ children, LogoComponent, session, appConfig, onLogin, onLogout, onLaunchAuthSession, onRefreshSession }) => {
|
|
36
|
+
const AuthProvider = ({ children, LogoComponent, session, appConfig, onLogin, onLogout, onLaunchAuthSession, onRefreshSession, openChatSupport }) => {
|
|
36
37
|
const [isLoadingProfile, setIsLoadingProfile] = useState(false);
|
|
37
38
|
const [profile, setProfile] = useState(null);
|
|
38
39
|
const [client, setClient] = useState(null);
|
|
@@ -177,6 +178,7 @@ const AuthProvider = ({ children, LogoComponent, session, appConfig, onLogin, on
|
|
|
177
178
|
onTokenChange: (token) => setToken(token),
|
|
178
179
|
onRegistrationMethodChange: (method) => setRegistrationMethod(method),
|
|
179
180
|
otpValue,
|
|
181
|
+
openChatSupport
|
|
180
182
|
};
|
|
181
183
|
return (_jsx(AuthContext.Provider, { value: AuthContextValues, children: _jsx(AuthPackageContext.Provider, { value: AuthPackageContextValues, children: children }) }));
|
|
182
184
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export var LoginMethodCode;
|
|
2
2
|
(function (LoginMethodCode) {
|
|
3
|
-
LoginMethodCode[LoginMethodCode["
|
|
3
|
+
LoginMethodCode[LoginMethodCode["Email"] = 1] = "Email";
|
|
4
4
|
LoginMethodCode[LoginMethodCode["Facebook"] = 2] = "Facebook";
|
|
5
5
|
LoginMethodCode[LoginMethodCode["Google"] = 3] = "Google";
|
|
6
6
|
LoginMethodCode[LoginMethodCode["Apple"] = 4] = "Apple";
|
|
@@ -16,8 +16,12 @@ import SSOSearchOrganization from '../screens/SSOLogin/SearchOrganization/index.
|
|
|
16
16
|
import SSOAuthenticationMethods from '../screens/SSOLogin/AuthenticationMethods/index.native';
|
|
17
17
|
import SSOAuthWebView from '../screens/SSOLogin/AuthWebView/index.native';
|
|
18
18
|
import SSOCallback from '../screens/SSOLogin/SSOCallback/index.native';
|
|
19
|
+
import LoginWithMobileOTP from '../screens/LoginWithMobileOTP/index.native';
|
|
20
|
+
import EnterMobile from '../screens/EnterMobile/index.native';
|
|
21
|
+
import VerifyLinkPrimaryAccountEmailOTP from '../screens/VerifyLinkPrimaryAccountEmailOTP/index.native';
|
|
22
|
+
import VerifyLinkPrimaryAccountMobileOTP from '../screens/VerifyLinkPrimaryAccountMobileOTP/index.native';
|
|
19
23
|
const { Navigator, Screen } = createNativeStackNavigator();
|
|
20
24
|
const AuthNavigator = () => {
|
|
21
|
-
return (_jsxs(Navigator, { screenOptions: { headerShown: false }, children: [_jsx(Screen, { name: "Welcome", component: Welcome }), _jsx(Screen, { name: "EnterEmail", component: EnterEmail }), _jsx(Screen, { name: "EnterPassword", component: EnterPassword }), _jsx(Screen, { name: "SignUp", component: SignUp }), _jsx(Screen, { name: "CountryCode", component: CountryCode }), _jsx(Screen, { name: "CreatePassword", component: CreatePassword }), _jsx(Screen, { name: "UserConsent", component: UserConsent }), _jsx(Screen, { name: "VerifyMobile", component: VerifyMobile }), _jsx(Screen, { name: "VerifyEmail", component: VerifyEmail }), _jsx(Screen, { name: "LoginWithEmailOTP", component: LoginWithEmailOTP }), _jsx(Screen, { name: "VerifyResetPasswordOTP", component: VerifyResetPasswordOTP }), _jsx(Screen, { name: "ResetPassword", component: ResetPassword }), _jsx(Screen, { name: "SSOSearchOrganization", component: SSOSearchOrganization }), _jsx(Screen, { name: "SSOAuthenticationMethods", component: SSOAuthenticationMethods }), _jsx(Screen, { name: "SSOAuthWebView", component: SSOAuthWebView }), _jsx(Screen, { name: "SSOCallback", component: SSOCallback })] }));
|
|
25
|
+
return (_jsxs(Navigator, { screenOptions: { headerShown: false }, children: [_jsx(Screen, { name: "Welcome", component: Welcome }), _jsx(Screen, { name: "EnterEmail", component: EnterEmail }), _jsx(Screen, { name: "EnterPassword", component: EnterPassword }), _jsx(Screen, { name: "SignUp", component: SignUp }), _jsx(Screen, { name: "CountryCode", component: CountryCode }), _jsx(Screen, { name: "CreatePassword", component: CreatePassword }), _jsx(Screen, { name: "UserConsent", component: UserConsent }), _jsx(Screen, { name: "VerifyMobile", component: VerifyMobile }), _jsx(Screen, { name: "VerifyEmail", component: VerifyEmail }), _jsx(Screen, { name: "LoginWithEmailOTP", component: LoginWithEmailOTP }), _jsx(Screen, { name: "VerifyResetPasswordOTP", component: VerifyResetPasswordOTP }), _jsx(Screen, { name: "ResetPassword", component: ResetPassword }), _jsx(Screen, { name: "LoginWithMobileOTP", component: LoginWithMobileOTP }), _jsx(Screen, { name: "EnterMobile", component: EnterMobile }), _jsx(Screen, { name: "VerifyLinkPrimaryAccountEmailOTP", component: VerifyLinkPrimaryAccountEmailOTP }), _jsx(Screen, { name: "VerifyLinkPrimaryAccountMobileOTP", component: VerifyLinkPrimaryAccountMobileOTP }), _jsx(Screen, { name: "SSOSearchOrganization", component: SSOSearchOrganization }), _jsx(Screen, { name: "SSOAuthenticationMethods", component: SSOAuthenticationMethods }), _jsx(Screen, { name: "SSOAuthWebView", component: SSOAuthWebView }), _jsx(Screen, { name: "SSOCallback", component: SSOCallback })] }));
|
|
22
26
|
};
|
|
23
27
|
export { AuthNavigator };
|
|
@@ -1,68 +1,78 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState, useCallback } from "react";
|
|
2
2
|
import { showMessage } from "../../../../helpers/show-message";
|
|
3
3
|
import { useAuthPackageContext } from "../../../../hooks/internal/useAuthPackageContext";
|
|
4
4
|
import { checkEmailExists } from "../../../../api/auth";
|
|
5
|
-
import { LoginMethodCode } from "../../../../enums";
|
|
6
|
-
const
|
|
5
|
+
import { LoginMethodCode, RegistrationMethod } from "../../../../enums";
|
|
6
|
+
const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
7
7
|
/**
|
|
8
8
|
* @internal
|
|
9
|
-
*
|
|
9
|
+
* Hook for managing Enter Email screen logic and authentication integration.
|
|
10
10
|
*/
|
|
11
11
|
const useEnterEmail = () => {
|
|
12
|
+
const [email, setEmail] = useState("");
|
|
13
|
+
const [loginType, setLoginType] = useState("");
|
|
12
14
|
const [loading, setLoading] = useState(false);
|
|
13
|
-
const [
|
|
14
|
-
const [
|
|
15
|
-
const [loginType, setLoginType] = useState('');
|
|
16
|
-
const [email, setEmail] = useState('');
|
|
15
|
+
const [isEmailValid, setIsEmailValid] = useState(false);
|
|
16
|
+
const [isLoginConflictModalVisible, setIsLoginConflictModalVisible] = useState(false);
|
|
17
17
|
const { appConfig, onRegistrationMethodChange } = useAuthPackageContext();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Handles email input change with validation
|
|
20
|
+
*/
|
|
21
|
+
const handleEmailChange = useCallback((value) => {
|
|
22
|
+
const normalizedEmail = value.toLowerCase().trim();
|
|
23
|
+
setEmail(normalizedEmail);
|
|
24
|
+
setIsEmailValid(EMAIL_REGEX.test(normalizedEmail));
|
|
25
|
+
}, []);
|
|
26
|
+
/**
|
|
27
|
+
* Validates email existence and handles login conflicts
|
|
28
|
+
*/
|
|
29
|
+
const handleEmailExists = useCallback(async ({ onValidate }) => {
|
|
24
30
|
setLoading(true);
|
|
25
31
|
try {
|
|
26
32
|
const { emailExist, loginType } = await checkEmailExists(email);
|
|
27
|
-
const
|
|
28
|
-
if (emailExist &&
|
|
29
|
-
const
|
|
30
|
-
[LoginMethodCode.Facebook]:
|
|
31
|
-
[LoginMethodCode.Google]:
|
|
32
|
-
[LoginMethodCode.Apple]:
|
|
33
|
-
[LoginMethodCode.SSO]:
|
|
33
|
+
const loginCode = Number(loginType);
|
|
34
|
+
if (emailExist && loginCode !== LoginMethodCode.Email) {
|
|
35
|
+
const loginMethodMap = {
|
|
36
|
+
[LoginMethodCode.Facebook]: "Facebook",
|
|
37
|
+
[LoginMethodCode.Google]: "Google",
|
|
38
|
+
[LoginMethodCode.Apple]: "Apple",
|
|
39
|
+
[LoginMethodCode.SSO]: "SSO",
|
|
34
40
|
};
|
|
35
|
-
setLoginType(
|
|
36
|
-
|
|
41
|
+
setLoginType(loginMethodMap[loginCode] || "your social account");
|
|
42
|
+
setIsLoginConflictModalVisible(true);
|
|
37
43
|
return;
|
|
38
44
|
}
|
|
39
|
-
|
|
45
|
+
onRegistrationMethodChange(RegistrationMethod.EMAIL);
|
|
46
|
+
onValidate({ emailExist });
|
|
40
47
|
}
|
|
41
|
-
catch (
|
|
42
|
-
const
|
|
43
|
-
showMessage({ message
|
|
48
|
+
catch (error) {
|
|
49
|
+
const message = error?.response?.data?.errors?.[0]?.message ?? "Something went wrong";
|
|
50
|
+
showMessage({ message });
|
|
44
51
|
}
|
|
45
52
|
finally {
|
|
46
53
|
setLoading(false);
|
|
47
54
|
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
}, [email]);
|
|
56
|
+
/**
|
|
57
|
+
* Clears email input field
|
|
58
|
+
*/
|
|
59
|
+
const handleClearEmail = useCallback(() => {
|
|
60
|
+
setEmail("");
|
|
61
|
+
setIsEmailValid(false);
|
|
52
62
|
}, []);
|
|
53
63
|
return {
|
|
54
64
|
email,
|
|
55
|
-
|
|
56
|
-
isInvalidEmail,
|
|
65
|
+
isEmailValid,
|
|
57
66
|
loading,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
handleEmailChange,
|
|
68
|
+
handleEmailExists,
|
|
69
|
+
handleClearEmail,
|
|
70
|
+
isLoginConflictModalVisible,
|
|
71
|
+
setIsLoginConflictModalVisible,
|
|
63
72
|
onRegistrationMethodChange,
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
appName: appConfig.appName,
|
|
74
|
+
loginConflictTitle: `Sign in with ${loginType}`,
|
|
75
|
+
loginConflictDescription: `Looks like you previously registered using ${loginType}. Please go back and sign in with ${loginType}.`,
|
|
66
76
|
};
|
|
67
77
|
};
|
|
68
78
|
export { useEnterEmail };
|
|
@@ -5,24 +5,22 @@ import { ScreenLayout } from "../../components/ScreenLayout";
|
|
|
5
5
|
import { useEnterEmail } from "./hooks/internal/useEnterEmail";
|
|
6
6
|
import { SupportDetails } from '../../components/SupportDetails';
|
|
7
7
|
const EnterEmail = ({ onContinue, onPressSignInWithSSO }) => {
|
|
8
|
-
const {
|
|
8
|
+
const { email, isEmailValid, handleEmailChange, appName, handleEmailExists, loading, loginConflictTitle, loginConflictDescription, isLoginConflictModalVisible, setIsLoginConflictModalVisible } = useEnterEmail();
|
|
9
9
|
const form = useForm({ defaultValues: { email } });
|
|
10
10
|
return (_jsxs(_Fragment, { children: [_jsxs(ScreenLayout, { title: `Hi, Welcome To ${appName}!`, subTitle: "Please enter email to get started.", buttonProps: {
|
|
11
11
|
loading,
|
|
12
12
|
label: 'Continue',
|
|
13
13
|
onClick: () => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
});
|
|
18
|
-
}
|
|
14
|
+
handleEmailExists({
|
|
15
|
+
onValidate: ({ emailExist }) => onContinue({ email, emailExist })
|
|
16
|
+
});
|
|
19
17
|
},
|
|
20
|
-
disabled:
|
|
18
|
+
disabled: !isEmailValid,
|
|
21
19
|
}, children: [_jsx(Form, { className: "w-full", form: form, children: _jsx(Form.Item, { name: "email", label: "Email", children: _jsx(TextInput, { type: "email", value: email, size: "medium", placeholder: "example@domain", ...form.register('email', {
|
|
22
20
|
onChange: (e) => {
|
|
23
|
-
|
|
21
|
+
handleEmailChange(e.target.value);
|
|
24
22
|
}
|
|
25
|
-
}) }) }) }),
|
|
26
|
-
_jsx(LoginConflictModal, { title:
|
|
23
|
+
}) }) }) }), isLoginConflictModalVisible &&
|
|
24
|
+
_jsx(LoginConflictModal, { title: loginConflictTitle, description: loginConflictDescription, visible: isLoginConflictModalVisible, onProceed: () => setIsLoginConflictModalVisible(false), onClose: () => setIsLoginConflictModalVisible(false), primaryLabel: 'Okay' })] }), _jsx(Button, { isFullWidth: true, type: "button", label: 'Sign In with SSO', variant: 'secondary', className: 'flex-none mt-6', onClick: onPressSignInWithSSO }), _jsx(SupportDetails, {})] }));
|
|
27
25
|
};
|
|
28
26
|
export default EnterEmail;
|
|
@@ -8,13 +8,12 @@ import { ConfirmationModal as LoginConflictModal } from '../../components/Confir
|
|
|
8
8
|
import { RegistrationMethod } from '../../enums';
|
|
9
9
|
const { utility } = Colors;
|
|
10
10
|
const EnterEmail = ({ navigation }) => {
|
|
11
|
-
const {
|
|
12
|
-
const
|
|
11
|
+
const { email, isEmailValid, handleEmailChange, handleClearEmail, handleEmailExists, loading, loginConflictTitle, loginConflictDescription, isLoginConflictModalVisible, setIsLoginConflictModalVisible } = useEnterEmail();
|
|
12
|
+
const onValidate = (params) => {
|
|
13
13
|
if (params.emailExist) {
|
|
14
14
|
navigation.navigate('EnterPassword', { email });
|
|
15
15
|
}
|
|
16
16
|
else {
|
|
17
|
-
onRegistrationMethodChange(RegistrationMethod.EMAIL);
|
|
18
17
|
navigation.navigate('SignUp', { email });
|
|
19
18
|
}
|
|
20
19
|
};
|
|
@@ -23,12 +22,10 @@ const EnterEmail = ({ navigation }) => {
|
|
|
23
22
|
label: 'Continue',
|
|
24
23
|
onPress: () => {
|
|
25
24
|
Keyboard.dismiss();
|
|
26
|
-
|
|
27
|
-
handleValidateEmail({ onContinue });
|
|
28
|
-
}
|
|
25
|
+
handleEmailExists({ onValidate });
|
|
29
26
|
},
|
|
30
|
-
disabled:
|
|
31
|
-
}, children: _jsx(TextInputField, { value: email, placeholder: 'Enter here...', onChangeValue:
|
|
32
|
-
_jsx(LoginConflictModal, { title:
|
|
27
|
+
disabled: !isEmailValid,
|
|
28
|
+
}, children: _jsx(TextInputField, { value: email, placeholder: 'Enter here...', onChangeValue: handleEmailChange, rightIcon2: email.length > 0 ? 'close' : '', onPressRightIcon2: handleClearEmail, autoFocus: true, autoCapitalize: 'none', keyboardType: 'email-address' }) }), isLoginConflictModalVisible &&
|
|
29
|
+
_jsx(LoginConflictModal, { title: loginConflictTitle, description: loginConflictDescription, visible: isLoginConflictModalVisible, onProceed: () => setIsLoginConflictModalVisible(false), onClose: () => setIsLoginConflictModalVisible(false), iconColor: utility.warning_main, primaryLabel: 'Okay' })] }));
|
|
33
30
|
};
|
|
34
31
|
export default EnterEmail;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
import { axiosClient } from '../../../../../../api/axiosClient';
|
|
3
|
+
import { showMessage } from "../../../../../../helpers/show-message";
|
|
4
|
+
/**
|
|
5
|
+
* @internal
|
|
6
|
+
* Internal hook for managing useExistingAccountsSheet hook state and auth context integration. Not exposed to package consumers.
|
|
7
|
+
*/
|
|
8
|
+
const useExistingAccountsSheet = () => {
|
|
9
|
+
const [loading, setLoading] = useState(false);
|
|
10
|
+
const [selectedAccount, setSelectedAccount] = useState(null);
|
|
11
|
+
const linkPrimaryAccount = useCallback(({ phone, onInitiateLinking }) => {
|
|
12
|
+
setLoading(true);
|
|
13
|
+
axiosClient({
|
|
14
|
+
url: '/auth/mobile/link-primary-account/initiate',
|
|
15
|
+
method: 'POST',
|
|
16
|
+
data: {
|
|
17
|
+
phone,
|
|
18
|
+
memberId: selectedAccount?.memberId,
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
.then((res) => onInitiateLinking(res.data))
|
|
22
|
+
.catch((error) => {
|
|
23
|
+
console.log(error);
|
|
24
|
+
const message = error?.response?.data?.errors?.[0]?.message ?? 'Unable to initiate linking. Please try again.';
|
|
25
|
+
showMessage({ message });
|
|
26
|
+
})
|
|
27
|
+
.finally(() => setLoading(false));
|
|
28
|
+
}, [selectedAccount]);
|
|
29
|
+
return {
|
|
30
|
+
loading,
|
|
31
|
+
linkPrimaryAccount,
|
|
32
|
+
selectedAccount,
|
|
33
|
+
setSelectedAccount
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export { useExistingAccountsSheet };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useExistingAccountsSheet } from './hooks/internal/useExistingAccountsSheet';
|
|
3
|
+
import { ResponsiveModal, Typography, Flex, Button, Card, Radio } from '@truworth/twc-web-design';
|
|
4
|
+
import { SupportDetails } from '../../../../components/SupportDetails';
|
|
5
|
+
import { IonIcon } from '../../../../components/IonIcon';
|
|
6
|
+
import { LoginMethodCode } from '../../../../enums';
|
|
7
|
+
import moment from 'moment';
|
|
8
|
+
const ExistingAccountsSheet = ({ visible, hide, phone, existingAccounts, onInitiateAccountLinking }) => {
|
|
9
|
+
const { loading, linkPrimaryAccount, selectedAccount, setSelectedAccount, } = useExistingAccountsSheet();
|
|
10
|
+
const onContinue = () => {
|
|
11
|
+
if (!phone || !selectedAccount?.email) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
linkPrimaryAccount({
|
|
15
|
+
phone,
|
|
16
|
+
onInitiateLinking: ({ sessionToken }) => {
|
|
17
|
+
onInitiateAccountLinking?.({
|
|
18
|
+
sessionToken,
|
|
19
|
+
email: selectedAccount?.email
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
const displayPhone = phone ? `+91${phone.replace(/^.{8}/, 'XXXXXXXX')}` : '+91**********';
|
|
25
|
+
return (_jsxs(ResponsiveModal, { open: visible, onClose: hide, onOpenChange: hide, maskClosable: false, title: _jsxs(_Fragment, { children: [_jsx(Typography, { type: "heading", size: "h6", children: "Multiple Accounts Found" }), _jsxs(Typography, { type: "utility", size: "medium", color: "gray-600", className: "mt-2 mb-3", children: ["The phone number ", displayPhone, " is linked to the following accounts."] }), _jsx("hr", {})] }), centered: true, showCloseButton: false, className: "px-0", footer: _jsxs(Flex, { direction: "column", className: 'pt-1', children: [_jsx(Flex, { className: "flex-1 border-t border-gray-300 mb-2" }), selectedAccount &&
|
|
26
|
+
_jsxs(Flex, { align: 'center', className: 'bg-utility-warning-bg p-2 rounded-lg gap-1', children: [_jsx(IonIcon, { name: "information-circle-outline", style: { color: "hsl(var(--tw-ui-utility---warning--main))", fontSize: 24 } }), _jsxs(Typography, { type: "utility", size: "small", children: [_jsx("span", { className: "text-gray-500 text-[12px]", children: "Once you proceed, this phone number will be removed" }), " from other accounts."] })] }), _jsx(Button, { isFullWidth: true, loading: loading, variant: "primary", label: "Link and Continue", className: 'mt-4 mb-[-16px]', onClick: onContinue, disabled: !selectedAccount }), _jsx(SupportDetails, {})] }), children: [_jsx(Typography, { type: "utility", size: "medium", className: "mb-4", children: "Select account you want to continue with." }), existingAccounts.map((item) => {
|
|
27
|
+
return (_jsx(OptionCard, { item: item, onClick: () => setSelectedAccount(item), selectedItem: selectedAccount }, item.memberId));
|
|
28
|
+
})] }));
|
|
29
|
+
};
|
|
30
|
+
const OptionCard = ({ item, onClick, selectedItem }) => {
|
|
31
|
+
return (_jsx(Card, { containerStyle: `p-4 mb-2 ${item.memberId === selectedItem?.memberId ? 'border-primary' : 'border-gray-200'}`, children: _jsxs(Flex, { className: 'gap-2', onClick: onClick, children: [_jsx(Radio, { selectedValue: selectedItem?.memberId, options: [{ label: '', value: item.memberId }] }), _jsx(Flex, { direction: 'column', className: 'mt-[-2px]', children: _jsxs(_Fragment, { children: [_jsxs(Flex, { direction: "column", className: "border-b-2 pb-2 w-full", children: [_jsx(Typography, { type: "utility", size: "large", className: "break-words w-full mb-1", children: item.name }), _jsx(Typography, { type: "utility", size: "medium", color: "primary", className: "truncate w-full", children: item.email })] }), _jsxs(_Fragment, { children: [_jsxs(Flex, { justify: "between", className: "mt-3", children: [_jsx(Typography, { type: "utility", size: "medium", color: "gray-700", children: "Registration Source" }), _jsx(Typography, { type: "utility", size: "medium", color: "gray-800", children: item.loginType ? LoginMethodCode[item.loginType] : '—' })] }), _jsxs(Flex, { justify: "between", className: "mt-3", children: [_jsx(Typography, { type: "utility", size: "medium", color: "gray-700", children: "Registration Date" }), _jsx(Typography, { type: "utility", size: "medium", color: "gray-800", children: item.createdOn ? moment(item.createdOn).format('DD/MM/YYYY') : '—' })] })] })] }) })] }) }));
|
|
32
|
+
};
|
|
33
|
+
export { ExistingAccountsSheet };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import { Divider } from '@ui-kitten/components';
|
|
4
|
+
import { Platform, Text, TouchableOpacity, View } from 'react-native';
|
|
5
|
+
import { useNavigation } from '@react-navigation/native';
|
|
6
|
+
import { BottomSheet, Colors, isIphoneX, RadioButton, RoundedButton } from '@truworth/twc-rn-common';
|
|
7
|
+
import { useModalize } from 'react-native-modalize';
|
|
8
|
+
import { useExistingAccountsSheet } from './hooks/internal/useExistingAccountsSheet';
|
|
9
|
+
import { useAuthPackageContext } from '../../../../hooks/internal/useAuthPackageContext';
|
|
10
|
+
import { LoginMethodCode } from '../../../../enums';
|
|
11
|
+
import moment from 'moment';
|
|
12
|
+
import IonIcons from 'react-native-vector-icons/Ionicons';
|
|
13
|
+
const { primary, gray, utility } = Colors;
|
|
14
|
+
const ExistingAccountsSheet = ({ visible, hide, phone, existingAccounts }) => {
|
|
15
|
+
const { ref: sheetRef, open: openSheet, close: closeSheet } = useModalize();
|
|
16
|
+
const navigation = useNavigation();
|
|
17
|
+
const { openChatSupport } = useAuthPackageContext();
|
|
18
|
+
const { loading, linkPrimaryAccount, selectedAccount, setSelectedAccount } = useExistingAccountsSheet();
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (visible) {
|
|
21
|
+
openSheet();
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
closeSheet();
|
|
25
|
+
}
|
|
26
|
+
}, [visible]);
|
|
27
|
+
const onContinue = () => {
|
|
28
|
+
if (!phone || !selectedAccount?.email) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
linkPrimaryAccount({
|
|
32
|
+
phone,
|
|
33
|
+
onInitiateLinking: ({ sessionToken }) => {
|
|
34
|
+
navigation.navigate('VerifyLinkPrimaryAccountEmailOTP', {
|
|
35
|
+
phone,
|
|
36
|
+
sessionToken,
|
|
37
|
+
email: selectedAccount?.email
|
|
38
|
+
});
|
|
39
|
+
hide();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
const displayPhone = phone ? `+91${phone.replace(/^.{8}/, 'XXXXXXXX')}` : '+91**********';
|
|
44
|
+
return (_jsx(BottomSheet, { sheetRef: sheetRef, onClose: hide, panGestureEnabled: false, HeaderComponent: _jsxs(_Fragment, { children: [_jsxs(View, { style: { paddingTop: 22, marginHorizontal: 22 }, children: [_jsx(Text, { style: { fontSize: 16, fontWeight: '600', color: gray.gray_900, textAlign: 'center' }, children: "Multiple Accounts Found" }), _jsxs(Text, { style: { fontSize: 12, fontWeight: '500', color: gray.gray_500, lineHeight: 20, textAlign: 'center', marginHorizontal: 16 }, children: ["The phone number ", displayPhone, " is linked to the following accounts."] })] }), _jsx(View, { style: { backgroundColor: gray.gray_200, height: 2, marginVertical: 8 } })] }), flatListProps: {
|
|
45
|
+
showsVerticalScrollIndicator: false,
|
|
46
|
+
contentContainerStyle: { flexGrow: 1 },
|
|
47
|
+
data: existingAccounts,
|
|
48
|
+
keyExtractor: (item) => item.memberId,
|
|
49
|
+
ListHeaderComponent: _jsx(Text, { style: { fontSize: 14, fontWeight: '600', color: gray.gray_900, marginHorizontal: 16, marginTop: 8 }, children: "Select account you want to continue with." }),
|
|
50
|
+
renderItem: ({ item }) => {
|
|
51
|
+
return (_jsxs(TouchableOpacity, { activeOpacity: 0.8, style: { padding: 16, margin: 8, borderWidth: 1, borderRadius: 8, borderColor: selectedAccount?.memberId === item.memberId ? primary.primary_main : gray.gray_200 }, onPress: () => setSelectedAccount(item), children: [_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center' }, children: [_jsx(RadioButton, { checked: selectedAccount?.memberId === item.memberId, onChecked: () => setSelectedAccount(item) }), _jsxs(View, { style: { flex: 1, marginStart: 8 }, children: [_jsx(Text, { style: { fontSize: 14, fontWeight: '600', color: gray.gray_900 }, children: item.name }), _jsx(Text, { style: { fontSize: 12, fontWeight: '500', color: primary.primary_main, marginTop: 3 }, children: item.email })] })] }), _jsx(Divider, { style: { marginVertical: 8, backgroundColor: gray.gray_200 } }), _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsx(Text, { style: { fontSize: 12, fontWeight: '500', color: gray.gray_500 }, children: "Registration Source" }), _jsx(Text, { style: { fontSize: 12, fontWeight: '600', color: gray.gray_800 }, children: LoginMethodCode[item.loginType] || 'Unknown' })] }), _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginTop: 8 }, children: [_jsx(Text, { style: { fontSize: 12, fontWeight: '500', color: gray.gray_500 }, children: "Registration Date" }), _jsx(Text, { style: { fontSize: 12, fontWeight: '600', color: gray.gray_800, }, children: moment(item.createdOn).format('DD/MM/YYYY') })] })] }, item.memberId));
|
|
52
|
+
}
|
|
53
|
+
}, FooterComponent: _jsxs(View, { style: {
|
|
54
|
+
width: '100%', backgroundColor: 'white', marginTop: 8,
|
|
55
|
+
padding: 16, marginBottom: isIphoneX() ? 30 : 0,
|
|
56
|
+
borderTopWidth: Platform.OS == 'android' ? 1 : 0, borderTopColor: gray.gray_300,
|
|
57
|
+
shadowColor: '#DDDDDD', shadowOffset: { width: 0, height: -2 },
|
|
58
|
+
shadowOpacity: 1, shadowRadius: 3, elevation: 3
|
|
59
|
+
}, children: [selectedAccount &&
|
|
60
|
+
_jsxs(View, { style: {
|
|
61
|
+
backgroundColor: utility.warning_bg,
|
|
62
|
+
padding: 8,
|
|
63
|
+
borderRadius: 8,
|
|
64
|
+
marginBottom: 8,
|
|
65
|
+
flexDirection: 'row',
|
|
66
|
+
alignItems: 'center',
|
|
67
|
+
}, children: [_jsx(IonIcons, { size: 16, name: "information-circle", style: { marginRight: 8 }, color: utility.warning_main }), _jsxs(Text, { style: {
|
|
68
|
+
flex: 1, fontSize: 12, fontWeight: '500',
|
|
69
|
+
lineHeight: 18, color: gray.gray_500,
|
|
70
|
+
}, children: ["Once you proceed, this phone number will be ", _jsx(Text, { style: { fontWeight: '600', color: gray.gray_900 }, children: "removed from other accounts." })] })] }), _jsx(RoundedButton, { label: 'Link and Continue', size: 'large', loading: loading, disabled: !selectedAccount, onPress: onContinue, containerStyle: { marginBottom: 8 } }), openChatSupport &&
|
|
71
|
+
_jsxs(TouchableOpacity, { activeOpacity: 0.8, onPress: openChatSupport, style: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', padding: 8 }, children: [_jsx(IonIcons, { size: 12, name: 'headset', color: primary.primary_main }), _jsx(Text, { style: { fontSize: 14, fontWeight: '600', color: primary.primary_main, marginStart: 8 }, children: "Connect with Support" })] })] }) }));
|
|
72
|
+
};
|
|
73
|
+
export { ExistingAccountsSheet };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { checkMobileExists } from "../../../../api/auth";
|
|
3
|
+
import { showMessage } from "../../../../helpers/show-message";
|
|
4
|
+
import { useAuthPackageContext } from "../../../../hooks/internal/useAuthPackageContext";
|
|
5
|
+
import { RegistrationMethod } from "../../../../enums";
|
|
6
|
+
const useEnterMobile = () => {
|
|
7
|
+
const [loading, setLoading] = useState(false);
|
|
8
|
+
const [isValidPhone, setValidPhone] = useState(false);
|
|
9
|
+
const [showExistingAccountsSheet, setShowExistingAccountsSheet] = useState(false);
|
|
10
|
+
const [phone, setPhone] = useState('');
|
|
11
|
+
const [countryCode, setCountryCode] = useState('91');
|
|
12
|
+
const [existingAccounts, setExistingAccounts] = useState([]);
|
|
13
|
+
const { onRegistrationMethodChange } = useAuthPackageContext();
|
|
14
|
+
const handleEnterMobile = (text) => {
|
|
15
|
+
setPhone(text);
|
|
16
|
+
const isNumeric = /^[0-9]+$/.test(text);
|
|
17
|
+
if (countryCode === '91' && text.length === 10 && isNumeric) {
|
|
18
|
+
setValidPhone(true);
|
|
19
|
+
}
|
|
20
|
+
else if (countryCode !== '91' && text.length >= 6 && text.length <= 15 && isNumeric) {
|
|
21
|
+
setValidPhone(true);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
setValidPhone(false);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const handleValidatePhone = async ({ onValidate }) => {
|
|
28
|
+
setLoading(true);
|
|
29
|
+
try {
|
|
30
|
+
const { mobileExist, linkedAccounts } = await checkMobileExists(phone);
|
|
31
|
+
if (mobileExist) {
|
|
32
|
+
if (linkedAccounts && linkedAccounts.length > 1) {
|
|
33
|
+
setExistingAccounts(linkedAccounts);
|
|
34
|
+
return setShowExistingAccountsSheet(true);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!mobileExist) {
|
|
38
|
+
onRegistrationMethodChange(RegistrationMethod.MOBILE);
|
|
39
|
+
}
|
|
40
|
+
onValidate({ mobileExist, email: linkedAccounts?.[0]?.email ?? '' });
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
const errorMessage = err?.response?.data?.errors?.[0]?.message ?? 'Something went wrong';
|
|
44
|
+
showMessage({ message: errorMessage });
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
setLoading(false);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const handleClearPhoneInput = () => {
|
|
51
|
+
setPhone('');
|
|
52
|
+
setValidPhone(false);
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
loading,
|
|
56
|
+
phone,
|
|
57
|
+
isValidPhone,
|
|
58
|
+
countryCode, setCountryCode,
|
|
59
|
+
existingAccounts,
|
|
60
|
+
showExistingAccountsSheet,
|
|
61
|
+
setShowExistingAccountsSheet,
|
|
62
|
+
handleValidatePhone,
|
|
63
|
+
handleEnterMobile,
|
|
64
|
+
handleClearPhoneInput,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
export { useEnterMobile };
|