@truworth/twc-auth 1.2.4 → 1.2.6

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 (116) hide show
  1. package/README.md +1 -4
  2. package/build/assets/email_icon.svg +6 -0
  3. package/build/src/api/axiosClient/index.js +1 -1
  4. package/build/src/api/axiosClient/index.native.js +1 -1
  5. package/build/src/components/VerifyMobileOTP/index.js +8 -6
  6. package/build/src/components/VerifyMobileOTP/index.native.js +6 -11
  7. package/build/src/constants/base-url/index.js +5 -0
  8. package/build/src/constants/base-url/index.native.js +1 -0
  9. package/build/src/constants/cdn-url/index.js +2 -1
  10. package/build/src/constants/social-login-options.js +16 -0
  11. package/build/src/contexts/AuthContext.js +6 -2
  12. package/build/src/enums/index.js +1 -0
  13. package/build/src/enums/loginMethod.enum.js +1 -1
  14. package/build/src/enums/socialLogins.enum.js +6 -0
  15. package/build/src/helpers/{Network.js → network.js} +1 -1
  16. package/build/src/hooks/useRequest.js +1 -1
  17. package/build/src/navigator/index.native.js +5 -1
  18. package/build/src/screens/EnterEmail/hooks/internal/useEnterEmail.js +50 -41
  19. package/build/src/screens/EnterEmail/index.js +37 -11
  20. package/build/src/screens/EnterEmail/index.native.js +6 -9
  21. package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/hooks/internal/useExistingAccountsSheet.js +36 -0
  22. package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/index.js +33 -0
  23. package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/index.native.js +73 -0
  24. package/build/src/screens/EnterMobile/components/ExistingAccountsSheet/types.js +1 -0
  25. package/build/src/screens/EnterMobile/hooks/internal/useEnterMobile.js +67 -0
  26. package/build/src/screens/EnterMobile/index.js +82 -0
  27. package/build/src/screens/EnterMobile/index.native.js +56 -0
  28. package/build/src/screens/EnterMobile/types.js +1 -0
  29. package/build/src/screens/EnterPassword/hooks/internal/useEnterPassword.js +42 -31
  30. package/build/src/screens/EnterPassword/index.js +6 -6
  31. package/build/src/screens/EnterPassword/index.native.js +5 -10
  32. package/build/src/screens/Login/components/LoginWebComponent/index.js +4 -1
  33. package/build/src/screens/LoginWithEmailOTP/hooks/internal/useLoginWithEmailOTP.js +8 -5
  34. package/build/src/screens/LoginWithMobileOTP/hooks/internal/useLoginWithMobileOTP.js +71 -0
  35. package/build/src/screens/LoginWithMobileOTP/index.js +8 -0
  36. package/build/src/screens/LoginWithMobileOTP/index.native.js +10 -0
  37. package/build/src/screens/SSOLogin/AuthenticationMethods/index.js +9 -8
  38. package/build/src/screens/SSOLogin/AuthenticationMethods/index.native.js +2 -6
  39. package/build/src/screens/SignUp/components/SignUpForm/index.js +20 -5
  40. package/build/src/screens/SignUp/components/SignUpWebComponent/index.js +12 -2
  41. package/build/src/screens/SignUp/hooks/internal/useSignUp.js +1 -1
  42. package/build/src/screens/SignUp/index.native.js +17 -13
  43. package/build/src/screens/UserConsent/hooks/internal/useConsent.js +10 -1
  44. package/build/src/screens/UserConsent/index.js +1 -1
  45. package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/hooks/internal/useVerifyLinkPrimaryAccountEmailOTP.js +73 -0
  46. package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/index.js +8 -0
  47. package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/index.native.js +14 -0
  48. package/build/src/screens/VerifyLinkPrimaryAccountEmailOTP/types.js +1 -0
  49. package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/hooks/internal/useVerifyLinkPrimaryAccountMobileOTP.js +82 -0
  50. package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/index.js +8 -0
  51. package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/index.native.js +10 -0
  52. package/build/src/screens/VerifyLinkPrimaryAccountMobileOTP/types.js +1 -0
  53. package/build/src/screens/Welcome/SocialAuth/commonSocialAuth.js +127 -0
  54. package/build/src/screens/Welcome/SocialAuth/hooks/useSocialAuth.native.js +192 -0
  55. package/build/src/screens/Welcome/SocialAuth/hooks/useSocialAuth.web.js +13 -0
  56. package/build/src/screens/Welcome/SocialAuth/hooks/web/useFacebookAuth.web.js +118 -0
  57. package/build/src/screens/Welcome/SocialAuth/hooks/web/useGoogleAuth.web.js +75 -0
  58. package/build/src/screens/Welcome/components/SocialLoginModal/index.js +9 -0
  59. package/build/src/screens/Welcome/components/SocialLoginModal/index.native.js +21 -0
  60. package/build/src/screens/Welcome/components/SocialLoginModal/types.js +1 -0
  61. package/build/src/screens/Welcome/hooks/internal/useWelcome.js +10 -5
  62. package/build/src/screens/Welcome/index.js +3 -2
  63. package/build/src/screens/Welcome/index.native.js +41 -4
  64. package/build/types/components/VerifyMobileOTP/index.d.ts +1 -1
  65. package/build/types/components/VerifyMobileOTP/types.d.ts +0 -1
  66. package/build/types/constants/base-url/index.d.ts +1 -0
  67. package/build/types/constants/base-url/index.native.d.ts +1 -0
  68. package/build/types/constants/cdn-url/index.d.ts +2 -1
  69. package/build/types/constants/social-login-options.d.ts +3 -0
  70. package/build/types/contexts/AuthContext.d.ts +3 -1
  71. package/build/types/contexts/type.d.ts +12 -0
  72. package/build/types/enums/index.d.ts +1 -0
  73. package/build/types/enums/loginMethod.enum.d.ts +1 -1
  74. package/build/types/enums/socialLogins.enum.d.ts +5 -0
  75. package/build/types/helpers/types.d.ts +7 -1
  76. package/build/types/navigator/index.native.d.ts +17 -0
  77. package/build/types/screens/EnterEmail/hooks/internal/useEnterEmail.d.ts +11 -15
  78. package/build/types/screens/EnterEmail/types.d.ts +6 -1
  79. package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/hooks/internal/useExistingAccountsSheet.d.ts +13 -0
  80. package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/index.d.ts +3 -0
  81. package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/index.native.d.ts +3 -0
  82. package/build/types/screens/EnterMobile/components/ExistingAccountsSheet/types.d.ts +28 -0
  83. package/build/types/screens/EnterMobile/hooks/internal/useEnterMobile.d.ts +15 -0
  84. package/build/types/screens/EnterMobile/index.d.ts +4 -0
  85. package/build/types/screens/EnterMobile/index.native.d.ts +4 -0
  86. package/build/types/screens/EnterMobile/types.d.ts +44 -0
  87. package/build/types/screens/EnterPassword/hooks/internal/useEnterPassword.d.ts +8 -8
  88. package/build/types/screens/LoginWithEmailOTP/hooks/internal/useLoginWithEmailOTP.d.ts +1 -1
  89. package/build/types/screens/LoginWithMobileOTP/hooks/internal/useLoginWithMobileOTP.d.ts +11 -0
  90. package/build/types/screens/LoginWithMobileOTP/index.d.ts +5 -0
  91. package/build/types/screens/LoginWithMobileOTP/index.native.d.ts +4 -0
  92. package/build/types/screens/SSOLogin/AuthenticationMethods/index.d.ts +1 -1
  93. package/build/types/screens/SSOLogin/AuthenticationMethods/types.d.ts +1 -0
  94. package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/hooks/internal/useVerifyLinkPrimaryAccountEmailOTP.d.ts +15 -0
  95. package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/index.d.ts +3 -0
  96. package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/index.native.d.ts +4 -0
  97. package/build/types/screens/VerifyLinkPrimaryAccountEmailOTP/types.d.ts +14 -0
  98. package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/hooks/internal/useVerifyLinkPrimaryAccountMobileOTP.d.ts +17 -0
  99. package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/index.d.ts +3 -0
  100. package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/index.native.d.ts +4 -0
  101. package/build/types/screens/VerifyLinkPrimaryAccountMobileOTP/types.d.ts +5 -0
  102. package/build/types/screens/Welcome/SocialAuth/commonSocialAuth.d.ts +50 -0
  103. package/build/types/screens/Welcome/SocialAuth/hooks/useSocialAuth.native.d.ts +7 -0
  104. package/build/types/screens/Welcome/SocialAuth/hooks/useSocialAuth.web.d.ts +7 -0
  105. package/build/types/screens/Welcome/SocialAuth/hooks/web/useFacebookAuth.web.d.ts +5 -0
  106. package/build/types/screens/Welcome/SocialAuth/hooks/web/useGoogleAuth.web.d.ts +4 -0
  107. package/build/types/screens/Welcome/components/SocialLoginModal/index.d.ts +3 -0
  108. package/build/types/screens/Welcome/components/SocialLoginModal/index.native.d.ts +3 -0
  109. package/build/types/screens/Welcome/components/SocialLoginModal/types.d.ts +8 -0
  110. package/build/types/screens/Welcome/hooks/internal/useWelcome.d.ts +8 -0
  111. package/build/types/types/types.d.ts +3 -0
  112. package/package.json +3 -5
  113. package/build/assets/okay_icon copy.svg +0 -3
  114. /package/build/src/helpers/{Validation.js → validation.js} +0 -0
  115. /package/build/types/helpers/{Network.d.ts → network.d.ts} +0 -0
  116. /package/build/types/helpers/{Validation.d.ts → validation.d.ts} +0 -0
@@ -48,11 +48,7 @@ const SSOAuthenticationMethods = ({ route }) => {
48
48
  return (_jsx(ScreenLayout, { title: "", containerStyle: { flex: 1, backgroundColor: primary.white }, children: _jsxs(View, { style: { flex: 1, justifyContent: 'center' }, children: [client.image ?
49
49
  _jsx(FastImage, { source: { uri: client.image }, resizeMode: 'contain', style: { width: 180, aspectRatio: aspectRatio, alignSelf: 'center', marginTop: -150 } })
50
50
  : renderLogo(), _jsx(Text, { style: { textAlign: 'center', fontSize: 24, fontWeight: '600', color: gray.gray_700, marginTop: 30 }, children: "Select how to sign-in" }), client?.ssoEnabled &&
51
- _jsxs(_Fragment, { children: [_jsx(RoundedButton, { loading: loading, type: 'primary', label: 'Login with SSO', size: 'large', containerStyle: { marginTop: 40 }, onPress: () => initiateSSOLogin({ clientId: client.id, onSSOLoginInitiated }), leftIcon: 'key-outline' }), _jsx(Text, { style: { textAlign: 'center', fontSize: 14, color: gray.gray_700, marginTop: 20 }, children: "Recommended for quick access" }), _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', marginTop: 30, marginHorizontal: 30 }, children: [_jsx(View, { style: { flex: 1, height: 1, backgroundColor: gray.gray_200 } }), _jsx(View, { children: _jsx(Text, { style: { width: 50, textAlign: 'center', color: gray.gray_500, fontSize: 16 }, children: "OR" }) }), _jsx(View, { style: { flex: 1, height: 1, backgroundColor: gray.gray_200 } })] })] }), _jsx(RoundedButton, { type: 'secondary', label: 'Login with Email & Password', size: 'large', containerStyle: { marginTop: 30 }, onPress: () => {
52
- const parent = navigation.getParent();
53
- if (parent) {
54
- parent.navigate('EnterEmail');
55
- }
56
- }, leftIcon: 'mail-outline' })] }) }));
51
+ _jsxs(_Fragment, { children: [_jsx(RoundedButton, { loading: loading, type: 'primary', label: 'Login with SSO', size: 'large', containerStyle: { marginTop: 40 }, onPress: () => initiateSSOLogin({ clientId: client.id, onSSOLoginInitiated }), leftIcon: 'key-outline' }), _jsx(Text, { style: { textAlign: 'center', fontSize: 14, color: gray.gray_700, marginTop: 20 }, children: "Recommended for quick access" }), _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', marginTop: 30, marginHorizontal: 30 }, children: [_jsx(View, { style: { flex: 1, height: 1, backgroundColor: gray.gray_200 } }), _jsx(View, { children: _jsx(Text, { style: { width: 50, textAlign: 'center', color: gray.gray_500, fontSize: 16 }, children: "OR" }) }), _jsx(View, { style: { flex: 1, height: 1, backgroundColor: gray.gray_200 } })] })] }), _jsx(RoundedButton, { type: 'secondary', label: 'Login with Email & Password', size: 'large', containerStyle: { marginTop: 30 }, onPress: () => navigation.navigate('EnterEmail'), leftIcon: 'mail-outline' }), client?.mobileLoginEnabled &&
52
+ _jsx(RoundedButton, { type: 'text', label: 'Login with Mobile Number', size: 'large', containerStyle: { marginHorizontal: 16, marginTop: 30 }, onPress: () => navigation.navigate('EnterMobile'), leftIcon: 'phone-portrait-outline' })] }) }));
57
53
  };
58
54
  export default SSOAuthenticationMethods;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React, { useEffect, useState } from "react";
3
- import { CDN_IMAGES_URL } from "@truworth/twc-web-common";
3
+ import { CDN_IMAGES_URL } from "../../../../constants/cdn-url";
4
4
  import { Button, Col, CustomCheckbox, DatePicker, Flex, Form, RadioGroup, ResponsiveModal, Row, TextInput, Typography, useForm, validationPatterns } from "@truworth/twc-web-design";
5
5
  import { CalendarDays } from "lucide-react";
6
6
  import { SupportDetails } from "../../../../components/SupportDetails";
@@ -12,6 +12,7 @@ import ReCAPTCHA from 'react-google-recaptcha';
12
12
  import moment from "moment";
13
13
  import dayjs from 'dayjs';
14
14
  import { RegistrationMethod } from "../../../../enums";
15
+ import { showMessage } from "../../../../helpers/show-message";
15
16
  const getQueryParam = (param) => {
16
17
  if (Array.isArray(param))
17
18
  return param[0];
@@ -36,6 +37,20 @@ const SignUpFormComponent = ({ userDetails, onContinue }) => {
36
37
  }
37
38
  });
38
39
  const values = form.watch();
40
+ useEffect(() => {
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]);
39
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();
40
55
  useEffect(() => {
41
56
  if (!registrationMethod) {
@@ -105,8 +120,8 @@ const SignUpFormComponent = ({ userDetails, onContinue }) => {
105
120
  loading,
106
121
  label: 'Continue',
107
122
  onClick: () => { handleSubmit({ onProceed }); },
108
- isDisabled
109
- }, 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", className: 'mt-5', rules: [
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: [
110
125
  {
111
126
  required: true,
112
127
  message: 'Please enter your first name'
@@ -124,7 +139,7 @@ const SignUpFormComponent = ({ userDetails, onContinue }) => {
124
139
  },
125
140
  ], normalize: (value) => (value ?? '').replace(/[^a-zA-Z]/g, ''), ...form.register('firstName', {
126
141
  onChange: (e) => handleFirstNameChange(e.target.value)
127
- }), 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: [
142
+ }), children: _jsx(TextInput, { placeholder: "Enter your first name" }) }) }), _jsx(Col, { xs: 24, md: 12, children: _jsx(Form.Item, { label: "Last Name", rules: [
128
143
  {
129
144
  required: true,
130
145
  message: 'Please enter your last name'
@@ -191,7 +206,7 @@ const LinkedAccountsSheet = ({ visible, hide, linkedAccounts, countryCode, phone
191
206
  hide();
192
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) => {
193
208
  const key = item.memberId ?? item.email ?? `${item.loginType}-${item.createdOn}`;
194
- 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));
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));
195
210
  })] }));
196
211
  };
197
212
  const RecaptchaComponent = React.memo(({ onChange }) => {
@@ -11,18 +11,28 @@ const SignUpWebComponent = () => {
11
11
  const [signUpStep, setSignUpStep] = useState('registration');
12
12
  const [userDetails, setUserDetails] = useState({});
13
13
  const [registrationToken, setRegistrationToken] = useState('');
14
+ const [fbUserId, setFbUserId] = useState('');
15
+ const [googleUserId, setGoogleUserId] = useState('');
14
16
  useEffect(() => {
15
17
  const rawRegistrationToken = router.query.registrationToken;
18
+ const rawFbUserId = router.query.fbUserId;
19
+ const rawGoogleUserId = router.query.googleUserId;
16
20
  if (typeof rawRegistrationToken === 'string') {
17
21
  setRegistrationToken(rawRegistrationToken);
18
22
  }
23
+ if (typeof rawFbUserId === 'string') {
24
+ setFbUserId(rawFbUserId);
25
+ }
26
+ if (typeof rawGoogleUserId === 'string') {
27
+ setGoogleUserId(rawGoogleUserId);
28
+ }
19
29
  }, [router.query.registrationToken]);
20
30
  const renderStep = () => {
21
31
  switch (signUpStep) {
22
32
  case 'registration':
23
33
  return (_jsx(SignUpFormComponent, { userDetails: userDetails, onContinue: (userDetails) => {
24
34
  if (registrationToken) {
25
- setUserDetails({ ...userDetails, registrationToken });
35
+ setUserDetails({ ...userDetails, registrationToken, fbUserId, googleUserId });
26
36
  setSignUpStep('user-consent');
27
37
  return;
28
38
  }
@@ -46,6 +56,6 @@ const SignUpWebComponent = () => {
46
56
  return null;
47
57
  }
48
58
  };
49
- return (_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() }) }));
59
+ 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() }) }));
50
60
  };
51
61
  export { SignUpWebComponent };
@@ -1,5 +1,5 @@
1
1
  import { useMemo, useState } from "react";
2
- import { validateEmojiRegex } from "../../../../helpers/Validation";
2
+ import { validateEmojiRegex } from "../../../../helpers/validation";
3
3
  import { showMessage } from "../../../../helpers/show-message";
4
4
  import { useAuthPackageContext } from "../../../../hooks/internal/useAuthPackageContext";
5
5
  import { RegistrationMethod } from "../../../../enums";
@@ -3,7 +3,6 @@ import { useEffect, useState } from 'react';
3
3
  import { View, Text, Platform, Keyboard, TouchableOpacity, ScrollView, TextInput } from 'react-native';
4
4
  import { useNavigation } from '@react-navigation/native';
5
5
  import { useModalize } from 'react-native-modalize';
6
- import { Freshchat } from 'react-native-freshchat-sdk';
7
6
  import { Layout } from '@ui-kitten/components';
8
7
  import DateTimePicker from '@react-native-community/datetimepicker';
9
8
  import IonIcon from 'react-native-vector-icons/Ionicons';
@@ -51,6 +50,9 @@ const SignUp = ({ navigation, route }) => {
51
50
  selectedDOB,
52
51
  countryCode,
53
52
  referralCode,
53
+ googleUserId: route.params?.googleUserId,
54
+ fbUserId: route.params?.fbUserId,
55
+ appleUserId: route.params?.appleUserId
54
56
  };
55
57
  if (route.params?.registrationToken) {
56
58
  navigation.navigate('UserConsent', {
@@ -132,6 +134,7 @@ const KnowMoreModal = ({ visible, hide }) => {
132
134
  const LinkedAccountsSheet = ({ visible, hide, linkedAccounts, countryCode, phone, getLoginTypeText }) => {
133
135
  const { ref: existingAccountsRef, open: openExistingAccountsSheet, close: closeExistingAccountsSheet } = useModalize();
134
136
  const navigation = useNavigation();
137
+ const { openChatSupport } = useAuthPackageContext();
135
138
  useEffect(() => {
136
139
  if (visible) {
137
140
  openExistingAccountsSheet();
@@ -168,17 +171,18 @@ const LinkedAccountsSheet = ({ visible, hide, linkedAccounts, countryCode, phone
168
171
  shadowOpacity: 0.5,
169
172
  shadowRadius: 3,
170
173
  elevation: 3
171
- }, children: [_jsx(RoundedButton, { label: "Go to Login", size: "large", onPress: () => navigation.navigate('EnterEmail'), containerStyle: { marginBottom: 8 } }), _jsxs(TouchableOpacity, { activeOpacity: 0.8, onPress: () => Freshchat.showConversations(), style: {
172
- flexDirection: 'row',
173
- alignItems: 'center',
174
- justifyContent: 'center',
175
- padding: 8,
176
- marginTop: 8
177
- }, children: [_jsx(IonIcon, { name: 'headset', size: 12, color: primary.primary_main }), _jsx(Text, { style: {
178
- fontSize: 14,
179
- fontWeight: '600',
180
- color: primary.primary_main,
181
- marginStart: 8
182
- }, children: "Contact Support" })] })] }) }));
174
+ }, children: [_jsx(RoundedButton, { label: "Go to Login", size: "large", onPress: () => navigation.navigate('EnterEmail'), containerStyle: { marginBottom: 8 } }), openChatSupport &&
175
+ _jsxs(TouchableOpacity, { activeOpacity: 0.8, onPress: openChatSupport, style: {
176
+ flexDirection: 'row',
177
+ alignItems: 'center',
178
+ justifyContent: 'center',
179
+ padding: 8,
180
+ marginTop: 8
181
+ }, children: [_jsx(IonIcon, { name: 'headset', size: 12, color: primary.primary_main }), _jsx(Text, { style: {
182
+ fontSize: 14,
183
+ fontWeight: '600',
184
+ color: primary.primary_main,
185
+ marginStart: 8
186
+ }, children: "Contact Support" })] })] }) }));
183
187
  };
184
188
  export default SignUp;
@@ -10,7 +10,7 @@ const useConsent = () => {
10
10
  const [loading, setLoading] = useState(false);
11
11
  const { registrationMethod } = useAuthPackageContext();
12
12
  const onAgree = ({ userDetails, source, onResult }) => {
13
- const { firstName, lastName, selectedDOB, gender, referralCode, email, phone, countryCode, password, registrationToken } = userDetails || {};
13
+ const { firstName, lastName, selectedDOB, gender, referralCode, email, phone, countryCode, password, registrationToken, fbUserId, googleUserId, appleUserId } = userDetails || {};
14
14
  const payload = {
15
15
  firstName,
16
16
  lastName,
@@ -37,6 +37,15 @@ const useConsent = () => {
37
37
  if (registrationToken) {
38
38
  payload.ssoRegistrationToken = registrationToken;
39
39
  }
40
+ if (googleUserId) {
41
+ payload.googleUserId = googleUserId;
42
+ }
43
+ if (fbUserId) {
44
+ payload.fbUserId = fbUserId;
45
+ }
46
+ if (appleUserId) {
47
+ payload.appleUserId = appleUserId;
48
+ }
40
49
  setLoading(true);
41
50
  axiosClient({
42
51
  url: '/auth/registration/initiate',
@@ -7,7 +7,7 @@ import { Info } from 'lucide-react';
7
7
  import { useRouter } from "next/router";
8
8
  import { Flex, Typography, ResponsiveModal as Modal, Button, ResponsiveModal } from '@truworth/twc-web-design';
9
9
  import { useAuthPackageContext } from '../../hooks/internal/useAuthPackageContext';
10
- import { CDN_IMAGES_URL } from '@truworth/twc-web-common';
10
+ import { CDN_IMAGES_URL } from '../../constants/cdn-url';
11
11
  import { useConsent } from './hooks/internal/useConsent';
12
12
  import { ScreenLayout } from "../../components/ScreenLayout";
13
13
  import VerifyMobile from "../VerifyMobile";
@@ -0,0 +1,73 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { showMessage } from "../../../../helpers/show-message";
3
+ import { axiosClient } from "../../../../api/axiosClient";
4
+ /**
5
+ * @internal
6
+ * Hook for managing useVerifyLinkPrimaryAccountEmailOTP hook state and auth context integration.
7
+ * This hook is not exposed to package consumers.
8
+ */
9
+ const useVerifyLinkPrimaryAccountEmailOTP = ({ sessionToken }) => {
10
+ const [status, setStatus] = useState("idle");
11
+ const [resendOTPCounter, setResendOTPCounter] = useState(0);
12
+ const invalidTimerRef = useRef(null);
13
+ const sessionTokenRef = useRef(sessionToken);
14
+ const resendOTP = useCallback(() => {
15
+ setStatus('loading');
16
+ axiosClient({
17
+ url: '/auth/mobile/link-primary-account/resend-email-otp',
18
+ method: 'POST',
19
+ data: { sessionToken: sessionTokenRef.current },
20
+ }).then((res) => {
21
+ setResendOTPCounter(prevCounter => prevCounter + 1);
22
+ sessionTokenRef.current = res.data.sessionToken;
23
+ }).catch((err) => {
24
+ console.log(err);
25
+ const message = err?.response?.data?.errors?.[0]?.message ?? 'Unable to send OTP. Please try again.';
26
+ showMessage({ message });
27
+ }).finally(() => setStatus("idle"));
28
+ }, []);
29
+ const validateOTP = useCallback(({ otp, onVerifiedOTP }) => {
30
+ setStatus('loading');
31
+ axiosClient({
32
+ url: '/auth/mobile/link-primary-account/verify-email-otp',
33
+ method: 'POST',
34
+ data: {
35
+ otp,
36
+ sessionToken: sessionTokenRef.current
37
+ },
38
+ }).then((res) => {
39
+ setStatus('valid');
40
+ onVerifiedOTP({ sessionToken: res?.data?.sessionToken });
41
+ setStatus('idle');
42
+ }).catch((error) => {
43
+ const errorCode = error?.response?.status;
44
+ const isInvalidOtp = errorCode === 400;
45
+ const message = error?.response?.data?.errors?.[0]?.message ||
46
+ (isInvalidOtp
47
+ ? "Invalid OTP. Please try again."
48
+ : "Verification failed. Please try again.");
49
+ showMessage({ message });
50
+ setStatus(isInvalidOtp ? "invalid" : "idle");
51
+ if (isInvalidOtp) {
52
+ // Clear any existing timeout before setting a new one
53
+ if (invalidTimerRef.current)
54
+ clearTimeout(invalidTimerRef.current);
55
+ invalidTimerRef.current = setTimeout(() => setStatus("idle"), 5000);
56
+ }
57
+ });
58
+ }, []);
59
+ useEffect(() => {
60
+ return () => {
61
+ if (invalidTimerRef.current) {
62
+ clearTimeout(invalidTimerRef.current);
63
+ }
64
+ };
65
+ }, []);
66
+ return {
67
+ status,
68
+ resendOTPCounter,
69
+ resendOTP,
70
+ validateOTP,
71
+ };
72
+ };
73
+ export { useVerifyLinkPrimaryAccountEmailOTP };
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useVerifyLinkPrimaryAccountEmailOTP } from "./hooks/internal/useVerifyLinkPrimaryAccountEmailOTP";
3
+ import { VerifyEmailOTP } from "../../components/VerifyEmailOTP";
4
+ const VerifyLinkPrimaryAccountEmailOTP = ({ email, sessionToken, onVerifiedOTP }) => {
5
+ const { status, resendOTPCounter, resendOTP, validateOTP, } = useVerifyLinkPrimaryAccountEmailOTP({ sessionToken });
6
+ return (_jsx(VerifyEmailOTP, { email: email, status: status, resendOTPCounter: resendOTPCounter, validateOTP: (otp) => validateOTP?.({ otp, onVerifiedOTP }), resendOTP: resendOTP }));
7
+ };
8
+ export default VerifyLinkPrimaryAccountEmailOTP;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { VerifyEmailOTP } from "../../components/VerifyEmailOTP";
3
+ import { useVerifyLinkPrimaryAccountEmailOTP } from "./hooks/internal/useVerifyLinkPrimaryAccountEmailOTP";
4
+ const VerifyLinkPrimaryAccountEmailOTP = ({ navigation, route }) => {
5
+ const { phone, email, sessionToken } = route.params;
6
+ const { status, resendOTPCounter, validateOTP, resendOTP, } = useVerifyLinkPrimaryAccountEmailOTP({ sessionToken });
7
+ return (_jsx(VerifyEmailOTP, { email: email, status: status, resendOTPCounter: resendOTPCounter, validateOTP: (otp) => validateOTP?.({
8
+ otp,
9
+ onVerifiedOTP: ({ sessionToken }) => {
10
+ navigation.navigate('VerifyLinkPrimaryAccountMobileOTP', { sessionToken, phone });
11
+ }
12
+ }), resendOTP: resendOTP }));
13
+ };
14
+ export default VerifyLinkPrimaryAccountEmailOTP;
@@ -0,0 +1,82 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { showMessage } from "../../../../helpers/show-message";
3
+ import { useInterval } from "../../../../hooks/internal/useTimer";
4
+ import { axiosClient } from "../../../../api/axiosClient";
5
+ import { useAuthPackageContext } from "../../../../hooks/internal/useAuthPackageContext";
6
+ const initialTimer = 180;
7
+ /**
8
+ * @internal
9
+ * Hook for managing useVerifyLinkPrimaryAccountMobileOTP hook state and auth context integration.
10
+ * This hook is not exposed to package consumers.
11
+ */
12
+ const useVerifyLinkPrimaryAccountMobileOTP = ({ sessionToken }) => {
13
+ const [status, setStatus] = useState('timer');
14
+ const [timer, setTimer] = useState(initialTimer);
15
+ const { onLogin } = useAuthPackageContext();
16
+ const invalidTimerRef = useRef(null);
17
+ const sessionTokenRef = useRef(sessionToken);
18
+ useInterval(() => {
19
+ setTimer((t) => (t > 0 ? t - 1 : 0));
20
+ }, 1000);
21
+ const sendOTP = useCallback(() => {
22
+ setStatus('loading');
23
+ axiosClient({
24
+ url: '/auth/mobile/link-primary-account/resend-mobile-otp',
25
+ method: 'POST',
26
+ data: { sessionToken: sessionTokenRef.current },
27
+ }).then((res) => {
28
+ setStatus('timer');
29
+ setTimer(initialTimer);
30
+ sessionTokenRef.current = res.data.sessionToken;
31
+ }).catch((err) => {
32
+ console.log(err);
33
+ const message = err?.response?.data?.errors?.[0]?.message ?? 'Unable to send OTP. Please try again.';
34
+ showMessage({ message });
35
+ }).finally(() => setStatus('timer'));
36
+ }, []);
37
+ const validateOTP = useCallback(({ otp, source }) => {
38
+ setStatus('loading');
39
+ axiosClient({
40
+ url: '/auth/mobile/link-primary-account/verify-mobile-otp',
41
+ method: 'POST',
42
+ data: {
43
+ otp,
44
+ sessionToken: sessionTokenRef.current,
45
+ source
46
+ },
47
+ }).then((res) => {
48
+ const { token, member } = res.data;
49
+ setStatus('valid');
50
+ onLogin({ token, member });
51
+ }).catch((err) => {
52
+ if (err?.response?.status === 400) {
53
+ setStatus('invalid');
54
+ if (invalidTimerRef.current)
55
+ clearTimeout(invalidTimerRef.current);
56
+ invalidTimerRef.current = setTimeout(() => setStatus('timer'), 5000);
57
+ showMessage({ message: err?.response?.data?.errors?.[0]?.message ?? 'Invalid OTP. Please try again.' });
58
+ }
59
+ else {
60
+ const message = err?.response?.data?.errors?.[0]?.message ?? 'Verification failed. Please try again.';
61
+ showMessage({ message });
62
+ setStatus('timer');
63
+ }
64
+ });
65
+ }, []);
66
+ useEffect(() => {
67
+ return () => {
68
+ if (invalidTimerRef.current)
69
+ clearTimeout(invalidTimerRef.current);
70
+ };
71
+ }, []);
72
+ useEffect(() => {
73
+ sendOTP();
74
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
75
+ return {
76
+ timer,
77
+ status,
78
+ sendOTP,
79
+ validateOTP
80
+ };
81
+ };
82
+ export { useVerifyLinkPrimaryAccountMobileOTP };
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { VerifyMobileOTP } from "../../components/VerifyMobileOTP";
3
+ import { useVerifyLinkPrimaryAccountMobileOTP } from "./hooks/internal/useVerifyLinkPrimaryAccountMobileOTP";
4
+ const VerifyLinkPrimaryAccountMobileOTP = ({ phone, sessionToken }) => {
5
+ const { timer, status, validateOTP, sendOTP, } = useVerifyLinkPrimaryAccountMobileOTP({ sessionToken });
6
+ return (_jsx(VerifyMobileOTP, { timer: timer, phone: phone, status: status, validateOTP: (otp) => validateOTP({ otp, source: 'web' }), resendOTP: sendOTP }));
7
+ };
8
+ export default VerifyLinkPrimaryAccountMobileOTP;
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { VerifyMobileOTP } from '../../components/VerifyMobileOTP';
3
+ import { useVerifyLinkPrimaryAccountMobileOTP } from './hooks/internal/useVerifyLinkPrimaryAccountMobileOTP';
4
+ import { Platform } from 'react-native';
5
+ const VerifyLinkPrimaryAccountMobileOTP = ({ route }) => {
6
+ const { sessionToken, phone } = route.params;
7
+ const { timer, status, validateOTP, sendOTP, } = useVerifyLinkPrimaryAccountMobileOTP({ sessionToken });
8
+ return (_jsx(VerifyMobileOTP, { timer: timer, phone: phone, status: status, validateOTP: (otp) => validateOTP({ otp, source: Platform.OS }), resendOTP: sendOTP }));
9
+ };
10
+ export default VerifyLinkPrimaryAccountMobileOTP;
@@ -0,0 +1,127 @@
1
+ // src/screens/Welcome/SocialAuth/commonSocialAuth.ts
2
+ import { LoginMethodCode, SocialLoginsEnum } from "../../../enums";
3
+ import { axiosClient } from "../../../api/axiosClient";
4
+ import { checkEmailExists } from "../../../api/auth";
5
+ // ============================================
6
+ // TYPES & ENUMS
7
+ // ============================================
8
+ export var SocialAuthStatus;
9
+ (function (SocialAuthStatus) {
10
+ SocialAuthStatus["REGISTER"] = "REGISTER";
11
+ SocialAuthStatus["INVALID"] = "INVALID";
12
+ SocialAuthStatus["SUCCESS"] = "SUCCESS";
13
+ })(SocialAuthStatus || (SocialAuthStatus = {}));
14
+ // ============================================
15
+ // CONSTANTS
16
+ // ============================================
17
+ const EXISTING_LOGIN_TYPE = {
18
+ [LoginMethodCode.Email]: 'Email Address',
19
+ [LoginMethodCode.Facebook]: 'Facebook Account',
20
+ [LoginMethodCode.Google]: 'Google Account',
21
+ [LoginMethodCode.Apple]: 'Apple ID',
22
+ };
23
+ const PROVIDER_CONFIG = {
24
+ [SocialLoginsEnum.Google]: {
25
+ endpoint: '/auth/google',
26
+ tokenKey: 'token',
27
+ loginMethodCode: LoginMethodCode.Google,
28
+ },
29
+ [SocialLoginsEnum.Facebook]: {
30
+ endpoint: '/auth/facebook',
31
+ tokenKey: 'token',
32
+ loginMethodCode: LoginMethodCode.Facebook,
33
+ },
34
+ [SocialLoginsEnum.Apple]: {
35
+ endpoint: '/auth/apple/appleid-exists',
36
+ tokenKey: 'token',
37
+ loginMethodCode: LoginMethodCode.Apple,
38
+ },
39
+ };
40
+ // ============================================
41
+ // HELPER FUNCTIONS
42
+ // ============================================
43
+ /**
44
+ * Verifies if the attempted login method matches the registered method for an email
45
+ * @param email - User's email address
46
+ * @param attemptedLoginCode - Login method code being attempted
47
+ * @returns Verification result with email existence and validity
48
+ */
49
+ const verifyLoginType = async (email, attemptedLoginCode) => {
50
+ const { emailExist, loginType } = await checkEmailExists(email);
51
+ const existingLoginCode = Number(loginType);
52
+ if (emailExist) {
53
+ const isValidLoginType = EXISTING_LOGIN_TYPE[attemptedLoginCode] === EXISTING_LOGIN_TYPE[existingLoginCode];
54
+ return {
55
+ emailExist,
56
+ isValidLoginType,
57
+ existingLoginType: EXISTING_LOGIN_TYPE[existingLoginCode],
58
+ };
59
+ }
60
+ return { emailExist };
61
+ };
62
+ /**
63
+ * Generic handler for social authentication
64
+ * @param provider - Social provider (google, facebook, apple)
65
+ * @param email - User's email
66
+ * @param identityToken - Provider's identity token
67
+ * @param platform - Platform (web, ios, android)
68
+ * @returns Authentication result
69
+ */
70
+ const handleSocialAuth = async (provider, email, identityToken, platform) => {
71
+ try {
72
+ const config = PROVIDER_CONFIG[provider];
73
+ // Verify login type
74
+ const { emailExist, isValidLoginType, existingLoginType } = await verifyLoginType(email, config.loginMethodCode);
75
+ // New user - needs registration
76
+ if (!emailExist) {
77
+ return {
78
+ status: SocialAuthStatus.REGISTER,
79
+ data: { email },
80
+ };
81
+ }
82
+ // Wrong Social login method
83
+ if (!isValidLoginType) {
84
+ return {
85
+ status: SocialAuthStatus.INVALID,
86
+ data: { existingLoginType },
87
+ };
88
+ }
89
+ // Authenticate with backend
90
+ const { data } = await axiosClient.post(config.endpoint, {
91
+ [config.tokenKey]: identityToken,
92
+ source: platform,
93
+ });
94
+ return {
95
+ status: SocialAuthStatus.SUCCESS,
96
+ data: {
97
+ token: data.token,
98
+ member: data.member,
99
+ },
100
+ };
101
+ }
102
+ catch (error) {
103
+ // Let the calling code handle the error
104
+ throw error;
105
+ }
106
+ };
107
+ // ============================================
108
+ // PUBLIC API
109
+ // ============================================
110
+ /**
111
+ * Handles Google authentication
112
+ */
113
+ export const handleGoogleAuth = async ({ email, googleIdentityToken, platform, }) => {
114
+ return handleSocialAuth(SocialLoginsEnum.Google, email, googleIdentityToken, platform);
115
+ };
116
+ /**
117
+ * Handles Facebook authentication
118
+ */
119
+ export const handleFacebookAuth = async ({ email, facebookIdentityToken, platform }) => {
120
+ return handleSocialAuth(SocialLoginsEnum.Facebook, email, facebookIdentityToken, platform);
121
+ };
122
+ /**
123
+ * Handles Apple authentication
124
+ */
125
+ export const handleAppleAuth = async ({ email, appleIdentityToken, platform }) => {
126
+ return handleSocialAuth(SocialLoginsEnum.Apple, email, appleIdentityToken, platform);
127
+ };