@truworth/twc-auth 1.2.12-beta.0 → 1.2.12-beta.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.
Files changed (101) hide show
  1. package/README.md +16 -14
  2. package/build/src/components/AdvancedTransitionWrapper/index.js +2 -8
  3. package/build/src/components/ConfirmationModal/index.js +2 -2
  4. package/build/src/components/LoadingAnimation/index.js +50 -0
  5. package/build/src/constants/password-requirements.js +7 -0
  6. package/build/src/contexts/AuthContext.js +5 -1
  7. package/build/src/hooks/useNavigator.js +83 -0
  8. package/build/src/index.js +8 -0
  9. package/build/src/screens/CountryCode/components/CountryCodeDropdown/index.js +2 -3
  10. package/build/src/screens/CreatePassword/hooks/internal/useCreatePassword.js +11 -4
  11. package/build/src/screens/CreatePassword/index.js +6 -30
  12. package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/index.js +1 -1
  13. package/build/src/screens/EnterMobile/hooks/internal/useEnterMobile.js +4 -1
  14. package/build/src/screens/EnterMobile/index.js +10 -10
  15. package/build/src/screens/EnterMobile/index.native.js +3 -3
  16. package/build/src/screens/Login/components/LoginWebComponent/index.js +3 -4
  17. package/build/src/screens/LoginWithMobileOTP/hooks/internal/useLoginWithMobileOTP.js +5 -5
  18. package/build/src/screens/LoginWithMobileOTP/index.js +2 -2
  19. package/build/src/screens/LoginWithMobileOTP/index.native.js +2 -2
  20. package/build/src/screens/PartnerSSO/PartnerLogin/components/PartnerLoginWebComponent/index.js +71 -0
  21. package/build/src/screens/PartnerSSO/PartnerLogin/components/PartnerLoginWebComponent/index.native.js +6 -0
  22. package/build/src/screens/PartnerSSO/PartnerLogin/hooks/internal/usePartnerLogin.js +52 -0
  23. package/build/src/screens/PartnerSSO/PartnerLogin/index.js +2 -0
  24. package/build/src/screens/PartnerSSO/PartnerLogin/types.js +1 -0
  25. package/build/src/screens/PartnerSSO/PartnerRegistration/components/PartnerRegistrationWebComponent/index.js +207 -0
  26. package/build/src/screens/PartnerSSO/PartnerRegistration/components/PartnerRegistrationWebComponent/index.native.js +6 -0
  27. package/build/src/screens/PartnerSSO/PartnerRegistration/hooks/internal/usePartnerRegistration.js +90 -0
  28. package/build/src/screens/PartnerSSO/PartnerRegistration/index.js +2 -0
  29. package/build/src/screens/PartnerSSO/PartnerRegistration/types.js +1 -0
  30. package/build/src/screens/PartnerSSO/index.js +2 -0
  31. package/build/src/screens/Profile/components/EditMobileNumber/index.js +31 -0
  32. package/build/src/screens/Profile/components/EditMobileNumber/index.native.js +8 -0
  33. package/build/src/screens/Profile/components/EditPassword/index.js +29 -0
  34. package/build/src/screens/Profile/components/EditPassword/index.native.js +8 -0
  35. package/build/src/screens/Profile/components/EditProfile/index.js +89 -0
  36. package/build/src/screens/Profile/components/EditProfile/index.native.js +8 -0
  37. package/build/src/screens/Profile/components/OtpVerificationModal/index.js +61 -0
  38. package/build/src/screens/Profile/components/OtpVerificationModal/index.native.js +7 -0
  39. package/build/src/screens/Profile/components/ProfileWebComponent/index.js +80 -0
  40. package/build/src/screens/Profile/components/ProfileWebComponent/index.native.js +9 -0
  41. package/build/src/screens/Profile/hooks/internal/useProfile.js +185 -0
  42. package/build/src/screens/Profile/index.js +6 -0
  43. package/build/src/screens/Profile/index.native.js +6 -0
  44. package/build/src/screens/Profile/types.js +1 -0
  45. package/build/src/screens/SSOLogin/AuthWebView/index.native.js +27 -12
  46. package/build/src/screens/SSOLogin/AuthenticationMethods/hooks/internal/useSSOAuthenticationMethods.js +3 -2
  47. package/build/src/screens/SSOLogin/AuthenticationMethods/index.js +1 -0
  48. package/build/src/screens/SSOLogin/AuthenticationMethods/index.native.js +6 -1
  49. package/build/src/screens/SSOLogin/SSOCallback/components/SSOCallbackComponent/index.js +31 -28
  50. package/build/src/screens/SSOLogin/SSOCallback/hooks/internal/useSSOCallback.js +23 -8
  51. package/build/src/screens/SSOLogin/SSOCallback/index.native.js +2 -2
  52. package/build/src/screens/SignUp/components/SignUpForm/index.js +17 -17
  53. package/build/src/screens/SignUp/components/SignUpWebComponent/index.js +7 -6
  54. package/build/src/screens/UserConsent/index.js +11 -17
  55. package/build/src/screens/Welcome/SocialAuth/hooks/web/useFacebookAuth.web.js +3 -4
  56. package/build/src/screens/Welcome/SocialAuth/hooks/web/useGoogleAuth.web.js +3 -4
  57. package/build/src/screens/Welcome/index.js +1 -1
  58. package/build/types/components/ConfirmationModal/index.d.ts +1 -1
  59. package/build/types/components/ConfirmationModal/types.d.ts +3 -0
  60. package/build/types/components/LoadingAnimation/index.d.ts +6 -0
  61. package/build/types/constants/password-requirements.d.ts +4 -0
  62. package/build/types/contexts/AuthContext.d.ts +3 -1
  63. package/build/types/contexts/type.d.ts +24 -1
  64. package/build/types/hooks/useNavigator.d.ts +66 -0
  65. package/build/types/index.d.ts +5 -0
  66. package/build/types/navigator/index.native.d.ts +5 -2
  67. package/build/types/screens/CreatePassword/hooks/internal/useCreatePassword.d.ts +12 -1
  68. package/build/types/screens/EnterMobile/types.d.ts +2 -2
  69. package/build/types/screens/LoginWithMobileOTP/hooks/internal/useLoginWithMobileOTP.d.ts +2 -2
  70. package/build/types/screens/LoginWithMobileOTP/index.d.ts +2 -2
  71. package/build/types/screens/PartnerSSO/PartnerLogin/components/PartnerLoginWebComponent/index.d.ts +25 -0
  72. package/build/types/screens/PartnerSSO/PartnerLogin/components/PartnerLoginWebComponent/index.native.d.ts +2 -0
  73. package/build/types/screens/PartnerSSO/PartnerLogin/hooks/internal/usePartnerLogin.d.ts +8 -0
  74. package/build/types/screens/PartnerSSO/PartnerLogin/index.d.ts +2 -0
  75. package/build/types/screens/PartnerSSO/PartnerLogin/types.d.ts +35 -0
  76. package/build/types/screens/PartnerSSO/PartnerRegistration/components/PartnerRegistrationWebComponent/index.d.ts +24 -0
  77. package/build/types/screens/PartnerSSO/PartnerRegistration/components/PartnerRegistrationWebComponent/index.native.d.ts +2 -0
  78. package/build/types/screens/PartnerSSO/PartnerRegistration/hooks/internal/usePartnerRegistration.d.ts +8 -0
  79. package/build/types/screens/PartnerSSO/PartnerRegistration/index.d.ts +2 -0
  80. package/build/types/screens/PartnerSSO/PartnerRegistration/types.d.ts +63 -0
  81. package/build/types/screens/PartnerSSO/index.d.ts +2 -0
  82. package/build/types/screens/Profile/components/EditMobileNumber/index.d.ts +6 -0
  83. package/build/types/screens/Profile/components/EditMobileNumber/index.native.d.ts +3 -0
  84. package/build/types/screens/Profile/components/EditPassword/index.d.ts +6 -0
  85. package/build/types/screens/Profile/components/EditPassword/index.native.d.ts +3 -0
  86. package/build/types/screens/Profile/components/EditProfile/index.d.ts +6 -0
  87. package/build/types/screens/Profile/components/EditProfile/index.native.d.ts +3 -0
  88. package/build/types/screens/Profile/components/OtpVerificationModal/index.d.ts +4 -0
  89. package/build/types/screens/Profile/components/OtpVerificationModal/index.native.d.ts +3 -0
  90. package/build/types/screens/Profile/components/ProfileWebComponent/index.d.ts +4 -0
  91. package/build/types/screens/Profile/components/ProfileWebComponent/index.native.d.ts +3 -0
  92. package/build/types/screens/Profile/hooks/internal/useProfile.d.ts +26 -0
  93. package/build/types/screens/Profile/index.d.ts +7 -0
  94. package/build/types/screens/Profile/index.native.d.ts +7 -0
  95. package/build/types/screens/Profile/types.d.ts +53 -0
  96. package/build/types/screens/SSOLogin/AuthenticationMethods/types.d.ts +4 -2
  97. package/build/types/screens/SSOLogin/SSOCallback/components/SSOCallbackComponent/index.d.ts +5 -1
  98. package/build/types/screens/SSOLogin/SSOCallback/hooks/internal/useSSOCallback.d.ts +5 -1
  99. package/build/types/screens/SSOLogin/SSOCallback/types.d.ts +3 -0
  100. package/get-metro-config.js +19 -26
  101. package/package.json +5 -6
package/README.md CHANGED
@@ -85,14 +85,15 @@ Truworth Auth Module - A comprehensive authentication solution for React Native
85
85
 
86
86
  | Package | Version |
87
87
  | ------------------------ | -------- |
88
- | @truworth/twc-web-design | ^1.9.0 |
89
- | antd | ^5.6.3 |
90
- | framer-motion | ^12.6.2 |
91
- | lodash | ^4.17.21 |
92
- | lucide-react | ^0.483.0 |
88
+ | @react-google-maps/api | >=2.20.6 |
89
+ | @truworth/twc-web-design | >=1.9.0 |
90
+ | antd | >=5.6.3 |
91
+ | framer-motion | >=12.6.2 |
92
+ | lodash | >=4.17.21 |
93
+ | lucide-react | >=0.483.0 |
93
94
  | next | ^15.0.4 |
94
- | react | ^18.2.0 |
95
- | react-dom | ^18.2.0 |
95
+ | react | >=18.2.0 |
96
+ | react-dom | >=18.2.0 |
96
97
 
97
98
  ### Web
98
99
 
@@ -106,13 +107,14 @@ Truworth Auth Module - A comprehensive authentication solution for React Native
106
107
  ```bash
107
108
  npm install \
108
109
  next@^15.0.4 \
109
- @truworth/twc-web-design@^1.9.0 \
110
- antd@^5.6.3 \
111
- framer-motion@^12.6.2 \
112
- lodash@^4.17.21 \
113
- lucide-react@^0.483.0 \
114
- react@^18.2.0 \
115
- react-dom@^18.2.0
110
+ @react-google-maps/api@>=2.20.6 \
111
+ @truworth/twc-web-design@>=1.9.0 \
112
+ antd@>=5.6.3 \
113
+ framer-motion@>=12.6.2 \
114
+ lodash@>=4.17.21 \
115
+ lucide-react@>=0.483.0 \
116
+ react@>=18.2.0 \
117
+ react-dom@>=18.2.0
116
118
  ```
117
119
 
118
120
  ## Running the Example Applications of the TWC-Auth Package
@@ -37,8 +37,8 @@ const AdvancedTransitionWrapper = ({ children, isVisible = true, direction = 'ri
37
37
  export { AdvancedTransitionWrapper };
38
38
  const getAdvancedVariants = (direction, type, duration, delay, options) => {
39
39
  // Extract options with defaults
40
- const { bounce = 0.25, damping = 10, mass = 1, velocity = 0, depth = 100, perspective = 1000, intensity = 1 } = options;
41
- // Base variants
40
+ const { bounce = 0.25, damping = 10, mass = 1, velocity = 0, depth = 100, intensity = 1 } = options;
41
+ // Base variants - using Record type to allow dynamic property assignment
42
42
  const baseVariants = {
43
43
  initial: { opacity: 0 },
44
44
  enter: {
@@ -104,17 +104,14 @@ const getAdvancedVariants = (direction, type, duration, delay, options) => {
104
104
  baseVariants.initial = {
105
105
  ...baseVariants.initial,
106
106
  [flipAxis]: direction === 'up' || direction === 'left' ? flipAmount : -flipAmount,
107
- transformPerspective: perspective
108
107
  };
109
108
  baseVariants.enter = {
110
109
  ...baseVariants.enter,
111
110
  [flipAxis]: 0,
112
- transformPerspective: perspective
113
111
  };
114
112
  baseVariants.exit = {
115
113
  ...baseVariants.exit,
116
114
  [flipAxis]: direction === 'up' || direction === 'left' ? -flipAmount : flipAmount,
117
- transformPerspective: perspective
118
115
  };
119
116
  break;
120
117
  }
@@ -281,21 +278,18 @@ const getAdvancedVariants = (direction, type, duration, delay, options) => {
281
278
  scale: direction === 'up' || direction === 'left' ? 1.5 * intensity : 0.6 / Math.max(0.1, intensity),
282
279
  opacity: 0,
283
280
  z: direction === 'up' || direction === 'left' ? -depth : depth,
284
- transformPerspective: perspective
285
281
  };
286
282
  baseVariants.enter = {
287
283
  ...baseVariants.enter,
288
284
  scale: 1,
289
285
  opacity: 1,
290
286
  z: 0,
291
- transformPerspective: perspective
292
287
  };
293
288
  baseVariants.exit = {
294
289
  ...baseVariants.exit,
295
290
  scale: direction === 'up' || direction === 'left' ? 0.6 / Math.max(0.1, intensity) : 1.5 * intensity,
296
291
  opacity: 0,
297
292
  z: direction === 'up' || direction === 'left' ? depth : -depth,
298
- transformPerspective: perspective
299
293
  };
300
294
  break;
301
295
  }
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { IonIcon } from '../../components/IonIcon';
3
3
  import { Button, Flex, ResponsiveModal, Typography } from '@truworth/twc-web-design';
4
- const ConfirmationModal = ({ title, visible, onClose, onProceed, onDismiss, primaryLabel, secondaryLabel, iconName = "information-circle-outline", iconColor = "hsl(var(--tw-ui-utility---warning--main))", description }) => {
5
- return (_jsx(ResponsiveModal, { title: "", open: visible, onClose: onClose, footer: null, showCloseButton: false, className: 'py-0', children: _jsxs(Flex, { direction: "column", align: "center", justify: "center", children: [_jsxs(Flex, { direction: "column", align: "center", justify: "center", children: [_jsx(IonIcon, { name: iconName, style: { color: iconColor, fontSize: 96 } }), title &&
4
+ const ConfirmationModal = ({ title, visible, onClose, onProceed, onDismiss, primaryLabel, secondaryLabel, iconName = "information-circle-outline", iconClassName = "text-utility-warning-main", description }) => {
5
+ return (_jsx(ResponsiveModal, { title: "", open: visible, onClose: onClose, footer: null, showCloseButton: false, className: 'py-0', children: _jsxs(Flex, { direction: "column", align: "center", justify: "center", children: [_jsxs(Flex, { direction: "column", align: "center", justify: "center", children: [_jsx(IonIcon, { name: iconName, className: `text-[96px] ${iconClassName}` }), title &&
6
6
  _jsx(Typography, { type: "heading", size: "h6", className: "mt-2 text-center", children: title }), description &&
7
7
  _jsx(Typography, { type: "utility", size: "medium", color: 'gray-600', className: "mt-2 mb-6 text-center", children: description })] }), primaryLabel &&
8
8
  _jsx(Button, { onClick: () => onProceed?.(), label: primaryLabel, className: 'w-full my-3' }), secondaryLabel &&
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { motion } from 'framer-motion';
4
+ const LoadingAnimation = ({ height = 230, width = 250, }) => {
5
+ return (_jsxs("div", { style: {
6
+ height,
7
+ width,
8
+ display: 'flex',
9
+ alignItems: 'center',
10
+ justifyContent: 'center',
11
+ flexDirection: 'column',
12
+ gap: 16,
13
+ }, children: [_jsx(motion.div, { style: {
14
+ display: 'flex',
15
+ gap: 8,
16
+ alignItems: 'center',
17
+ justifyContent: 'center',
18
+ }, children: [0, 1, 2].map((i) => (_jsx(motion.div, { style: {
19
+ width: 12,
20
+ height: 12,
21
+ borderRadius: '50%',
22
+ backgroundColor: '#26C6DA',
23
+ }, animate: {
24
+ y: [0, -16, 0],
25
+ opacity: [0.5, 1, 0.5],
26
+ }, transition: {
27
+ duration: 0.8,
28
+ repeat: Infinity,
29
+ delay: i * 0.15,
30
+ ease: 'easeInOut',
31
+ } }, i))) }), _jsx(motion.div, { style: {
32
+ width: 120,
33
+ height: 4,
34
+ backgroundColor: '#E0E0E0',
35
+ borderRadius: 2,
36
+ overflow: 'hidden',
37
+ }, children: _jsx(motion.div, { style: {
38
+ width: '40%',
39
+ height: '100%',
40
+ backgroundColor: '#26C6DA',
41
+ borderRadius: 2,
42
+ }, animate: {
43
+ x: ['-100%', '250%'],
44
+ }, transition: {
45
+ duration: 1.2,
46
+ repeat: Infinity,
47
+ ease: 'easeInOut',
48
+ } }) })] }));
49
+ };
50
+ export { LoadingAnimation };
@@ -0,0 +1,7 @@
1
+ export const strongPasswordRequirements = [
2
+ { regex: /.{6,}/, text: "At least 6 characters" },
3
+ { regex: /[0-9]/, text: "At least 1 number" },
4
+ { regex: /[a-z]/, text: "At least 1 lowercase letter" },
5
+ { regex: /[A-Z]/, text: "At least 1 uppercase letter" },
6
+ { regex: /[!@#$%^&*()_+]/, text: "At least 1 special character" }
7
+ ];
@@ -23,6 +23,8 @@ const AuthPackageContext = React.createContext(null);
23
23
  * Wraps both AuthContext (public) and AuthPackageContext (internal).
24
24
  *
25
25
  * @param children - React children to be rendered inside the provider
26
+ * @param router - Router adapter for navigation in web apps only
27
+ * @param basePath - Base path for web routes where the auth module is mounted (default: '')
26
28
  * @param LogoComponent - Optional component for branding/logo in auth flows
27
29
  * @param session - Initial session containing token & sessionTimeout (if available)
28
30
  * @param supportEmail - Optional support email for auth flows
@@ -34,7 +36,7 @@ const AuthPackageContext = React.createContext(null);
34
36
  * @param openChatSupport - Optional callback to open chat support
35
37
  * @param socialLoginConfig - Optional social login configuration
36
38
  */
37
- const AuthProvider = ({ children, LogoComponent, session, appConfig, onLogin, onLogout, onLaunchAuthSession, onRefreshSession, openChatSupport, socialLoginConfig }) => {
39
+ const AuthProvider = ({ children, router, basePath = '', LogoComponent, session, appConfig, onLogin, onLogout, onLaunchAuthSession, onRefreshSession, openChatSupport, socialLoginConfig }) => {
38
40
  const [isLoadingProfile, setIsLoadingProfile] = useState(false);
39
41
  const [profile, setProfile] = useState(null);
40
42
  const [client, setClient] = useState(null);
@@ -168,6 +170,8 @@ const AuthProvider = ({ children, LogoComponent, session, appConfig, onLogin, on
168
170
  };
169
171
  const AuthPackageContextValues = {
170
172
  token,
173
+ router,
174
+ basePath,
171
175
  LogoComponent,
172
176
  appConfig: appConfigValue,
173
177
  registrationMethod,
@@ -0,0 +1,83 @@
1
+ import { useContext, useMemo } from 'react';
2
+ import { AuthPackageContext } from '../contexts/AuthContext';
3
+ /**
4
+ * useNavigator Hook
5
+ *
6
+ * Provides framework-agnostic navigation capabilities.
7
+ * Uses the RouterAdapter provided by the host app through AuthProvider.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * const navigator = useNavigator();
12
+ *
13
+ * // Relative navigation (uses basePath)
14
+ * navigator.push('/registration');
15
+ *
16
+ * // Absolute navigation (ignores basePath)
17
+ * navigator.pushAbsolute('/dashboard');
18
+ *
19
+ * // With query params
20
+ * navigator.push('/registration', { query: { email: 'test@example.com' } });
21
+ *
22
+ * // Access query params
23
+ * const { email } = navigator.query;
24
+ * ```
25
+ */
26
+ const useNavigator = () => {
27
+ const context = useContext(AuthPackageContext);
28
+ if (!context?.router) {
29
+ throw new Error('useNavigator: router not found in context. ' +
30
+ 'Make sure to wrap your component with AuthProvider and pass a router adapter.');
31
+ }
32
+ const { router, basePath = '' } = context;
33
+ const navigator = useMemo(() => ({
34
+ /**
35
+ * Navigate to a path relative to basePath
36
+ */
37
+ push: (path, options) => {
38
+ const fullPath = path.startsWith('/') ? `${basePath}${path}` : `${basePath}/${path}`;
39
+ router.push(fullPath, options);
40
+ },
41
+ /**
42
+ * Replace current path with a path relative to basePath
43
+ */
44
+ replace: (path, options) => {
45
+ const fullPath = path.startsWith('/') ? `${basePath}${path}` : `${basePath}/${path}`;
46
+ router.replace(fullPath, options);
47
+ },
48
+ /**
49
+ * Navigate to an absolute path (ignores basePath)
50
+ */
51
+ pushAbsolute: (path, options) => {
52
+ router.push(path, options);
53
+ },
54
+ /**
55
+ * Replace with an absolute path (ignores basePath)
56
+ */
57
+ replaceAbsolute: (path, options) => {
58
+ router.replace(path, options);
59
+ },
60
+ /**
61
+ * Go back to the previous page
62
+ */
63
+ back: () => router.back(),
64
+ /**
65
+ * Get current query parameters
66
+ */
67
+ get query() {
68
+ return router.getQuery();
69
+ },
70
+ /**
71
+ * Get current pathname
72
+ */
73
+ get pathname() {
74
+ return router.getPathname();
75
+ },
76
+ /**
77
+ * The base path where the auth module is mounted
78
+ */
79
+ basePath,
80
+ }), [router, basePath]);
81
+ return navigator;
82
+ };
83
+ export { useNavigator };
@@ -5,6 +5,7 @@ export * from './contexts/type';
5
5
  // export hooks
6
6
  export * from './hooks/useAuthContext';
7
7
  export * from './hooks/useRequest';
8
+ export * from './hooks/useNavigator';
8
9
  // export axiosClient
9
10
  export * from './api/axiosClient';
10
11
  // export navigator/router
@@ -13,3 +14,10 @@ export * from './navigator';
13
14
  export * from './screens/Login/components/LoginWebComponent/index';
14
15
  export * from './screens/SignUp/components/SignUpWebComponent/index';
15
16
  export * from './screens/SSOLogin/SSOCallback/components/SSOCallbackComponent/index';
17
+ // export partner SSO components
18
+ export * from './screens/PartnerSSO/PartnerLogin/components/PartnerLoginWebComponent';
19
+ export * from './screens/PartnerSSO/PartnerRegistration/components/PartnerRegistrationWebComponent';
20
+ // export profile components
21
+ export * from './screens/Profile';
22
+ // export constants
23
+ export { strongPasswordRequirements } from './constants/password-requirements';
@@ -1,5 +1,4 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import Image from 'next/image';
3
2
  import React, { useMemo } from "react";
4
3
  import { Typography, SelectField, Flex } from '@truworth/twc-web-design';
5
4
  import { useCountryCode } from '../../hooks/internal/useCountryCode';
@@ -22,10 +21,10 @@ export const CountryCodeDropdown = React.memo(({ selectedCountry, handleSelect }
22
21
  const code = item.countryCode.toLowerCase();
23
22
  const flagUrl = `https://cdn.thewellnesscorner.com/country-flags/${code}.png`;
24
23
  return {
25
- leftIcon: (_jsx(_Fragment, { children: isValidCountryCode(code) && (_jsx(Image, { src: flagUrl, width: 20, height: 20, className: "h-auto shrink-0", alt: `${item.name} flag`, loading: "lazy" })) })),
24
+ leftIcon: (_jsx(_Fragment, { children: isValidCountryCode(code) && (_jsx("img", { src: flagUrl, width: 20, height: 20, className: "h-5 w-5 shrink-0", alt: `${item.name} flag`, loading: "lazy" })) })),
26
25
  label: (_jsxs(Typography, { type: "body", size: "small", children: [item.name, " (+", item.phoneCode, ")"] })),
27
26
  value: code,
28
- selectedField: (_jsxs(Flex, { align: "center", className: "gap-2 pl-2 pr-2 cursor-pointer", children: [isValidCountryCode(code) && (_jsx(Image, { src: flagUrl, width: 20, height: 20, className: "h-auto shrink-0", alt: `${item.name} flag`, loading: "lazy" })), _jsx(Typography, { type: "body", size: "medium", className: "countryCode cursor-pointer", children: `+${item.phoneCode}` })] })),
27
+ selectedField: (_jsxs(Flex, { align: "center", className: "gap-2 pl-2 pr-2 cursor-pointer", children: [isValidCountryCode(code) && (_jsx("img", { src: flagUrl, width: 20, height: 20, className: "h-5 w-5 shrink-0", alt: `${item.name} flag`, loading: "lazy" })), _jsx(Typography, { type: "body", size: "medium", className: "countryCode cursor-pointer", children: `+${item.phoneCode}` })] })),
29
28
  };
30
29
  });
31
30
  }, [countries]);
@@ -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 isContinueDisabled = !Object.keys(criteria).every(c => criteria[c]) || (password !== confirmPassword);
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,19 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button, Flex, Form, PasswordInput, Typography, useForm } from "@truworth/twc-web-design";
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 form = useForm({
9
- defaultValues: {
10
- password: userDetails.password || '',
11
- confirmPassword: userDetails.confirmPassword || '',
12
- }
8
+ const { password, confirmPassword, handlePassword, handleConfirmPassword, passwordVisible, setPasswordVisible, confirmPasswordVisible, setConfirmPasswordVisible, criteria, setCriteria, maxLength, setMaxLength, handleSkip, isContinueDisabled } = useCreatePassword({
9
+ initialPassword: userDetails.password,
10
+ initialConfirmPassword: userDetails.confirmPassword,
13
11
  });
14
- const { password, confirmPassword } = form.watch();
15
- const { criteria, setCriteria, maxLength, setMaxLength, handleSkip, isContinueDisabled } = useCreatePassword();
16
12
  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: {
13
+ _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
14
  label: 'Continue',
19
15
  onClick: () => onContinue(password, confirmPassword),
20
16
  disabled: isContinueDisabled
21
- }, onPressBack: handleBack, children: _jsxs(Form, { form: form, className: 'w-full', children: [_jsx(Form.Item, { name: "password", label: "Enter Password", normalize: (value) => value.replace(/\s/g, ''), rules: [
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 }) })] }) }));
17
+ }, 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
18
  };
43
19
  export default CreatePassword;
@@ -23,7 +23,7 @@ const ExistingAccountsSheet = ({ visible, hide, phone, existingAccounts, onIniti
23
23
  };
24
24
  const displayPhone = phone ? `+91${phone.replace(/^.{8}/, 'XXXXXXXX')}` : '+91**********';
25
25
  return (_jsxs(ResponsiveModal, { open: visible, onClose: hide, onOpenChange: hide, maskClosable: false, title: _jsxs(_Fragment, { children: [_jsx(Typography, { type: "heading", size: "h6", children: "Multiple Accounts Found" }), _jsxs(Typography, { type: "utility", size: "medium", color: "gray-600", className: "mt-2 mb-3", children: ["The phone number ", displayPhone, " is linked to the following accounts."] }), _jsx("hr", {})] }), centered: true, showCloseButton: false, className: "px-0", footer: _jsxs(Flex, { direction: "column", className: 'pt-1', children: [_jsx(Flex, { className: "flex-1 border-t border-gray-300 mb-2" }), selectedAccount &&
26
- _jsxs(Flex, { align: 'center', className: 'bg-utility-warning-bg p-2 rounded-lg gap-1', children: [_jsx(IonIcon, { name: "information-circle-outline", style: { color: "hsl(var(--tw-ui-utility---warning--main))", fontSize: 24 } }), _jsxs(Typography, { type: "utility", size: "small", children: [_jsx("span", { className: "text-gray-500 text-[12px]", children: "Once you proceed, this phone number will be removed" }), " from other accounts."] })] }), _jsx(Button, { isFullWidth: true, loading: loading, variant: "primary", label: "Link and Continue", className: 'mt-4 mb-[-16px]', onClick: onContinue, disabled: !selectedAccount }), _jsx(SupportDetails, {})] }), children: [_jsx(Typography, { type: "utility", size: "medium", className: "mb-4", children: "Select account you want to continue with." }), existingAccounts.map((item) => {
26
+ _jsxs(Flex, { align: 'center', className: 'bg-utility-warning-bg p-2 rounded-lg gap-1', children: [_jsx(IonIcon, { name: "information-circle-outline", className: "text-utility-warning-main text-2xl" }), _jsxs(Typography, { type: "utility", size: "small", children: [_jsx("span", { className: "text-gray-500 text-[12px]", children: "Once you proceed, this phone number will be removed" }), " from other accounts."] })] }), _jsx(Button, { isFullWidth: true, loading: loading, variant: "primary", label: "Link and Continue", className: 'mt-4 mb-[-16px]', onClick: onContinue, disabled: !selectedAccount }), _jsx(SupportDetails, {})] }), children: [_jsx(Typography, { type: "utility", size: "medium", className: "mb-4", children: "Select account you want to continue with." }), existingAccounts.map((item) => {
27
27
  return (_jsx(OptionCard, { item: item, onClick: () => setSelectedAccount(item), selectedItem: selectedAccount }, item.memberId));
28
28
  })] }));
29
29
  };
@@ -37,7 +37,10 @@ const useEnterMobile = () => {
37
37
  if (!mobileExist) {
38
38
  onRegistrationMethodChange(RegistrationMethod.MOBILE);
39
39
  }
40
- onValidate({ mobileExist, email: linkedAccounts?.[0]?.email ?? '' });
40
+ onValidate({
41
+ mobileExist,
42
+ memberId: linkedAccounts?.[0]?.memberId ?? ''
43
+ });
41
44
  }
42
45
  catch (err) {
43
46
  const errorMessage = err?.response?.data?.errors?.[0]?.message ?? 'Something went wrong';
@@ -3,7 +3,7 @@ import { Flex, Form, ResponsiveModal, TextInput, Typography, useForm } from '@tr
3
3
  import { ScreenLayout } from "../../components/ScreenLayout";
4
4
  import { useEnterMobile } from "./hooks/internal/useEnterMobile";
5
5
  import { CountryCodeDropdown } from '../CountryCode/components/CountryCodeDropdown';
6
- import { useRouter } from 'next/router';
6
+ import { useNavigator } from '../../hooks/useNavigator';
7
7
  import { useState } from 'react';
8
8
  import { ExistingAccountsSheet } from './components/ExistingAccountsSheet';
9
9
  import LoginWithMobileOTP from '../LoginWithMobileOTP';
@@ -15,6 +15,7 @@ const EnterMobile = ({ onPressBack }) => {
15
15
  const [showVerifyLinkPrimaryEmailModal, setShowVerifyLinkPrimaryEmailModal] = useState(false);
16
16
  const [showVerifyLinkPrimaryMobileModal, setShowVerifyLinkPrimaryMobileModal] = useState(false);
17
17
  const [email, setEmail] = useState('');
18
+ const [memberId, setMemberId] = useState('');
18
19
  const [sessionToken, setSessionToken] = useState('');
19
20
  const [selectedCountry, setSelectedCountry] = useState({
20
21
  countryCode: "in",
@@ -22,18 +23,17 @@ const EnterMobile = ({ onPressBack }) => {
22
23
  name: "INDIA",
23
24
  });
24
25
  const form = useForm();
25
- const router = useRouter();
26
+ const navigator = useNavigator();
26
27
  const { loading, phone, isValidPhone, countryCode, setCountryCode, existingAccounts, showExistingAccountsSheet, setShowExistingAccountsSheet, handleValidatePhone, handleEnterMobile, } = useEnterMobile();
27
28
  const handleSubmit = () => {
28
29
  handleValidatePhone({
29
- onValidate: ({ mobileExist, email }) => {
30
- if (mobileExist && email) {
31
- setEmail(email);
30
+ onValidate: ({ mobileExist, memberId }) => {
31
+ if (mobileExist && memberId) {
32
+ setMemberId(memberId);
32
33
  setShowLoginWithMobileOTPModal(true);
33
34
  }
34
35
  else {
35
- router.push({
36
- pathname: '/registration',
36
+ navigator.pushAbsolute('/registration', {
37
37
  query: { phone, registrationMethod: RegistrationMethod.MOBILE }
38
38
  });
39
39
  }
@@ -56,7 +56,7 @@ const EnterMobile = ({ onPressBack }) => {
56
56
  setCountryCode(country.phoneCode);
57
57
  setSelectedCountry(country);
58
58
  } }) }) }) }) }), showLoginWithMobileOTPModal &&
59
- _jsx(LoginWithMobileOTPModal, { email: email, phone: phone, show: showLoginWithMobileOTPModal, hide: () => setShowLoginWithMobileOTPModal(false) }), showExistingAccountsSheet &&
59
+ _jsx(LoginWithMobileOTPModal, { memberId: memberId, phone: phone, show: showLoginWithMobileOTPModal, hide: () => setShowLoginWithMobileOTPModal(false) }), showExistingAccountsSheet &&
60
60
  _jsx(ExistingAccountsSheet, { phone: phone, visible: showExistingAccountsSheet, existingAccounts: existingAccounts, onInitiateAccountLinking: ({ sessionToken, email }) => {
61
61
  setSessionToken(sessionToken);
62
62
  setEmail(email);
@@ -76,7 +76,7 @@ const VerifyLinkPrimaryAccountEmailOTPModal = ({ show, hide, email, sessionToken
76
76
  const VerifyLinkPrimaryAccountMobileOTPModal = ({ show, hide, phone, sessionToken }) => {
77
77
  return (_jsx(ResponsiveModal, { title: "Verify Mobile Number", open: show, onClose: hide, maskClosable: false, showCloseButton: false, size: 'sm', children: _jsx(VerifyLinkPrimaryAccountMobileOTP, { phone: phone, sessionToken: sessionToken }) }));
78
78
  };
79
- const LoginWithMobileOTPModal = ({ show, hide, email, phone }) => {
80
- return (_jsx(ResponsiveModal, { open: show, onClose: hide, title: _jsx(Typography, { type: "heading", size: "h6", className: "text-center mb-0", children: "Verify Mobile Number" }), showCloseButton: false, maskClosable: false, size: 'sm', children: _jsx(LoginWithMobileOTP, { phone: phone, email: email }) }));
79
+ const LoginWithMobileOTPModal = ({ show, hide, memberId, phone }) => {
80
+ return (_jsx(ResponsiveModal, { open: show, onClose: hide, title: _jsx(Typography, { type: "heading", size: "h6", className: "text-center mb-0", children: "Verify Mobile Number" }), showCloseButton: false, maskClosable: false, size: 'sm', children: _jsx(LoginWithMobileOTP, { phone: phone, memberId: memberId }) }));
81
81
  };
82
82
  export default EnterMobile;
@@ -23,11 +23,11 @@ const EnterMobile = ({ navigation }) => {
23
23
  const handleSubmit = () => {
24
24
  Keyboard.dismiss();
25
25
  handleValidatePhone({
26
- onValidate: ({ mobileExist, email }) => {
27
- if (mobileExist && email) {
26
+ onValidate: ({ mobileExist, memberId }) => {
27
+ if (mobileExist && memberId) {
28
28
  navigation.navigate('LoginWithMobileOTP', {
29
29
  phone,
30
- email
30
+ memberId
31
31
  });
32
32
  }
33
33
  else {
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useState } from 'react';
3
3
  import { Flex } from '@truworth/twc-web-design';
4
- import { useRouter } from 'next/router';
5
4
  import { AdvancedTransitionWrapper } from '../../../../components/AdvancedTransitionWrapper';
6
5
  import { useAuthPackageContext } from '../../../../hooks/internal/useAuthPackageContext';
6
+ import { useNavigator } from '../../../../hooks/useNavigator';
7
7
  import EnterEmail from '../../../EnterEmail/index';
8
8
  import EnterPassword from '../../../EnterPassword/index';
9
9
  import ResetPassword from '../../../ResetPassword/index';
@@ -16,14 +16,13 @@ const LoginWebComponent = () => {
16
16
  const [sessionToken, setSessionToken] = useState('');
17
17
  const [selectedClient, setSelectedClient] = useState(null);
18
18
  const { LogoComponent } = useAuthPackageContext();
19
- const router = useRouter();
19
+ const navigator = useNavigator();
20
20
  const onRedirectToPassword = (email) => {
21
21
  setEmail(email);
22
22
  setLoginState('EnterPassword');
23
23
  };
24
24
  const onRedirectToSignUp = (email) => {
25
- router.push({
26
- pathname: '/registration',
25
+ navigator.pushAbsolute('/registration', {
27
26
  query: { email, registrationMethod: 'email' }
28
27
  });
29
28
  };
@@ -3,7 +3,7 @@ import { useAuthPackageContext } from "../../../../hooks/internal/useAuthPackage
3
3
  import { axiosClient } from "../../../../api/axiosClient";
4
4
  import { useInterval } from "../../../../hooks/internal/useTimer";
5
5
  import { showMessage } from "../../../../helpers/show-message";
6
- const useLoginWithMobileOTP = ({ phone, email, source }) => {
6
+ const useLoginWithMobileOTP = ({ phone, source, memberId }) => {
7
7
  const [timer, setTimer] = useState(180);
8
8
  const [status, setStatus] = useState('timer');
9
9
  const [sessionToken, setSessionToken] = useState('');
@@ -19,7 +19,7 @@ const useLoginWithMobileOTP = ({ phone, email, source }) => {
19
19
  axiosClient({
20
20
  url: '/auth/login/mobile/v2',
21
21
  method: 'POST',
22
- data: { phone, email, source },
22
+ data: { phone, source, memberId },
23
23
  }).then((res) => {
24
24
  setSessionToken(res.data.sessionToken);
25
25
  setStatus('timer');
@@ -28,7 +28,7 @@ const useLoginWithMobileOTP = ({ phone, email, source }) => {
28
28
  console.log(err);
29
29
  showMessage({ message: err.response.data.errors[0].message || "Verification failed" });
30
30
  });
31
- }, [phone, email, source]);
31
+ }, [phone, source, memberId]);
32
32
  const verifyOtp = useCallback((otp) => {
33
33
  if (!sessionToken) {
34
34
  showMessage({ message: "Session expired. Please resend OTP." });
@@ -58,10 +58,10 @@ const useLoginWithMobileOTP = ({ phone, email, source }) => {
58
58
  });
59
59
  }, [sessionToken]);
60
60
  useEffect(() => {
61
- if (email && source) {
61
+ if (memberId && phone && source) {
62
62
  sendOtp();
63
63
  }
64
- }, [email, source, sendOtp]);
64
+ }, [memberId, phone, source, sendOtp]);
65
65
  return {
66
66
  timer,
67
67
  status,
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { VerifyMobileOTP } from '../../components/VerifyMobileOTP';
3
3
  import { useLoginWithMobileOTP } from './hooks/internal/useLoginWithMobileOTP';
4
- const LoginWithMobileOTP = ({ phone, email }) => {
5
- const { timer, status, verifyOtp, sendOtp, } = useLoginWithMobileOTP({ phone, email, source: 'web' });
4
+ const LoginWithMobileOTP = ({ phone, memberId }) => {
5
+ const { timer, status, verifyOtp, sendOtp, } = useLoginWithMobileOTP({ phone, memberId, source: 'web' });
6
6
  return (_jsx(VerifyMobileOTP, { timer: timer, phone: phone, status: status, validateOTP: verifyOtp, resendOTP: sendOtp }));
7
7
  };
8
8
  export default LoginWithMobileOTP;
@@ -3,8 +3,8 @@ import { VerifyMobileOTP } from '../../components/VerifyMobileOTP';
3
3
  import { useLoginWithMobileOTP } from './hooks/internal/useLoginWithMobileOTP';
4
4
  import { Platform } from 'react-native';
5
5
  const LoginWithMobileOTP = ({ route }) => {
6
- const { phone, email } = route.params;
7
- const { timer, status, verifyOtp, sendOtp, } = useLoginWithMobileOTP({ phone, email, source: Platform.OS });
6
+ const { phone, memberId } = route.params;
7
+ const { timer, status, verifyOtp, sendOtp, } = useLoginWithMobileOTP({ phone, memberId, source: Platform.OS });
8
8
  return (_jsx(VerifyMobileOTP, { timer: timer, phone: phone, status: status, validateOTP: verifyOtp, resendOTP: sendOtp }));
9
9
  };
10
10
  export default LoginWithMobileOTP;