@truworth/twc-auth 1.1.0 → 1.2.2
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 +239 -306
- package/build/assets/animation/redirect-home.json +1101 -0
- package/build/assets/cross_icon copy.svg +5 -0
- package/build/assets/cross_icon.svg +5 -0
- package/build/assets/gender-diversity.svg +22 -0
- package/build/assets/logo.svg +55 -0
- package/build/assets/okay_icon copy.svg +3 -0
- package/build/assets/okay_icon.svg +3 -0
- package/build/src/api/axiosClient/index.js +5 -0
- package/build/src/api/axiosClient/index.native.js +5 -0
- package/build/src/components/AdvancedTransitionWrapper/index.js +380 -0
- package/build/src/components/AdvancedTransitionWrapper/index.native.js +10 -0
- package/build/src/components/AdvancedTransitionWrapper/types.js +1 -0
- package/build/src/components/ConfirmationModal/index.js +11 -0
- package/build/src/components/ConfirmationModal/index.native.js +15 -0
- package/build/src/components/ConfirmationModal/types.js +1 -0
- package/build/src/components/EmailOTPVerify/index.js +20 -0
- package/build/src/components/EmailOTPVerify/index.native.js +26 -0
- package/build/src/components/EmailOTPVerify/type.js +1 -0
- package/build/src/components/IonIcon/index.js +11 -0
- package/build/src/components/IonIcon/index.native.js +9 -0
- package/build/src/components/IonIcon/types.js +1 -0
- package/build/src/components/OTPStatusLabel/index.js +10 -0
- package/build/src/components/OTPStatusLabel/index.native.js +21 -0
- package/build/src/components/OTPStatusLabel/types.js +1 -0
- package/build/src/components/PasswordCriteria/hooks/usePasswordCriteria.js +78 -0
- package/build/src/components/PasswordCriteria/index.js +47 -0
- package/build/src/components/PasswordCriteria/index.native.js +22 -0
- package/build/src/components/PasswordCriteria/types.js +1 -0
- package/build/src/components/ScreenLayout/index.js +12 -0
- package/build/src/components/ScreenLayout/index.native.js +18 -0
- package/build/src/components/ScreenLayout/types.js +1 -0
- package/build/src/components/SupportDetails/index.js +9 -0
- package/build/src/components/SupportDetails/index.native.js +6 -0
- package/build/src/components/VerifyOTP/index.js +23 -0
- package/build/src/components/VerifyOTP/index.native.js +38 -0
- package/build/src/components/VerifyOTP/types.js +1 -0
- package/build/src/constants/cdn-url/index.js +1 -0
- package/build/src/constants/cdn-url/index.native.js +5 -0
- package/build/src/contexts/AuthContext.js +185 -0
- package/build/src/contexts/type.js +1 -0
- package/build/src/helpers/Network.js +93 -0
- package/build/src/helpers/Validation.js +12 -0
- package/build/src/helpers/show-message/index.js +19 -0
- package/build/src/helpers/show-message/index.native.js +14 -0
- package/build/src/helpers/show-message/types.js +1 -0
- package/build/src/helpers/types.js +1 -0
- package/build/src/hooks/internal/useAuthPackageContext.js +9 -0
- package/build/src/hooks/internal/useTimer.js +40 -0
- package/build/src/hooks/useAuthContext.js +10 -0
- package/build/src/hooks/useRequest.js +41 -0
- package/build/src/index.js +14 -0
- package/build/src/navigator/index.js +10 -0
- package/build/src/navigator/index.native.js +16 -0
- package/build/src/screens/CountryCode/components/CountryCodeDropdown/index.js +38 -0
- package/build/src/screens/CountryCode/components/CountryCodeDropdown/index.native.js +6 -0
- package/build/src/screens/CountryCode/components/CountryCodeDropdown/types.js +1 -0
- package/build/src/screens/CountryCode/hooks/internal/useCountryCode.js +38 -0
- package/build/src/screens/CountryCode/index.js +10 -0
- package/build/src/screens/CountryCode/index.native.js +37 -0
- package/build/src/screens/CountryCode/type.js +1 -0
- package/build/src/screens/CreatePassword/hooks/internal/useCreatePassword.js +52 -0
- package/build/src/screens/CreatePassword/index.js +43 -0
- package/build/src/screens/CreatePassword/index.native.js +32 -0
- package/build/src/screens/CreatePassword/type.js +1 -0
- package/build/src/screens/EnterEmail/hooks/internal/useEnterEmail.js +86 -0
- package/build/src/screens/EnterEmail/index.js +30 -0
- package/build/src/screens/EnterEmail/index.native.js +34 -0
- package/build/src/screens/EnterPassword/hooks/internal/useEnterPassword.js +47 -0
- package/build/src/screens/EnterPassword/index.js +22 -0
- package/build/src/screens/EnterPassword/index.native.js +23 -0
- package/build/src/screens/EnterPassword/types.js +1 -0
- package/build/src/screens/Login/components/LoginWebComponent/index.js +44 -0
- package/build/src/screens/Login/components/LoginWebComponent/index.native.js +6 -0
- package/build/src/screens/Login/index.js +10 -0
- package/build/src/screens/Login/index.native.js +6 -0
- package/build/src/screens/SignUp/components/SignUpForm/index.js +174 -0
- package/build/src/screens/SignUp/components/SignUpForm/index.native.js +6 -0
- package/build/src/screens/SignUp/components/SignUpForm/type.js +1 -0
- package/build/src/screens/SignUp/components/SignUpWebComponent/index.js +82 -0
- package/build/src/screens/SignUp/components/SignUpWebComponent/index.native.js +6 -0
- package/build/src/screens/SignUp/components/SignUpWebComponent/types.js +1 -0
- package/build/src/screens/SignUp/hooks/internal/useSignUp.js +138 -0
- package/build/src/screens/SignUp/index.js +6 -0
- package/build/src/screens/SignUp/index.native.js +185 -0
- package/build/src/screens/SignUp/types.js +1 -0
- package/build/src/screens/UserConsent/hooks/internal/useConsent.js +48 -0
- package/build/src/screens/UserConsent/index.js +69 -0
- package/build/src/screens/UserConsent/index.native.js +46 -0
- package/build/src/screens/UserConsent/types.js +1 -0
- package/build/src/screens/VerifyEmail/hooks/internal/useVerifyEmail.js +69 -0
- package/build/src/screens/VerifyEmail/index.js +8 -0
- package/build/src/screens/VerifyEmail/index.native.js +14 -0
- package/build/src/screens/VerifyEmail/types.js +1 -0
- package/build/src/screens/VerifyMobile/hooks/internal/useVerifyMobile.js +73 -0
- package/build/src/screens/VerifyMobile/index.js +8 -0
- package/build/src/screens/VerifyMobile/index.native.js +9 -0
- package/build/src/screens/VerifyMobile/types.js +1 -0
- package/build/src/screens/Welcome/hooks/internal/useWelcome.js +21 -0
- package/build/src/screens/Welcome/index.js +28 -0
- package/build/src/screens/Welcome/index.native.js +41 -0
- package/build/src/types/types.js +1 -0
- package/build/types/api/axiosClient/index.d.ts +1 -0
- package/build/types/api/axiosClient/index.native.d.ts +1 -0
- package/build/types/components/AdvancedTransitionWrapper/index.d.ts +3 -0
- package/build/types/components/AdvancedTransitionWrapper/index.native.d.ts +5 -0
- package/build/types/components/AdvancedTransitionWrapper/types.d.ts +25 -0
- package/build/types/components/ConfirmationModal/index.d.ts +3 -0
- package/build/types/components/ConfirmationModal/index.native.d.ts +3 -0
- package/build/types/components/ConfirmationModal/types.d.ts +13 -0
- package/build/types/components/EmailOTPVerify/index.d.ts +3 -0
- package/build/types/components/EmailOTPVerify/index.native.d.ts +3 -0
- package/build/types/components/EmailOTPVerify/type.d.ts +9 -0
- package/build/types/components/IonIcon/index.d.ts +3 -0
- package/build/types/components/IonIcon/index.native.d.ts +4 -0
- package/build/types/components/IonIcon/types.d.ts +6 -0
- package/build/types/components/OTPStatusLabel/index.d.ts +2 -0
- package/build/types/components/OTPStatusLabel/index.native.d.ts +3 -0
- package/build/types/components/OTPStatusLabel/types.d.ts +6 -0
- package/build/types/components/PasswordCriteria/hooks/usePasswordCriteria.d.ts +13 -0
- package/build/types/components/PasswordCriteria/index.d.ts +3 -0
- package/build/types/components/PasswordCriteria/index.native.d.ts +3 -0
- package/build/types/components/PasswordCriteria/types.d.ts +15 -0
- package/build/types/components/ScreenLayout/index.d.ts +3 -0
- package/build/types/components/ScreenLayout/index.native.d.ts +3 -0
- package/build/types/components/ScreenLayout/types.d.ts +12 -0
- package/build/types/components/SupportDetails/index.d.ts +2 -0
- package/build/types/components/SupportDetails/index.native.d.ts +2 -0
- package/build/types/components/VerifyOTP/index.d.ts +3 -0
- package/build/types/components/VerifyOTP/index.native.d.ts +3 -0
- package/build/types/components/VerifyOTP/types.d.ts +10 -0
- package/build/types/constants/cdn-url/index.d.ts +1 -0
- package/build/types/constants/cdn-url/index.native.d.ts +3 -0
- package/build/types/contexts/AuthContext.d.ts +36 -0
- package/build/types/contexts/type.d.ts +59 -0
- package/build/types/helpers/Network.d.ts +5 -0
- package/build/types/helpers/Validation.d.ts +2 -0
- package/build/types/helpers/show-message/index.d.ts +3 -0
- package/build/types/helpers/show-message/index.native.d.ts +3 -0
- package/build/types/helpers/show-message/types.d.ts +2 -0
- package/build/types/helpers/types.d.ts +13 -0
- package/build/types/hooks/internal/useAuthPackageContext.d.ts +1 -0
- package/build/types/hooks/internal/useTimer.d.ts +3 -0
- package/build/types/hooks/useAuthContext.d.ts +2 -0
- package/build/types/hooks/useRequest.d.ts +5 -0
- package/build/types/index.d.ts +9 -0
- package/build/types/navigator/index.d.ts +2 -0
- package/build/types/navigator/index.native.d.ts +36 -0
- package/build/types/screens/CountryCode/components/CountryCodeDropdown/index.d.ts +3 -0
- package/build/types/screens/CountryCode/components/CountryCodeDropdown/index.native.d.ts +2 -0
- package/build/types/screens/CountryCode/components/CountryCodeDropdown/types.d.ts +17 -0
- package/build/types/screens/CountryCode/hooks/internal/useCountryCode.d.ts +12 -0
- package/build/types/screens/CountryCode/index.d.ts +2 -0
- package/build/types/screens/CountryCode/index.native.d.ts +2 -0
- package/build/types/screens/CountryCode/type.d.ts +11 -0
- package/build/types/screens/CreatePassword/hooks/internal/useCreatePassword.d.ts +26 -0
- package/build/types/screens/CreatePassword/index.d.ts +3 -0
- package/build/types/screens/CreatePassword/index.native.d.ts +4 -0
- package/build/types/screens/CreatePassword/type.d.ts +43 -0
- package/build/types/screens/EnterEmail/hooks/internal/useEnterEmail.d.ts +24 -0
- package/build/types/screens/EnterEmail/index.d.ts +7 -0
- package/build/types/screens/EnterEmail/index.native.d.ts +4 -0
- package/build/types/screens/EnterPassword/hooks/internal/useEnterPassword.d.ts +20 -0
- package/build/types/screens/EnterPassword/index.d.ts +3 -0
- package/build/types/screens/EnterPassword/index.native.d.ts +4 -0
- package/build/types/screens/EnterPassword/types.d.ts +5 -0
- package/build/types/screens/Login/components/LoginWebComponent/index.d.ts +2 -0
- package/build/types/screens/Login/components/LoginWebComponent/index.native.d.ts +2 -0
- package/build/types/screens/Login/index.d.ts +2 -0
- package/build/types/screens/Login/index.native.d.ts +2 -0
- package/build/types/screens/SignUp/components/SignUpForm/index.d.ts +3 -0
- package/build/types/screens/SignUp/components/SignUpForm/index.native.d.ts +2 -0
- package/build/types/screens/SignUp/components/SignUpForm/type.d.ts +9 -0
- package/build/types/screens/SignUp/components/SignUpWebComponent/index.d.ts +2 -0
- package/build/types/screens/SignUp/components/SignUpWebComponent/index.native.d.ts +2 -0
- package/build/types/screens/SignUp/components/SignUpWebComponent/types.d.ts +24 -0
- package/build/types/screens/SignUp/hooks/internal/useSignUp.d.ts +50 -0
- package/build/types/screens/SignUp/index.d.ts +2 -0
- package/build/types/screens/SignUp/index.native.d.ts +4 -0
- package/build/types/screens/SignUp/types.d.ts +18 -0
- package/build/types/screens/UserConsent/hooks/internal/useConsent.d.ts +10 -0
- package/build/types/screens/UserConsent/index.d.ts +3 -0
- package/build/types/screens/UserConsent/index.native.d.ts +4 -0
- package/build/types/screens/UserConsent/types.d.ts +27 -0
- package/build/types/screens/VerifyEmail/hooks/internal/useVerifyEmail.d.ts +19 -0
- package/build/types/screens/VerifyEmail/index.d.ts +3 -0
- package/build/types/screens/VerifyEmail/index.native.d.ts +4 -0
- package/build/types/screens/VerifyEmail/types.d.ts +8 -0
- package/build/types/screens/VerifyMobile/hooks/internal/useVerifyMobile.d.ts +14 -0
- package/build/types/screens/VerifyMobile/index.d.ts +3 -0
- package/build/types/screens/VerifyMobile/index.native.d.ts +4 -0
- package/build/types/screens/VerifyMobile/types.d.ts +5 -0
- package/build/types/screens/Welcome/hooks/internal/useWelcome.d.ts +14 -0
- package/build/types/screens/Welcome/index.d.ts +4 -0
- package/build/types/screens/Welcome/index.native.d.ts +4 -0
- package/build/types/types/types.d.ts +90 -0
- package/get-metro-config.js +40 -0
- package/get-next-config.js +26 -0
- package/package.json +86 -38
- package/dist/index.esm.js +0 -2028
- package/dist/index.umd.js +0 -70
- package/dist/vite.svg +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Dimensions, Platform, ScrollView, Text, TouchableOpacity, View } from "react-native";
|
|
4
|
+
import { Layout } from "@ui-kitten/components";
|
|
5
|
+
import { Header, Colors, CustomKeyboardAvoidingView } from "@truworth/twc-rn-common";
|
|
6
|
+
import { ScreenLayout } from "../ScreenLayout";
|
|
7
|
+
import { OTPStatusLabel } from "../OTPStatusLabel/index.native";
|
|
8
|
+
import OTPInputView from "@twotalltotems/react-native-otp-input";
|
|
9
|
+
const EmailOTPVerify = ({ status, validateOTP, resendOTP, resendOTPCounter, email }) => {
|
|
10
|
+
const [otp, setOTP] = useState('');
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (otp && otp.length === 6) {
|
|
13
|
+
validateOTP?.(otp);
|
|
14
|
+
}
|
|
15
|
+
}, [otp]);
|
|
16
|
+
return (_jsxs(Layout, { style: { flex: 1, backgroundColor: '#fff' }, children: [_jsx(Header, {}), _jsxs(CustomKeyboardAvoidingView, { behavior: Platform.OS === 'ios' ? 'padding' : undefined, keyboardVerticalOffset: Platform.OS === 'ios' ? 100 : 0, children: [_jsx(ScrollView, { showsVerticalScrollIndicator: false, children: _jsxs(ScreenLayout, { hideHeader: true, title: _jsxs(_Fragment, { children: ["OTP sent to ", '\n', _jsx(Text, { style: { fontSize: 20 }, children: email })] }), children: [_jsx(View, { style: { justifyContent: 'center', flexDirection: 'row', marginBottom: 30, position: 'relative' }, children: _jsx(OTPInputView, { pinCount: 6, autoFocusOnLoad: false, codeInputFieldStyle: {
|
|
17
|
+
fontSize: 20, color: 'black',
|
|
18
|
+
height: 45, width: 30,
|
|
19
|
+
borderWidth: 0, borderBottomWidth: 1,
|
|
20
|
+
}, codeInputHighlightStyle: { borderColor: '#03DAC6' }, style: {
|
|
21
|
+
height: 50,
|
|
22
|
+
width: Dimensions.get('window').width - 100,
|
|
23
|
+
}, onCodeFilled: code => setOTP(code) }) }), resendOTPCounter < 3 &&
|
|
24
|
+
_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center' }, children: [_jsxs(Text, { style: { fontSize: 14, fontWeight: '500', color: Colors.gray.gray_400, lineHeight: 20 }, children: ["Did not receive OTP?", ' '] }), _jsx(TouchableOpacity, { activeOpacity: 0.8, onPress: resendOTP, children: _jsx(Text, { style: { fontSize: 14, fontWeight: '500', color: '#2cbaa4', lineHeight: 20 }, children: "Re-send OTP" }) })] })] }) }), _jsx(View, { style: { alignSelf: 'flex-end', width: '100%' }, children: _jsx(OTPStatusLabel, { status: status }) })] })] }));
|
|
25
|
+
};
|
|
26
|
+
export { EmailOTPVerify };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
const IonIcon = ({ name, size, className, ...props }) => {
|
|
3
|
+
const customElementProps = {
|
|
4
|
+
...props,
|
|
5
|
+
name,
|
|
6
|
+
size,
|
|
7
|
+
class: className // For the custom element
|
|
8
|
+
};
|
|
9
|
+
return _jsx("ion-icon", { ...customElementProps });
|
|
10
|
+
};
|
|
11
|
+
export { IonIcon };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
const OTPStatusLabel = () => {
|
|
3
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
4
|
+
if (typeof window !== 'undefined') {
|
|
5
|
+
console.warn("[@truworth/twc-auth] We use only OTPStatusLabel for the app");
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
return null;
|
|
9
|
+
};
|
|
10
|
+
export { OTPStatusLabel };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { isIphoneX } from "@truworth/twc-rn-common";
|
|
3
|
+
import { ActivityIndicator, Platform, Text, View } from "react-native";
|
|
4
|
+
import LinearGradient from "react-native-linear-gradient";
|
|
5
|
+
import OkayIcon from '../../../assets/okay_icon.svg';
|
|
6
|
+
import CrossIcon from '../../../assets/cross_icon.svg';
|
|
7
|
+
const OTPStatusLabel = ({ status, timer }) => {
|
|
8
|
+
switch (status) {
|
|
9
|
+
case 'timer':
|
|
10
|
+
return (_jsx(View, { style: { height: isIphoneX() ? 80 : 70, width: '100%', justifyContent: 'center', marginBottom: Platform.OS === 'ios' ? 14 : 0 }, children: _jsx(LinearGradient, { colors: ['#b0bbbd', '#b0bbbd'], style: { flex: 1, justifyContent: 'center', alignItems: 'center' }, start: { x: 0, y: 0 }, end: { x: 1, y: 0 }, children: _jsx(Text, { style: { textAlign: 'center', fontSize: 15, color: '#FFFFFF', textTransform: 'uppercase' }, children: timer && timer > 0 ? `${timer} seconds` : 'OTP expired' }) }) }));
|
|
11
|
+
case 'valid':
|
|
12
|
+
return (_jsx(View, { style: { height: isIphoneX() ? 80 : 70, width: '100%', justifyContent: 'center', marginBottom: Platform.OS === 'ios' ? 14 : 0 }, children: _jsx(LinearGradient, { colors: ['#44cfb9', '#1EC2C9'], style: { flex: 1, alignItems: 'center', justifyContent: 'center' }, start: { x: 0, y: 0 }, end: { x: 1, y: 0 }, children: _jsx(Text, { style: { textAlign: 'center', fontSize: 15, color: '#fff', textTransform: 'uppercase' }, children: _jsx(OkayIcon, {}) }) }) }));
|
|
13
|
+
case 'invalid':
|
|
14
|
+
return (_jsx(View, { style: { height: isIphoneX() ? 80 : 70, width: '100%', justifyContent: 'center', marginBottom: Platform.OS === 'ios' ? 14 : 0 }, children: _jsx(LinearGradient, { colors: ['#F3698B', '#F18A8A'], style: { flex: 1, alignItems: 'center', justifyContent: 'center' }, start: { x: 0, y: 0 }, end: { x: 1, y: 0 }, children: _jsx(Text, { style: { textAlign: 'center', fontSize: 15, color: '#fff', textTransform: 'uppercase' }, children: _jsx(CrossIcon, {}) }) }) }));
|
|
15
|
+
case 'loading':
|
|
16
|
+
return (_jsx(View, { style: { height: isIphoneX() ? 80 : 70, width: '100%', justifyContent: 'center', marginBottom: Platform.OS === 'ios' ? 14 : 0 }, children: _jsx(LinearGradient, { colors: ['#b0bbbd', '#b0bbbd'], style: { flex: 1, alignItems: 'center', justifyContent: 'center' }, start: { x: 0, y: 0 }, end: { x: 1, y: 0 }, children: _jsx(View, { style: { alignItems: 'center' }, children: _jsx(ActivityIndicator, { color: 'black' }) }) }) }));
|
|
17
|
+
default:
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
export { OTPStatusLabel };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { axiosClient } from "../../../api/axiosClient";
|
|
3
|
+
const defaultPolicy = {
|
|
4
|
+
minLength: 6,
|
|
5
|
+
maxLength: 30,
|
|
6
|
+
numbers: true,
|
|
7
|
+
uppercase: true,
|
|
8
|
+
lowercase: true,
|
|
9
|
+
specialCharacters: true,
|
|
10
|
+
};
|
|
11
|
+
const usePasswordCriteria = ({ email, password, onCriteriaChange, onMaxLengthChange }) => {
|
|
12
|
+
const { maxLength: defaultMaxLength, ...restDefaultPolicy } = defaultPolicy;
|
|
13
|
+
const [loading, setLoading] = useState(false);
|
|
14
|
+
const [passwordPolicy, setPasswordPolicy] = useState(restDefaultPolicy);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!email) {
|
|
17
|
+
setPasswordPolicy(restDefaultPolicy);
|
|
18
|
+
onMaxLengthChange(defaultMaxLength);
|
|
19
|
+
setLoading(false);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
return getPasswordPolicy();
|
|
23
|
+
}, [email]);
|
|
24
|
+
const getPasswordPolicy = () => {
|
|
25
|
+
let isActive = true;
|
|
26
|
+
if (email) {
|
|
27
|
+
setPasswordPolicy(restDefaultPolicy);
|
|
28
|
+
onMaxLengthChange(defaultMaxLength);
|
|
29
|
+
setLoading(true);
|
|
30
|
+
axiosClient({
|
|
31
|
+
url: `/auth/password-policy?email=${encodeURIComponent(email)}`,
|
|
32
|
+
method: 'GET',
|
|
33
|
+
}).then(({ data }) => {
|
|
34
|
+
if (!isActive)
|
|
35
|
+
return;
|
|
36
|
+
const { maxLength, ...rest } = (data || {});
|
|
37
|
+
// Apply server-provided policy when present, falling back to defaults
|
|
38
|
+
setPasswordPolicy({
|
|
39
|
+
minLength: typeof rest.minLength === 'number' ? rest.minLength : restDefaultPolicy.minLength,
|
|
40
|
+
numbers: typeof rest.numbers === 'boolean' ? rest.numbers : restDefaultPolicy.numbers,
|
|
41
|
+
uppercase: typeof rest.uppercase === 'boolean' ? rest.uppercase : restDefaultPolicy.uppercase,
|
|
42
|
+
lowercase: typeof rest.lowercase === 'boolean' ? rest.lowercase : restDefaultPolicy.lowercase,
|
|
43
|
+
specialCharacters: typeof rest.specialCharacters === 'boolean' ? rest.specialCharacters : restDefaultPolicy.specialCharacters,
|
|
44
|
+
});
|
|
45
|
+
onMaxLengthChange(typeof maxLength === 'number' ? maxLength : defaultMaxLength);
|
|
46
|
+
}).catch(err => {
|
|
47
|
+
if (!isActive)
|
|
48
|
+
return;
|
|
49
|
+
console.warn('password-policy fetch failed', err);
|
|
50
|
+
setPasswordPolicy(restDefaultPolicy);
|
|
51
|
+
onMaxLengthChange(defaultMaxLength);
|
|
52
|
+
}).finally(() => isActive && setLoading(false));
|
|
53
|
+
}
|
|
54
|
+
return () => { isActive = false; };
|
|
55
|
+
};
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
onCriteriaChange({
|
|
58
|
+
minLength: password.length >= passwordPolicy.minLength,
|
|
59
|
+
specialCharacters: passwordPolicy.specialCharacters ? /[!@#$%^&*(),.?":{}|<>]/.test(password) : true,
|
|
60
|
+
numbers: passwordPolicy.numbers ? /\d/.test(password) : true,
|
|
61
|
+
uppercase: passwordPolicy.uppercase ? /[A-Z]/.test(password) : true,
|
|
62
|
+
lowercase: passwordPolicy.lowercase ? /[a-z]/.test(password) : true,
|
|
63
|
+
});
|
|
64
|
+
}, [password, passwordPolicy]);
|
|
65
|
+
const renderLabel = (criteria) => {
|
|
66
|
+
switch (criteria) {
|
|
67
|
+
case 'minLength': return `min ${passwordPolicy.minLength} characters`;
|
|
68
|
+
case 'specialCharacters': return 'special character';
|
|
69
|
+
default: return criteria;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
loading,
|
|
74
|
+
passwordPolicy,
|
|
75
|
+
renderLabel,
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
export { usePasswordCriteria };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useId, useMemo } from "react";
|
|
3
|
+
import { usePasswordCriteria } from "./hooks/usePasswordCriteria";
|
|
4
|
+
import { Check, X } from "lucide-react";
|
|
5
|
+
const PasswordCriteria = ({ email, password, criteria, onCriteriaChange, onMaxLengthChange }) => {
|
|
6
|
+
const id = useId();
|
|
7
|
+
const { passwordPolicy, renderLabel, } = usePasswordCriteria({ email, password, onCriteriaChange, onMaxLengthChange });
|
|
8
|
+
const activeRequirementKeys = useMemo(() => {
|
|
9
|
+
// Include minLength always; include other flags only if enabled by policy
|
|
10
|
+
return Object.keys(passwordPolicy).filter((key) => {
|
|
11
|
+
if (key === "minLength")
|
|
12
|
+
return true;
|
|
13
|
+
// @ts-ignore boolean flags present on policy
|
|
14
|
+
return Boolean(passwordPolicy[key]);
|
|
15
|
+
});
|
|
16
|
+
}, [passwordPolicy]);
|
|
17
|
+
const strengthScore = useMemo(() => {
|
|
18
|
+
return activeRequirementKeys.reduce((acc, key) => acc + (criteria[key] ? 1 : 0), 0);
|
|
19
|
+
}, [activeRequirementKeys, criteria]);
|
|
20
|
+
const maxScore = activeRequirementKeys.length || 1;
|
|
21
|
+
const getStrengthColor = (score) => {
|
|
22
|
+
const ratio = score / maxScore;
|
|
23
|
+
if (score === 0)
|
|
24
|
+
return "bg-border";
|
|
25
|
+
if (ratio < 0.4)
|
|
26
|
+
return "bg-red-500";
|
|
27
|
+
if (ratio < 0.7)
|
|
28
|
+
return "bg-orange-500";
|
|
29
|
+
if (ratio < 1)
|
|
30
|
+
return "bg-amber-500";
|
|
31
|
+
return "bg-emerald-500";
|
|
32
|
+
};
|
|
33
|
+
const getStrengthText = (score) => {
|
|
34
|
+
if (score === 0)
|
|
35
|
+
return "Enter a password";
|
|
36
|
+
const ratio = score / maxScore;
|
|
37
|
+
if (ratio < 0.4)
|
|
38
|
+
return "Weak password";
|
|
39
|
+
if (ratio < 0.8)
|
|
40
|
+
return "Medium password";
|
|
41
|
+
return "Strong password";
|
|
42
|
+
};
|
|
43
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "h-1 w-full overflow-hidden rounded-full bg-border", role: "progressbar", "aria-valuenow": strengthScore, "aria-valuemin": 0, "aria-valuemax": maxScore, "aria-label": "Password strength", children: _jsx("div", { className: `h-full ${getStrengthColor(strengthScore)} transition-all duration-500 ease-out`, style: { width: `${(strengthScore / maxScore) * 100}%` } }) }), _jsxs("p", { id: `${id}-description`, className: "mt-2 text-sm font-medium text-foreground", children: [getStrengthText(strengthScore), ". Must contain:"] }), _jsx("ul", { className: "mt-2 space-y-1.5", "aria-label": "Password requirements", children: activeRequirementKeys.map((req, index) => (_jsxs("li", { className: "flex items-center gap-2", children: [criteria[req]
|
|
44
|
+
? _jsx(Check, { size: 16, className: "text-emerald-500", "aria-hidden": "true" })
|
|
45
|
+
: _jsx(X, { size: 16, className: "text-muted-foreground/80", "aria-hidden": "true" }), _jsxs("span", { className: `text-xs ${criteria[req] ? "text-emerald-600" : "text-muted-foreground"}`, children: [renderLabel(req), _jsx("span", { className: "sr-only", children: criteria[req] ? " - Requirement met" : " - Requirement not met" })] })] }, index))) })] }));
|
|
46
|
+
};
|
|
47
|
+
export { PasswordCriteria };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { LoadingPlaceholder, Colors } from '@truworth/twc-rn-common';
|
|
3
|
+
import { Text, View } from 'react-native';
|
|
4
|
+
import { usePasswordCriteria } from './hooks/usePasswordCriteria';
|
|
5
|
+
const { gray, utility } = Colors;
|
|
6
|
+
const PasswordCriteria = ({ email, password, criteria, onCriteriaChange, onMaxLengthChange }) => {
|
|
7
|
+
const { passwordPolicy, loading, renderLabel, } = usePasswordCriteria({ email, password, onCriteriaChange, onMaxLengthChange });
|
|
8
|
+
const getCriteriaColor = (isValid) => (isValid ? utility.success_main : gray.gray_600);
|
|
9
|
+
const getCriteriaBackground = (isValid) => (isValid ? utility.success_bg : gray.gray_100);
|
|
10
|
+
return (_jsx(View, { style: { flexDirection: 'row', alignItems: 'center', flexWrap: 'wrap', alignContent: 'space-between', marginTop: 8 }, children: Object.keys(passwordPolicy).map((item, index) => (loading
|
|
11
|
+
? _jsx(LoadingPlaceholder, { height: 24, width: renderLabel(item).length * 8, borderRadius: 12, containerStyle: { marginRight: 8, marginTop: 8 } }, index)
|
|
12
|
+
:
|
|
13
|
+
_jsx(View, { style: {
|
|
14
|
+
marginRight: 8, marginTop: 8, borderRadius: 32,
|
|
15
|
+
paddingVertical: 4, paddingHorizontal: 12,
|
|
16
|
+
backgroundColor: getCriteriaBackground(criteria[item]),
|
|
17
|
+
}, children: _jsx(Text, { style: {
|
|
18
|
+
fontSize: 12, fontWeight: '500',
|
|
19
|
+
color: getCriteriaColor(criteria[item]),
|
|
20
|
+
}, children: renderLabel(item) }) }, index))) }));
|
|
21
|
+
};
|
|
22
|
+
export { PasswordCriteria };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Typography } from "@truworth/twc-web-design";
|
|
3
|
+
import { AdvancedTransitionWrapper } from "../AdvancedTransitionWrapper";
|
|
4
|
+
import { ArrowLeft } from "lucide-react";
|
|
5
|
+
const ScreenLayout = ({ children, title, subTitle, buttonProps, onPressBack }) => {
|
|
6
|
+
return (_jsxs(AdvancedTransitionWrapper, { type: 'slide', duration: 0.5, children: [onPressBack &&
|
|
7
|
+
_jsx(Button, { label: "Back", size: "large", variant: "link", leftIcon: _jsx(ArrowLeft, {}), className: "p-0 h-auto", onClick: onPressBack }), Boolean(title) &&
|
|
8
|
+
_jsx(Typography, { type: 'heading', size: 'h5', className: 'mb-2 mt-6', children: title }), Boolean(subTitle) &&
|
|
9
|
+
_jsx(Typography, { type: 'body', size: 'large', className: "md:mb-8 mb-6 text-gray-400", children: subTitle }), children, Boolean(buttonProps) &&
|
|
10
|
+
_jsx(Button, { label: "Continue", isFullWidth: true, variant: 'primary', className: "mt-3", ...buttonProps })] }));
|
|
11
|
+
};
|
|
12
|
+
export { ScreenLayout };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { View, Text } from 'react-native';
|
|
3
|
+
import { Colors, Header, RoundedButton } from '@truworth/twc-rn-common';
|
|
4
|
+
const { gray } = Colors;
|
|
5
|
+
const ScreenLayout = ({ children, title, subTitle, hideHeader, buttonProps, containerStyle, accessoryRight }) => {
|
|
6
|
+
return (_jsxs(_Fragment, { children: [!hideHeader &&
|
|
7
|
+
_jsx(Header, { accessoryRight: accessoryRight }), _jsxs(View, { style: [{ paddingVertical: 32, paddingHorizontal: 16 }, containerStyle], children: [Boolean(title) &&
|
|
8
|
+
_jsx(Text, { textBreakStrategy: 'simple', style: {
|
|
9
|
+
fontSize: 20, fontWeight: '600', color: gray.gray_900,
|
|
10
|
+
lineHeight: 32, marginBottom: 32,
|
|
11
|
+
}, children: title }), Boolean(subTitle) &&
|
|
12
|
+
_jsx(Text, { textBreakStrategy: 'simple', style: {
|
|
13
|
+
fontSize: 14, fontWeight: '500', color: gray.gray_400,
|
|
14
|
+
lineHeight: 20, marginTop: -24, marginBottom: 32,
|
|
15
|
+
}, children: subTitle }), children, Boolean(buttonProps) &&
|
|
16
|
+
_jsx(RoundedButton, { containerStyle: { marginTop: 32 }, type: buttonProps?.type ?? 'secondary', size: buttonProps?.size ?? 'large', ...buttonProps })] })] }));
|
|
17
|
+
};
|
|
18
|
+
export { ScreenLayout };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CircleHelpIcon } from 'lucide-react';
|
|
3
|
+
import { Flex, Typography } from "@truworth/twc-web-design";
|
|
4
|
+
import { useAuthPackageContext } from "../../hooks/internal/useAuthPackageContext";
|
|
5
|
+
const SupportDetails = () => {
|
|
6
|
+
const { appConfig } = useAuthPackageContext();
|
|
7
|
+
return (_jsxs(Flex, { padding: "sm", className: 'rounded-lg bg-gray-100 md:mt-8 mt-6 gap-3', children: [_jsx(CircleHelpIcon, { size: 20, className: "min-w-5 text-primary" }), _jsxs(Typography, { type: "body", size: "small", children: ["For any customer support\u2013related queries, please write to us at", _jsx("a", { href: `mailto:${appConfig.supportEmail}`, className: "text-primary block", children: _jsx("u", { children: appConfig.supportEmail }) })] })] }));
|
|
8
|
+
};
|
|
9
|
+
export { SupportDetails };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { Button, Flex, OTPInput, Typography } from "@truworth/twc-web-design";
|
|
4
|
+
const OTPVerify = ({ validateOTP, timer, resendOTP, phone, status, resendTextClassName }) => {
|
|
5
|
+
const [otp, setOtp] = useState('');
|
|
6
|
+
const [otpError, setOtpError] = useState(false);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (status === 'invalid') {
|
|
9
|
+
setOtpError(true);
|
|
10
|
+
setOtp('');
|
|
11
|
+
}
|
|
12
|
+
}, [status]);
|
|
13
|
+
const defaultPhoneDisplayText = (_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' })] }));
|
|
14
|
+
return (_jsxs(_Fragment, { children: [defaultPhoneDisplayText, _jsx(OTPInput, { value: otp, onChange: (code) => {
|
|
15
|
+
setOtp(code);
|
|
16
|
+
setOtpError(false);
|
|
17
|
+
}, 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." }), (timer <= 0) ?
|
|
19
|
+
_jsxs(Flex, { justify: 'between', align: 'center', className: 'mt-4', children: [_jsx(Typography, { type: 'utility', size: 'medium', className: resendTextClassName, children: "Didn't receive OTP?" }), _jsx(Button, { label: 'Resend Code', size: 'small', variant: 'link', onClick: () => resendOTP() })] })
|
|
20
|
+
:
|
|
21
|
+
_jsxs(Typography, { type: 'utility', size: 'medium', className: `mt-3 ${resendTextClassName}`, children: ["Resend Code in ", timer > 0 ? `${timer} seconds` : 'OTP expired'] }), _jsx(Button, { label: "Continue", isFullWidth: true, onClick: () => validateOTP?.(otp), disabled: otp ? otp?.length < 6 : true, className: "mt-6" })] }));
|
|
22
|
+
};
|
|
23
|
+
export { OTPVerify };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { Colors, CustomKeyboardAvoidingView, Header } from '@truworth/twc-rn-common';
|
|
4
|
+
import { Layout } from '@ui-kitten/components';
|
|
5
|
+
import { Dimensions, Platform, ScrollView, Text, TouchableOpacity, View, } from 'react-native';
|
|
6
|
+
import { useAuthPackageContext } from '../../hooks/internal/useAuthPackageContext';
|
|
7
|
+
import { OTPStatusLabel } from '../OTPStatusLabel/index.native';
|
|
8
|
+
import OTPInputView from '@twotalltotems/react-native-otp-input';
|
|
9
|
+
const { gray } = Colors;
|
|
10
|
+
const OTPVerify = ({ validateOTP, timer, status, resendOTP, phone }) => {
|
|
11
|
+
const [otp, setOTP] = useState('');
|
|
12
|
+
const { otpValue } = useAuthPackageContext();
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (otp?.length === 6) {
|
|
15
|
+
validateOTP(otp);
|
|
16
|
+
}
|
|
17
|
+
}, [otp]);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (otpValue && otpValue.length == 6) {
|
|
20
|
+
setOTP(otpValue);
|
|
21
|
+
}
|
|
22
|
+
}, [otpValue]);
|
|
23
|
+
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
|
+
fontSize: 20, fontWeight: '600', color: gray.gray_900,
|
|
25
|
+
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 => setOTP(text), codeInputFieldStyle: {
|
|
27
|
+
fontSize: 20, color: 'black', width: 30,
|
|
28
|
+
height: 45, borderWidth: 0, borderBottomWidth: 1,
|
|
29
|
+
}, codeInputHighlightStyle: { borderColor: '#03DAC6' }, style: {
|
|
30
|
+
height: 50,
|
|
31
|
+
width: Dimensions.get('window').width - 100,
|
|
32
|
+
}, code: otp ?? '', onCodeFilled: code => setOTP(code) }) }), timer <= 0 &&
|
|
33
|
+
_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center' }, children: [_jsxs(Text, { style: { fontSize: 12, color: '#000', fontWeight: '400', opacity: 0.5 }, children: ["Did not receive OTP?", ' '] }), _jsx(TouchableOpacity, { disabled: timer > 0, onPress: () => {
|
|
34
|
+
setOTP('');
|
|
35
|
+
resendOTP();
|
|
36
|
+
}, 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
|
+
};
|
|
38
|
+
export { OTPVerify };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MEMBER_IMAGES_URL } from "@truworth/twc-web-common";
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { useEffect, useState, useMemo, useCallback } from 'react';
|
|
3
|
+
import { MEMBER_IMAGES_URL } from '../constants/cdn-url';
|
|
4
|
+
import { createHttpClient } from '../helpers/Network';
|
|
5
|
+
/**
|
|
6
|
+
* Public Auth Authentication Context
|
|
7
|
+
*
|
|
8
|
+
* Exposed to consumers of the Auth package.
|
|
9
|
+
* Provides access to user profile, client info, logout, and helper utilities.
|
|
10
|
+
*/
|
|
11
|
+
const AuthContext = React.createContext(null);
|
|
12
|
+
/**
|
|
13
|
+
* Package Auth Authentication Context
|
|
14
|
+
*
|
|
15
|
+
* Not meant for public use. Contains lower-level auth state such as
|
|
16
|
+
* token, login/logout functions, and refresh session.
|
|
17
|
+
*/
|
|
18
|
+
const AuthPackageContext = React.createContext(null);
|
|
19
|
+
/**
|
|
20
|
+
* AuthProvider
|
|
21
|
+
*
|
|
22
|
+
* Provides authentication state and actions to children.
|
|
23
|
+
* Wraps both AuthContext (public) and AuthPackageContext (internal).
|
|
24
|
+
*
|
|
25
|
+
* @param children - React children to be rendered inside the provider
|
|
26
|
+
* @param LogoComponent - Optional component for branding/logo in auth flows
|
|
27
|
+
* @param session - Initial session containing token & sessionTimeout (if available)
|
|
28
|
+
* @param supportEmail - Optional support email for auth flows
|
|
29
|
+
* @param appConfig - Optional app config for auth flows
|
|
30
|
+
* @param onLogin - Optional callback after successful login
|
|
31
|
+
* @param onLogout - Optional callback after successful logout
|
|
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
|
+
* @param onRefreshSession - Optional handler for refreshing user session
|
|
34
|
+
*/
|
|
35
|
+
const AuthProvider = ({ children, LogoComponent, session, appConfig, onLogin, onLogout, onLaunchAuthSession, onRefreshSession }) => {
|
|
36
|
+
const [isLoadingProfile, setIsLoadingProfile] = useState(false);
|
|
37
|
+
const [profile, setProfile] = useState(null);
|
|
38
|
+
const [client, setClient] = useState(null);
|
|
39
|
+
const [registrationMethod, setRegistrationMethod] = useState(null);
|
|
40
|
+
const [token, setToken] = useState('');
|
|
41
|
+
const [otpValue, setOtpValue] = useState('');
|
|
42
|
+
const { request } = useMemo(() => createHttpClient({
|
|
43
|
+
token,
|
|
44
|
+
onRefreshSession: onRefreshSession
|
|
45
|
+
? (t) => onRefreshSession({ token: t })
|
|
46
|
+
: undefined,
|
|
47
|
+
onLogout: async () => {
|
|
48
|
+
onLogout?.();
|
|
49
|
+
clearSession();
|
|
50
|
+
},
|
|
51
|
+
}), [token, onRefreshSession, onLogout]);
|
|
52
|
+
/**
|
|
53
|
+
* Sync local token state with session prop
|
|
54
|
+
*/
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (session?.token) {
|
|
57
|
+
setToken(session?.token);
|
|
58
|
+
}
|
|
59
|
+
}, [session?.token]);
|
|
60
|
+
/**
|
|
61
|
+
* fetch user profile if not already loaded.
|
|
62
|
+
*/
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (token && !profile) {
|
|
65
|
+
getUserProfile();
|
|
66
|
+
}
|
|
67
|
+
}, [token, profile]);
|
|
68
|
+
/**
|
|
69
|
+
* Logout user and clear authentication state.
|
|
70
|
+
* Falls back to default /auth/logout request
|
|
71
|
+
*
|
|
72
|
+
* @returns Promise<any> Resolves when logout is completed
|
|
73
|
+
*/
|
|
74
|
+
const logout = useCallback(() => {
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
request({
|
|
77
|
+
url: '/auth/logout',
|
|
78
|
+
method: 'POST',
|
|
79
|
+
}).then((res) => {
|
|
80
|
+
clearSession();
|
|
81
|
+
onLogout?.();
|
|
82
|
+
resolve(res);
|
|
83
|
+
}).catch((err) => {
|
|
84
|
+
reject(err);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}, [request, onLogout]);
|
|
88
|
+
/**
|
|
89
|
+
* Fetch and update user profile and client data.
|
|
90
|
+
*
|
|
91
|
+
* @param token - Optional token for API request
|
|
92
|
+
* @returns Promise<any> Resolves with profile/config response
|
|
93
|
+
*/
|
|
94
|
+
const getUserProfile = useCallback(() => {
|
|
95
|
+
if (isLoadingProfile)
|
|
96
|
+
return Promise.resolve(); // Prevent concurrent calls
|
|
97
|
+
setIsLoadingProfile(true);
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
request({
|
|
100
|
+
url: '/auth/config',
|
|
101
|
+
method: 'GET',
|
|
102
|
+
}).then((res) => {
|
|
103
|
+
const data = res?.data;
|
|
104
|
+
if (!data?.profile) {
|
|
105
|
+
console.warn('No profile data received from /auth/config');
|
|
106
|
+
return resolve(data);
|
|
107
|
+
}
|
|
108
|
+
const formatted = formatUserData(data);
|
|
109
|
+
setProfile(formatted.profile);
|
|
110
|
+
setClient(formatted.client);
|
|
111
|
+
resolve(data);
|
|
112
|
+
}).catch((err) => {
|
|
113
|
+
reject(err);
|
|
114
|
+
});
|
|
115
|
+
}).finally(() => {
|
|
116
|
+
setIsLoadingProfile(false);
|
|
117
|
+
});
|
|
118
|
+
}, [request, isLoadingProfile]);
|
|
119
|
+
const clearSession = useCallback(() => {
|
|
120
|
+
setToken('');
|
|
121
|
+
setClient(null);
|
|
122
|
+
setProfile(null);
|
|
123
|
+
setRegistrationMethod(null);
|
|
124
|
+
}, []);
|
|
125
|
+
/**
|
|
126
|
+
* Helper to normalize and format user profile data
|
|
127
|
+
* similar to legacy implementation.
|
|
128
|
+
*
|
|
129
|
+
* @param data - AuthConfigResponse from API
|
|
130
|
+
* @returns Object containing client and profile data
|
|
131
|
+
*/
|
|
132
|
+
const formatUserData = useCallback((data) => {
|
|
133
|
+
const clientData = {
|
|
134
|
+
name: data.profile.clientName,
|
|
135
|
+
clientId: data.profile.clientId,
|
|
136
|
+
image: data.profile.clientImage,
|
|
137
|
+
partner: data.profile.partner,
|
|
138
|
+
directClient: data.profile.directClient
|
|
139
|
+
};
|
|
140
|
+
const profileData = {
|
|
141
|
+
...data.profile,
|
|
142
|
+
firstName: data.profile.firstName,
|
|
143
|
+
lastName: data.profile.lastName,
|
|
144
|
+
image: data.profile?.image ? `${MEMBER_IMAGES_URL}${data.profile.image}` : '',
|
|
145
|
+
};
|
|
146
|
+
return { client: clientData, profile: profileData };
|
|
147
|
+
}, []);
|
|
148
|
+
const handleOtpReceived = (otp) => {
|
|
149
|
+
setOtpValue(otp);
|
|
150
|
+
setTimeout(() => setOtpValue(''), 0);
|
|
151
|
+
};
|
|
152
|
+
const AuthContextValues = {
|
|
153
|
+
token,
|
|
154
|
+
profile,
|
|
155
|
+
client,
|
|
156
|
+
isLoadingProfile,
|
|
157
|
+
logout,
|
|
158
|
+
onLaunchAuthSession,
|
|
159
|
+
getUserProfile,
|
|
160
|
+
onOtpReceived: handleOtpReceived,
|
|
161
|
+
};
|
|
162
|
+
const appConfigValue = {
|
|
163
|
+
appName: appConfig?.appName ?? 'The Wellness Corner',
|
|
164
|
+
supportEmail: appConfig?.supportEmail ?? 'support@thewellnesscorner.com',
|
|
165
|
+
privacyPolicyUrl: appConfig?.privacyPolicyUrl ?? 'https://thewellnesscorner.com/privacy-policy',
|
|
166
|
+
termsAndConditionsUrl: appConfig?.termsAndConditionsUrl ?? 'https://thewellnesscorner.com/privacy-policy'
|
|
167
|
+
};
|
|
168
|
+
const AuthPackageContextValues = {
|
|
169
|
+
token,
|
|
170
|
+
LogoComponent,
|
|
171
|
+
appConfig: appConfigValue,
|
|
172
|
+
registrationMethod,
|
|
173
|
+
onLaunchAuthSession,
|
|
174
|
+
onLogin,
|
|
175
|
+
logout,
|
|
176
|
+
refreshSession: onRefreshSession,
|
|
177
|
+
onTokenChange: (token) => setToken(token),
|
|
178
|
+
onRegistrationMethodChange: (method) => setRegistrationMethod(method),
|
|
179
|
+
otpValue,
|
|
180
|
+
};
|
|
181
|
+
return (_jsx(AuthContext.Provider, { value: AuthContextValues, children: _jsx(AuthPackageContext.Provider, { value: AuthPackageContextValues, children: children }) }));
|
|
182
|
+
};
|
|
183
|
+
export { AuthProvider };
|
|
184
|
+
export default AuthContext;
|
|
185
|
+
export { AuthPackageContext };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|