refactor(client): split client to cms/mobile/party

Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
2026-01-20 16:11:38 +08:00
parent ecbb890cac
commit b2c5f8de38
144 changed files with 21 additions and 17 deletions

View File

@@ -0,0 +1,18 @@
import { useQuery } from '@tanstack/react-query';
import { axiosClient } from '@/lib/axios';
export function useCheckinCode(eventId: string, enabled: boolean) {
return useQuery({
queryKey: ['getCheckinCode', eventId],
queryFn: async () => {
return axiosClient.get<{
checkin_code: string;
}>('/user/checkin', {
params: {
event_id: eventId,
},
});
},
enabled,
});
}

View File

@@ -0,0 +1,16 @@
import type { AuthorizeSearchParams } from '@/routes/authorize';
import { useMutation } from '@tanstack/react-query';
import { axiosClient } from '@/lib/axios';
interface GetMagicLinkPayload extends AuthorizeSearchParams {
email: string;
turnstile_token: string;
}
export function useGetMagicLink() {
return useMutation({
mutationFn: async (payload: GetMagicLinkPayload) => {
return axiosClient.post<{ status: string }>('/auth/magic', payload);
},
});
}

View File

@@ -0,0 +1,22 @@
import { useSuspenseQuery } from '@tanstack/react-query';
import { axiosClient } from '@/lib/axios';
export function useUserInfo() {
return useSuspenseQuery({
queryKey: ['userInfo'],
queryFn: async () => {
const response = await axiosClient.get<{
user_id: string;
email: string;
type: string;
nickname: string;
subtitle: string;
avatar: string;
bio: string;
}
>('/user/info');
return response.data;
},
staleTime: 10 * 60 * 1000,
});
}

View File

@@ -0,0 +1,11 @@
import { useSuspenseQuery } from '@tanstack/react-query';
import { axiosClient } from '@/lib/axios';
export function useValidateMagicLink(ticket: string) {
return useSuspenseQuery({
queryKey: ['validateMagicLink', ticket],
queryFn: async () => {
return axiosClient.get<{ access_token: string; refresh_token: string }>('/auth/magic/verify', { params: { token: ticket } });
},
});
}

View File

@@ -0,0 +1,19 @@
import * as React from 'react';
const MOBILE_BREAKPOINT = 768;
export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
};
mql.addEventListener('change', onChange);
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
return () => mql.removeEventListener('change', onChange);
}, []);
return !!isMobile;
}

View File

@@ -0,0 +1,14 @@
import { useNavigate } from '@tanstack/react-router';
import { useCallback } from 'react';
import { clearTokens } from '@/lib/token';
export function useLogout() {
const navigate = useNavigate();
const logout = useCallback(() => {
clearTokens();
void navigate({ to: '/authorize' });
}, [navigate]);
return { logout };
}

View File

@@ -0,0 +1,24 @@
import { createContext, use } from 'react';
export type Theme = 'dark' | 'light' | 'system';
interface ThemeProviderState {
theme: Theme;
setTheme: (theme: Theme) => void;
}
const initialState: ThemeProviderState = {
theme: 'system',
setTheme: () => null,
};
export const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
export function useTheme() {
const context = use(ThemeProviderContext);
if (context === undefined)
throw new Error('useTheme must be used within a ThemeProvider');
return context;
}