@truworth/twc-auth 1.1.0 → 1.2.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 +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 +19 -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 +184 -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 +38 -0
- package/build/src/index.js +12 -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 +181 -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 +58 -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 +8 -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, 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' }, 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' }, 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' }, 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' }, 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,19 @@
|
|
|
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
|
+
: _jsx(Text, { style: {
|
|
13
|
+
fontSize: 12, fontWeight: '500', marginRight: 8, marginTop: 8, borderRadius: 32,
|
|
14
|
+
paddingVertical: 4, paddingHorizontal: 12,
|
|
15
|
+
backgroundColor: getCriteriaBackground(criteria[item]),
|
|
16
|
+
color: getCriteriaColor(criteria[item]),
|
|
17
|
+
}, children: renderLabel(item) }, index))) }));
|
|
18
|
+
};
|
|
19
|
+
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: Platform.OS === 'ios' ? 100 : 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,184 @@
|
|
|
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 [member, setMember] = 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 && !member) {
|
|
65
|
+
getUserProfile();
|
|
66
|
+
}
|
|
67
|
+
}, [token, member]);
|
|
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
|
+
setMember(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
|
+
setMember(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
|
+
isLoadingProfile,
|
|
154
|
+
member,
|
|
155
|
+
client,
|
|
156
|
+
logout,
|
|
157
|
+
onLaunchAuthSession,
|
|
158
|
+
getUserProfile,
|
|
159
|
+
onOtpReceived: handleOtpReceived,
|
|
160
|
+
};
|
|
161
|
+
const appConfigValue = {
|
|
162
|
+
appName: appConfig?.appName ?? 'The Wellness Corner',
|
|
163
|
+
supportEmail: appConfig?.supportEmail ?? 'support@thewellnesscorner.com',
|
|
164
|
+
privacyPolicyUrl: appConfig?.privacyPolicyUrl ?? 'https://thewellnesscorner.com/privacy-policy',
|
|
165
|
+
termsAndConditionsUrl: appConfig?.termsAndConditionsUrl ?? 'https://thewellnesscorner.com/privacy-policy'
|
|
166
|
+
};
|
|
167
|
+
const AuthPackageContextValues = {
|
|
168
|
+
token,
|
|
169
|
+
LogoComponent,
|
|
170
|
+
appConfig: appConfigValue,
|
|
171
|
+
registrationMethod,
|
|
172
|
+
onLaunchAuthSession,
|
|
173
|
+
onLogin,
|
|
174
|
+
logout,
|
|
175
|
+
refreshSession: onRefreshSession,
|
|
176
|
+
onTokenChange: (token) => setToken(token),
|
|
177
|
+
onRegistrationMethodChange: (method) => setRegistrationMethod(method),
|
|
178
|
+
otpValue,
|
|
179
|
+
};
|
|
180
|
+
return (_jsx(AuthContext.Provider, { value: AuthContextValues, children: _jsx(AuthPackageContext.Provider, { value: AuthPackageContextValues, children: children }) }));
|
|
181
|
+
};
|
|
182
|
+
export { AuthProvider };
|
|
183
|
+
export default AuthContext;
|
|
184
|
+
export { AuthPackageContext };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|