feat: integrate all backend APIs into frontend apps
- Fix API service paths to use /v1/iam/, /v1/dimentorin/, /v1/gacha/, /v1/hackathon/ prefixes - Add roles, permissions, events, testimonials, sessions API services and hooks - Rewrite gacha service with full CRUD + roll/claim endpoints - Replace all mock data in backoffice pages with real API calls (accounts, roles, permissions, gacha-roll, dashboard, sessions, users-dimentorin, feedback-review, settings) - Wire dimentorin mentoring list to useMentorList with search + pagination - Wire dimentorin mentor detail page to useMentorById, pass real data to all sections - Wire appointment modal to useBookSession with controlled schedule inputs - Wire gacha app Spin Now to useExecuteGachaRoll, show credits and real items Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
8d2aaf5188
commit
53ad40f3fd
@@ -1,242 +1,140 @@
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { hackathonApi, HackathonApiResponse } from '../../api/hackathon';
|
||||
import { backofficeApi, BackofficeApiResponse } from '../../api/backoffice';
|
||||
import { useAuthStore } from './use-auth-store';
|
||||
import {
|
||||
postLogin,
|
||||
postRegister,
|
||||
postVerifyEmail,
|
||||
postSendOtp,
|
||||
postForgotPassword,
|
||||
postNewPassword,
|
||||
} from '../../api/auth';
|
||||
import { getUserMe } from '../../api/users';
|
||||
|
||||
export * from './use-auth-store';
|
||||
|
||||
interface TokenInfo {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
email: string;
|
||||
fullname: string;
|
||||
phone_number?: string;
|
||||
avatar?: string;
|
||||
birthdate?: string;
|
||||
gender?: string;
|
||||
is_active: boolean;
|
||||
location?: string;
|
||||
bio?: string;
|
||||
skills?: string[];
|
||||
role_id?: string;
|
||||
created_at: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
interface AuthResponse {
|
||||
token: TokenInfo;
|
||||
user: User;
|
||||
}
|
||||
|
||||
interface SessionResponse {
|
||||
user: User;
|
||||
}
|
||||
|
||||
interface MessageResponse {
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface LoginRequest {
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
interface SignupRequest {
|
||||
email: string;
|
||||
password: string;
|
||||
fullname: string;
|
||||
}
|
||||
|
||||
interface GitHubAuthRequest {
|
||||
code: string;
|
||||
}
|
||||
|
||||
interface ForgotPasswordRequest {
|
||||
email: string;
|
||||
}
|
||||
|
||||
interface ResetPasswordRequest {
|
||||
access_token: string;
|
||||
new_password: string;
|
||||
}
|
||||
|
||||
export const useLogin = () => {
|
||||
const { setSession } = useAuthStore();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: LoginRequest) => {
|
||||
const response = await hackathonApi.post<
|
||||
HackathonApiResponse<AuthResponse>
|
||||
>('/auth/login', data);
|
||||
return response.data.data;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
mutationFn: postLogin,
|
||||
onSuccess: (res) => {
|
||||
const u = res.data?.user;
|
||||
const t = res.data?.token;
|
||||
if (!u || !t) return;
|
||||
setSession({
|
||||
token: data.token,
|
||||
token: t,
|
||||
user: {
|
||||
id: data.user.id,
|
||||
email: data.user.email,
|
||||
fullname: data.user.fullname,
|
||||
phone_number: data.user.phone_number || '',
|
||||
avatar: data.user.avatar || '',
|
||||
birthdate: data.user.birthdate || '',
|
||||
gender: data.user.gender || '',
|
||||
is_active: data.user.is_active,
|
||||
location: data.user.location,
|
||||
bio: data.user.bio,
|
||||
skills: data.user.skills,
|
||||
role: {
|
||||
id: '',
|
||||
name: 'user',
|
||||
permissions: [],
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
},
|
||||
id: u.id,
|
||||
email: u.email,
|
||||
fullname: u.fullname,
|
||||
phone_number: u.phone_number || '',
|
||||
avatar: u.avatar || '',
|
||||
birthdate: u.birthdate || '',
|
||||
gender: u.gender || '',
|
||||
is_active: u.is_active,
|
||||
location: u.location,
|
||||
bio: u.bio,
|
||||
skills: u.skills,
|
||||
role: u.role ?? { id: '', name: 'user', permissions: [], created_at: '', updated_at: '' },
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useSignup = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (data: SignupRequest) => {
|
||||
const response = await hackathonApi.post<
|
||||
HackathonApiResponse<MessageResponse>
|
||||
>('/auth/signup', data);
|
||||
return response.data.data;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useGitHubCallback = () => {
|
||||
const { setSession } = useAuthStore();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: GitHubAuthRequest) => {
|
||||
const response = await hackathonApi.post<
|
||||
HackathonApiResponse<AuthResponse>
|
||||
>('/auth/github', data);
|
||||
return response.data.data;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
setSession({
|
||||
token: data.token,
|
||||
user: {
|
||||
id: data.user.id,
|
||||
email: data.user.email,
|
||||
fullname: data.user.fullname,
|
||||
phone_number: data.user.phone_number || '',
|
||||
avatar: data.user.avatar || '',
|
||||
birthdate: data.user.birthdate || '',
|
||||
gender: data.user.gender || '',
|
||||
is_active: data.user.is_active,
|
||||
location: data.user.location,
|
||||
bio: data.user.bio,
|
||||
skills: data.user.skills,
|
||||
role: {
|
||||
id: '',
|
||||
name: 'user',
|
||||
permissions: [],
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useSessionQuery = () => {
|
||||
const { session } = useAuthStore();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ['auth-session'],
|
||||
queryFn: async () => {
|
||||
const response = await hackathonApi.get<
|
||||
HackathonApiResponse<SessionResponse>
|
||||
>('/auth/session');
|
||||
return response.data.data;
|
||||
},
|
||||
enabled: !!session?.token,
|
||||
});
|
||||
};
|
||||
|
||||
export const useForgotPassword = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (data: ForgotPasswordRequest) => {
|
||||
const response = await hackathonApi.post<
|
||||
HackathonApiResponse<MessageResponse>
|
||||
>('/auth/forgot-password', data);
|
||||
return response.data.data;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useResetPassword = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (data: ResetPasswordRequest) => {
|
||||
const response = await hackathonApi.post<
|
||||
HackathonApiResponse<MessageResponse>
|
||||
>('/auth/reset-password', data);
|
||||
return response.data.data;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useSignOut = () => {
|
||||
const { clearSession } = useAuthStore();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
clearSession();
|
||||
return { success: true };
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useBackofficeLogin = () => {
|
||||
const { setSession } = useAuthStore();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: LoginRequest) => {
|
||||
const response = await backofficeApi.post<
|
||||
BackofficeApiResponse<AuthResponse>
|
||||
>('/auth/login', data);
|
||||
return response.data.data;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
mutationFn: postLogin,
|
||||
onSuccess: (res) => {
|
||||
const u = res.data?.user;
|
||||
const t = res.data?.token;
|
||||
if (!u || !t) return;
|
||||
setSession({
|
||||
token: data.token,
|
||||
token: t,
|
||||
user: {
|
||||
id: data.user.id,
|
||||
email: data.user.email,
|
||||
fullname: data.user.fullname,
|
||||
phone_number: data.user.phone_number || '',
|
||||
avatar: data.user.avatar || '',
|
||||
birthdate: data.user.birthdate || '',
|
||||
gender: data.user.gender || '',
|
||||
is_active: data.user.is_active,
|
||||
location: data.user.location,
|
||||
bio: data.user.bio,
|
||||
skills: data.user.skills,
|
||||
role: {
|
||||
id: data.user.role_id || '',
|
||||
name: 'admin',
|
||||
permissions: [],
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
},
|
||||
id: u.id,
|
||||
email: u.email,
|
||||
fullname: u.fullname,
|
||||
phone_number: u.phone_number || '',
|
||||
avatar: u.avatar || '',
|
||||
birthdate: u.birthdate || '',
|
||||
gender: u.gender || '',
|
||||
is_active: u.is_active,
|
||||
location: u.location,
|
||||
bio: u.bio,
|
||||
skills: u.skills,
|
||||
role: u.role ?? { id: '', name: 'admin', permissions: [], created_at: '', updated_at: '' },
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useSignup = () => {
|
||||
return useMutation({ mutationFn: postRegister });
|
||||
};
|
||||
|
||||
export const usePostLogin = () => {
|
||||
return useMutation({
|
||||
mutationFn: postLogin,
|
||||
onSuccess: (res) => res,
|
||||
});
|
||||
};
|
||||
|
||||
export const usePostRegister = () => {
|
||||
return useMutation({ mutationFn: postRegister });
|
||||
};
|
||||
|
||||
export const usePostVerifyEmail = () => {
|
||||
return useMutation({ mutationFn: postVerifyEmail });
|
||||
};
|
||||
|
||||
export const usePostSendOtp = () => {
|
||||
return useMutation({ mutationFn: postSendOtp });
|
||||
};
|
||||
|
||||
export const useForgotPassword = () => {
|
||||
return useMutation({ mutationFn: postForgotPassword });
|
||||
};
|
||||
|
||||
export const useResetPassword = () => {
|
||||
return useMutation({
|
||||
mutationFn: (data: { token: string; password: string }) => postNewPassword(data),
|
||||
});
|
||||
};
|
||||
|
||||
export const useSignOut = () => {
|
||||
const { clearSession } = useAuthStore();
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
clearSession();
|
||||
return { success: true };
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useSessionQuery = () => {
|
||||
const { session } = useAuthStore();
|
||||
return useQuery({
|
||||
queryKey: ['auth-session'],
|
||||
queryFn: async () => {
|
||||
const user = await getUserMe();
|
||||
return { user };
|
||||
},
|
||||
enabled: !!session?.token,
|
||||
});
|
||||
};
|
||||
|
||||
export const useGoogleCallback = () => {
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
throw new Error('Google OAuth not supported. Use GitHub OAuth instead.');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getGitHubOAuthUrl = (clientId: string, redirectUri: string) => {
|
||||
const params = new URLSearchParams({
|
||||
client_id: clientId,
|
||||
@@ -257,21 +155,23 @@ export const useGitHubAuth = () => {
|
||||
if (meta.env?.VITE_GITHUB_CLIENT_ID) clientId = meta.env.VITE_GITHUB_CLIENT_ID;
|
||||
} catch { /* not in Vite context */ }
|
||||
}
|
||||
if (!clientId) {
|
||||
throw new Error(
|
||||
'GitHub Client ID not configured.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!clientId) throw new Error('GitHub Client ID not configured.');
|
||||
const redirectUri = `${globalThis.location.origin}/auth/callback`;
|
||||
const url = getGitHubOAuthUrl(clientId, redirectUri);
|
||||
|
||||
return { url };
|
||||
return { url: getGitHubOAuthUrl(clientId, redirectUri) };
|
||||
};
|
||||
return { signInWithGitHub };
|
||||
};
|
||||
|
||||
return {
|
||||
signInWithGitHub,
|
||||
};
|
||||
export const useGitHubCallback = () => {
|
||||
const { setSession } = useAuthStore();
|
||||
return useMutation({
|
||||
mutationFn: async (data: { code: string }) => {
|
||||
// GitHub OAuth callback is handled by the backend redirect.
|
||||
// This hook exists for compatibility; in practice the backend
|
||||
// redirects to the frontend with a token in the URL params.
|
||||
throw new Error(`GitHub callback must be handled via backend redirect. Code: ${data.code}`);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useEmailAuth = () => {
|
||||
@@ -282,82 +182,20 @@ export const useEmailAuth = () => {
|
||||
const signInWithEmail = async (email: string, password: string) => {
|
||||
const result = await loginMutation.mutateAsync({ email, password });
|
||||
return {
|
||||
user: result.user,
|
||||
user: result.data?.user,
|
||||
session: {
|
||||
access_token: result.token.access_token,
|
||||
refresh_token: result.token.refresh_token,
|
||||
access_token: result.data?.token?.access_token,
|
||||
refresh_token: result.data?.token?.refresh_token,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const signUpWithEmail = async (
|
||||
email: string,
|
||||
password: string,
|
||||
fullname: string
|
||||
) => {
|
||||
const result = await signupMutation.mutateAsync({
|
||||
email,
|
||||
password,
|
||||
fullname,
|
||||
});
|
||||
return {
|
||||
message: result.message,
|
||||
};
|
||||
const signUpWithEmail = async (email: string, password: string, fullname: string) => {
|
||||
const result = await signupMutation.mutateAsync({ email, password, fullname });
|
||||
return { message: result.message };
|
||||
};
|
||||
|
||||
const signOut = async () => {
|
||||
clearSession();
|
||||
};
|
||||
const signOut = async () => { clearSession(); };
|
||||
|
||||
return {
|
||||
signInWithEmail,
|
||||
signUpWithEmail,
|
||||
signOut,
|
||||
};
|
||||
};
|
||||
|
||||
export const usePostLogin = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (data: LoginRequest) => {
|
||||
const response = await hackathonApi.post<
|
||||
HackathonApiResponse<AuthResponse>
|
||||
>('/auth/login', data);
|
||||
return { data: response.data.data };
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const usePostRegister = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (data: SignupRequest) => {
|
||||
const response = await hackathonApi.post<
|
||||
HackathonApiResponse<AuthResponse>
|
||||
>('/auth/signup', data);
|
||||
return { data: response.data.data };
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const usePostVerifyEmail = () => {
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
throw new Error('Email verification not required with new backend');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const usePostSendOtp = () => {
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
throw new Error('OTP not required with new backend');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useGoogleCallback = () => {
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
throw new Error('Google OAuth not supported. Use GitHub OAuth instead.');
|
||||
},
|
||||
});
|
||||
return { signInWithEmail, signUpWithEmail, signOut };
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user