@truworth/twc-auth 1.2.5 → 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 (46) hide show
  1. package/build/assets/email_icon.svg +6 -0
  2. package/build/src/constants/social-login-options.js +16 -0
  3. package/build/src/contexts/AuthContext.js +4 -2
  4. package/build/src/enums/index.js +1 -0
  5. package/build/src/enums/socialLogins.enum.js +6 -0
  6. package/build/src/helpers/{Network.js → network.js} +1 -1
  7. package/build/src/hooks/useRequest.js +1 -1
  8. package/build/src/screens/EnterEmail/hooks/internal/useEnterEmail.js +0 -1
  9. package/build/src/screens/EnterEmail/index.js +31 -3
  10. package/build/src/screens/SignUp/components/SignUpWebComponent/index.js +11 -1
  11. package/build/src/screens/SignUp/hooks/internal/useSignUp.js +1 -1
  12. package/build/src/screens/SignUp/index.native.js +3 -0
  13. package/build/src/screens/UserConsent/hooks/internal/useConsent.js +10 -1
  14. package/build/src/screens/Welcome/SocialAuth/commonSocialAuth.js +127 -0
  15. package/build/src/screens/Welcome/SocialAuth/hooks/useSocialAuth.native.js +192 -0
  16. package/build/src/screens/Welcome/SocialAuth/hooks/useSocialAuth.web.js +13 -0
  17. package/build/src/screens/Welcome/SocialAuth/hooks/web/useFacebookAuth.web.js +118 -0
  18. package/build/src/screens/Welcome/SocialAuth/hooks/web/useGoogleAuth.web.js +75 -0
  19. package/build/src/screens/Welcome/components/SocialLoginModal/index.js +9 -0
  20. package/build/src/screens/Welcome/components/SocialLoginModal/index.native.js +21 -0
  21. package/build/src/screens/Welcome/components/SocialLoginModal/types.js +1 -0
  22. package/build/src/screens/Welcome/hooks/internal/useWelcome.js +10 -5
  23. package/build/src/screens/Welcome/index.native.js +41 -4
  24. package/build/types/constants/social-login-options.d.ts +3 -0
  25. package/build/types/contexts/AuthContext.d.ts +2 -1
  26. package/build/types/contexts/type.d.ts +9 -0
  27. package/build/types/enums/index.d.ts +1 -0
  28. package/build/types/enums/socialLogins.enum.d.ts +5 -0
  29. package/build/types/helpers/types.d.ts +7 -1
  30. package/build/types/navigator/index.native.d.ts +3 -0
  31. package/build/types/screens/EnterEmail/hooks/internal/useEnterEmail.d.ts +0 -1
  32. package/build/types/screens/Welcome/SocialAuth/commonSocialAuth.d.ts +50 -0
  33. package/build/types/screens/Welcome/SocialAuth/hooks/useSocialAuth.native.d.ts +7 -0
  34. package/build/types/screens/Welcome/SocialAuth/hooks/useSocialAuth.web.d.ts +7 -0
  35. package/build/types/screens/Welcome/SocialAuth/hooks/web/useFacebookAuth.web.d.ts +5 -0
  36. package/build/types/screens/Welcome/SocialAuth/hooks/web/useGoogleAuth.web.d.ts +4 -0
  37. package/build/types/screens/Welcome/components/SocialLoginModal/index.d.ts +3 -0
  38. package/build/types/screens/Welcome/components/SocialLoginModal/index.native.d.ts +3 -0
  39. package/build/types/screens/Welcome/components/SocialLoginModal/types.d.ts +8 -0
  40. package/build/types/screens/Welcome/hooks/internal/useWelcome.d.ts +8 -0
  41. package/build/types/types/types.d.ts +3 -0
  42. package/package.json +3 -1
  43. package/build/assets/okay_icon copy.svg +0 -3
  44. /package/build/src/helpers/{Validation.js → validation.js} +0 -0
  45. /package/build/types/helpers/{Network.d.ts → network.d.ts} +0 -0
  46. /package/build/types/helpers/{Validation.d.ts → validation.d.ts} +0 -0
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="22" height="18" viewBox="0 0 22 18">
2
+ <g fill="#ACD7D3">
3
+ <path d="M6.058 5.341c0 .568-.462 1.031-1.032 1.031H2.62c-.57 0-1.032-.463-1.032-1.03 0-.57.463-1.033 1.032-1.033h2.406c.57 0 1.032.463 1.032 1.032zM8.78 8.97c0 .568-.462 1.031-1.033 1.031H5.341c-.569 0-1.032-.463-1.032-1.03 0-.57.463-1.033 1.032-1.033h2.406c.57 0 1.032.463 1.032 1.032zM11.274 12.6c0 .567-.462 1.03-1.032 1.03H7.836c-.569 0-1.032-.463-1.032-1.03 0-.57.463-1.033 1.032-1.033h2.406c.57 0 1.032.463 1.032 1.032z"/>
4
+ <path d="M18.448.005H3.462C3.454.005 3.447 0 3.438 0H1.032C.462 0 0 .463 0 1.032 0 1.6.463 2.063 1.032 2.063h4.126l5.277 5.347c1.375 1.392 3.623 1.407 5.016.033l4.406-4.349c.048.145.08.297.08.457v10.361c0 .82-.668 1.488-1.489 1.488h-6.232c-.016 0-.03-.01-.047-.01H9.763c-.57 0-1.032.464-1.032 1.033 0 .568.463 1.03 1.032 1.03h.595v.006h8.09c1.956 0 3.547-1.59 3.547-3.547V3.552c0-1.957-1.59-3.547-3.547-3.547zm-4.443 5.973c-.584.576-1.529.57-2.105-.014L8.05 2.063h9.92l-3.965 3.915z"/>
5
+ </g>
6
+ </svg>
@@ -0,0 +1,16 @@
1
+ import { SocialLoginsEnum } from "../enums";
2
+ const socialLoginOptions = [
3
+ {
4
+ type: SocialLoginsEnum.Google,
5
+ iconImageUrl: `https://cdn-thewellnesscorner.s3.amazonaws.com/twc-web-images/template/google-icon.png`,
6
+ },
7
+ {
8
+ type: SocialLoginsEnum.Facebook,
9
+ iconImageUrl: `https://cdn-thewellnesscorner.s3.amazonaws.com/twc-web-images/template/facebook-icon.png`,
10
+ },
11
+ {
12
+ type: SocialLoginsEnum.Apple,
13
+ iconImageUrl: `https://cdn-thewellnesscorner.s3.amazonaws.com/twc-web-images/template/apple-icon.png`,
14
+ }
15
+ ];
16
+ export { socialLoginOptions };
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React, { useEffect, useState, useMemo, useCallback } from 'react';
3
3
  import { MEMBER_IMAGES_URL } from '../constants/cdn-url';
4
- import { createHttpClient } from '../helpers/Network';
4
+ import { createHttpClient } from '../helpers/network';
5
5
  /**
6
6
  * Public Auth Authentication Context
7
7
  *
@@ -32,8 +32,9 @@ const AuthPackageContext = React.createContext(null);
32
32
  * @param onLaunchAuthSession - Optional callback after successfully launching the auth session. For example, it can be used to set the Firebase notification token or request Android permissions.
33
33
  * @param onRefreshSession - Optional handler for refreshing user session
34
34
  * @param openChatSupport - Optional callback to open chat support
35
+ * @param socialLoginConfig - Optional social login configuration
35
36
  */
36
- const AuthProvider = ({ children, LogoComponent, session, appConfig, onLogin, onLogout, onLaunchAuthSession, onRefreshSession, openChatSupport }) => {
37
+ const AuthProvider = ({ children, LogoComponent, session, appConfig, onLogin, onLogout, onLaunchAuthSession, onRefreshSession, openChatSupport, socialLoginConfig }) => {
37
38
  const [isLoadingProfile, setIsLoadingProfile] = useState(false);
38
39
  const [profile, setProfile] = useState(null);
39
40
  const [client, setClient] = useState(null);
@@ -171,6 +172,7 @@ const AuthProvider = ({ children, LogoComponent, session, appConfig, onLogin, on
171
172
  LogoComponent,
172
173
  appConfig: appConfigValue,
173
174
  registrationMethod,
175
+ socialLoginConfig,
174
176
  onLaunchAuthSession,
175
177
  onLogin,
176
178
  logout,
@@ -1,2 +1,3 @@
1
1
  export * from './registrationMethod.enum';
2
2
  export * from './loginMethod.enum';
3
+ export * from './socialLogins.enum';
@@ -0,0 +1,6 @@
1
+ export var SocialLoginsEnum;
2
+ (function (SocialLoginsEnum) {
3
+ SocialLoginsEnum["Google"] = "google";
4
+ SocialLoginsEnum["Facebook"] = "facebook";
5
+ SocialLoginsEnum["Apple"] = "apple";
6
+ })(SocialLoginsEnum || (SocialLoginsEnum = {}));
@@ -1,5 +1,5 @@
1
1
  import { axiosClient } from '../api/axiosClient';
2
- import { showMessage } from '../helpers/show-message';
2
+ import { showMessage } from './show-message';
3
3
  import {} from 'axios';
4
4
  export const createHttpClient = ({ token, onRefreshSession, onLogout }) => {
5
5
  let currentToken = token;
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useMemo, useState } from 'react';
2
2
  import { showMessage } from '../helpers/show-message';
3
3
  import { useAuthPackageContext } from './internal/useAuthPackageContext';
4
- import { createHttpClient } from '../helpers/Network';
4
+ import { createHttpClient } from '../helpers/network';
5
5
  const useRequest = () => {
6
6
  const { token: sessionToken, logout, refreshSession } = useAuthPackageContext();
7
7
  const [token, setToken] = useState(sessionToken);
@@ -69,7 +69,6 @@ const useEnterEmail = () => {
69
69
  handleClearEmail,
70
70
  isLoginConflictModalVisible,
71
71
  setIsLoginConflictModalVisible,
72
- onRegistrationMethodChange,
73
72
  appName: appConfig.appName,
74
73
  loginConflictTitle: `Sign in with ${loginType}`,
75
74
  loginConflictDescription: `Looks like you previously registered using ${loginType}. Please go back and sign in with ${loginType}.`,
@@ -1,12 +1,31 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Button, Form, TextInput, useForm } from '@truworth/twc-web-design';
2
+ import { Button, Flex, Form, TextInput, Typography, useForm } from '@truworth/twc-web-design';
3
3
  import { ConfirmationModal as LoginConflictModal } from '../../components/ConfirmationModal';
4
4
  import { ScreenLayout } from "../../components/ScreenLayout";
5
5
  import { useEnterEmail } from "./hooks/internal/useEnterEmail";
6
6
  import { SupportDetails } from '../../components/SupportDetails';
7
+ import { useWelcome } from '../Welcome/hooks/internal/useWelcome';
8
+ import { socialLoginOptions } from '../../constants/social-login-options';
9
+ import { SocialLoginModal } from '../Welcome/components/SocialLoginModal';
10
+ import { useSocialAuth } from '../Welcome/SocialAuth/hooks/useSocialAuth.web';
11
+ import { SocialLoginsEnum } from '../../enums';
12
+ import _ from 'lodash';
7
13
  const EnterEmail = ({ onContinue, onPressSignInWithSSO }) => {
8
- const { email, isEmailValid, handleEmailChange, appName, handleEmailExists, loading, loginConflictTitle, loginConflictDescription, isLoginConflictModalVisible, setIsLoginConflictModalVisible } = useEnterEmail();
14
+ const { loginWithGoogle, loginWithFacebook } = useSocialAuth();
15
+ const { email, isEmailValid, handleEmailChange, appName, handleEmailExists, loading, loginConflictTitle, loginConflictDescription, isLoginConflictModalVisible, setIsLoginConflictModalVisible, } = useEnterEmail();
16
+ const { showSocialLoginModal, setShowSocialLoginModal, socialLoginType, setSocialLoginType, isSocialLoginEnabled, socialLoginConfig, } = useWelcome();
9
17
  const form = useForm({ defaultValues: { email } });
18
+ const handleLogin = () => {
19
+ setShowSocialLoginModal(false);
20
+ switch (socialLoginType) {
21
+ case SocialLoginsEnum.Google:
22
+ return loginWithGoogle();
23
+ case SocialLoginsEnum.Facebook:
24
+ return loginWithFacebook();
25
+ default:
26
+ return;
27
+ }
28
+ };
10
29
  return (_jsxs(_Fragment, { children: [_jsxs(ScreenLayout, { title: `Hi, Welcome To ${appName}!`, subTitle: "Please enter email to get started.", buttonProps: {
11
30
  loading,
12
31
  label: 'Continue',
@@ -21,6 +40,15 @@ const EnterEmail = ({ onContinue, onPressSignInWithSSO }) => {
21
40
  handleEmailChange(e.target.value);
22
41
  }
23
42
  }) }) }) }), isLoginConflictModalVisible &&
24
- _jsx(LoginConflictModal, { title: loginConflictTitle, description: loginConflictDescription, visible: isLoginConflictModalVisible, onProceed: () => setIsLoginConflictModalVisible(false), onClose: () => setIsLoginConflictModalVisible(false), primaryLabel: 'Okay' })] }), _jsx(Button, { isFullWidth: true, type: "button", label: 'Sign In with SSO', variant: 'secondary', className: 'flex-none mt-6', onClick: onPressSignInWithSSO }), _jsx(SupportDetails, {})] }));
43
+ _jsx(LoginConflictModal, { title: loginConflictTitle, description: loginConflictDescription, visible: isLoginConflictModalVisible, onProceed: () => setIsLoginConflictModalVisible(false), onClose: () => setIsLoginConflictModalVisible(false), primaryLabel: 'Okay' })] }), _jsx(Button, { isFullWidth: true, type: "button", label: 'Sign In with SSO', variant: 'secondary', className: 'flex-none mt-6', onClick: onPressSignInWithSSO }), isSocialLoginEnabled && (_jsxs(_Fragment, { children: [_jsxs(Flex, { align: "center", className: "my-6", children: [_jsx(Flex, { className: "flex-1 border-t border-gray-300" }), _jsx(Typography, { type: 'body', size: 'small', className: "text-gray-500 px-4", children: "or continue with" }), _jsx(Flex, { className: "flex-1 border-t border-gray-300" })] }), _jsx(Flex, { justify: 'center', align: 'center', className: "gap-4", children: socialLoginOptions.map(({ type, iconImageUrl }) => {
44
+ if (type === SocialLoginsEnum.Apple) {
45
+ return null;
46
+ }
47
+ return socialLoginConfig?.[type]?.enabled && (_jsxs("button", { type: "button", className: "flex justify-center p-3 gap-2 items-center\n rounded-[50px] flex-1 border text-gray-800 hover:text-gray-800\n border-gray-100 bg-gray-100 hover:border-gray-300 transition-all duration-300 cursor-pointer", onClick: () => {
48
+ setSocialLoginType(type);
49
+ setShowSocialLoginModal(true);
50
+ }, children: [_jsx("img", { src: iconImageUrl, style: { width: 20, height: 20 } }), _jsx(Typography, { type: 'utility', size: 'medium', children: _.startCase(type) })] }, type));
51
+ }) })] })), showSocialLoginModal &&
52
+ _jsx(SocialLoginModal, { visible: showSocialLoginModal, hide: () => setShowSocialLoginModal(false), socialLoginType: socialLoginType, onClick: handleLogin }), _jsx(SupportDetails, {})] }));
25
53
  };
26
54
  export default EnterEmail;
@@ -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
  }
@@ -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";
@@ -50,6 +50,9 @@ const SignUp = ({ navigation, route }) => {
50
50
  selectedDOB,
51
51
  countryCode,
52
52
  referralCode,
53
+ googleUserId: route.params?.googleUserId,
54
+ fbUserId: route.params?.fbUserId,
55
+ appleUserId: route.params?.appleUserId
53
56
  };
54
57
  if (route.params?.registrationToken) {
55
58
  navigation.navigate('UserConsent', {
@@ -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',
@@ -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
+ };
@@ -0,0 +1,192 @@
1
+ import { useCallback, useState } from "react";
2
+ import { Alert, Linking, Platform } from "react-native";
3
+ import { useAuthPackageContext } from "../../../../hooks/internal/useAuthPackageContext";
4
+ import { useNavigation } from "@react-navigation/native";
5
+ import { GoogleSignin } from "@react-native-google-signin/google-signin";
6
+ import { handleAppleAuth, handleFacebookAuth, handleGoogleAuth, SocialAuthStatus } from "../commonSocialAuth";
7
+ import { RegistrationMethod, SocialLoginsEnum } from "../../../../enums";
8
+ import { showMessage } from "../../../../helpers/show-message";
9
+ import { AccessToken, GraphRequest, GraphRequestManager, LoginManager } from "react-native-fbsdk-next";
10
+ import AppleAuth, { AppleAuthRequestOperation, AppleAuthRequestScope, AppleAuthCredentialState } from '@invertase/react-native-apple-authentication';
11
+ import { axiosClient } from "../../../../api/axiosClient";
12
+ const useSocialAuth = () => {
13
+ const [loading, setLoading] = useState(false);
14
+ const { onLogin, socialLoginConfig, onRegistrationMethodChange } = useAuthPackageContext();
15
+ const navigation = useNavigation();
16
+ const googleAppId = socialLoginConfig?.google?.webClientId;
17
+ const loginWithGoogle = useCallback(async () => {
18
+ try {
19
+ setLoading(true);
20
+ GoogleSignin.configure({ webClientId: googleAppId });
21
+ await GoogleSignin.hasPlayServices();
22
+ const googleResponse = await GoogleSignin.signIn();
23
+ const { user, idToken } = googleResponse.data || {};
24
+ if (!user || !idToken) {
25
+ return showMessage({
26
+ message: "Google login failed",
27
+ type: "error"
28
+ });
29
+ }
30
+ const result = await handleGoogleAuth({
31
+ email: user.email,
32
+ googleIdentityToken: idToken,
33
+ platform: Platform.OS === "ios" ? "ios" : "android",
34
+ });
35
+ return handleSocialAuthResult(result, {
36
+ email: user.email,
37
+ firstName: user.givenName ?? '',
38
+ lastName: user.familyName ?? '',
39
+ googleUserId: user.id,
40
+ }, SocialLoginsEnum.Google);
41
+ }
42
+ catch (err) {
43
+ console.error("Google login failed:", err);
44
+ return { error: err };
45
+ }
46
+ finally {
47
+ setLoading(false);
48
+ }
49
+ }, [googleAppId]);
50
+ const loginWithFacebook = useCallback(async () => {
51
+ try {
52
+ const facebookResponse = await LoginManager.logInWithPermissions(['public_profile', 'email']);
53
+ if (facebookResponse.isCancelled) {
54
+ return;
55
+ }
56
+ setLoading(true);
57
+ const fbAccessToken = await AccessToken.getCurrentAccessToken();
58
+ const profile = await new Promise((resolve, reject) => {
59
+ new GraphRequestManager().addRequest(new GraphRequest('/me', {
60
+ accessToken: fbAccessToken?.accessToken,
61
+ parameters: { fields: { string: 'email,name' } },
62
+ }, (err, res) => (err ? reject(err) : resolve(res)))).start();
63
+ });
64
+ if (!profile.email || !profile.id) {
65
+ return showMessage({
66
+ message: "Facebook login failed",
67
+ type: "error"
68
+ });
69
+ }
70
+ const nameParts = profile.name?.split(' ') || [];
71
+ const firstName = nameParts[0] || undefined;
72
+ const lastName = nameParts.slice(1).join(' ') || undefined;
73
+ const result = await handleFacebookAuth({
74
+ email: profile.email,
75
+ facebookIdentityToken: fbAccessToken?.accessToken ?? '',
76
+ platform: Platform.OS === "ios" ? "ios" : "android",
77
+ });
78
+ return handleSocialAuthResult(result, {
79
+ email: profile.email,
80
+ firstName,
81
+ lastName,
82
+ fbUserId: profile.id
83
+ }, SocialLoginsEnum.Facebook);
84
+ }
85
+ catch (err) {
86
+ console.error("Facebook login failed:", err);
87
+ return { error: err };
88
+ }
89
+ finally {
90
+ setLoading(false);
91
+ }
92
+ }, []);
93
+ const loginWithApple = useCallback(async () => {
94
+ try {
95
+ const appleAuthResponse = await AppleAuth.performRequest({
96
+ requestedOperation: AppleAuthRequestOperation.LOGIN,
97
+ requestedScopes: [AppleAuthRequestScope.EMAIL,
98
+ AppleAuthRequestScope.FULL_NAME],
99
+ });
100
+ const credentialState = await AppleAuth.getCredentialStateForUser(appleAuthResponse.user);
101
+ if (credentialState !== AppleAuthCredentialState.AUTHORIZED) {
102
+ return;
103
+ }
104
+ setLoading(true);
105
+ if (!appleAuthResponse.email) {
106
+ try {
107
+ const { data } = await axiosClient.post('/auth/apple', {
108
+ token: appleAuthResponse.identityToken,
109
+ source: Platform.OS,
110
+ });
111
+ onLogin({
112
+ token: data.token,
113
+ member: data.member
114
+ });
115
+ return;
116
+ }
117
+ catch (error) {
118
+ return Alert.alert('Account Not Found!', "The Wellness Corner account linked with this Apple ID was not found. Please unlink this Apple ID from The Wellness Corner app and try again. To stop using this Apple ID with The Wellness Corner, tap on 'Know More' below.", [
119
+ {
120
+ text: 'Know More',
121
+ style: 'default',
122
+ onPress: () => Linking.openURL('https://support.apple.com/en-in/HT210426')
123
+ },
124
+ {
125
+ text: 'Cancel',
126
+ style: 'cancel'
127
+ }
128
+ ], { cancelable: true });
129
+ }
130
+ finally {
131
+ setLoading(false);
132
+ }
133
+ }
134
+ if (!appleAuthResponse.identityToken || !appleAuthResponse.email) {
135
+ return showMessage({
136
+ message: "Apple login failed",
137
+ type: "error"
138
+ });
139
+ }
140
+ const result = await handleAppleAuth({
141
+ email: appleAuthResponse.email,
142
+ appleIdentityToken: appleAuthResponse.identityToken,
143
+ platform: Platform.OS === "ios" ? "ios" : "android",
144
+ });
145
+ return handleSocialAuthResult(result, {
146
+ email: appleAuthResponse.email,
147
+ firstName: appleAuthResponse.fullName?.givenName ?? '',
148
+ lastName: appleAuthResponse.fullName?.familyName ?? '',
149
+ appleUserId: appleAuthResponse.user
150
+ }, SocialLoginsEnum.Apple);
151
+ }
152
+ catch (error) {
153
+ console.error("Apple login failed:", error);
154
+ return { error: error };
155
+ }
156
+ finally {
157
+ setLoading(false);
158
+ }
159
+ }, []);
160
+ const providerCleanup = {
161
+ google: () => GoogleSignin.signOut(),
162
+ facebook: () => LoginManager.logOut(),
163
+ apple: () => Promise.resolve(), // Apple doesn't need explicit cleanup
164
+ };
165
+ const handleSocialAuthResult = async (result, userData, providerName) => {
166
+ switch (result.status) {
167
+ case SocialAuthStatus.REGISTER:
168
+ onRegistrationMethodChange(RegistrationMethod.SOCIAL);
169
+ return navigation.navigate('SignUp', userData);
170
+ case SocialAuthStatus.INVALID:
171
+ // Clean up provider session
172
+ await providerCleanup[providerName]();
173
+ return showMessage({
174
+ message: `You have previously registered using your ${result.data.existingLoginType}. Please use your ${result.data.existingLoginType} to login.`,
175
+ type: 'error'
176
+ });
177
+ case SocialAuthStatus.SUCCESS:
178
+ onLogin({
179
+ token: result.data.token,
180
+ member: result.data.member
181
+ });
182
+ break;
183
+ }
184
+ };
185
+ return {
186
+ loading,
187
+ loginWithGoogle,
188
+ loginWithFacebook,
189
+ loginWithApple
190
+ };
191
+ };
192
+ export { useSocialAuth };
@@ -0,0 +1,13 @@
1
+ import { useFacebookAuth } from "./web/useFacebookAuth.web";
2
+ import { useGoogleAuth } from "./web/useGoogleAuth.web";
3
+ const useSocialAuth = () => {
4
+ const { loginWithGoogle, googleSignOut } = useGoogleAuth();
5
+ const { loginWithFacebook, facebookSignOut } = useFacebookAuth();
6
+ return {
7
+ loginWithGoogle,
8
+ googleSignOut,
9
+ loginWithFacebook,
10
+ facebookSignOut
11
+ };
12
+ };
13
+ export { useSocialAuth };
@@ -0,0 +1,118 @@
1
+ import { useEffect, useCallback, useState } from "react";
2
+ import { useRouter } from "next/router";
3
+ import { useAuthPackageContext } from "../../../../../hooks/internal/useAuthPackageContext";
4
+ import { RegistrationMethod } from "../../../../../enums";
5
+ import { handleFacebookAuth } from "../../commonSocialAuth";
6
+ import { showMessage } from "../../../../../helpers/show-message";
7
+ export const useFacebookAuth = () => {
8
+ const [error, setError] = useState(null);
9
+ const { onLogin, socialLoginConfig, onRegistrationMethodChange } = useAuthPackageContext();
10
+ const router = useRouter();
11
+ const facebookAppId = socialLoginConfig?.facebook?.webClientId;
12
+ // Load Facebook SDK once
13
+ useEffect(() => {
14
+ if (!facebookAppId) {
15
+ return;
16
+ }
17
+ (function (d, s, id) {
18
+ var js, fjs = d.getElementsByTagName(s)[0];
19
+ if (d.getElementById(id)) {
20
+ return;
21
+ }
22
+ js = d.createElement(s);
23
+ js.id = id;
24
+ js.src = "https://connect.facebook.net/en_US/sdk.js";
25
+ if (fjs && fjs.parentNode) {
26
+ fjs.parentNode.insertBefore(js, fjs);
27
+ }
28
+ }(document, 'script', 'facebook-jssdk'));
29
+ initFacebookSdk();
30
+ }, [facebookAppId]);
31
+ const initFacebookSdk = () => {
32
+ window.fbAsyncInit = () => {
33
+ window.FB.init({
34
+ appId: facebookAppId,
35
+ cookie: true,
36
+ xfbml: true,
37
+ version: 'v16.0'
38
+ });
39
+ };
40
+ };
41
+ const loginWithFacebook = () => {
42
+ if (!window.FB) {
43
+ showMessage({
44
+ message: "Facebook login is still initialising. Please try again in a moment.",
45
+ type: "warning",
46
+ });
47
+ return;
48
+ }
49
+ window.FB.login(() => checkLoginState(), {
50
+ scope: "public_profile,email",
51
+ return_scopes: true,
52
+ });
53
+ };
54
+ const checkLoginState = () => window.FB.getLoginStatus((response) => {
55
+ statusChangeCallback(response);
56
+ });
57
+ // ✅ Handle status
58
+ const statusChangeCallback = useCallback(async (response) => {
59
+ try {
60
+ if (response.status === "connected") {
61
+ const accessToken = response.authResponse.accessToken;
62
+ window.FB.api("/me", { fields: "name,email" }, async (userResponse) => {
63
+ const { email, name, id: fbUserId } = userResponse;
64
+ if (!email) {
65
+ facebookSignOut();
66
+ showMessage({
67
+ message: "We couldn’t retrieve your Facebook email. Please use another login method or update your Facebook permissions.",
68
+ type: "error",
69
+ });
70
+ return;
71
+ }
72
+ const nameParts = name.split(" ");
73
+ //{ error, isValid, loginType } = await verifyLoginType(email, LoginMethodCode.Facebook);
74
+ const result = await handleFacebookAuth({
75
+ email,
76
+ facebookIdentityToken: accessToken,
77
+ platform: "web",
78
+ });
79
+ switch (result.status) {
80
+ case "REGISTER":
81
+ onRegistrationMethodChange(RegistrationMethod.SOCIAL);
82
+ return router.push({
83
+ pathname: "/registration",
84
+ query: {
85
+ email,
86
+ firstName: nameParts[0],
87
+ lastName: nameParts[1] || "",
88
+ fbUserId,
89
+ },
90
+ });
91
+ case "INVALID":
92
+ facebookSignOut();
93
+ return showMessage({
94
+ message: `You have previously registered using your ${result.data.existingLoginType}. Please use your ${result.data.existingLoginType} to login method.`,
95
+ type: "error",
96
+ });
97
+ case "SUCCESS":
98
+ onLogin({
99
+ token: result.data.token,
100
+ member: result.data.member
101
+ });
102
+ break;
103
+ }
104
+ });
105
+ }
106
+ }
107
+ catch (error) {
108
+ console.error("Google login failed:", error);
109
+ setError(error);
110
+ return { error };
111
+ }
112
+ }, []);
113
+ // ✅ Logout
114
+ const facebookSignOut = useCallback(() => {
115
+ window.FB.api("/me/permissions", "delete", null, () => window.FB.logout((res) => statusChangeCallback(res)));
116
+ }, [statusChangeCallback]);
117
+ return { loginWithFacebook, facebookSignOut, error };
118
+ };
@@ -0,0 +1,75 @@
1
+ import { useCallback } from "react";
2
+ import { useGoogleLogin } from "react-google-login";
3
+ import { useAuthPackageContext } from "../../../../../hooks/internal/useAuthPackageContext";
4
+ import { showMessage } from "../../../../../helpers/show-message";
5
+ import { RegistrationMethod } from "../../../../../enums";
6
+ import { useRouter } from "next/router";
7
+ import { handleGoogleAuth } from "../../commonSocialAuth";
8
+ export const useGoogleAuth = () => {
9
+ const router = useRouter();
10
+ const { onLogin, socialLoginConfig, onRegistrationMethodChange } = useAuthPackageContext();
11
+ const googleAppId = socialLoginConfig?.google?.webClientId;
12
+ const onSuccess = async (response) => {
13
+ const { tokenId, profileObj, googleId } = response;
14
+ const { email, givenName, familyName } = profileObj;
15
+ const result = await handleGoogleAuth({
16
+ email,
17
+ googleIdentityToken: tokenId,
18
+ platform: "web",
19
+ });
20
+ switch (result.status) {
21
+ case "REGISTER":
22
+ onRegistrationMethodChange(RegistrationMethod.SOCIAL);
23
+ return router.push({
24
+ pathname: "/registration",
25
+ query: {
26
+ email,
27
+ firstName: givenName,
28
+ lastName: familyName,
29
+ googleUserId: googleId,
30
+ },
31
+ });
32
+ case "INVALID":
33
+ googleSignOut();
34
+ return showMessage({
35
+ message: `You have previously registered using your ${result.data.existingLoginType}. Please use your ${result.data.existingLoginType} to login method.`,
36
+ type: "error",
37
+ });
38
+ case "SUCCESS":
39
+ onLogin({
40
+ token: result.data.token,
41
+ member: result.data.member
42
+ });
43
+ break;
44
+ }
45
+ };
46
+ const onFailure = (response) => {
47
+ if (response.error === "popup_closed_by_user") {
48
+ showMessage({
49
+ message: "If you tried logging in with Google and seeing this error then please enable third-party cookies and try again.",
50
+ type: "warning"
51
+ });
52
+ }
53
+ };
54
+ const { signIn } = useGoogleLogin({
55
+ clientId: googleAppId || "",
56
+ onSuccess,
57
+ onFailure,
58
+ isSignedIn: false,
59
+ accessType: "offline",
60
+ cookiePolicy: "single_host_origin",
61
+ });
62
+ const loginWithGoogle = useCallback(() => {
63
+ if (!googleAppId) {
64
+ return;
65
+ }
66
+ return signIn();
67
+ }, [googleAppId, signIn]);
68
+ const googleSignOut = useCallback(() => {
69
+ const auth2 = window.gapi?.auth2?.getAuthInstance?.();
70
+ if (auth2) {
71
+ auth2.signOut().then(() => auth2.disconnect());
72
+ }
73
+ }, []);
74
+ return { loginWithGoogle, googleSignOut };
75
+ };
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Flex, ResponsiveModal, Typography } from "@truworth/twc-web-design";
3
+ const SocialLoginModal = ({ visible, hide, socialLoginType, onClick }) => {
4
+ return (_jsxs(ResponsiveModal, { title: _jsx(Typography, { type: "heading", size: "h6", className: "text-center mb-0", children: "Corporate Users" }), open: visible, onClose: hide, showCloseButton: false, children: [_jsxs(Typography, { type: "body", size: "small", children: ["If you are a corporate user, you will", ' ', _jsx("span", { style: { textDecoration: 'underline' }, children: "NOT" }), ' ', "be able to avail all the health benefits offered on The Wellness Corner by your employer if you login through ", socialLoginType, ".", _jsxs(Flex, { direction: "column", className: "mt-3", children: ["In that case you will have to go back ", '&', " register using your official Email Address."] })] }), _jsx(Button, { label: "I understand, I'm NOT a corporate user", className: "mt-4", onClick: (e) => {
5
+ e.preventDefault();
6
+ onClick();
7
+ } })] }));
8
+ };
9
+ export { SocialLoginModal };
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect } from 'react';
3
+ import { Text } from 'react-native';
4
+ import { BottomSheet, RoundedButton } from '@truworth/twc-rn-common';
5
+ import { useModalize } from 'react-native-modalize';
6
+ const SocialLoginModal = ({ visible, hide, socialLoginType, onClick }) => {
7
+ const { ref: socialSheetRef, open: openSheet, close: closeSheet } = useModalize();
8
+ useEffect(() => {
9
+ if (visible) {
10
+ openSheet();
11
+ }
12
+ else {
13
+ closeSheet();
14
+ }
15
+ }, [visible]);
16
+ return (_jsxs(BottomSheet, { title: 'Corporate Users', sheetRef: socialSheetRef, childrenStyle: { padding: 16 }, onClose: hide, children: [_jsxs(Text, { style: {
17
+ fontSize: 12, fontWeight: '600', color: '#000',
18
+ lineHeight: 16, marginBottom: 30,
19
+ }, children: ["If you are a corporate user, you will", ' ', _jsx(Text, { style: { textDecorationLine: 'underline' }, children: "NOT" }), ' ', "be able to avail all the health benefits offered on The Wellness Corner by your employer if you login through ", socialLoginType, ".", '\n', '\n', "In that case you will have to go back ", '&', " register using your official Email Address."] }), _jsx(RoundedButton, { label: "I understand, I'm NOT a corporate user", onPress: onClick })] }));
20
+ };
21
+ export { SocialLoginModal };
@@ -1,6 +1,7 @@
1
1
  import { useState } from "react";
2
- import { useAuthContext } from "../../../../hooks/useAuthContext";
3
2
  import { useAuthPackageContext } from "../../../../hooks/internal/useAuthPackageContext";
3
+ import { SocialLoginsEnum } from "../../../../enums";
4
+ import { socialLoginOptions } from "../../../../constants/social-login-options";
4
5
  /**
5
6
  * @internal
6
7
  * Hook for managing Welcome screen state and auth context integration.
@@ -9,13 +10,17 @@ import { useAuthPackageContext } from "../../../../hooks/internal/useAuthPackage
9
10
  const useWelcome = () => {
10
11
  const [loading, setLoading] = useState(false);
11
12
  const [showSocialLoginModal, setShowSocialLoginModal] = useState(false);
12
- const { LogoComponent, onLaunchAuthSession } = useAuthPackageContext();
13
+ const [socialLoginType, setSocialLoginType] = useState();
14
+ const { LogoComponent, socialLoginConfig, onLaunchAuthSession } = useAuthPackageContext();
15
+ const isSocialLoginEnabled = socialLoginOptions.some(({ type }) => socialLoginConfig?.[type]?.enabled);
13
16
  return {
14
- loading,
15
- setLoading,
17
+ loading, setLoading,
16
18
  showSocialLoginModal, setShowSocialLoginModal,
19
+ socialLoginType, setSocialLoginType,
17
20
  LogoComponent,
18
- onLaunchAuthSession
21
+ onLaunchAuthSession,
22
+ socialLoginConfig,
23
+ isSocialLoginEnabled,
19
24
  };
20
25
  };
21
26
  export { useWelcome };
@@ -1,14 +1,20 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React, { useCallback } from 'react';
3
3
  import { useFocusEffect } from '@react-navigation/native';
4
- import { View, Text, BackHandler, ScrollView } from 'react-native';
4
+ import { View, Text, BackHandler, ScrollView, TouchableOpacity, Platform } from 'react-native';
5
5
  import { Colors, LoadingModal, RoundedButton } from '@truworth/twc-rn-common';
6
6
  import { Layout } from '@ui-kitten/components';
7
7
  import { useWelcome } from './hooks/internal/useWelcome';
8
+ import { SocialLoginModal } from './components/SocialLoginModal';
9
+ import { socialLoginOptions } from '../../constants/social-login-options';
8
10
  import Logo from '../../../assets/logo.svg';
11
+ import { useSocialAuth } from './SocialAuth/hooks/useSocialAuth.native';
12
+ import { SocialLoginsEnum } from '../../enums';
13
+ import FastImage from 'react-native-fast-image';
9
14
  const { gray } = Colors;
10
15
  const Welcome = ({ navigation }) => {
11
- const { loading, LogoComponent, onLaunchAuthSession } = useWelcome();
16
+ const { loading, loginWithFacebook, loginWithGoogle, loginWithApple } = useSocialAuth();
17
+ const { LogoComponent, isSocialLoginEnabled, showSocialLoginModal, setShowSocialLoginModal, socialLoginType, setSocialLoginType, socialLoginConfig, onLaunchAuthSession, } = useWelcome();
12
18
  useFocusEffect(useCallback(() => {
13
19
  onLaunchAuthSession?.();
14
20
  const backHandler = BackHandler.addEventListener('hardwareBackPress', () => true);
@@ -30,12 +36,43 @@ const Welcome = ({ navigation }) => {
30
36
  // Fallback to default logo
31
37
  return (_jsx(View, { style: { marginTop: 70, alignSelf: 'center' }, children: _jsx(Logo, {}) }));
32
38
  };
39
+ const handleLogin = () => {
40
+ setShowSocialLoginModal(false);
41
+ switch (socialLoginType) {
42
+ case SocialLoginsEnum.Google:
43
+ return loginWithGoogle();
44
+ case SocialLoginsEnum.Facebook:
45
+ return loginWithFacebook();
46
+ case SocialLoginsEnum.Apple:
47
+ return loginWithApple();
48
+ default:
49
+ return;
50
+ }
51
+ };
33
52
  return (_jsxs(Layout, { style: { flex: 1, backgroundColor: '#FFFFFF' }, children: [_jsx(ScrollView, { showsVerticalScrollIndicator: false, children: _jsxs(View, { style: { padding: 16 }, children: [renderLogo(), _jsx(Text, { style: {
34
53
  fontSize: 32, fontWeight: '600', color: gray.gray_900,
35
54
  marginTop: 56, textAlign: 'center', lineHeight: 48,
36
55
  }, children: "Welcome!" }), _jsx(Text, { style: {
37
56
  fontSize: 16, fontWeight: '500', color: gray.gray_400,
38
57
  marginTop: 4, lineHeight: 24, textAlign: 'center',
39
- }, children: "Select an option to proceed" }), _jsxs(View, { style: { marginTop: 48 }, children: [_jsx(RoundedButton, { type: "secondary", label: "Enter Your Email", leftIcon: "mail", size: "large", onPress: () => navigation.navigate('EnterEmail') }), _jsx(RoundedButton, { type: "outline", label: "Search Your Organization", leftIcon: "key", containerStyle: { marginTop: 24 }, size: "large", onPress: () => navigation.navigate('SSOSearchOrganization') })] })] }) }), _jsx(LoadingModal, { loading: loading })] }));
58
+ }, children: "Select an option to proceed" }), _jsxs(View, { style: { marginTop: 48 }, children: [_jsx(RoundedButton, { type: "secondary", label: "Enter Your Email", leftIcon: "mail", size: "large", onPress: () => navigation.navigate('EnterEmail') }), _jsx(RoundedButton, { type: "outline", label: "Search Your Organization", leftIcon: "key", containerStyle: { marginTop: 24 }, size: "large", onPress: () => navigation.navigate('SSOSearchOrganization') })] }), isSocialLoginEnabled && (_jsxs(_Fragment, { children: [_jsxs(View, { style: {
59
+ flexDirection: 'row', alignItems: 'center',
60
+ justifyContent: 'center', marginVertical: 40
61
+ }, children: [_jsx(View, { style: { height: 1, width: 20, backgroundColor: gray.gray_600 } }), _jsx(Text, { style: { fontSize: 14, color: gray.gray_600, paddingHorizontal: 3, fontWeight: '500' }, children: ` or continue with ` }), _jsx(View, { style: { height: 1, width: 20, backgroundColor: gray.gray_600 } })] }), _jsx(View, { style: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center' }, children: socialLoginOptions.map(({ type, iconImageUrl }) => {
62
+ if (Platform.OS === 'android' && type === SocialLoginsEnum.Apple) {
63
+ return null;
64
+ }
65
+ return (socialLoginConfig?.[type]?.enabled &&
66
+ _jsx(TouchableOpacity, { activeOpacity: 0.8, onPress: () => {
67
+ setSocialLoginType(type);
68
+ setShowSocialLoginModal(true);
69
+ }, style: {
70
+ height: 56, backgroundColor: '#FFFFFF', width: 56,
71
+ flexDirection: 'row', alignItems: 'center',
72
+ justifyContent: 'center', marginHorizontal: 12,
73
+ borderWidth: 1, borderColor: gray.gray_200, borderRadius: 28,
74
+ }, children: _jsx(FastImage, { source: { uri: iconImageUrl }, style: { width: 24, height: 24 } }) }, type));
75
+ }) })] }))] }) }), showSocialLoginModal &&
76
+ _jsx(SocialLoginModal, { visible: showSocialLoginModal, hide: () => setShowSocialLoginModal(false), socialLoginType: socialLoginType, onClick: handleLogin }), _jsx(LoadingModal, { loading: loading })] }));
40
77
  };
41
78
  export default Welcome;
@@ -0,0 +1,3 @@
1
+ import type { SocialLoginOptions } from "../helpers/types";
2
+ declare const socialLoginOptions: SocialLoginOptions[];
3
+ export { socialLoginOptions };
@@ -30,8 +30,9 @@ declare const AuthPackageContext: React.Context<AuthPackageContextValue | null>;
30
30
  * @param onLaunchAuthSession - Optional callback after successfully launching the auth session. For example, it can be used to set the Firebase notification token or request Android permissions.
31
31
  * @param onRefreshSession - Optional handler for refreshing user session
32
32
  * @param openChatSupport - Optional callback to open chat support
33
+ * @param socialLoginConfig - Optional social login configuration
33
34
  */
34
- declare const AuthProvider: ({ children, LogoComponent, session, appConfig, onLogin, onLogout, onLaunchAuthSession, onRefreshSession, openChatSupport }: AuthContextProps) => import("react/jsx-runtime").JSX.Element;
35
+ declare const AuthProvider: ({ children, LogoComponent, session, appConfig, onLogin, onLogout, onLaunchAuthSession, onRefreshSession, openChatSupport, socialLoginConfig }: AuthContextProps) => import("react/jsx-runtime").JSX.Element;
35
36
  export { AuthProvider };
36
37
  export default AuthContext;
37
38
  export { AuthPackageContext };
@@ -1,5 +1,6 @@
1
1
  import type React from 'react';
2
2
  import type { ClientProfile, MemberProfile, Profile, Partner, RegistrationMethod } from '../types/types';
3
+ import type { SocialLoginsEnum } from '../enums';
3
4
  interface LoginResponse {
4
5
  token: string;
5
6
  member?: MemberProfile;
@@ -22,6 +23,10 @@ interface AuthContextProps {
22
23
  sessionTimeout?: boolean;
23
24
  };
24
25
  appConfig?: AppConfig;
26
+ socialLoginConfig?: Partial<Record<SocialLoginsEnum, {
27
+ enabled?: boolean;
28
+ webClientId?: string;
29
+ }>>;
25
30
  onLogin: (result: LoginResponse) => void;
26
31
  onLogout: () => Promise<any>;
27
32
  onRefreshSession?: (result: RefreshSessionResponse) => Promise<void>;
@@ -42,6 +47,10 @@ interface AuthPackageContextValue {
42
47
  token: string;
43
48
  LogoComponent?: React.ComponentType | React.ReactElement;
44
49
  appConfig: AppConfig;
50
+ socialLoginConfig?: Partial<Record<SocialLoginsEnum, {
51
+ enabled?: boolean;
52
+ webClientId?: string;
53
+ }>>;
45
54
  onTokenChange: (token: string) => void;
46
55
  onLogin: (result: LoginResponse) => void;
47
56
  logout: () => void;
@@ -1,2 +1,3 @@
1
1
  export * from './registrationMethod.enum';
2
2
  export * from './loginMethod.enum';
3
+ export * from './socialLogins.enum';
@@ -0,0 +1,5 @@
1
+ export declare enum SocialLoginsEnum {
2
+ Google = "google",
3
+ Facebook = "facebook",
4
+ Apple = "apple"
5
+ }
@@ -1,3 +1,4 @@
1
+ import type { SocialLoginsEnum } from "../enums";
1
2
  import type { RefreshSessionResponse } from "../contexts/type";
2
3
  import type { AxiosRequestConfig } from "axios";
3
4
  interface RequestOptionsProps extends AxiosRequestConfig {
@@ -10,4 +11,9 @@ interface NetworkProps {
10
11
  onRefreshSession?: (token: string) => Promise<any>;
11
12
  onLogout?: () => Promise<any>;
12
13
  }
13
- export type { RequestOptionsProps, NetworkProps };
14
+ interface SocialLoginOptions {
15
+ type: SocialLoginsEnum;
16
+ icon?: React.ReactNode;
17
+ iconImageUrl?: string;
18
+ }
19
+ export type { RequestOptionsProps, NetworkProps, SocialLoginOptions };
@@ -17,6 +17,9 @@ export type AuthStackParamList = {
17
17
  registrationToken?: string;
18
18
  clientId?: number | string;
19
19
  registrationMethod?: string;
20
+ googleUserId?: string;
21
+ fbUserId?: string;
22
+ appleUserId?: string;
20
23
  };
21
24
  CountryCode: {
22
25
  prevRoute: 'LoginMobile' | 'MobileNumber' | 'SignUp' | 'EnterMobile';
@@ -12,7 +12,6 @@ declare const useEnterEmail: () => {
12
12
  handleClearEmail: () => void;
13
13
  isLoginConflictModalVisible: boolean;
14
14
  setIsLoginConflictModalVisible: import("react").Dispatch<import("react").SetStateAction<boolean>>;
15
- onRegistrationMethodChange: (method: import("../../../../types/types").RegistrationMethod) => void;
16
15
  appName: string | undefined;
17
16
  loginConflictTitle: string;
18
17
  loginConflictDescription: string;
@@ -0,0 +1,50 @@
1
+ import type { MemberProfile } from "../../../types/types";
2
+ export declare enum SocialAuthStatus {
3
+ REGISTER = "REGISTER",
4
+ INVALID = "INVALID",
5
+ SUCCESS = "SUCCESS"
6
+ }
7
+ type Platform = "web" | "ios" | "android";
8
+ interface BaseSocialLoginParams {
9
+ email: string;
10
+ platform: Platform;
11
+ }
12
+ export interface GoogleLoginParams extends BaseSocialLoginParams {
13
+ googleIdentityToken: string;
14
+ }
15
+ export interface FacebookLoginParams extends BaseSocialLoginParams {
16
+ facebookIdentityToken: string;
17
+ }
18
+ export interface AppleLoginParams extends BaseSocialLoginParams {
19
+ appleIdentityToken: string;
20
+ }
21
+ export type SocialAuthResult = {
22
+ status: SocialAuthStatus.REGISTER;
23
+ data: {
24
+ email: string;
25
+ };
26
+ } | {
27
+ status: SocialAuthStatus.INVALID;
28
+ data: {
29
+ existingLoginType?: string;
30
+ };
31
+ } | {
32
+ status: SocialAuthStatus.SUCCESS;
33
+ data: {
34
+ token: string;
35
+ member: MemberProfile;
36
+ };
37
+ };
38
+ /**
39
+ * Handles Google authentication
40
+ */
41
+ export declare const handleGoogleAuth: ({ email, googleIdentityToken, platform, }: GoogleLoginParams) => Promise<SocialAuthResult>;
42
+ /**
43
+ * Handles Facebook authentication
44
+ */
45
+ export declare const handleFacebookAuth: ({ email, facebookIdentityToken, platform }: FacebookLoginParams) => Promise<SocialAuthResult>;
46
+ /**
47
+ * Handles Apple authentication
48
+ */
49
+ export declare const handleAppleAuth: ({ email, appleIdentityToken, platform }: AppleLoginParams) => Promise<SocialAuthResult>;
50
+ export {};
@@ -0,0 +1,7 @@
1
+ declare const useSocialAuth: () => {
2
+ loading: boolean;
3
+ loginWithGoogle: () => Promise<any>;
4
+ loginWithFacebook: () => Promise<any>;
5
+ loginWithApple: () => Promise<any>;
6
+ };
7
+ export { useSocialAuth };
@@ -0,0 +1,7 @@
1
+ declare const useSocialAuth: () => {
2
+ loginWithGoogle: () => void;
3
+ googleSignOut: () => void;
4
+ loginWithFacebook: () => void;
5
+ facebookSignOut: () => void;
6
+ };
7
+ export { useSocialAuth };
@@ -0,0 +1,5 @@
1
+ export declare const useFacebookAuth: () => {
2
+ loginWithFacebook: () => void;
3
+ facebookSignOut: () => void;
4
+ error: any;
5
+ };
@@ -0,0 +1,4 @@
1
+ export declare const useGoogleAuth: () => {
2
+ loginWithGoogle: () => void;
3
+ googleSignOut: () => void;
4
+ };
@@ -0,0 +1,3 @@
1
+ import type { SocialLoginModalProps } from "./types";
2
+ declare const SocialLoginModal: ({ visible, hide, socialLoginType, onClick }: SocialLoginModalProps) => import("react/jsx-runtime").JSX.Element;
3
+ export { SocialLoginModal };
@@ -0,0 +1,3 @@
1
+ import type { SocialLoginModalProps } from './types';
2
+ declare const SocialLoginModal: ({ visible, hide, socialLoginType, onClick }: SocialLoginModalProps) => import("react/jsx-runtime").JSX.Element;
3
+ export { SocialLoginModal };
@@ -0,0 +1,8 @@
1
+ import type { SocialLoginsEnum } from "../../../../enums";
2
+ interface SocialLoginModalProps {
3
+ visible: boolean;
4
+ hide: () => void;
5
+ socialLoginType?: SocialLoginsEnum;
6
+ onClick: () => void;
7
+ }
8
+ export type { SocialLoginModalProps };
@@ -1,3 +1,4 @@
1
+ import { SocialLoginsEnum } from "../../../../enums";
1
2
  /**
2
3
  * @internal
3
4
  * Hook for managing Welcome screen state and auth context integration.
@@ -8,7 +9,14 @@ declare const useWelcome: () => {
8
9
  setLoading: import("react").Dispatch<import("react").SetStateAction<boolean>>;
9
10
  showSocialLoginModal: boolean;
10
11
  setShowSocialLoginModal: import("react").Dispatch<import("react").SetStateAction<boolean>>;
12
+ socialLoginType: SocialLoginsEnum | undefined;
13
+ setSocialLoginType: import("react").Dispatch<import("react").SetStateAction<SocialLoginsEnum | undefined>>;
11
14
  LogoComponent: import("react").ComponentType<{}> | import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | undefined;
12
15
  onLaunchAuthSession: (() => void) | undefined;
16
+ socialLoginConfig: Partial<Record<SocialLoginsEnum, {
17
+ enabled?: boolean;
18
+ webClientId?: string;
19
+ }>> | undefined;
20
+ isSocialLoginEnabled: boolean;
13
21
  };
14
22
  export { useWelcome };
@@ -86,6 +86,9 @@ interface PersonalDetails {
86
86
  registrationMethod?: RegistrationMethod;
87
87
  password?: string;
88
88
  confirmPassword?: string;
89
+ googleUserId?: string;
90
+ fbUserId?: string;
91
+ appleUserId?: string;
89
92
  }
90
93
  interface PasswordPolicy {
91
94
  minLength: number;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "description": "Truworth Auth Package for React Native and Web",
7
- "version": "1.2.5",
7
+ "version": "1.2.6",
8
8
  "main": "build/src/index.js",
9
9
  "types": "build/types/index.d.ts",
10
10
  "files": [
@@ -23,6 +23,7 @@
23
23
  "@invertase/react-native-apple-authentication": "^1.1.2",
24
24
  "@react-native-clipboard/clipboard": "1.14.1",
25
25
  "@react-native-community/datetimepicker": "8.1.1",
26
+ "@react-native-google-signin/google-signin": "^16.0.0",
26
27
  "@react-navigation/native": "^6.1.17",
27
28
  "@react-navigation/native-stack": "^6.10.0",
28
29
  "@truworth/twc-rn-common": "^1.0.15",
@@ -48,6 +49,7 @@
48
49
  "next": "^15.0.4",
49
50
  "react": "^18.2.0",
50
51
  "react-dom": "^18.2.0",
52
+ "react-google-login": "^5.2.2",
51
53
  "react-google-recaptcha": "^3.1.0",
52
54
  "react-infinite-scroll-component": "^6.1.0",
53
55
  "react-lottie": "^1.2.3",
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="28" height="21" viewBox="0 0 28 21">
2
- <path fill="none" fill-rule="nonzero" stroke="#FFF" stroke-linecap="round" stroke-width="4" d="M2 9.903l7.93 8.141m.026 0L26 2"/>
3
- </svg>