chore: upgrade dependencies, restructure shared libs, and fix UI
- Upgrade Nx 22.1.1 → 22.6.3 and all patch/minor dependencies - Restructure shared libs: move business logic from utils to service - Consolidate shadcn-ui into ui lib with atomic design pattern - Fix container centering for landing app (Tailwind v4 compatibility) - Fix button styling by updating @source directive in globals.css - Fix SiCss3 → SiCss rename in react-icons 5.6 - Fix duplicate useSession export conflict - Remove dead code, comments, and unused files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
f68d97188c
commit
3f4461c65c
@@ -5,7 +5,6 @@ import { useAuthStore } from './use-auth-store';
|
||||
|
||||
export * from './use-auth-store';
|
||||
|
||||
// Types matching backend response
|
||||
interface TokenInfo {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
@@ -41,38 +40,30 @@ interface MessageResponse {
|
||||
message: string;
|
||||
}
|
||||
|
||||
// Login request type
|
||||
interface LoginRequest {
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
// Signup request type
|
||||
interface SignupRequest {
|
||||
email: string;
|
||||
password: string;
|
||||
fullname: string;
|
||||
}
|
||||
|
||||
// GitHub auth request type
|
||||
interface GitHubAuthRequest {
|
||||
code: string;
|
||||
}
|
||||
|
||||
// Forgot password request type
|
||||
interface ForgotPasswordRequest {
|
||||
email: string;
|
||||
}
|
||||
|
||||
// Reset password request type
|
||||
interface ResetPasswordRequest {
|
||||
access_token: string;
|
||||
new_password: string;
|
||||
}
|
||||
|
||||
// Backend API-based auth hooks
|
||||
|
||||
// Email/Password Login
|
||||
export const useLogin = () => {
|
||||
const { setSession } = useAuthStore();
|
||||
|
||||
@@ -111,7 +102,6 @@ export const useLogin = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// Email/Password Signup - returns message only (user needs to activate via email)
|
||||
export const useSignup = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (data: SignupRequest) => {
|
||||
@@ -123,7 +113,6 @@ export const useSignup = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// GitHub OAuth - exchange code for token
|
||||
export const useGitHubCallback = () => {
|
||||
const { setSession } = useAuthStore();
|
||||
|
||||
@@ -162,8 +151,7 @@ export const useGitHubCallback = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// Get current session (protected)
|
||||
export const useSession = () => {
|
||||
export const useSessionQuery = () => {
|
||||
const { session } = useAuthStore();
|
||||
|
||||
return useQuery({
|
||||
@@ -178,7 +166,6 @@ export const useSession = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// Forgot password
|
||||
export const useForgotPassword = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (data: ForgotPasswordRequest) => {
|
||||
@@ -190,7 +177,6 @@ export const useForgotPassword = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// Reset password
|
||||
export const useResetPassword = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (data: ResetPasswordRequest) => {
|
||||
@@ -202,20 +188,17 @@ export const useResetPassword = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// Sign out (clears local session)
|
||||
export const useSignOut = () => {
|
||||
const { clearSession } = useAuthStore();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
// No backend call needed - just clear local session
|
||||
clearSession();
|
||||
return { success: true };
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// Backoffice Login
|
||||
export const useBackofficeLogin = () => {
|
||||
const { setSession } = useAuthStore();
|
||||
|
||||
@@ -254,9 +237,6 @@ export const useBackofficeLogin = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// GitHub OAuth URL helper
|
||||
// The frontend needs to redirect to GitHub with the client_id
|
||||
// After GitHub redirects back with a code, use useGitHubCallback
|
||||
export const getGitHubOAuthUrl = (clientId: string, redirectUri: string) => {
|
||||
const params = new URLSearchParams({
|
||||
client_id: clientId,
|
||||
@@ -266,16 +246,20 @@ export const getGitHubOAuthUrl = (clientId: string, redirectUri: string) => {
|
||||
return `https://github.com/login/oauth/authorize?${params.toString()}`;
|
||||
};
|
||||
|
||||
// Backward compatibility hooks - these wrap the new backend API
|
||||
|
||||
// GitHub OAuth hook (backward compatible)
|
||||
export const useGitHubAuth = () => {
|
||||
const signInWithGitHub = async () => {
|
||||
// Get GitHub client ID from environment
|
||||
const clientId = import.meta.env.VITE_GITHUB_CLIENT_ID || '';
|
||||
let clientId = '';
|
||||
if (typeof process !== 'undefined' && process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID) {
|
||||
clientId = process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID;
|
||||
} else {
|
||||
try {
|
||||
const meta = import.meta as unknown as Record<string, Record<string, string>>;
|
||||
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. Set VITE_GITHUB_CLIENT_ID environment variable.'
|
||||
'GitHub Client ID not configured.'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -290,7 +274,6 @@ export const useGitHubAuth = () => {
|
||||
};
|
||||
};
|
||||
|
||||
// Email/Password auth hook (backward compatible)
|
||||
export const useEmailAuth = () => {
|
||||
const loginMutation = useLogin();
|
||||
const signupMutation = useSignup();
|
||||
@@ -317,7 +300,6 @@ export const useEmailAuth = () => {
|
||||
password,
|
||||
fullname,
|
||||
});
|
||||
// Signup only returns a message (user needs to verify email first)
|
||||
return {
|
||||
message: result.message,
|
||||
};
|
||||
@@ -334,9 +316,6 @@ export const useEmailAuth = () => {
|
||||
};
|
||||
};
|
||||
|
||||
// Legacy hooks for old API compatibility (deprecated)
|
||||
|
||||
/** @deprecated Use useLogin instead */
|
||||
export const usePostLogin = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (data: LoginRequest) => {
|
||||
@@ -348,7 +327,6 @@ export const usePostLogin = () => {
|
||||
});
|
||||
};
|
||||
|
||||
/** @deprecated Use useSignup instead */
|
||||
export const usePostRegister = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (data: SignupRequest) => {
|
||||
@@ -360,7 +338,6 @@ export const usePostRegister = () => {
|
||||
});
|
||||
};
|
||||
|
||||
/** @deprecated Not needed with new backend */
|
||||
export const usePostVerifyEmail = () => {
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
@@ -369,7 +346,6 @@ export const usePostVerifyEmail = () => {
|
||||
});
|
||||
};
|
||||
|
||||
/** @deprecated Not needed with new backend */
|
||||
export const usePostSendOtp = () => {
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
@@ -378,7 +354,6 @@ export const usePostSendOtp = () => {
|
||||
});
|
||||
};
|
||||
|
||||
/** @deprecated Use useGitHubCallback instead */
|
||||
export const useGoogleCallback = () => {
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
|
||||
@@ -6,3 +6,4 @@ export * from './upload';
|
||||
export * from './teams';
|
||||
export * from './messages';
|
||||
export * from './winners';
|
||||
export * from './use-session';
|
||||
|
||||
@@ -17,13 +17,11 @@ export type Message = {
|
||||
};
|
||||
};
|
||||
|
||||
// Query keys
|
||||
export const messageKeys = {
|
||||
all: ['messages'] as const,
|
||||
team: (teamId: string) => [...messageKeys.all, 'team', teamId] as const,
|
||||
};
|
||||
|
||||
// Fetch messages for a team with polling
|
||||
export const useTeamMessages = (teamId: string) => {
|
||||
return useQuery({
|
||||
queryKey: messageKeys.team(teamId),
|
||||
@@ -34,14 +32,11 @@ export const useTeamMessages = (teamId: string) => {
|
||||
return response.data.data || [];
|
||||
},
|
||||
enabled: !!teamId,
|
||||
// Poll every 3 seconds for new messages
|
||||
refetchInterval: 3000,
|
||||
// Keep refetching even when window loses focus
|
||||
refetchIntervalInBackground: true,
|
||||
});
|
||||
};
|
||||
|
||||
// Send a message
|
||||
export const useSendMessage = (teamId: string) => {
|
||||
const queryClient = useQueryClient();
|
||||
const { session } = useAuthStore();
|
||||
@@ -60,13 +55,11 @@ export const useSendMessage = (teamId: string) => {
|
||||
return response.data.data;
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Invalidate to trigger immediate refetch
|
||||
queryClient.invalidateQueries({ queryKey: messageKeys.team(teamId) });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// Delete a message
|
||||
export const useDeleteMessage = (teamId: string) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import type {
|
||||
TSubmitProjectRequest,
|
||||
} from '../../types/teams';
|
||||
|
||||
// Query keys
|
||||
export const teamKeys = {
|
||||
all: ['teams'] as const,
|
||||
lists: () => [...teamKeys.all, 'list'] as const,
|
||||
@@ -23,7 +22,6 @@ export const teamKeys = {
|
||||
myInvitations: () => [...teamKeys.all, 'my-invitations'] as const,
|
||||
};
|
||||
|
||||
// API response types
|
||||
interface TeamMember {
|
||||
id: string;
|
||||
team_id: string;
|
||||
@@ -106,7 +104,6 @@ interface Submission {
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
// List response type with pagination
|
||||
interface ListResponseWithMeta<T> {
|
||||
message: string;
|
||||
data: T[];
|
||||
@@ -118,7 +115,6 @@ interface ListResponseWithMeta<T> {
|
||||
};
|
||||
}
|
||||
|
||||
// Team CRUD Hooks
|
||||
export const useTeams = (params?: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
@@ -158,7 +154,6 @@ export const useTeams = (params?: {
|
||||
});
|
||||
};
|
||||
|
||||
// Infinite scroll teams hook
|
||||
const TEAMS_PAGE_SIZE = 12;
|
||||
|
||||
export const useInfiniteTeams = (params?: {
|
||||
@@ -258,7 +253,6 @@ export const useUpdateTeam = (teamId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
// Team Members Hooks - using team detail endpoint which includes members
|
||||
export const useTeamMembers = (teamId: string, enabled = true) => {
|
||||
return useQuery({
|
||||
queryKey: teamKeys.members(teamId),
|
||||
@@ -298,8 +292,6 @@ export const useManageMember = (teamId: string) => {
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ userId, data }: { userId: string; data: { role?: string; status?: string } }) => {
|
||||
// This endpoint may not exist in the backend yet
|
||||
// For now, we'll throw an error indicating it's not implemented
|
||||
throw new Error('Manage member functionality not yet implemented in backend');
|
||||
},
|
||||
onSuccess: () => {
|
||||
@@ -329,7 +321,6 @@ export const useRemoveMember = (teamId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
// Join Requests Hooks
|
||||
export const useJoinTeam = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { session } = useAuthStore();
|
||||
@@ -376,7 +367,6 @@ export const useRespondToJoinRequest = (teamId: string) => {
|
||||
throw new Error('You must be logged in to respond to join requests');
|
||||
}
|
||||
|
||||
// Backend uses 'accept' instead of 'approve'
|
||||
const backendAction = action === 'approve' ? 'accept' : 'reject';
|
||||
|
||||
await hackathonApi.post(`/join-requests/${requestId}/respond`, {
|
||||
@@ -393,7 +383,6 @@ export const useRespondToJoinRequest = (teamId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
// Invitations Hooks
|
||||
export const useMyInvitations = () => {
|
||||
const { session } = useAuthStore();
|
||||
|
||||
@@ -429,7 +418,6 @@ export const useRespondToInvitation = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// User's Teams
|
||||
export const useMyTeams = () => {
|
||||
const { session } = useAuthStore();
|
||||
|
||||
@@ -438,7 +426,6 @@ export const useMyTeams = () => {
|
||||
queryFn: async () => {
|
||||
const response = await hackathonApi.get<HackathonApiResponse<any[]>>('/teams/my');
|
||||
const rawData = response.data.data || [];
|
||||
// Unwrap nested team data if present (API returns [{team: {...}}] or [{id, name, ...}])
|
||||
const teams = rawData.map((item: any) => item.team || item);
|
||||
return { data: teams };
|
||||
},
|
||||
@@ -446,7 +433,6 @@ export const useMyTeams = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// Project Submission Hooks
|
||||
export const useSubmitProject = (teamId: string) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -454,14 +440,12 @@ export const useSubmitProject = (teamId: string) => {
|
||||
mutationFn: async (data: TSubmitProjectRequest) => {
|
||||
let submissionId: string;
|
||||
|
||||
// First, check if submission exists
|
||||
try {
|
||||
const existingResponse = await hackathonApi.get<HackathonApiResponse<Submission | null>>(
|
||||
`/submissions/teams/${teamId}`
|
||||
);
|
||||
|
||||
if (existingResponse.data.data?.id) {
|
||||
// Update existing submission
|
||||
const response = await hackathonApi.put<HackathonApiResponse<Submission>>(
|
||||
`/submissions/${existingResponse.data.data.id}`,
|
||||
{
|
||||
@@ -479,7 +463,6 @@ export const useSubmitProject = (teamId: string) => {
|
||||
throw new Error('No existing submission');
|
||||
}
|
||||
} catch {
|
||||
// No existing submission, create new one
|
||||
const response = await hackathonApi.post<HackathonApiResponse<Submission>>(
|
||||
`/submissions/teams/${teamId}`,
|
||||
{
|
||||
@@ -495,12 +478,10 @@ export const useSubmitProject = (teamId: string) => {
|
||||
submissionId = response.data.data.id;
|
||||
}
|
||||
|
||||
// Step 2: Submit the project (draft -> pending_verification)
|
||||
await hackathonApi.post<HackathonApiResponse<Submission>>(
|
||||
`/submissions/${submissionId}/submit`
|
||||
);
|
||||
|
||||
// Step 3: Confirm the submission (pending_verification -> submitted)
|
||||
const finalResponse = await hackathonApi.post<HackathonApiResponse<Submission>>(
|
||||
`/submissions/${submissionId}/confirm`
|
||||
);
|
||||
@@ -527,7 +508,6 @@ export const useTeamSubmission = (teamId: string, enabled = true) => {
|
||||
});
|
||||
};
|
||||
|
||||
// Leave Team Hook
|
||||
export const useLeaveTeam = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { session } = useAuthStore();
|
||||
@@ -538,7 +518,6 @@ export const useLeaveTeam = () => {
|
||||
throw new Error('You must be logged in to leave a team');
|
||||
}
|
||||
|
||||
// Use the dedicated leave team endpoint
|
||||
await hackathonApi.post(`/teams/${teamId}/leave`);
|
||||
return { success: true };
|
||||
},
|
||||
@@ -549,7 +528,6 @@ export const useLeaveTeam = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// Delete Team Hook (Leader only)
|
||||
export const useDeleteTeam = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { session } = useAuthStore();
|
||||
@@ -570,14 +548,12 @@ export const useDeleteTeam = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// Get Teams by User ID - uses /users/{user_id}/teams
|
||||
export const useTeamsByUserId = (userId: string) => {
|
||||
return useQuery({
|
||||
queryKey: ['teams-by-user', userId],
|
||||
queryFn: async () => {
|
||||
const response = await hackathonApi.get<HackathonApiResponse<any[]>>(`/users/${userId}/teams`);
|
||||
const rawData = response.data.data || [];
|
||||
// Unwrap nested team data if present (API returns [{team: {...}}] or [{id, name, ...}])
|
||||
const teams = rawData.map((item: any) => item.team || item);
|
||||
return { data: teams };
|
||||
},
|
||||
|
||||
@@ -2,18 +2,15 @@ import { useMutation } from '@tanstack/react-query';
|
||||
import { hackathonApi, HackathonApiResponse } from '../../api/hackathon';
|
||||
import { useAuthStore } from '../auth';
|
||||
|
||||
// Upload response type from backend
|
||||
interface UploadResponse {
|
||||
url: string;
|
||||
}
|
||||
|
||||
// Helper function to convert File to base64
|
||||
const fileToBase64 = (file: File): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => {
|
||||
// Remove the data:image/xxx;base64, prefix
|
||||
const base64 = (reader.result as string).split(',')[1];
|
||||
resolve(base64);
|
||||
};
|
||||
@@ -21,8 +18,6 @@ const fileToBase64 = (file: File): Promise<string> => {
|
||||
});
|
||||
};
|
||||
|
||||
// Backend API-based upload hooks
|
||||
|
||||
export const useUploadFile = () => {
|
||||
const { session } = useAuthStore();
|
||||
|
||||
@@ -59,13 +54,11 @@ export const useUploadAvatar = () => {
|
||||
throw new Error('You must be logged in to upload avatar');
|
||||
}
|
||||
|
||||
// Validate file type
|
||||
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/gif'];
|
||||
if (!allowedTypes.includes(file.type)) {
|
||||
throw new Error('Invalid file type. Allowed types: JPEG, PNG, WebP, GIF');
|
||||
}
|
||||
|
||||
// Validate file size (max 5MB)
|
||||
const maxSize = 5 * 1024 * 1024;
|
||||
if (file.size > maxSize) {
|
||||
throw new Error('File too large. Maximum size: 5MB');
|
||||
@@ -97,7 +90,6 @@ export const useUploadTeamFile = () => {
|
||||
throw new Error('You must be logged in to upload files');
|
||||
}
|
||||
|
||||
// Validate file type
|
||||
const allowedTypes = [
|
||||
'image/jpeg',
|
||||
'image/jpg',
|
||||
@@ -110,7 +102,6 @@ export const useUploadTeamFile = () => {
|
||||
throw new Error('Invalid file type. Allowed types: JPEG, PNG, WebP, GIF, PDF');
|
||||
}
|
||||
|
||||
// Validate file size (max 20MB)
|
||||
const maxSize = 20 * 1024 * 1024;
|
||||
if (file.size > maxSize) {
|
||||
throw new Error('File too large. Maximum size: 20MB');
|
||||
@@ -142,7 +133,6 @@ export const useUploadSubmission = () => {
|
||||
throw new Error('You must be logged in to upload submissions');
|
||||
}
|
||||
|
||||
// Validate file type
|
||||
const allowedTypes = [
|
||||
'image/jpeg',
|
||||
'image/jpg',
|
||||
@@ -161,7 +151,6 @@ export const useUploadSubmission = () => {
|
||||
);
|
||||
}
|
||||
|
||||
// Validate file size (max 50MB)
|
||||
const maxSize = 50 * 1024 * 1024;
|
||||
if (file.size > maxSize) {
|
||||
throw new Error('File too large. Maximum size: 50MB');
|
||||
@@ -183,7 +172,6 @@ export const useUploadSubmission = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// Keep useUploadCV for compatibility, using team upload endpoint
|
||||
export const useUploadCV = () => {
|
||||
const { session } = useAuthStore();
|
||||
|
||||
@@ -194,12 +182,10 @@ export const useUploadCV = () => {
|
||||
throw new Error('You must be logged in to upload CV');
|
||||
}
|
||||
|
||||
// Validate file type
|
||||
if (file.type !== 'application/pdf') {
|
||||
throw new Error('CV must be a PDF file');
|
||||
}
|
||||
|
||||
// Validate file size (max 20MB)
|
||||
const maxSize = 20 * 1024 * 1024;
|
||||
if (file.size > maxSize) {
|
||||
throw new Error('File too large. Maximum size: 20MB');
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
'use client';
|
||||
|
||||
import { useAuthStore } from './auth';
|
||||
|
||||
export const useSession = () => {
|
||||
const { clearSession, session, status } = useAuthStore();
|
||||
const isAuthenticated = status === 'authenticated';
|
||||
|
||||
const signOut = () => {
|
||||
clearSession();
|
||||
localStorage.clear();
|
||||
window.location.href = '/auth/login';
|
||||
};
|
||||
|
||||
return {
|
||||
session,
|
||||
signOut,
|
||||
isAuthenticated,
|
||||
};
|
||||
};
|
||||
@@ -2,7 +2,6 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { hackathonApi, HackathonApiResponse } from '../../api/hackathon';
|
||||
import { useAuthStore } from '../auth';
|
||||
|
||||
// User type
|
||||
interface User {
|
||||
id: string;
|
||||
email: string;
|
||||
@@ -15,7 +14,6 @@ interface User {
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
// Certificate public data types
|
||||
interface CertificateUserData {
|
||||
id: string;
|
||||
fullname: string;
|
||||
@@ -50,7 +48,6 @@ export interface CertificatePublicData {
|
||||
winner?: CertificateWinnerData;
|
||||
}
|
||||
|
||||
// Update user request type
|
||||
interface UpdateUserRequest {
|
||||
fullname?: string;
|
||||
bio?: string;
|
||||
@@ -59,8 +56,6 @@ interface UpdateUserRequest {
|
||||
skills?: string[];
|
||||
}
|
||||
|
||||
// Backend API-based user hooks
|
||||
|
||||
export const useUserMe = () => {
|
||||
const { session } = useAuthStore();
|
||||
|
||||
@@ -107,7 +102,6 @@ export const useUpdateUserMe = () => {
|
||||
return { data: response.data.data };
|
||||
},
|
||||
onSuccess: (result) => {
|
||||
// Update Zustand session store with new user data
|
||||
if (session?.user && result.data) {
|
||||
setSession({
|
||||
token: session.token,
|
||||
@@ -132,8 +126,6 @@ export const useUpdateUserById = () => {
|
||||
return useMutation({
|
||||
mutationKey: ['update-user-by-id'],
|
||||
mutationFn: async ({ id, data }: { id: string; data: UpdateUserRequest }) => {
|
||||
// Note: This might not be supported by backend (only /users/me for updates)
|
||||
// Keeping for API compatibility but it will likely fail
|
||||
const response = await hackathonApi.put<HackathonApiResponse<User>>(`/users/${id}`, data);
|
||||
return { data: response.data.data };
|
||||
},
|
||||
@@ -154,7 +146,6 @@ export const useUserDetailsById = (userId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
// Public certificate data hook (no authentication required)
|
||||
export const useCertificatePublicData = (userId: string, enabled = true) => {
|
||||
return useQuery({
|
||||
queryKey: ['certificate-public-data', userId],
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { hackathonApi, HackathonApiResponse } from '../../api/hackathon';
|
||||
|
||||
// Query keys
|
||||
export const winnerKeys = {
|
||||
all: ['winners'] as const,
|
||||
lists: () => [...winnerKeys.all, 'list'] as const,
|
||||
};
|
||||
|
||||
// API response types
|
||||
interface Team {
|
||||
id: string;
|
||||
name: string;
|
||||
|
||||
Reference in New Issue
Block a user