@truworth/twc-auth 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.md +1 -4
  2. package/build/assets/loading-spinner.json +1 -0
  3. package/build/src/api/auth.js +36 -0
  4. package/build/src/api/axiosClient/index.js +1 -1
  5. package/build/src/api/axiosClient/index.native.js +1 -1
  6. package/build/src/components/ScreenLayout/index.native.js +2 -2
  7. package/build/src/components/VerifyEmailOTP/index.native.js +14 -11
  8. package/build/src/components/VerifyMobileOTP/index.js +8 -6
  9. package/build/src/components/VerifyMobileOTP/index.native.js +6 -11
  10. package/build/src/constants/base-url/index.js +5 -0
  11. package/build/src/constants/base-url/index.native.js +1 -0
  12. package/build/src/constants/cdn-url/index.js +2 -1
  13. package/build/src/contexts/AuthContext.js +4 -2
  14. package/build/src/enums/index.js +2 -0
  15. package/build/src/enums/loginMethod.enum.js +8 -0
  16. package/build/src/enums/registrationMethod.enum.js +7 -0
  17. package/build/src/index.js +3 -2
  18. package/build/src/navigator/index.native.js +9 -1
  19. package/build/src/screens/EnterEmail/hooks/internal/useEnterEmail.js +58 -66
  20. package/build/src/screens/EnterEmail/index.js +11 -15
  21. package/build/src/screens/EnterEmail/index.native.js +14 -17
  22. package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/hooks/internal/useExistingAccountsSheet.js +36 -0
  23. package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/index.js +33 -0
  24. package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/index.native.js +73 -0
  25. package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/types.js +1 -0
  26. package/build/src/screens/EnterMobile/hooks/internal/useEnterMobile.js +67 -0
  27. package/build/src/screens/EnterMobile/index.js +82 -0
  28. package/build/src/screens/EnterMobile/index.native.js +56 -0
  29. package/build/src/screens/EnterMobile/types.js +1 -0
  30. package/build/src/screens/EnterPassword/hooks/internal/useEnterPassword.js +42 -31
  31. package/build/src/screens/EnterPassword/index.js +17 -8
  32. package/build/src/screens/EnterPassword/index.native.js +5 -10
  33. package/build/src/screens/Login/components/LoginWebComponent/index.js +19 -15
  34. package/build/src/screens/LoginWithEmailOTP/hooks/internal/useLoginWithEmailOTP.js +8 -5
  35. package/build/src/screens/LoginWithMobileOTP/hooks/internal/useLoginWithMobileOTP.js +71 -0
  36. package/build/src/screens/LoginWithMobileOTP/index.js +8 -0
  37. package/build/src/screens/LoginWithMobileOTP/index.native.js +10 -0
  38. package/build/src/screens/SSOLogin/AuthWebView/index.js +9 -0
  39. package/build/src/screens/SSOLogin/AuthWebView/index.native.js +27 -0
  40. package/build/src/screens/SSOLogin/AuthWebView/types.js +1 -0
  41. package/build/src/screens/SSOLogin/AuthenticationMethods/hooks/internal/useSSOAuthenticationMethods.js +38 -0
  42. package/build/src/screens/SSOLogin/AuthenticationMethods/index.js +49 -0
  43. package/build/src/screens/SSOLogin/AuthenticationMethods/index.native.js +54 -0
  44. package/build/src/screens/SSOLogin/AuthenticationMethods/types.js +1 -0
  45. package/build/src/screens/SSOLogin/SSOCallback/components/SSOCallbackComponent/index.js +59 -0
  46. package/build/src/screens/SSOLogin/SSOCallback/components/SSOCallbackComponent/index.native.js +6 -0
  47. package/build/src/screens/SSOLogin/SSOCallback/hooks/internal/useSSOCallback.js +42 -0
  48. package/build/src/screens/SSOLogin/SSOCallback/index.js +9 -0
  49. package/build/src/screens/SSOLogin/SSOCallback/index.native.js +35 -0
  50. package/build/src/screens/SSOLogin/SSOCallback/types.js +1 -0
  51. package/build/src/screens/SSOLogin/SearchOrganization/hooks/internal/useSSOSearchOrganization.js +71 -0
  52. package/build/src/screens/SSOLogin/SearchOrganization/index.js +46 -0
  53. package/build/src/screens/SSOLogin/SearchOrganization/index.native.js +37 -0
  54. package/build/src/screens/SSOLogin/SearchOrganization/types.js +1 -0
  55. package/build/src/screens/SignUp/components/SignUpForm/index.js +109 -68
  56. package/build/src/screens/SignUp/components/SignUpWebComponent/index.js +22 -53
  57. package/build/src/screens/SignUp/hooks/internal/useSignUp.js +77 -81
  58. package/build/src/screens/SignUp/index.native.js +90 -90
  59. package/build/src/screens/UserConsent/hooks/internal/useConsent.js +10 -3
  60. package/build/src/screens/UserConsent/index.js +39 -19
  61. package/build/src/screens/UserConsent/index.native.js +1 -1
  62. package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/hooks/internal/useVerifyLinkPrimaryAccountEmailOTP.js +73 -0
  63. package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/index.js +8 -0
  64. package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/index.native.js +14 -0
  65. package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/types.js +1 -0
  66. package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/hooks/internal/useVerifyLinkPrimaryAccountMobileOTP.js +82 -0
  67. package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/index.js +8 -0
  68. package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/index.native.js +10 -0
  69. package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/types.js +1 -0
  70. package/build/src/screens/VerifyMobile/hooks/internal/useVerifyMobile.js +2 -2
  71. package/build/src/screens/Welcome/index.js +5 -5
  72. package/build/src/screens/Welcome/index.native.js +1 -1
  73. package/build/src/types/types.js +1 -1
  74. package/build/types/api/auth.d.ts +11 -0
  75. package/build/types/components/ScreenLayout/index.native.d.ts +1 -1
  76. package/build/types/components/ScreenLayout/types.d.ts +1 -0
  77. package/build/types/components/VerifyMobileOTP/index.d.ts +1 -1
  78. package/build/types/components/VerifyMobileOTP/types.d.ts +0 -1
  79. package/build/types/constants/base-url/index.d.ts +1 -0
  80. package/build/types/constants/base-url/index.native.d.ts +1 -0
  81. package/build/types/constants/cdn-url/index.d.ts +2 -1
  82. package/build/types/contexts/AuthContext.d.ts +2 -1
  83. package/build/types/contexts/type.d.ts +3 -0
  84. package/build/types/enums/index.d.ts +2 -0
  85. package/build/types/enums/loginMethod.enum.d.ts +7 -0
  86. package/build/types/enums/registrationMethod.enum.d.ts +6 -0
  87. package/build/types/index.d.ts +3 -2
  88. package/build/types/navigator/index.native.d.ts +28 -1
  89. package/build/types/screens/EnterEmail/hooks/internal/useEnterEmail.d.ts +11 -15
  90. package/build/types/screens/EnterEmail/index.d.ts +2 -6
  91. package/build/types/screens/EnterEmail/types.d.ts +13 -0
  92. package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/hooks/internal/useExistingAccountsSheet.d.ts +13 -0
  93. package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/index.d.ts +3 -0
  94. package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/index.native.d.ts +3 -0
  95. package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/types.d.ts +28 -0
  96. package/build/types/screens/EnterMobile/hooks/internal/useEnterMobile.d.ts +15 -0
  97. package/build/types/screens/EnterMobile/index.d.ts +4 -0
  98. package/build/types/screens/EnterMobile/index.native.d.ts +4 -0
  99. package/build/types/screens/EnterMobile/types.d.ts +44 -0
  100. package/build/types/screens/EnterPassword/hooks/internal/useEnterPassword.d.ts +8 -8
  101. package/build/types/screens/EnterPassword/index.d.ts +1 -1
  102. package/build/types/screens/EnterPassword/types.d.ts +6 -2
  103. package/build/types/screens/LoginWithEmailOTP/hooks/internal/useLoginWithEmailOTP.d.ts +1 -1
  104. package/build/types/screens/LoginWithMobileOTP/hooks/internal/useLoginWithMobileOTP.d.ts +11 -0
  105. package/build/types/screens/LoginWithMobileOTP/index.d.ts +5 -0
  106. package/build/types/screens/LoginWithMobileOTP/index.native.d.ts +4 -0
  107. package/build/types/screens/SSOLogin/AuthWebView/index.d.ts +2 -0
  108. package/build/types/screens/SSOLogin/AuthWebView/index.native.d.ts +4 -0
  109. package/build/types/screens/SSOLogin/AuthWebView/types.d.ts +8 -0
  110. package/build/types/screens/SSOLogin/AuthenticationMethods/hooks/internal/useSSOAuthenticationMethods.d.ts +9 -0
  111. package/build/types/screens/SSOLogin/AuthenticationMethods/index.d.ts +3 -0
  112. package/build/types/screens/SSOLogin/AuthenticationMethods/index.native.d.ts +4 -0
  113. package/build/types/screens/SSOLogin/AuthenticationMethods/types.d.ts +12 -0
  114. package/build/types/screens/SSOLogin/SSOCallback/components/SSOCallbackComponent/index.d.ts +2 -0
  115. package/build/types/screens/SSOLogin/SSOCallback/components/SSOCallbackComponent/index.native.d.ts +2 -0
  116. package/build/types/screens/SSOLogin/SSOCallback/hooks/internal/useSSOCallback.d.ts +11 -0
  117. package/build/types/screens/SSOLogin/SSOCallback/index.d.ts +2 -0
  118. package/build/types/screens/SSOLogin/SSOCallback/index.native.d.ts +4 -0
  119. package/build/types/screens/SSOLogin/SSOCallback/types.d.ts +11 -0
  120. package/build/types/screens/SSOLogin/SearchOrganization/hooks/internal/useSSOSearchOrganization.d.ts +18 -0
  121. package/build/types/screens/SSOLogin/SearchOrganization/index.d.ts +3 -0
  122. package/build/types/screens/SSOLogin/SearchOrganization/index.native.d.ts +4 -0
  123. package/build/types/screens/SSOLogin/SearchOrganization/types.d.ts +13 -0
  124. package/build/types/screens/SignUp/components/SignUpForm/index.d.ts +1 -1
  125. package/build/types/screens/SignUp/components/SignUpForm/type.d.ts +1 -4
  126. package/build/types/screens/SignUp/components/SignUpWebComponent/types.d.ts +1 -16
  127. package/build/types/screens/SignUp/hooks/internal/useSignUp.d.ts +16 -18
  128. package/build/types/screens/SignUp/types.d.ts +29 -7
  129. package/build/types/screens/UserConsent/hooks/internal/useConsent.d.ts +1 -1
  130. package/build/types/screens/UserConsent/index.d.ts +1 -1
  131. package/build/types/screens/UserConsent/types.d.ts +19 -13
  132. package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/hooks/internal/useVerifyLinkPrimaryAccountEmailOTP.d.ts +15 -0
  133. package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/index.d.ts +3 -0
  134. package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/index.native.d.ts +4 -0
  135. package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/types.d.ts +14 -0
  136. package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/hooks/internal/useVerifyLinkPrimaryAccountMobileOTP.d.ts +17 -0
  137. package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/index.d.ts +3 -0
  138. package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/index.native.d.ts +4 -0
  139. package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/types.d.ts +5 -0
  140. package/build/types/types/types.d.ts +16 -2
  141. package/package.json +6 -8
  142. package/build/types/screens/Login/components/LoginWebComponent/types.d.ts +0 -6
  143. /package/build/src/screens/{Login/components/LoginWebComponent → EnterEmail}/types.js +0 -0
@@ -1,44 +1,85 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import Image from "next/image";
3
2
  import React, { useEffect, useState } from "react";
4
- import { CDN_IMAGES_URL } from "@truworth/twc-web-common";
3
+ import { CDN_IMAGES_URL } from "../../../../constants/cdn-url";
5
4
  import { Button, Col, CustomCheckbox, DatePicker, Flex, Form, RadioGroup, ResponsiveModal, Row, TextInput, Typography, useForm, validationPatterns } from "@truworth/twc-web-design";
6
5
  import { CalendarDays } from "lucide-react";
7
6
  import { SupportDetails } from "../../../../components/SupportDetails";
8
7
  import { ScreenLayout } from "../../../../components/ScreenLayout";
9
8
  import { CountryCodeDropdown } from "../../../CountryCode/components/CountryCodeDropdown";
10
9
  import { useSignUp } from "../../hooks/internal/useSignUp";
10
+ import { useRouter } from "next/router";
11
11
  import ReCAPTCHA from 'react-google-recaptcha';
12
12
  import moment from "moment";
13
13
  import dayjs from 'dayjs';
14
+ import { RegistrationMethod } from "../../../../enums";
15
+ import { showMessage } from "../../../../helpers/show-message";
16
+ const getQueryParam = (param) => {
17
+ if (Array.isArray(param))
18
+ return param[0];
19
+ return param;
20
+ };
14
21
  const isProduction = process.env.NODE_ENV === 'production';
15
- const SignUpFormComponent = ({ email, registrationMethod, userDetails, onContinue, onGoToLogin }) => {
22
+ const SignUpFormComponent = ({ userDetails, onContinue }) => {
16
23
  const [isHuman, setIsHuman] = useState(isProduction ? false : true);
17
24
  const [termsAndConditions, setTermsAndConditions] = useState(false);
18
- const [selectedCountry, setSelectedCountry] = useState({
19
- countryCode: "in",
20
- phoneCode: "91",
21
- name: "INDIA",
22
- });
25
+ const [selectedCountry, setSelectedCountry] = useState({ countryCode: "in", phoneCode: "91", name: "INDIA" });
26
+ const router = useRouter();
23
27
  const form = useForm({
24
28
  liveValidation: true,
25
29
  defaultValues: {
26
30
  firstName: userDetails.firstName ?? "",
27
31
  lastName: userDetails.lastName ?? "",
28
32
  dateOfBirth: userDetails.selectedDOB,
33
+ email: userDetails.email ?? "",
29
34
  phone: userDetails.phone ?? "",
30
35
  gender: userDetails.gender ?? "",
31
36
  referralCode: userDetails.referralCode ?? "",
32
37
  }
33
38
  });
34
39
  const values = form.watch();
35
- const { loading, setGender, setSelectedDOB, phone, setPhone, setEmail, setReferralCode, setCountryCode, countryCode, setIsPhoneValid, existingAccounts, existingAccountModal, setExistingAccountModal, onFirstName, onLastName, handleSubmit, getLoginTypeText, appName, termsAndConditionsUrl, } = useSignUp();
36
40
  useEffect(() => {
37
- if (values.phone) {
38
- setPhone(values.phone);
39
- setEmail(email);
41
+ const rawMethod = router.query.registrationMethod;
42
+ const registrationMethodFromQuery = Array.isArray(rawMethod) ? rawMethod[0] : rawMethod;
43
+ if (typeof registrationMethodFromQuery === 'string') {
44
+ const method = registrationMethodFromQuery.toLowerCase();
45
+ // Validate that method is a valid RegistrationMethod value
46
+ const validMethods = Object.values(RegistrationMethod);
47
+ if (!validMethods.includes(method)) {
48
+ showMessage({ message: `Invalid registration method: ${method}` });
49
+ return;
50
+ }
51
+ onRegistrationMethodChange(method);
52
+ }
53
+ }, [router.query.registrationMethod]);
54
+ const { loading, setGender, setSelectedDOB, phone, setPhone, email, setEmail, setReferralCode, setCountryCode, countryCode, linkedAccounts, registrationMethod, onRegistrationMethodChange, linkedAccountsSheet, showLinkedAccountsSheet, handleFirstNameChange, handleLastNameChange, handleEmailChange, handleMobileChange, handleSubmit, getLoginTypeText, appName, termsAndConditionsUrl } = useSignUp();
55
+ useEffect(() => {
56
+ if (!registrationMethod) {
57
+ const registrationMethodFromQuery = router.query.registrationMethod;
58
+ if (typeof registrationMethodFromQuery === 'string') {
59
+ const method = registrationMethodFromQuery.toLowerCase();
60
+ onRegistrationMethodChange(method);
61
+ }
62
+ }
63
+ ;
64
+ }, [registrationMethod]);
65
+ useEffect(() => {
66
+ if (router.query.registrationToken) {
67
+ form.reset({
68
+ firstName: getQueryParam(router.query.firstName) ?? userDetails.firstName,
69
+ lastName: getQueryParam(router.query.lastName) ?? userDetails.lastName,
70
+ });
71
+ }
72
+ }, []);
73
+ useEffect(() => {
74
+ if (values.phone || values.email) {
75
+ if (registrationMethod === RegistrationMethod.MOBILE) {
76
+ setEmail(values.email);
77
+ }
78
+ else {
79
+ setPhone(values.phone);
80
+ }
40
81
  }
41
- }, [values.phone]);
82
+ }, [values.phone, values.email, registrationMethod]);
42
83
  const disabledDate = (current) => {
43
84
  const currentDate = dayjs(current);
44
85
  if (!currentDate.isValid()) {
@@ -51,38 +92,36 @@ const SignUpFormComponent = ({ email, registrationMethod, userDetails, onContinu
51
92
  const handleCaptcha = (value) => {
52
93
  setIsHuman(Boolean(value));
53
94
  };
54
- const enterMobile = (text) => {
55
- const digits = String(text).replace(/\D/g, '');
56
- setPhone(digits);
57
- if (countryCode === "91") {
58
- setIsPhoneValid(/^\d{10}$/.test(digits));
59
- }
60
- else {
61
- setIsPhoneValid(digits.length > 5);
62
- }
95
+ const onGoToLogin = () => {
96
+ router.push('/login');
97
+ };
98
+ const onProceed = () => {
99
+ const params = {
100
+ firstName: values.firstName,
101
+ lastName: values.lastName,
102
+ gender: values.gender,
103
+ selectedDOB: values.dateOfBirth,
104
+ referralCode: values.referralCode,
105
+ email: email.length > 0 ? email : getQueryParam(router.query.email) || '',
106
+ phone: phone.length > 0 ? phone : getQueryParam(router.query.phone) || '',
107
+ countryCode,
108
+ };
109
+ onContinue(params);
63
110
  };
111
+ const isMobileRegistration = registrationMethod === RegistrationMethod.MOBILE;
112
+ const isDisabled = !values.firstName
113
+ || !values.lastName
114
+ || !values.gender
115
+ || !values.dateOfBirth
116
+ || (!isMobileRegistration && !values.phone)
117
+ || !termsAndConditions
118
+ || !isHuman;
64
119
  return (_jsxs(_Fragment, { children: [_jsx(ScreenLayout, { title: "Looks like you're new here!", subTitle: "Tell us more about you so we can set up your account.", buttonProps: {
65
120
  loading,
66
121
  label: 'Continue',
67
- onClick: () => {
68
- handleSubmit({
69
- onResult: () => {
70
- onContinue({
71
- firstName: values.firstName,
72
- lastName: values.lastName,
73
- gender: values.gender,
74
- selectedDOB: values.dateOfBirth,
75
- referralCode: values.referralCode,
76
- email: email,
77
- phone,
78
- countryCode,
79
- registrationMethod,
80
- });
81
- }
82
- });
83
- },
84
- disabled: !values.firstName || !values.lastName || !values.gender || !values.dateOfBirth || !values.phone || !termsAndConditions || !isHuman
85
- }, onPressBack: onGoToLogin, children: _jsxs(Form, { form: form, className: "w-full", onSubmit: () => { }, children: [_jsxs(Row, { gutter: 18, className: "py-0 my-0", children: [_jsx(Col, { xs: 24, md: 12, children: _jsx(Form.Item, { label: "First Name", className: 'mt-5', rules: [
122
+ onClick: () => { handleSubmit({ onProceed }); },
123
+ disabled: isDisabled
124
+ }, onPressBack: onGoToLogin, children: _jsxs(Form, { form: form, className: "w-full", children: [_jsxs(Row, { gutter: 18, className: "py-0 my-0", children: [_jsx(Col, { xs: 24, md: 12, children: _jsx(Form.Item, { label: "First Name", rules: [
86
125
  {
87
126
  required: true,
88
127
  message: 'Please enter your first name'
@@ -99,8 +138,8 @@ const SignUpFormComponent = ({ email, registrationMethod, userDetails, onContinu
99
138
  },
100
139
  },
101
140
  ], normalize: (value) => (value ?? '').replace(/[^a-zA-Z]/g, ''), ...form.register('firstName', {
102
- onChange: (e) => onFirstName(e.target.value)
103
- }), children: _jsx(TextInput, { placeholder: "Enter your first name" }) }) }), _jsx(Col, { xs: 24, md: 12, children: _jsx(Form.Item, { label: "Last Name", className: 'mt-5', rules: [
141
+ onChange: (e) => handleFirstNameChange(e.target.value)
142
+ }), children: _jsx(TextInput, { placeholder: "Enter your first name" }) }) }), _jsx(Col, { xs: 24, md: 12, children: _jsx(Form.Item, { label: "Last Name", rules: [
104
143
  {
105
144
  required: true,
106
145
  message: 'Please enter your last name'
@@ -117,8 +156,8 @@ const SignUpFormComponent = ({ email, registrationMethod, userDetails, onContinu
117
156
  },
118
157
  },
119
158
  ], normalize: (value) => (value ?? '').replace(/[^a-zA-Z]/g, ''), ...form.register('lastName', {
120
- onChange: (e) => onLastName(e.target.value)
121
- }), children: _jsx(TextInput, { placeholder: "Enter your last name" }) }) })] }), _jsxs(Row, { gutter: 18, className: "py-0 mt-4 relative", children: [_jsx(Col, { xs: 18, md: 19, children: _jsx(Typography, { type: "body", size: "large", className: "text-gray-700", children: "Your biological sex at the time of birth" }) }), _jsxs(Col, { xs: 6, md: 5, className: "flex justify-end group", children: [_jsx(Typography, { type: "body", size: "large", className: "text-primary cursor-pointer whitespace-nowrap", children: "Know More" }), _jsxs(Flex, { className: "hidden group-hover:block w-full absolute left-2 top-6 rounded-md p-4 z-10 text-gray-950 bg-white shadow-[0_0_10px_0_rgba(0,0,0,0.3)]", children: [_jsxs(Flex, { className: "p-0 mb-3 gap-3", children: [_jsx(Image, { src: `${CDN_IMAGES_URL}/registration/gender-diversity.svg`, alt: "gender diversity", width: 44, height: 44, className: "h-auto" }), _jsxs(Typography, { type: "body", size: "large", className: "text-gray-800", children: ["The ", appName, " respects Gender Diversity & Inclusion!"] })] }), _jsxs(Typography, { type: "body", size: "small", className: "text-gray-500", children: [appName, " aims to provide you with a personalized wellness experience. This requires us to incorporate certain algorithms based on protocols provided by established health & medical institutions around the world. These protocols are based on your biological sex at birth."] })] })] })] }), _jsx(Row, { className: "py-0 mb-5", children: _jsx(Col, { children: _jsx(Form.Item, { className: "mt-4", rules: [
159
+ onChange: (e) => handleLastNameChange(e.target.value)
160
+ }), children: _jsx(TextInput, { placeholder: "Enter your last name" }) }) })] }), _jsxs(Row, { gutter: 18, className: "py-0 mt-4 relative", children: [_jsx(Col, { xs: 18, md: 19, children: _jsx(Typography, { type: "body", size: "large", className: "text-gray-700", children: "Your biological sex at the time of birth" }) }), _jsxs(Col, { xs: 6, md: 5, className: "flex justify-end group", children: [_jsx(Typography, { type: "body", size: "large", className: "text-primary cursor-pointer whitespace-nowrap", children: "Know More" }), _jsxs(Flex, { className: "hidden group-hover:block w-full absolute left-2 top-6 rounded-md p-4 z-10 text-gray-950 bg-white shadow-[0_0_10px_0_rgba(0,0,0,0.3)]", children: [_jsxs(Flex, { className: "p-0 mb-3 gap-3", children: [_jsx("img", { src: `${CDN_IMAGES_URL}/registration/gender-diversity.svg`, alt: "gender diversity", width: 44, height: 44, className: "h-auto" }), _jsxs(Typography, { type: "body", size: "large", className: "text-gray-800", children: ["The ", appName, " respects Gender Diversity & Inclusion!"] })] }), _jsxs(Typography, { type: "body", size: "small", className: "text-gray-500", children: [appName, " aims to provide you with a personalized wellness experience. This requires us to incorporate certain algorithms based on protocols provided by established health & medical institutions around the world. These protocols are based on your biological sex at birth."] })] })] })] }), _jsx(Row, { className: "py-0 mb-5", children: _jsx(Col, { children: _jsx(Form.Item, { className: "mt-4", rules: [
122
161
  {
123
162
  required: true,
124
163
  message: 'Please select your biological sex'
@@ -128,7 +167,7 @@ const SignUpFormComponent = ({ email, registrationMethod, userDetails, onContinu
128
167
  }), children: _jsx(RadioGroup, { orientation: "horizontal", options: [
129
168
  { label: 'Male', value: 'M' },
130
169
  { label: 'Female', value: 'F' },
131
- ] }) }) }) }), _jsxs(Row, { gutter: 18, className: "py-0 my-5", children: [_jsx(Col, { xs: 24, md: 24, lg: 12, children: _jsx(Form.Item, { label: "Date of Birth", rules: [
170
+ ] }) }) }) }), _jsxs(Row, { gutter: 18, className: "py-0 my-5", children: [_jsx(Col, { xs: 24, md: 24, lg: !isMobileRegistration ? 12 : 24, children: _jsx(Form.Item, { label: "Date of Birth", rules: [
132
171
  {
133
172
  required: true,
134
173
  message: 'Please select your date of birth'
@@ -137,35 +176,37 @@ const SignUpFormComponent = ({ email, registrationMethod, userDetails, onContinu
137
176
  onChange: (value, dateString) => setSelectedDOB(dateString ?? (value?.toISOString ? value.toISOString() : String(value)))
138
177
  }), children: _jsx(DatePicker, { required: true, size: "middle", format: "dd/MM/yyyy", placeholder: "DD/MM/YYYY",
139
178
  /* @ts-ignore */
140
- disabledDate: disabledDate, iconPosition: "right", defaultPickerValue: dayjs('1990-01-01').toDate(), suffixIcon: _jsx(CalendarDays, { className: "-mt-2" }) }) }) }), _jsx(Col, { xs: 24, md: 24, lg: 12, children: _jsx(Form.Item, { label: "Mobile Number", className: "mb-0", rules: [
141
- {
142
- required: true,
143
- message: 'Please enter your mobile number'
144
- }
145
- ], ...form.register("phone", {
146
- onChange: (e) => enterMobile(e.target.value)
147
- }), children: _jsx(Flex, { className: "border border-gray-400 rounded-md", children: _jsx(TextInput, { type: "tel", value: phone, placeholder: "Mobile number", maxLength: countryCode === "91" ? 10 : 14, className: "py-4 border-0 md:text-base", addonBefore: _jsx(CountryCodeDropdown, { selectedCountry: selectedCountry, handleSelect: (country) => {
148
- setCountryCode(country.phoneCode);
149
- setSelectedCountry(country);
150
- setIsPhoneValid(country.phoneCode === "91"
151
- ? /^[0-9]+$/.test(phone) && phone.length >= 10
152
- : phone.length > 5);
153
- } }) }) }) }) })] }), _jsx(Col, { children: _jsx(Form.Item, { name: "referralCode", label: "Referral Code (Optional)", className: "mt-4", children: _jsx(TextInput, { placeholder: "Referral code", ...form.register('referralCode', {
179
+ disabledDate: disabledDate, iconPosition: "right", defaultPickerValue: dayjs('1990-01-01').toDate(), suffixIcon: _jsx(CalendarDays, { className: "-mt-2" }) }) }) }), !isMobileRegistration &&
180
+ _jsx(Col, { xs: 24, md: 24, lg: 12, children: _jsx(Form.Item, { label: "Mobile Number", className: "mb-0", rules: [
181
+ {
182
+ required: true,
183
+ message: 'Please enter your mobile number'
184
+ }
185
+ ], ...form.register("phone", {
186
+ onChange: (e) => handleMobileChange(e.target.value)
187
+ }), children: _jsx(Flex, { className: "border border-gray-400 rounded-md", children: _jsx(TextInput, { type: "tel", value: phone, placeholder: "Mobile number", maxLength: countryCode === "91" ? 10 : 14, className: "py-4 border-0 md:text-base", addonBefore: _jsx(CountryCodeDropdown, { selectedCountry: selectedCountry, handleSelect: (country) => {
188
+ setCountryCode(country.phoneCode);
189
+ setSelectedCountry(country);
190
+ } }) }) }) }) })] }), isMobileRegistration &&
191
+ _jsx(Col, { children: _jsx(Form.Item, { label: "Enter Your Email (Optional)", className: "mt-4", ...form.register('email', {
192
+ onChange: (e) => handleEmailChange(e.target.value)
193
+ }), children: _jsx(TextInput, { value: email, placeholder: "Enter Your Email (Optional)" }) }) }), _jsx(Col, { children: _jsx(Form.Item, { name: "referralCode", label: "Referral Code (Optional)", className: "mt-6", children: _jsx(TextInput, { placeholder: "Referral code", ...form.register('referralCode', {
154
194
  onChange: (e) => setReferralCode(e.target.value)
155
195
  }) }) }) }), isProduction && (process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY
156
196
  ? _jsx(RecaptchaComponent, { onChange: handleCaptcha })
157
197
  : _jsx(Typography, { type: "utility", size: "small", color: "red-600", children: "reCAPTCHA misconfigured. Set NEXT_PUBLIC_RECAPTCHA_SITE_KEY." })), _jsx(Row, { className: "py-0 my-5", children: _jsx(Col, { children: _jsx(CustomCheckbox, { checked: termsAndConditions, onClick: (e) => {
158
198
  setTermsAndConditions(prev => !prev);
159
- }, className: "mt-4", label: _jsxs(Typography, { type: "body", size: "medium", children: ["I accept the", _jsx("a", { target: "_blank", rel: "noopener noreferrer", href: termsAndConditionsUrl, className: "px-1 text-primary", children: "Terms & Conditions" }), "listed on ", appName] }) }) }) })] }) }), _jsxs(Flex, { align: 'center', className: 'p-0 mt-4', children: [_jsx(Typography, { type: "body", size: "large", className: "text-gray-700", children: "Already have an account?" }), _jsx(Button, { label: "Sign-In", variant: "link", size: "medium", className: "ml-2 h-auto px-0", onClick: onGoToLogin })] }), existingAccountModal &&
160
- _jsx(ExistingAccountsModal, { phone: phone, countryCode: countryCode, visible: existingAccountModal, hide: () => setExistingAccountModal(false), existingAccounts: existingAccounts, getLoginTypeText: getLoginTypeText, onGoToLogin: onGoToLogin })] }));
199
+ }, className: "mt-4", label: _jsxs(Typography, { type: "body", size: "medium", children: ["I accept the", _jsx("a", { target: "_blank", rel: "noopener noreferrer", href: termsAndConditionsUrl, className: "px-1 text-primary", children: "Terms & Conditions" }), "listed on ", appName] }) }) }) })] }) }), _jsxs(Flex, { align: 'center', className: 'p-0 mt-4', children: [_jsx(Typography, { type: "body", size: "large", className: "text-gray-700", children: "Already have an account?" }), _jsx(Button, { label: "Sign-In", variant: "link", size: "medium", className: "ml-2 h-auto px-0", onClick: onGoToLogin })] }), linkedAccountsSheet &&
200
+ _jsx(LinkedAccountsSheet, { phone: phone, countryCode: countryCode, visible: linkedAccountsSheet, hide: () => showLinkedAccountsSheet(false), linkedAccounts: linkedAccounts, getLoginTypeText: getLoginTypeText })] }));
161
201
  };
162
- const ExistingAccountsModal = ({ visible, hide, existingAccounts, countryCode, phone, getLoginTypeText, onGoToLogin }) => {
163
- return (_jsxs(ResponsiveModal, { open: visible, onClose: hide, onOpenChange: hide, title: _jsxs(_Fragment, { children: [_jsx(Typography, { type: "heading", size: "h6", children: "Mobile Number Already Linked" }), _jsxs(Typography, { type: "utility", size: "medium", color: "gray-600", className: "mt-2 mb-3", children: ["The mobile number +", countryCode, " ", String(phone).replace(/\d(?=\d{2})/g, 'X'), " is linked to the following ", existingAccounts.length === 1 ? 'account' : `${existingAccounts.length} accounts`, "."] }), _jsx("hr", {})] }), centered: true, showCloseButton: false, className: "px-0", footer: _jsxs(Flex, { direction: "column", children: [_jsx(Button, { isFullWidth: true, variant: "primary", label: "Go to Login", onClick: () => {
164
- onGoToLogin();
202
+ const LinkedAccountsSheet = ({ visible, hide, linkedAccounts, countryCode, phone, getLoginTypeText }) => {
203
+ const router = useRouter();
204
+ return (_jsxs(ResponsiveModal, { open: visible, onClose: hide, onOpenChange: hide, title: _jsxs(_Fragment, { children: [_jsx(Typography, { type: "heading", size: "h6", children: "Mobile Number Already Linked" }), _jsxs(Typography, { type: "utility", size: "medium", color: "gray-600", className: "mt-2 mb-3", children: ["The mobile number +", countryCode, " ", String(phone).replace(/\d(?=\d{2})/g, 'X'), " is linked to the following ", linkedAccounts.length === 1 ? 'account' : `${linkedAccounts.length} accounts`, "."] }), _jsx("hr", {})] }), centered: true, showCloseButton: false, className: "px-0", footer: _jsxs(Flex, { direction: "column", children: [_jsx(Button, { isFullWidth: true, variant: "primary", label: "Go to Login", onClick: () => {
205
+ router.push('/login');
165
206
  hide();
166
- }, className: "!ml-0 mb-[-4px]" }), _jsx(SupportDetails, {})] }), children: [_jsx(Typography, { type: "utility", size: "medium", children: "Please login through any of the below account or contact our support team for assistance" }), existingAccounts.map((item) => {
167
- const key = item.id ?? item.email ?? `${item.loginType}-${item.createdOn}`;
168
- return (_jsxs(Flex, { direction: "column", className: "border border-gray-300 p-4 rounded-md mt-3", children: [_jsxs(Flex, { direction: "column", className: "border-b-2 pb-2", children: [_jsx(Typography, { type: "utility", size: "large", children: item.name }), _jsx(Typography, { type: "utility", size: "medium", color: "primary", children: item.email })] }), _jsxs(Flex, { justify: "between", className: "mt-3", children: [_jsx(Typography, { type: "utility", size: "medium", color: "gray-700", children: "Login Type" }), _jsx(Typography, { type: "utility", size: "medium", color: "gray-800", children: getLoginTypeText(item.loginType) })] }), _jsxs(Flex, { justify: "between", className: "mt-3", children: [_jsx(Typography, { type: "utility", size: "medium", color: "gray-700", children: "Registration Date" }), _jsx(Typography, { type: "utility", size: "medium", color: "gray-800", children: moment(item.createdOn).format('DD/MM/YYYY') })] })] }, key));
207
+ }, className: "!ml-0 mb-[-4px]" }), _jsx(SupportDetails, {})] }), children: [_jsx(Typography, { type: "utility", size: "medium", children: "Please login through any of the below account or contact our support team for assistance" }), linkedAccounts.map((item) => {
208
+ const key = item.memberId ?? item.email ?? `${item.loginType}-${item.createdOn}`;
209
+ return (_jsxs(Flex, { direction: "column", className: "border border-gray-300 p-4 rounded-md mt-3", children: [_jsxs(Flex, { direction: "column", className: "border-b-2 pb-2", children: [_jsx(Typography, { type: "utility", size: "large", className: "break-words w-full mb-1", children: item.name }), _jsx(Typography, { type: "utility", size: "medium", color: "primary", className: "truncate w-full", children: item.email })] }), _jsxs(Flex, { justify: "between", className: "mt-3", children: [_jsx(Typography, { type: "utility", size: "medium", color: "gray-700", children: "Login Type" }), _jsx(Typography, { type: "utility", size: "medium", color: "gray-800", children: getLoginTypeText(item.loginType) })] }), _jsxs(Flex, { justify: "between", className: "mt-3", children: [_jsx(Typography, { type: "utility", size: "medium", color: "gray-700", children: "Registration Date" }), _jsx(Typography, { type: "utility", size: "medium", color: "gray-800", children: moment(item.createdOn).format('DD/MM/YYYY') })] })] }, key));
169
210
  })] }));
170
211
  };
171
212
  const RecaptchaComponent = React.memo(({ onChange }) => {
@@ -1,82 +1,51 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Flex, ResponsiveModal } from "@truworth/twc-web-design";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Flex } from "@truworth/twc-web-design";
3
3
  import { useRouter } from "next/router";
4
4
  import { useEffect, useState } from "react";
5
5
  import { AdvancedTransitionWrapper } from "../../../../components/AdvancedTransitionWrapper";
6
- import { useAuthPackageContext } from "../../../../hooks/internal/useAuthPackageContext";
7
6
  import { SignUpFormComponent } from "../SignUpForm";
8
7
  import CreatePassword from "../../../CreatePassword";
9
8
  import UserConsent from "../../../UserConsent";
10
- import VerifyMobile from "../../../VerifyMobile";
11
- import VerifyEmail from "../../../VerifyEmail";
12
9
  const SignUpWebComponent = () => {
13
10
  const router = useRouter();
14
- const [email, setEmail] = useState('');
15
11
  const [signUpStep, setSignUpStep] = useState('registration');
16
12
  const [userDetails, setUserDetails] = useState({});
17
- const [registrationParams, setRegistrationParams] = useState({});
18
- const [showVerifyMobileModal, setShowVerifyMobileModal] = useState(false);
19
- const [showVerifyEmailModal, setShowVerifyEmailModal] = useState(false);
20
- const { onRegistrationMethodChange, registrationMethod } = useAuthPackageContext();
13
+ const [registrationToken, setRegistrationToken] = useState('');
21
14
  useEffect(() => {
22
- const rawEmail = router.query.email;
23
- const rawMethod = router.query.registrationMethod;
24
- const emailFromQuery = Array.isArray(rawEmail) ? rawEmail[0] : rawEmail;
25
- const registrationMethodFromQuery = Array.isArray(rawMethod) ? rawMethod[0] : rawMethod;
26
- const isValidEmail = (val) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val);
27
- if (typeof emailFromQuery === 'string') {
28
- if (isValidEmail(emailFromQuery)) {
29
- setEmail(emailFromQuery);
30
- }
31
- else {
32
- console.warn('Ignoring invalid email in query:', emailFromQuery);
33
- }
15
+ const rawRegistrationToken = router.query.registrationToken;
16
+ if (typeof rawRegistrationToken === 'string') {
17
+ setRegistrationToken(rawRegistrationToken);
34
18
  }
35
- if (typeof registrationMethodFromQuery === 'string') {
36
- const method = registrationMethodFromQuery.toLowerCase();
37
- if (method === 'email' || method === 'mobile') {
38
- onRegistrationMethodChange(method);
39
- }
40
- }
41
- }, [router.query.email, router.query.registrationMethod, onRegistrationMethodChange]);
42
- const onGoToLogin = () => {
43
- router.push('/login');
44
- };
19
+ }, [router.query.registrationToken]);
45
20
  const renderStep = () => {
46
21
  switch (signUpStep) {
47
22
  case 'registration':
48
- return (_jsx(SignUpFormComponent, { email: email, userDetails: userDetails, registrationMethod: registrationMethod, onContinue: (userDetails) => {
49
- setUserDetails(userDetails);
23
+ return (_jsx(SignUpFormComponent, { userDetails: userDetails, onContinue: (userDetails) => {
24
+ if (registrationToken) {
25
+ setUserDetails({ ...userDetails, registrationToken });
26
+ setSignUpStep('user-consent');
27
+ return;
28
+ }
29
+ setUserDetails({ ...userDetails });
50
30
  setSignUpStep('create-password');
51
- }, onGoToLogin: onGoToLogin }));
31
+ } }));
52
32
  case 'create-password':
53
33
  return userDetails && (_jsx(CreatePassword, { userDetails: userDetails, handleBack: () => setSignUpStep('registration'), onContinue: (password, confirmPassword) => {
54
34
  setUserDetails({ ...userDetails, password, confirmPassword });
55
35
  setSignUpStep('user-consent');
56
36
  } }));
57
37
  case 'user-consent':
58
- return (_jsx(UserConsent, { routeParams: userDetails, onBackHandler: () => setSignUpStep('create-password'), onVerifyEmail: ({ email, phone, sessionToken }) => {
59
- setRegistrationParams({ email, phone, sessionToken });
60
- setShowVerifyEmailModal(true);
61
- }, onVerifyMobile: ({ phone, sessionToken }) => {
62
- setRegistrationParams({ phone, sessionToken });
63
- setShowVerifyMobileModal(true);
38
+ return (_jsx(UserConsent, { userDetails: userDetails, handleBack: () => {
39
+ if (registrationToken) {
40
+ setSignUpStep('registration');
41
+ return;
42
+ }
43
+ setSignUpStep('create-password');
64
44
  } }));
65
45
  default:
66
46
  return null;
67
47
  }
68
48
  };
69
- return (_jsxs(_Fragment, { children: [_jsx(AdvancedTransitionWrapper, { type: 'slide', duration: 0.5, children: _jsx(Flex, { direction: 'column', justify: 'center', style: { width: '70%' }, className: `lg:w-[70%] lg:h-screen mx-auto h-full my-10`, children: renderStep() }) }), showVerifyMobileModal &&
70
- _jsx(VerifyMobileModal, { visible: showVerifyMobileModal, hide: () => setShowVerifyMobileModal(false), sessionToken: registrationParams?.sessionToken || '', phone: registrationParams?.phone || '' }), showVerifyEmailModal &&
71
- _jsx(VerifyEmailModal, { email: email, visible: showVerifyEmailModal, hide: () => setShowVerifyEmailModal(false), sessionToken: registrationParams?.sessionToken || '', onVerifiedOTP: () => {
72
- setShowVerifyEmailModal(false);
73
- setShowVerifyMobileModal(true);
74
- } })] }));
49
+ return (_jsx(AdvancedTransitionWrapper, { type: 'slide', duration: 0.5, children: _jsx(Flex, { direction: 'column', justify: 'center', className: `lg:w-[70%] lg:h-screen mx-auto h-full my-10`, children: renderStep() }) }));
75
50
  };
76
51
  export { SignUpWebComponent };
77
- const VerifyMobileModal = ({ visible, hide, sessionToken, phone }) => {
78
- return (_jsx(ResponsiveModal, { title: 'Verify Mobile', open: visible, onClose: hide, onOpenChange: hide, maskClosable: false, showCloseButton: false, children: _jsx(VerifyMobile, { sessionToken: sessionToken, phone: phone }) }));
79
- };
80
- const VerifyEmailModal = ({ visible, hide, sessionToken, email, onVerifiedOTP }) => {
81
- return (_jsx(ResponsiveModal, { title: 'Verify Email', open: visible, onOpenChange: hide, onClose: hide, maskClosable: false, showCloseButton: false, children: _jsx(VerifyEmail, { email: email, sessionToken: sessionToken, onVerifiedOTP: onVerifiedOTP }) }));
82
- };
@@ -1,101 +1,87 @@
1
1
  import { useMemo, useState } from "react";
2
2
  import { validateEmojiRegex } from "../../../../helpers/Validation";
3
- import { axiosClient } from "../../../../api/axiosClient";
4
3
  import { showMessage } from "../../../../helpers/show-message";
5
4
  import { useAuthPackageContext } from "../../../../hooks/internal/useAuthPackageContext";
5
+ import { RegistrationMethod } from "../../../../enums";
6
+ import { checkMobileExists, checkEmailExists } from "../../../../api/auth";
6
7
  /**
7
- * @internal
8
- * Hook for managing SignUp screen state and auth context integration.
9
- * This hook is not exposed to package consumers.
10
- */
8
+ * @internal
9
+ * Hook for managing SignUp screen state and auth context integration.
10
+ */
11
11
  const useSignUp = () => {
12
12
  const [loading, setLoading] = useState(false);
13
13
  const [datePicker, showDatePicker] = useState(false);
14
- const [isPhoneValid, setIsPhoneValid] = useState(false);
15
- const [existingAccountModal, setExistingAccountModal] = useState(false);
14
+ const [linkedAccounts, setLinkedAccounts] = useState([]);
15
+ const [linkedAccountsSheet, showLinkedAccountsSheet] = useState(false);
16
16
  const [firstName, setFirstName] = useState('');
17
17
  const [lastName, setLastName] = useState('');
18
18
  const [phone, setPhone] = useState('');
19
+ const [email, setEmail] = useState('');
19
20
  const [gender, setGender] = useState('');
20
21
  const [referralCode, setReferralCode] = useState('');
21
22
  const [selectedDOB, setSelectedDOB] = useState('');
22
23
  const [countryCode, setCountryCode] = useState('91');
23
24
  const [error, setError] = useState({});
24
- const [phoneError, setPhoneError] = useState(false);
25
- const [email, setEmail] = useState('');
26
- const [emailLinkedError, setEmailLinkedError] = useState('');
27
- const [existingAccounts, setExistingAccounts] = useState([]);
28
- const { appConfig, registrationMethod } = useAuthPackageContext();
29
- const onFirstName = (text) => {
25
+ const { appConfig, registrationMethod, onRegistrationMethodChange } = useAuthPackageContext();
26
+ /** Initialize default values */
27
+ const initializeValues = (params) => {
28
+ setFirstName(params?.firstName || '');
29
+ setLastName(params?.lastName || '');
30
+ setCountryCode(params?.countryCode || '91');
31
+ };
32
+ /** Validate first name */
33
+ const handleFirstNameChange = (text) => {
30
34
  text = validateEmojiRegex(text).replace(/[^A-Za-z]/g, '');
31
35
  setFirstName(text);
32
36
  };
33
- const onLastName = (text) => {
37
+ /** Validate last name */
38
+ const handleLastNameChange = (text) => {
34
39
  text = validateEmojiRegex(text).replace(/[^A-Za-z]/g, '');
35
- ;
36
40
  setLastName(text);
37
41
  };
38
- const handleEmail = (text) => {
39
- let reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
40
- if (text.length === 0) {
41
- setEmailLinkedError('');
42
- }
43
- else if (reg.test(text) === false) {
44
- setEmailLinkedError('Invalid email');
45
- }
46
- else {
47
- setEmailLinkedError('');
48
- }
49
- setEmail(text);
42
+ /** Validate email input */
43
+ const handleEmailChange = (emailInput) => {
44
+ const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
45
+ setEmail(emailInput);
46
+ setError(prev => ({ ...prev, email: !emailRegex.test(emailInput) }));
47
+ };
48
+ const handleMobileChange = (mobileInput) => {
49
+ setPhone(mobileInput);
50
+ const isNumeric = /^[0-9\b]+$/.test(mobileInput);
51
+ const isValid = (countryCode === '91' && isNumeric && mobileInput.length === 10) ||
52
+ (countryCode !== '91' && mobileInput.length > 5);
53
+ setError((prev) => ({ ...prev, phone: !isValid }));
50
54
  };
51
- const handleSubmit = ({ onResult }) => {
52
- if (registrationMethod === 'email' && countryCode === '91') {
53
- setLoading(true);
54
- axiosClient({
55
- url: '/auth/mobile-exists',
56
- method: 'POST',
57
- data: { phone }
58
- }).then(res => {
59
- setLoading(false);
60
- if (res?.data?.exists) {
61
- setExistingAccounts(res?.data?.memberDetails || []);
62
- setExistingAccountModal(true);
55
+ /** Handle submit for signup */
56
+ const handleSubmit = async ({ onProceed }) => {
57
+ setLoading(true);
58
+ try {
59
+ if (phone) {
60
+ const { mobileExist, linkedAccounts = [] } = await checkMobileExists(phone);
61
+ if (mobileExist) {
62
+ setLinkedAccounts(linkedAccounts);
63
+ showLinkedAccountsSheet(true);
63
64
  return;
64
65
  }
65
- onResult();
66
- }).catch(err => onHandleError(err, onResult));
67
- }
68
- else if (registrationMethod === 'mobile' && email) {
69
- setLoading(true);
70
- axiosClient({
71
- url: '/auth/email-exists',
72
- method: 'POST',
73
- data: { email }
74
- }).then(() => {
75
- setLoading(false);
76
- setEmailLinkedError('This email is already linked with another user.');
77
- }).catch(err => onHandleError(err, onResult));
78
- }
79
- else {
80
- onResult();
81
- }
82
- };
83
- const onHandleError = (err, onResult) => {
84
- setLoading(false);
85
- const status = err?.response?.status;
86
- if (!status) {
87
- return showMessage({ message: 'Network error. Please try again.' });
88
- }
89
- if (status === 404) {
90
- return onResult();
66
+ }
67
+ if (email) {
68
+ const { emailExist } = await checkEmailExists(email);
69
+ if (emailExist) {
70
+ showMessage({ message: 'This email is already linked with another user.' });
71
+ return;
72
+ }
73
+ }
74
+ onProceed();
91
75
  }
92
- if (status === 400) {
93
- return showMessage({ message: err?.response?.data?.errors?.[0]?.message ?? 'Something went wrong' });
76
+ catch (err) {
77
+ const errorMessage = err?.response?.data?.errors?.[0]?.message ?? 'Something went wrong';
78
+ showMessage({ message: errorMessage });
94
79
  }
95
- if (typeof status === 'number' && status >= 500) {
96
- return showMessage({ message: 'Something went wrong' });
80
+ finally {
81
+ setLoading(false);
97
82
  }
98
83
  };
84
+ /** Get display text for login type */
99
85
  const getLoginTypeText = (loginType) => {
100
86
  switch (loginType) {
101
87
  case 1: return 'Email';
@@ -106,10 +92,20 @@ const useSignUp = () => {
106
92
  default: return 'Email';
107
93
  }
108
94
  };
95
+ /** Disable submit button logic */
109
96
  const disabled = useMemo(() => {
110
- return !firstName || firstName.length < 3 || !lastName || lastName.length < 3 || !selectedDOB || !gender
111
- || (registrationMethod == "email" && (!phone || !isPhoneValid)) || emailLinkedError.length > 0;
112
- }, [firstName, lastName, selectedDOB, gender, phone, isPhoneValid, emailLinkedError, registrationMethod]);
97
+ const isPhoneInvalid = !phone || error.phone;
98
+ // Optional email: treat empty as valid; only flag when provided and invalid
99
+ const isEmailInvalid = email && error.email;
100
+ return (!firstName
101
+ || firstName.length < 3
102
+ || !lastName
103
+ || lastName.length < 3
104
+ || !selectedDOB
105
+ || !gender
106
+ || (registrationMethod === RegistrationMethod.MOBILE && isEmailInvalid)
107
+ || (registrationMethod !== RegistrationMethod.MOBILE && isPhoneInvalid));
108
+ }, [firstName, lastName, selectedDOB, gender, phone, email, error.phone, error.email, registrationMethod]);
113
109
  return {
114
110
  loading,
115
111
  firstName, lastName,
@@ -121,18 +117,18 @@ const useSignUp = () => {
121
117
  countryCode, setCountryCode,
122
118
  error, setError,
123
119
  email, setEmail,
124
- phoneError, setPhoneError,
125
- isPhoneValid, setIsPhoneValid,
126
- emailLinkedError,
127
- existingAccounts,
128
- existingAccountModal, setExistingAccountModal,
129
- onFirstName, onLastName,
130
- handleEmail, handleSubmit,
120
+ linkedAccounts,
121
+ linkedAccountsSheet, showLinkedAccountsSheet,
122
+ handleFirstNameChange, handleLastNameChange,
123
+ handleEmailChange,
124
+ handleMobileChange,
125
+ handleSubmit,
131
126
  getLoginTypeText,
132
127
  disabled,
133
- registrationMethod,
128
+ registrationMethod, onRegistrationMethodChange,
134
129
  appName: appConfig.appName,
135
- termsAndConditionsUrl: appConfig.termsAndConditionsUrl
130
+ termsAndConditionsUrl: appConfig.termsAndConditionsUrl,
131
+ initializeValues
136
132
  };
137
133
  };
138
134
  export { useSignUp };