107
common/resources/client/auth/requests/use-social-login.ts
Executable file
107
common/resources/client/auth/requests/use-social-login.ts
Executable file
@@ -0,0 +1,107 @@
|
||||
import {useCallback, useState} from 'react';
|
||||
import {toast} from '../../ui/toast/toast';
|
||||
import {useDisconnectSocial} from './disconnect-social';
|
||||
import {useTrans} from '../../i18n/use-trans';
|
||||
import {getBootstrapData} from '../../core/bootstrap-data/use-backend-bootstrap-data';
|
||||
import {useBootstrapData} from '../../core/bootstrap-data/bootstrap-data-context';
|
||||
|
||||
export type SocialService = 'google' | 'twitter' | 'facebook' | 'envato';
|
||||
|
||||
interface SocialMessageEvent {
|
||||
status?: 'SUCCESS' | 'ALREADY_LOGGED_IN' | 'REQUEST_PASSWORD' | 'ERROR';
|
||||
callbackData?: {
|
||||
bootstrapData?: string;
|
||||
errorMessage?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function useSocialLogin() {
|
||||
const {trans} = useTrans();
|
||||
const {setBootstrapData} = useBootstrapData();
|
||||
const disconnectSocial = useDisconnectSocial();
|
||||
|
||||
const [requestingPassword, setIsRequestingPassword] = useState(false);
|
||||
|
||||
const handleSocialLoginCallback = useCallback(
|
||||
(e: SocialMessageEvent) => {
|
||||
const {status, callbackData} = e;
|
||||
if (!status) return;
|
||||
switch (status.toUpperCase()) {
|
||||
case 'SUCCESS':
|
||||
if (callbackData?.bootstrapData) {
|
||||
setBootstrapData(callbackData.bootstrapData);
|
||||
}
|
||||
return e;
|
||||
case 'REQUEST_PASSWORD':
|
||||
setIsRequestingPassword(true);
|
||||
return e;
|
||||
case 'ERROR':
|
||||
const message: string =
|
||||
callbackData?.errorMessage ||
|
||||
trans({
|
||||
message: 'An error occurred. Please try again later',
|
||||
});
|
||||
toast.danger(message);
|
||||
return e;
|
||||
default:
|
||||
return e;
|
||||
}
|
||||
},
|
||||
[trans, setBootstrapData],
|
||||
);
|
||||
|
||||
return {
|
||||
requestingPassword,
|
||||
setIsRequestingPassword,
|
||||
loginWithSocial: async (serviceName: SocialService) => {
|
||||
const event = await openNewSocialAuthWindow(
|
||||
`secure/auth/social/${serviceName}/login`,
|
||||
);
|
||||
return handleSocialLoginCallback(event);
|
||||
},
|
||||
connectSocial: async (serviceNameOrUrl: SocialService | string) => {
|
||||
const url = serviceNameOrUrl.includes('/')
|
||||
? serviceNameOrUrl
|
||||
: `secure/auth/social/${serviceNameOrUrl}/connect`;
|
||||
const event = await openNewSocialAuthWindow(url);
|
||||
return handleSocialLoginCallback(event);
|
||||
},
|
||||
disconnectSocial,
|
||||
};
|
||||
}
|
||||
|
||||
const windowHeight = 550;
|
||||
const windowWidth = 650;
|
||||
let win: Window | null;
|
||||
|
||||
function openNewSocialAuthWindow(url: string): Promise<SocialMessageEvent> {
|
||||
const left = window.screen.width / 2 - windowWidth / 2;
|
||||
const top = window.screen.height / 2 - windowHeight / 2;
|
||||
|
||||
return new Promise(resolve => {
|
||||
win = window.open(
|
||||
url,
|
||||
'Authenticate Account',
|
||||
`menubar=0, location=0, toolbar=0, titlebar=0, status=0, scrollbars=1, width=${windowWidth}, height=${windowHeight}, left=${left}, top=${top}`,
|
||||
);
|
||||
|
||||
const messageListener = (e: MessageEvent) => {
|
||||
const baseUrl = getBootstrapData().settings.base_url;
|
||||
if (e.data.type === 'social-auth' && baseUrl.indexOf(e.origin) > -1) {
|
||||
resolve(e.data);
|
||||
window.removeEventListener('message', messageListener);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', messageListener);
|
||||
|
||||
// if user closes social login callback without interacting with it, remove message event listener
|
||||
const timer = setInterval(() => {
|
||||
if (!win || win.closed) {
|
||||
clearInterval(timer);
|
||||
resolve({});
|
||||
window.removeEventListener('message', messageListener);
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user