@truworth/twc-auth 3.0.2 → 3.0.4
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/build/src/screens/CreatePassword/hooks/internal/useCreatePassword.js +11 -4
- package/build/src/screens/CreatePassword/index.js +4 -31
- package/build/src/screens/SSOLogin/AuthWebView/index.native.js +27 -12
- package/build/src/screens/SSOLogin/AuthenticationMethods/hooks/internal/useSSOAuthenticationMethods.js +3 -2
- package/build/src/screens/SSOLogin/AuthenticationMethods/index.js +1 -0
- package/build/src/screens/SSOLogin/AuthenticationMethods/index.native.js +6 -1
- package/build/src/screens/SSOLogin/SSOCallback/components/SSOCallbackComponent/index.js +41 -13
- package/build/src/screens/SSOLogin/SSOCallback/hooks/internal/useSSOCallback.js +17 -8
- package/build/src/screens/SSOLogin/SSOCallback/index.native.js +2 -2
- package/build/src/screens/UserConsent/index.js +12 -7
- package/build/types/navigator/index.native.d.ts +4 -1
- package/build/types/screens/CreatePassword/hooks/internal/useCreatePassword.d.ts +12 -1
- package/build/types/screens/SSOLogin/AuthenticationMethods/types.d.ts +4 -2
- package/build/types/screens/SSOLogin/SSOCallback/components/SSOCallbackComponent/index.d.ts +5 -1
- package/build/types/screens/SSOLogin/SSOCallback/hooks/internal/useSSOCallback.d.ts +5 -1
- package/build/types/screens/SSOLogin/SSOCallback/types.d.ts +3 -0
- package/package.json +1 -1
|
@@ -4,12 +4,17 @@ import { defaultPolicy } from "../../../../constants/defaultPolicy";
|
|
|
4
4
|
* @internal
|
|
5
5
|
* Internal hook for managing CreatePassword screen state and auth context integration.
|
|
6
6
|
* Not exposed to package consumers.
|
|
7
|
+
*
|
|
8
|
+
* Both web and native use the same pattern:
|
|
9
|
+
* - Hook manages password state internally
|
|
10
|
+
* - Use handlePassword/handleConfirmPassword to update state
|
|
11
|
+
* - Optional initial values for preserving state when navigating back
|
|
7
12
|
*/
|
|
8
|
-
const useCreatePassword = () => {
|
|
13
|
+
const useCreatePassword = (props) => {
|
|
9
14
|
const [passwordVisible, setPasswordVisible] = useState(false);
|
|
10
15
|
const [confirmPasswordVisible, setConfirmPasswordVisible] = useState(false);
|
|
11
|
-
const [password, setPassword] = useState('');
|
|
12
|
-
const [confirmPassword, setConfirmPassword] = useState('');
|
|
16
|
+
const [password, setPassword] = useState(props?.initialPassword || '');
|
|
17
|
+
const [confirmPassword, setConfirmPassword] = useState(props?.initialConfirmPassword || '');
|
|
13
18
|
const [maxLength, setMaxLength] = useState(defaultPolicy.maxLength);
|
|
14
19
|
const [criteria, setCriteria] = useState({});
|
|
15
20
|
const handlePassword = (text) => {
|
|
@@ -23,7 +28,9 @@ const useCreatePassword = () => {
|
|
|
23
28
|
setConfirmPassword('');
|
|
24
29
|
onResult();
|
|
25
30
|
};
|
|
26
|
-
const
|
|
31
|
+
const allCriteriaMet = Object.keys(criteria).length > 0 && Object.keys(criteria).every(c => criteria[c]);
|
|
32
|
+
const passwordsMatch = password.length > 0 && password === confirmPassword;
|
|
33
|
+
const isContinueDisabled = !allCriteriaMet || !passwordsMatch;
|
|
27
34
|
return {
|
|
28
35
|
password, setPassword,
|
|
29
36
|
confirmPassword, setConfirmPassword,
|
|
@@ -1,43 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Button, Flex,
|
|
2
|
+
import { Button, Flex, PasswordInput, Typography } from "@truworth/twc-web-design";
|
|
3
3
|
import { useCreatePassword } from "./hooks/internal/useCreatePassword";
|
|
4
4
|
import { ScreenLayout } from "../../components/ScreenLayout";
|
|
5
5
|
import { PasswordCriteria } from "../../components/PasswordCriteria";
|
|
6
6
|
const CreatePassword = ({ userDetails, handleBack, onContinue }) => {
|
|
7
7
|
const { countryCode, email } = userDetails;
|
|
8
|
-
const
|
|
9
|
-
defaultValues: {
|
|
10
|
-
password: userDetails.password || '',
|
|
11
|
-
confirmPassword: userDetails.confirmPassword || '',
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
const { password, confirmPassword } = form.watch();
|
|
15
|
-
const { criteria, setCriteria, maxLength, setMaxLength, handleSkip, isContinueDisabled } = useCreatePassword();
|
|
8
|
+
const { password, confirmPassword, handlePassword, handleConfirmPassword, passwordVisible, setPasswordVisible, confirmPasswordVisible, setConfirmPasswordVisible, criteria, setCriteria, maxLength, setMaxLength, handleSkip, isContinueDisabled } = useCreatePassword();
|
|
16
9
|
return (_jsx(ScreenLayout, { title: _jsxs(Flex, { justify: "between", align: "center", children: [_jsx(Typography, { type: "heading", size: "h5", children: "Create your Password" }), countryCode == '91' &&
|
|
17
|
-
_jsx(Button, { label: "Skip Now", variant: "link", onClick: () => handleSkip({ onResult: onContinue }) })] }), subTitle: "Use a password that's easy to remember and fulfills all the requirements listed below.", buttonProps: {
|
|
10
|
+
_jsx(Button, { label: "Skip Now", variant: "link", onClick: () => handleSkip({ onResult: () => onContinue('', '') }) })] }), subTitle: "Use a password that's easy to remember and fulfills all the requirements listed below.", buttonProps: {
|
|
18
11
|
label: 'Continue',
|
|
19
12
|
onClick: () => onContinue(password, confirmPassword),
|
|
20
13
|
disabled: isContinueDisabled
|
|
21
|
-
}, onPressBack: handleBack, children: _jsxs(
|
|
22
|
-
{
|
|
23
|
-
required: true,
|
|
24
|
-
message: 'Please enter your password'
|
|
25
|
-
}
|
|
26
|
-
], children: _jsx(PasswordInput, { placeholder: "Enter password", value: password, maxLength: maxLength, showStrengthIndicator: false }) }), _jsx(PasswordCriteria, { email: email, password: password, criteria: criteria, onCriteriaChange: setCriteria, onMaxLengthChange: setMaxLength }), _jsx(Form.Item, { name: "confirmPassword", label: "Confirm Password", className: "mt-6", normalize: (value) => value.replace(/\s/g, ''), rules: [
|
|
27
|
-
{
|
|
28
|
-
required: true,
|
|
29
|
-
message: 'Please confirm your password',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
validator: async (_, value) => {
|
|
33
|
-
const password = form.getValues('password');
|
|
34
|
-
if (!value)
|
|
35
|
-
return;
|
|
36
|
-
if (!value || password !== value) {
|
|
37
|
-
throw new Error('Passwords don’t match');
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
], children: _jsx(PasswordInput, { className: "mb-6", value: confirmPassword, placeholder: "Re-enter password", maxLength: maxLength, showStrengthIndicator: false }) })] }) }));
|
|
14
|
+
}, onPressBack: handleBack, children: _jsxs("div", { style: { width: '100%' }, children: [_jsxs("div", { style: { marginBottom: '8px', width: '100%' }, children: [_jsx(Typography, { type: "body", size: "small", className: "mb-1 font-medium", children: "Enter Password" }), _jsx("div", { style: { width: '100%' }, children: _jsx(PasswordInput, { placeholder: "Enter password", value: password, onChange: (value) => handlePassword(value), maxLength: maxLength, showStrengthIndicator: false, style: { width: '100%' } }) })] }), _jsx(PasswordCriteria, { email: email, password: password, criteria: criteria, onCriteriaChange: setCriteria, onMaxLengthChange: setMaxLength }), _jsxs("div", { style: { marginTop: '24px', marginBottom: '24px', width: '100%' }, children: [_jsx(Typography, { type: "body", size: "small", className: "mb-1 font-medium", children: "Confirm Password" }), _jsx("div", { style: { width: '100%' }, children: _jsx(PasswordInput, { placeholder: "Re-enter password", value: confirmPassword, onChange: (value) => handleConfirmPassword(value), maxLength: maxLength, showStrengthIndicator: false, style: { width: '100%' } }) }), confirmPassword && password !== confirmPassword && (_jsx(Typography, { type: "body", size: "tiny", className: "text-red-500 mt-1", children: "Passwords don't match" }))] })] }) }));
|
|
42
15
|
};
|
|
43
16
|
export default CreatePassword;
|
|
@@ -3,25 +3,40 @@ import { WebView } from '@truworth/twc-rn-common';
|
|
|
3
3
|
import { Layout } from '@ui-kitten/components';
|
|
4
4
|
import { Text } from 'react-native';
|
|
5
5
|
import parse from 'url-parse';
|
|
6
|
-
import { useState } from 'react';
|
|
6
|
+
import { useState, useCallback } from 'react';
|
|
7
|
+
const SAML_CALLBACK_PATHS = ['/saml', 'thewellnesscorner.com/saml'];
|
|
7
8
|
const SSOAuthWebView = ({ navigation, route }) => {
|
|
8
|
-
const { clientId, authenticationUrl, redirectUri } = route.params;
|
|
9
|
+
const { clientId, authenticationUrl, redirectUri, authMethod } = route.params;
|
|
9
10
|
const [error, setError] = useState(null);
|
|
11
|
+
const handleNavigationStateChange = useCallback((navState) => {
|
|
12
|
+
setError(null);
|
|
13
|
+
const parsedUrl = parse(navState.url, true);
|
|
14
|
+
const currentUrl = parsedUrl.href;
|
|
15
|
+
const authUrl = parse(authenticationUrl, true).href;
|
|
16
|
+
if (currentUrl === authUrl)
|
|
17
|
+
return;
|
|
18
|
+
if (authMethod === 'saml') {
|
|
19
|
+
const isSamlCallback = SAML_CALLBACK_PATHS.some(path => navState.url.includes(path));
|
|
20
|
+
if (isSamlCallback) {
|
|
21
|
+
const { code } = parsedUrl.query;
|
|
22
|
+
if (code) {
|
|
23
|
+
navigation.replace('SSOCallback', { clientId, code: code, authMethod: 'saml' });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
if (redirectUri && navState.url.includes(redirectUri)) {
|
|
29
|
+
const { code } = parsedUrl.query;
|
|
30
|
+
navigation.replace('SSOCallback', { clientId, code: code, authMethod: 'oidc' });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, [authenticationUrl, authMethod, clientId, navigation, redirectUri]);
|
|
10
34
|
return (_jsxs(Layout, { style: { flex: 1 }, children: [error && (_jsx(Layout, { style: { padding: 16, backgroundColor: '#fee' }, children: _jsx(Text, { style: { color: 'red' }, children: error }) })), _jsx(WebView, { source: { uri: authenticationUrl }, style: { flex: 1 }, onError: (syntheticEvent) => {
|
|
11
35
|
const { nativeEvent } = syntheticEvent;
|
|
12
36
|
setError(`Failed to load authentication page: ${nativeEvent.description}`);
|
|
13
37
|
}, onHttpError: (syntheticEvent) => {
|
|
14
38
|
const { nativeEvent } = syntheticEvent;
|
|
15
39
|
setError(`Authentication provider error: ${nativeEvent.statusCode}`);
|
|
16
|
-
}, onNavigationStateChange:
|
|
17
|
-
setError(null);
|
|
18
|
-
const currentUrl = parse(navState.url, true).href;
|
|
19
|
-
const authUrl = parse(authenticationUrl, true).href;
|
|
20
|
-
if (currentUrl != authUrl && navState.url.includes(redirectUri)) {
|
|
21
|
-
const query = parse(navState.url, true).query;
|
|
22
|
-
const { code } = query;
|
|
23
|
-
navigation.replace('SSOCallback', { clientId, code });
|
|
24
|
-
}
|
|
25
|
-
} })] }));
|
|
40
|
+
}, onNavigationStateChange: handleNavigationStateChange })] }));
|
|
26
41
|
};
|
|
27
42
|
export default SSOAuthWebView;
|
|
@@ -17,8 +17,9 @@ const useSSOAuthenticationMethods = () => {
|
|
|
17
17
|
}).then((res) => {
|
|
18
18
|
if (!isMountedRef.current)
|
|
19
19
|
return;
|
|
20
|
-
const { authenticationUrl, redirectUri } = res.data;
|
|
21
|
-
|
|
20
|
+
const { authenticationUrl, redirectUri, authMethod } = res.data;
|
|
21
|
+
const resolvedAuthMethod = authMethod === 'saml' ? 'saml' : 'oidc';
|
|
22
|
+
onSSOLoginInitiated({ clientId, authenticationUrl, redirectUri, authMethod: resolvedAuthMethod });
|
|
22
23
|
}).catch((error) => {
|
|
23
24
|
if (!isMountedRef.current)
|
|
24
25
|
return;
|
|
@@ -29,6 +29,7 @@ const SSOAuthenticationMethods = ({ client, onPressBack, handleMobileLogin }) =>
|
|
|
29
29
|
const onSSOLoginInitiated = (result) => {
|
|
30
30
|
try {
|
|
31
31
|
localStorage.setItem('clientId', String(result.clientId));
|
|
32
|
+
localStorage.setItem('authMethod', result.authMethod);
|
|
32
33
|
const u = new URL(result.authenticationUrl);
|
|
33
34
|
window.location.href = u.toString();
|
|
34
35
|
}
|
|
@@ -43,7 +43,12 @@ const SSOAuthenticationMethods = ({ route }) => {
|
|
|
43
43
|
return (_jsx(View, { style: { marginTop: 70, alignSelf: 'center' }, children: _jsx(Logo, {}) }));
|
|
44
44
|
};
|
|
45
45
|
const onSSOLoginInitiated = (result) => {
|
|
46
|
-
navigation.navigate('SSOAuthWebView', {
|
|
46
|
+
navigation.navigate('SSOAuthWebView', {
|
|
47
|
+
clientId: result.clientId,
|
|
48
|
+
authenticationUrl: result.authenticationUrl,
|
|
49
|
+
redirectUri: result.redirectUri,
|
|
50
|
+
authMethod: result.authMethod,
|
|
51
|
+
});
|
|
47
52
|
};
|
|
48
53
|
return (_jsx(ScreenLayout, { title: "", containerStyle: { flex: 1, backgroundColor: primary.white }, children: _jsxs(View, { style: { flex: 1, justifyContent: 'center' }, children: [client.image ?
|
|
49
54
|
_jsx(FastImage, { source: { uri: client.image }, resizeMode: 'contain', style: { width: 180, aspectRatio: aspectRatio, alignSelf: 'center', marginTop: -150 } })
|
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { Suspense, lazy, useEffect, useState } from 'react';
|
|
2
|
+
import React, { Suspense, lazy, useEffect, useState, Component } from 'react';
|
|
3
3
|
import { Flex, Typography } from '@truworth/twc-web-design';
|
|
4
4
|
import { useSSOCallback } from '../../hooks/internal/useSSOCallback';
|
|
5
5
|
import { useNavigator } from '../../../../../hooks/useNavigator';
|
|
6
6
|
import redirectAnimation from '../../../../../../assets/animation/redirect-home.json';
|
|
7
7
|
import { RegistrationMethod } from '../../../../../enums';
|
|
8
8
|
const Lottie = lazy(() => import('react-lottie'));
|
|
9
|
-
|
|
9
|
+
class LottieErrorBoundary extends Component {
|
|
10
|
+
constructor(props) {
|
|
11
|
+
super(props);
|
|
12
|
+
this.state = { hasError: false };
|
|
13
|
+
}
|
|
14
|
+
static getDerivedStateFromError() {
|
|
15
|
+
return { hasError: true };
|
|
16
|
+
}
|
|
17
|
+
componentDidCatch() { }
|
|
18
|
+
render() {
|
|
19
|
+
if (this.state.hasError)
|
|
20
|
+
return this.props.fallback;
|
|
21
|
+
return this.props.children;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const SSOCallbackComponents = ({ authMethodOverride } = {}) => {
|
|
10
25
|
const navigator = useNavigator();
|
|
11
26
|
const [clientId, setClientId] = useState('');
|
|
12
27
|
const [code, setCode] = useState('');
|
|
28
|
+
const [authMethod, setAuthMethod] = useState(authMethodOverride ?? null);
|
|
29
|
+
const [isReady, setIsReady] = useState(false);
|
|
13
30
|
// Resolve code/token from query (preferred) or localStorage; clientId/authMethod from localStorage only
|
|
14
31
|
useEffect(() => {
|
|
15
32
|
const query = navigator.query;
|
|
@@ -17,17 +34,27 @@ const SSOCallbackComponents = () => {
|
|
|
17
34
|
if (typeof window !== 'undefined') {
|
|
18
35
|
try {
|
|
19
36
|
const storedClientId = localStorage.getItem('clientId') || '';
|
|
37
|
+
const storedAuthMethod = localStorage.getItem('authMethod') || 'oidc';
|
|
20
38
|
setClientId(storedClientId);
|
|
39
|
+
if (!authMethodOverride) {
|
|
40
|
+
setAuthMethod(storedAuthMethod);
|
|
41
|
+
}
|
|
21
42
|
setCode(typeof codeFromQuery === 'string' ? codeFromQuery : '');
|
|
43
|
+
setIsReady(true);
|
|
22
44
|
}
|
|
23
45
|
catch (error) {
|
|
24
46
|
console.log('Failed to read from localStorage:', error);
|
|
25
47
|
setCode(typeof codeFromQuery === 'string' ? codeFromQuery : '');
|
|
26
|
-
|
|
48
|
+
setIsReady(true);
|
|
27
49
|
}
|
|
28
50
|
}
|
|
29
|
-
}, [navigator.query]);
|
|
30
|
-
const { result, error } = useSSOCallback({
|
|
51
|
+
}, [navigator.query, authMethodOverride]);
|
|
52
|
+
const { result, error } = useSSOCallback({
|
|
53
|
+
clientId,
|
|
54
|
+
code,
|
|
55
|
+
authMethod: authMethod ?? 'oidc',
|
|
56
|
+
isReady,
|
|
57
|
+
});
|
|
31
58
|
useEffect(() => {
|
|
32
59
|
if (result?.registrationToken) {
|
|
33
60
|
navigator.pushAbsolute('/registration', {
|
|
@@ -45,14 +72,15 @@ const SSOCallbackComponents = () => {
|
|
|
45
72
|
}, 1500);
|
|
46
73
|
}
|
|
47
74
|
}, [error, navigator]);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
, {
|
|
75
|
+
const loadingFallback = _jsx("div", { className: "h-[230px] w-[250px]" });
|
|
76
|
+
return (_jsx(Flex, { justify: 'center', align: 'center', className: 'h-[100vh]', children: _jsxs("div", { children: [_jsx(LottieErrorBoundary, { fallback: loadingFallback, children: _jsx(Suspense, { fallback: loadingFallback, children: _jsx(Lottie
|
|
51
77
|
//@ts-ignore
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
78
|
+
, {
|
|
79
|
+
//@ts-ignore
|
|
80
|
+
options: {
|
|
81
|
+
animationData: redirectAnimation,
|
|
82
|
+
loop: true,
|
|
83
|
+
autoplay: true
|
|
84
|
+
}, height: 230, width: 250 }) }) }), _jsx(Typography, { size: 'h6', type: 'heading', color: 'gray-400', children: "Authenticating and Redirecting ..." })] }) }));
|
|
57
85
|
};
|
|
58
86
|
export { SSOCallbackComponents };
|
|
@@ -7,17 +7,25 @@ import { RegistrationMethod } from "../../../../../enums";
|
|
|
7
7
|
* @internal
|
|
8
8
|
* Hook for managing SSOCallback screen state and auth context integration.
|
|
9
9
|
* This hook is not exposed to package consumers.
|
|
10
|
+
*
|
|
11
|
+
* Supports both OIDC and SAML flows:
|
|
12
|
+
* - OIDC: Calls /callback endpoint with authorization code
|
|
13
|
+
* - SAML: Calls /saml-sso-complete endpoint with exchange code
|
|
10
14
|
*/
|
|
11
|
-
const useSSOCallback = ({ clientId, code }) => {
|
|
15
|
+
const useSSOCallback = ({ clientId, code, authMethod, isReady = true }) => {
|
|
12
16
|
const [error, setError] = useState(null);
|
|
13
17
|
const [result, setResult] = useState(null);
|
|
18
|
+
const [hasProcessed, setHasProcessed] = useState(false);
|
|
14
19
|
const { onLogin, onRegistrationMethodChange, onTokenChange } = useAuthPackageContext();
|
|
15
|
-
const
|
|
20
|
+
const processSSOCallback = useCallback((codeToProcess) => {
|
|
16
21
|
setError(null);
|
|
22
|
+
const endpoint = authMethod === 'saml'
|
|
23
|
+
? `/auth/login-sso/${clientId}/saml-sso-complete`
|
|
24
|
+
: `/auth/login-sso/${clientId}/callback`;
|
|
17
25
|
axiosClient({
|
|
18
|
-
url:
|
|
26
|
+
url: endpoint,
|
|
19
27
|
method: 'POST',
|
|
20
|
-
data: { code },
|
|
28
|
+
data: { code: codeToProcess },
|
|
21
29
|
}).then((res) => {
|
|
22
30
|
if (res?.data?.registrationToken) {
|
|
23
31
|
onRegistrationMethodChange(RegistrationMethod.SSO);
|
|
@@ -32,12 +40,13 @@ const useSSOCallback = ({ clientId, code }) => {
|
|
|
32
40
|
setError(errorMessage);
|
|
33
41
|
return showMessage({ message: errorMessage });
|
|
34
42
|
});
|
|
35
|
-
}, [clientId,
|
|
43
|
+
}, [clientId, authMethod, onLogin, onRegistrationMethodChange, onTokenChange]);
|
|
36
44
|
useEffect(() => {
|
|
37
|
-
if (code && clientId) {
|
|
38
|
-
|
|
45
|
+
if (isReady && code && clientId && !hasProcessed) {
|
|
46
|
+
setHasProcessed(true);
|
|
47
|
+
processSSOCallback(code);
|
|
39
48
|
}
|
|
40
|
-
}, [code, clientId]);
|
|
49
|
+
}, [isReady, code, clientId, hasProcessed, processSSOCallback]);
|
|
41
50
|
return { result, error };
|
|
42
51
|
};
|
|
43
52
|
export { useSSOCallback };
|
|
@@ -8,8 +8,8 @@ import loadingSpinner from '../../../../assets/loading-spinner.json';
|
|
|
8
8
|
import Lottie from 'lottie-react-native';
|
|
9
9
|
const { gray } = Colors;
|
|
10
10
|
const SSOCallback = ({ navigation, route }) => {
|
|
11
|
-
const { clientId, code } = route.params;
|
|
12
|
-
const { result, error } = useSSOCallback({ clientId, code });
|
|
11
|
+
const { clientId, code, authMethod } = route.params;
|
|
12
|
+
const { result, error } = useSSOCallback({ clientId, code, authMethod });
|
|
13
13
|
useEffect(() => {
|
|
14
14
|
if (result?.registrationToken) {
|
|
15
15
|
navigation.replace('SignUp', { ...result });
|
|
@@ -7,7 +7,6 @@ import { useAuthPackageContext } from '../../hooks/internal/useAuthPackageContex
|
|
|
7
7
|
import { CDN_IMAGES_URL } from '../../constants/cdn-url';
|
|
8
8
|
import { useConsent } from './hooks/internal/useConsent';
|
|
9
9
|
import { ScreenLayout } from "../../components/ScreenLayout";
|
|
10
|
-
import { useNavigator } from '../../hooks/useNavigator';
|
|
11
10
|
import VerifyMobile from "../VerifyMobile";
|
|
12
11
|
import VerifyEmail from "../VerifyEmail";
|
|
13
12
|
import redirectHome from '../../../assets/animation/redirect-home.json';
|
|
@@ -20,7 +19,6 @@ const UserConsent = ({ userDetails, handleBack }) => {
|
|
|
20
19
|
const [sessionToken, setSessionToken] = useState('');
|
|
21
20
|
const { onLogin, appConfig: { appName, privacyPolicyUrl }, LogoComponent, onTokenChange } = useAuthPackageContext();
|
|
22
21
|
const { loading, onAgree } = useConsent();
|
|
23
|
-
const navigator = useNavigator();
|
|
24
22
|
const onAgreeHandler = (res) => {
|
|
25
23
|
const { token, member, emailVerificationRequired, mobileVerificationRequired, sessionToken } = res;
|
|
26
24
|
if (token && member) {
|
|
@@ -58,18 +56,25 @@ const UserConsent = ({ userDetails, handleBack }) => {
|
|
|
58
56
|
source: 'web',
|
|
59
57
|
onResult: onAgreeHandler
|
|
60
58
|
}), className: "w-full lg:!w-auto lg:!mt-0" }), _jsx(Button, { label: "Not Now, I Will Register Later", variant: "link", onClick: () => setRedirectModal(true), className: "w-full lg:!w-auto lg:!mt-0" })] })] }) })] }), subTitle: "", onPressBack: handleBack }), redirectModal &&
|
|
61
|
-
_jsx(RedirectToHomeModal, { redirectModal: redirectModal
|
|
59
|
+
_jsx(RedirectToHomeModal, { redirectModal: redirectModal }), showVerifyMobileModal &&
|
|
62
60
|
_jsx(VerifyMobileModal, { phone: phone, visible: showVerifyMobileModal, hide: () => setShowVerifyMobileModal(false), sessionToken: sessionToken }), showVerifyEmailModal &&
|
|
63
61
|
_jsx(VerifyEmailModal, { email: email, visible: showVerifyEmailModal, hide: () => setShowVerifyEmailModal(false), sessionToken: sessionToken, onVerifiedOTP: () => {
|
|
64
62
|
setShowVerifyEmailModal(false);
|
|
65
63
|
setShowVerifyMobileModal(true);
|
|
66
64
|
} })] }));
|
|
67
65
|
};
|
|
68
|
-
const RedirectToHomeModal = ({ redirectModal
|
|
66
|
+
const RedirectToHomeModal = ({ redirectModal }) => {
|
|
67
|
+
const [isMounted, setIsMounted] = useState(false);
|
|
69
68
|
useEffect(() => {
|
|
70
|
-
|
|
69
|
+
setIsMounted(true);
|
|
70
|
+
// Redirect after a short delay to show the modal
|
|
71
|
+
const timer = setTimeout(() => {
|
|
72
|
+
// Use window.location for full page navigation to avoid context issues
|
|
73
|
+
window.location.href = '/login';
|
|
74
|
+
}, 2000);
|
|
75
|
+
return () => clearTimeout(timer);
|
|
71
76
|
}, []);
|
|
72
|
-
return (_jsxs(Modal, { title: "", open: redirectModal, showCloseButton: false, footer: null, children: [_jsx(Suspense, { fallback: _jsx("div", { className: "h-[150px] w-[250px]" }), children: _jsx(Lottie
|
|
77
|
+
return (_jsxs(Modal, { title: "", open: redirectModal, showCloseButton: false, footer: null, children: [isMounted && (_jsx(Suspense, { fallback: _jsx("div", { className: "h-[150px] w-[250px]" }), children: _jsx(Lottie
|
|
73
78
|
/* @ts-ignore */
|
|
74
79
|
, {
|
|
75
80
|
/* @ts-ignore */
|
|
@@ -77,7 +82,7 @@ const RedirectToHomeModal = ({ redirectModal, navigator }) => {
|
|
|
77
82
|
animationData: redirectHome,
|
|
78
83
|
loop: true,
|
|
79
84
|
autoplay: true
|
|
80
|
-
}, height: 150, width: 250 }) }), _jsxs(Flex, { direction: 'column', style: { marginTop: "-30px" }, children: [_jsx(Typography, { type: 'heading', size: 'h5', className: 'text-center mb-6', color: "text-gray-800", children: "Redirecting to the website homepage" }), _jsxs(Flex, { children: [_jsx(Info, { color: 'blue' }), _jsx(Typography, { type: 'body', size: 'small', className: 'text-center mb-6', color: "text-gray-800", children: "We have not stored any information you shared during registration." })] })] })] }));
|
|
85
|
+
}, height: 150, width: 250 }) })), _jsxs(Flex, { direction: 'column', style: { marginTop: isMounted ? "-30px" : "0" }, children: [_jsx(Typography, { type: 'heading', size: 'h5', className: 'text-center mb-6', color: "text-gray-800", children: "Redirecting to the website homepage" }), _jsxs(Flex, { children: [_jsx(Info, { color: 'blue' }), _jsx(Typography, { type: 'body', size: 'small', className: 'text-center mb-6', color: "text-gray-800", children: "We have not stored any information you shared during registration." })] })] })] }));
|
|
81
86
|
};
|
|
82
87
|
const VerifyMobileModal = ({ visible, hide, sessionToken, phone }) => {
|
|
83
88
|
return (_jsx(ResponsiveModal, { title: 'Verify Mobile', open: visible, onClose: hide, onOpenChange: hide, maskClosable: false, showCloseButton: false, children: _jsx(VerifyMobile, { sessionToken: sessionToken, phone: phone }) }));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type NativeStackScreenProps } from '@react-navigation/native-stack';
|
|
2
2
|
import type { Client, PersonalDetails } from '../types/types';
|
|
3
|
+
import type { AuthMethod } from '../screens/SSOLogin/AuthenticationMethods/types';
|
|
3
4
|
declare const AuthNavigator: () => import("react/jsx-runtime").JSX.Element;
|
|
4
5
|
export { AuthNavigator };
|
|
5
6
|
export type AuthStackParamList = {
|
|
@@ -55,11 +56,13 @@ export type AuthStackParamList = {
|
|
|
55
56
|
SSOCallback: {
|
|
56
57
|
code?: string;
|
|
57
58
|
clientId: number;
|
|
59
|
+
authMethod?: AuthMethod;
|
|
58
60
|
};
|
|
59
61
|
SSOAuthWebView: {
|
|
60
62
|
clientId: number;
|
|
61
63
|
authenticationUrl: string;
|
|
62
|
-
redirectUri
|
|
64
|
+
redirectUri?: string;
|
|
65
|
+
authMethod: AuthMethod;
|
|
63
66
|
};
|
|
64
67
|
EnterMobile: undefined;
|
|
65
68
|
LoginWithMobileOTP: {
|
|
@@ -1,9 +1,20 @@
|
|
|
1
|
+
interface UseCreatePasswordProps {
|
|
2
|
+
/** Initial password value (for preserving state when navigating back) */
|
|
3
|
+
initialPassword?: string;
|
|
4
|
+
/** Initial confirm password value (for preserving state when navigating back) */
|
|
5
|
+
initialConfirmPassword?: string;
|
|
6
|
+
}
|
|
1
7
|
/**
|
|
2
8
|
* @internal
|
|
3
9
|
* Internal hook for managing CreatePassword screen state and auth context integration.
|
|
4
10
|
* Not exposed to package consumers.
|
|
11
|
+
*
|
|
12
|
+
* Both web and native use the same pattern:
|
|
13
|
+
* - Hook manages password state internally
|
|
14
|
+
* - Use handlePassword/handleConfirmPassword to update state
|
|
15
|
+
* - Optional initial values for preserving state when navigating back
|
|
5
16
|
*/
|
|
6
|
-
declare const useCreatePassword: () => {
|
|
17
|
+
declare const useCreatePassword: (props?: UseCreatePasswordProps) => {
|
|
7
18
|
password: string;
|
|
8
19
|
setPassword: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
9
20
|
confirmPassword: string;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { Client } from "../../../types/types";
|
|
2
|
+
type AuthMethod = 'oidc' | 'saml';
|
|
2
3
|
interface SSOInitiationData {
|
|
3
4
|
clientId: number;
|
|
4
5
|
authenticationUrl: string;
|
|
5
|
-
redirectUri
|
|
6
|
+
redirectUri?: string;
|
|
7
|
+
authMethod: AuthMethod;
|
|
6
8
|
}
|
|
7
9
|
interface SSOAuthenticationMethodsProps {
|
|
8
10
|
client: Client;
|
|
9
11
|
onPressBack: () => void;
|
|
10
12
|
handleMobileLogin: () => void;
|
|
11
13
|
}
|
|
12
|
-
export type { SSOAuthenticationMethodsProps, SSOInitiationData };
|
|
14
|
+
export type { SSOAuthenticationMethodsProps, SSOInitiationData, AuthMethod };
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { AuthMethod } from '../../../AuthenticationMethods/types';
|
|
2
|
+
interface SSOCallbackComponentsProps {
|
|
3
|
+
authMethodOverride?: AuthMethod;
|
|
4
|
+
}
|
|
5
|
+
declare const SSOCallbackComponents: ({ authMethodOverride }?: SSOCallbackComponentsProps) => import("react/jsx-runtime").JSX.Element;
|
|
2
6
|
export { SSOCallbackComponents };
|
|
@@ -3,8 +3,12 @@ import type { useSSOCallbackProps, SignUpData } from "../../types";
|
|
|
3
3
|
* @internal
|
|
4
4
|
* Hook for managing SSOCallback screen state and auth context integration.
|
|
5
5
|
* This hook is not exposed to package consumers.
|
|
6
|
+
*
|
|
7
|
+
* Supports both OIDC and SAML flows:
|
|
8
|
+
* - OIDC: Calls /callback endpoint with authorization code
|
|
9
|
+
* - SAML: Calls /saml-sso-complete endpoint with exchange code
|
|
6
10
|
*/
|
|
7
|
-
declare const useSSOCallback: ({ clientId, code }: useSSOCallbackProps) => {
|
|
11
|
+
declare const useSSOCallback: ({ clientId, code, authMethod, isReady }: useSSOCallbackProps) => {
|
|
8
12
|
result: SignUpData | null;
|
|
9
13
|
error: string | null;
|
|
10
14
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AuthMethod } from '../AuthenticationMethods/types';
|
|
1
2
|
interface SignUpData {
|
|
2
3
|
email: string;
|
|
3
4
|
firstName: string;
|
|
@@ -7,5 +8,7 @@ interface SignUpData {
|
|
|
7
8
|
interface useSSOCallbackProps {
|
|
8
9
|
code?: string;
|
|
9
10
|
clientId: number | string;
|
|
11
|
+
authMethod?: AuthMethod;
|
|
12
|
+
isReady?: boolean;
|
|
10
13
|
}
|
|
11
14
|
export type { useSSOCallbackProps, SignUpData };
|