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:
Asep Haryana Saputra
2025-08-18 12:50:32 +07:00
committed by GitHub
parent 65a6bb686c
commit 3c301ec2c4
65 changed files with 7215 additions and 26 deletions
@@ -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,
};
};