feat(auth): add Google authentication endpoints and hooks (#51)
- Implemented `getGoogleAuthUrl` and `postGoogleCallback` in auth API. - Added corresponding hooks `useGoogleAuth` and `useGoogleCallback` for handling Google authentication. feat(api): enhance API structure with mentors and upload services - Created `mentors` and `upload` API modules with respective services for managing mentor details and file uploads. - Added session management utilities to handle authentication tokens in cookies. feat(users): expand user service with detailed user management - Enhanced user service to include detailed user information and update capabilities. - Added hooks for fetching and updating user data. feat(hooks): introduce hooks for mentors and upload functionalities - Added hooks for fetching mentor details and updating mentor information. - Implemented hooks for file upload, avatar upload, and CV upload with validation. refactor(types): organize and extend type definitions - Introduced new types for mentors and enhanced existing user types. - Re-exported user-related types for better accessibility. chore: update index files to include new services and hooks - Updated index files to export new services and hooks for mentors and uploads.
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import { useCallback } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuthStore } from '@imphnen-frontend-service/utils';
|
||||
|
||||
export interface GoogleLoginResponse {
|
||||
access_token?: string;
|
||||
token?: string | {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
};
|
||||
accessToken?: string;
|
||||
refresh_token?: string;
|
||||
refreshToken?: string;
|
||||
user?: {
|
||||
id: string;
|
||||
email: string;
|
||||
fullname: string;
|
||||
avatar: string;
|
||||
birthdate?: string;
|
||||
gender?: string;
|
||||
is_active?: boolean;
|
||||
phone_number?: string;
|
||||
role?: {
|
||||
id: string;
|
||||
name: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
permissions: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}>;
|
||||
};
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
export const useGoogleLogin = () => {
|
||||
const navigate = useNavigate();
|
||||
const { setSession } = useAuthStore();
|
||||
|
||||
const handleGoogleLogin = useCallback(async () => {
|
||||
try {
|
||||
const baseUrl = import.meta.env.VITE_API_URL || 'http://localhost:4099';
|
||||
const callbackUrl = `${window.location.origin}/auth/google-oauth-popup`;
|
||||
|
||||
let authUrl;
|
||||
if (baseUrl.endsWith('/v1')) {
|
||||
authUrl = `${baseUrl}/auth/google/login?redirect_uri=${encodeURIComponent(callbackUrl)}`;
|
||||
} else {
|
||||
authUrl = `${baseUrl}/v1/auth/google/login?redirect_uri=${encodeURIComponent(callbackUrl)}`;
|
||||
}
|
||||
|
||||
const popup = window.open(
|
||||
authUrl,
|
||||
'google-oauth',
|
||||
'width=500,height=600,scrollbars=yes,resizable=yes'
|
||||
);
|
||||
|
||||
if (!popup) {
|
||||
toast.error('Popup diblokir. Silakan aktifkan popup untuk situs ini.');
|
||||
return;
|
||||
}
|
||||
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
if (event.origin !== window.location.origin) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type === 'GOOGLE_OAUTH_SUCCESS') {
|
||||
const { payload } = event.data as { payload: GoogleLoginResponse };
|
||||
|
||||
const tokenObj = typeof payload.token === 'object' ? payload.token : null;
|
||||
const accessToken = tokenObj?.access_token || payload.access_token;
|
||||
const refreshToken = tokenObj?.refresh_token || payload.refresh_token;
|
||||
const user = payload.user;
|
||||
|
||||
if (accessToken && refreshToken && user && typeof accessToken === 'string' && typeof refreshToken === 'string') {
|
||||
// Convert Google user data to match TUserItem structure
|
||||
const convertedUser = {
|
||||
id: user.id,
|
||||
avatar: user.avatar || '',
|
||||
birthdate: user.birthdate || '',
|
||||
email: user.email,
|
||||
fullname: user.fullname,
|
||||
gender: user.gender || '',
|
||||
is_active: user.is_active ?? true,
|
||||
phone_number: user.phone_number || '',
|
||||
role: user.role || {
|
||||
id: '',
|
||||
name: 'User',
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
permissions: []
|
||||
}
|
||||
};
|
||||
|
||||
// Use setSession like credential login does
|
||||
setSession({
|
||||
token: {
|
||||
access_token: accessToken,
|
||||
refresh_token: refreshToken,
|
||||
},
|
||||
user: convertedUser,
|
||||
});
|
||||
|
||||
toast.success('Login berhasil!');
|
||||
navigate(0); // Same as credential login
|
||||
} else {
|
||||
toast.error('Data login tidak lengkap');
|
||||
}
|
||||
|
||||
window.removeEventListener('message', handleMessage);
|
||||
} else if (event.data.type === 'GOOGLE_OAUTH_ERROR') {
|
||||
const { error } = event.data;
|
||||
toast.error(`Login gagal: ${error}`);
|
||||
window.removeEventListener('message', handleMessage);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', handleMessage);
|
||||
|
||||
setTimeout(() => {
|
||||
window.removeEventListener('message', handleMessage);
|
||||
toast.error('Login timeout. Silakan coba lagi.');
|
||||
}, 300000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Google login error:', error);
|
||||
toast.error('Terjadi kesalahan saat login dengan Google');
|
||||
}
|
||||
}, [navigate, setSession]);
|
||||
|
||||
return {
|
||||
handleGoogleLogin,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user