diff --git a/client/src/components/app-sidebar.tsx b/client/src/components/app-sidebar.tsx index 518ac82..801d55c 100644 --- a/client/src/components/app-sidebar.tsx +++ b/client/src/components/app-sidebar.tsx @@ -7,7 +7,6 @@ import * as React from 'react'; import NixOSLogo from '@/assets/nixos.svg?react'; import { NavMain } from '@/components/nav-main'; import { NavSecondary } from '@/components/nav-secondary'; -import { NavUser } from '@/components/nav-user'; import { Sidebar, SidebarContent, @@ -17,6 +16,7 @@ import { SidebarMenuButton, SidebarMenuItem, } from '@/components/ui/sidebar'; +import { NavUser } from './nav-user'; const data = { user: { @@ -48,7 +48,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { diff --git a/client/src/components/checkin/qr-dialog.tsx b/client/src/components/checkin/qr-dialog.tsx index dbc7424..dd6af35 100644 --- a/client/src/components/checkin/qr-dialog.tsx +++ b/client/src/components/checkin/qr-dialog.tsx @@ -1,3 +1,4 @@ +import { useState } from 'react'; import { Dialog, DialogContent, @@ -14,9 +15,9 @@ import { Button } from '../ui/button'; export function QrDialog( { eventId }: { eventId: string }, ) { - const { data } = useCheckinCode(eventId); + const [open, setOpen] = useState(false); return ( - + @@ -27,21 +28,41 @@ export function QrDialog( 请工作人员扫描下面的二维码为你签到。 - + ); } -function QrDialogContent({ checkinCode }: { checkinCode: string }) { +function QrSection({ eventId, enabled }: { eventId: string; enabled: boolean }) { + const { data } = useCheckinCode(eventId, enabled); + return data + ? ( + <> +
+ +
+ +
+ {data.data.checkin_code} +
+
+ + ) + : ( + + ); +} + +function QrSectionSkeleton() { return ( <>
- +
- {checkinCode} + Loading...
diff --git a/client/src/components/hoc/with-fallback.tsx b/client/src/components/hoc/with-fallback.tsx new file mode 100644 index 0000000..e4e8679 --- /dev/null +++ b/client/src/components/hoc/with-fallback.tsx @@ -0,0 +1,20 @@ +import type { ReactNode } from 'react'; +import React, { Suspense } from 'react'; + +export function withFallback

( + Component: React.ComponentType

, + fallback: ReactNode, +) { + const Wrapped: React.FC

= (props) => { + return ( + + + + ); + }; + + Wrapped.displayName = `withFallback(${Component.displayName! || Component.name || 'Component' + })`; + + return Wrapped; +} diff --git a/client/src/components/nav-user.tsx b/client/src/components/nav-user.tsx index d21cba2..9f6c5dd 100644 --- a/client/src/components/nav-user.tsx +++ b/client/src/components/nav-user.tsx @@ -24,8 +24,10 @@ import { } from '@/components/ui/sidebar'; import { useUserInfo } from '@/hooks/data/useUserInfo'; import { useLogout } from '@/hooks/useLogout'; +import { withFallback } from './hoc/with-fallback'; +import { Skeleton } from './ui/skeleton'; -export function NavUser() { +function NavUser_() { const { isMobile } = useSidebar(); const { data: user } = useUserInfo(); const { logout } = useLogout(); @@ -83,3 +85,20 @@ export function NavUser() { ); } + +function NavUserSkeleton() { + return ( + + +

+ + +
+ +
+ ); +} + +export const NavUser = withFallback(NavUser_, ); diff --git a/client/src/components/workbenchCards/card-skeleton.tsx b/client/src/components/workbenchCards/card-skeleton.tsx new file mode 100644 index 0000000..007b499 --- /dev/null +++ b/client/src/components/workbenchCards/card-skeleton.tsx @@ -0,0 +1,9 @@ +import { Skeleton } from '../ui/skeleton'; + +export function CardSkeleton() { + return ( + + ); +} diff --git a/client/src/components/workbenchCards/checkin.tsx b/client/src/components/workbenchCards/checkin.tsx index 45f84aa..fcfb34a 100644 --- a/client/src/components/workbenchCards/checkin.tsx +++ b/client/src/components/workbenchCards/checkin.tsx @@ -2,29 +2,31 @@ import { Badge } from '@/components/ui/badge'; import { Card, CardAction, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; import { useUserInfo } from '@/hooks/data/useUserInfo'; import { QrDialog } from '../checkin/qr-dialog'; +import { withFallback } from '../hoc/with-fallback'; +import { CardSkeleton } from './card-skeleton'; -export function CheckinCard() { +function CheckinCard_() { const { data } = useUserInfo(); return ( - <> - - - 签到状态 - - {data.checkin !== null ? '已签到' : '未签到'} - {data.checkin !== null && {`${new Date(data.checkin).toLocaleString()}`}} - - - Day 1 - - - - - - - - + + + 签到状态 + + {data.checkin !== null ? '已签到' : '未签到'} + {data.checkin !== null && {`${new Date(data.checkin).toLocaleString()}`}} + + + Day 1 + + + + + + + ); } + +export const CheckinCard = withFallback(CheckinCard_, ); diff --git a/client/src/hooks/data/useGetCheckInCode.ts b/client/src/hooks/data/useGetCheckInCode.ts index d0acd35..e4d5f05 100644 --- a/client/src/hooks/data/useGetCheckInCode.ts +++ b/client/src/hooks/data/useGetCheckInCode.ts @@ -1,8 +1,8 @@ -import { useSuspenseQuery } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import { axiosClient } from '@/lib/axios'; -export function useCheckinCode(eventId: string) { - return useSuspenseQuery({ +export function useCheckinCode(eventId: string, enabled: boolean) { + return useQuery({ queryKey: ['getCheckinCode', eventId], queryFn: async () => { return axiosClient.get<{ @@ -13,5 +13,6 @@ export function useCheckinCode(eventId: string) { }, }); }, + enabled, }); } diff --git a/client/src/routes/__root.tsx b/client/src/routes/__root.tsx index 6a5987c..faf535a 100644 --- a/client/src/routes/__root.tsx +++ b/client/src/routes/__root.tsx @@ -4,7 +4,24 @@ import { ThemeProvider } from '@/components/theme-provider'; import { Toaster } from '@/components/ui/sonner'; import '@/index.css'; -const queryClient = new QueryClient(); +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: (failureCount, error: any) => { + // eslint-disable-next-line ts/no-unsafe-assignment + const status + // eslint-disable-next-line ts/no-unsafe-member-access + = error?.response?.status ?? error?.status; + + if (status >= 400 && status < 500) { + return false; + } + + return failureCount < 3; + }, + }, + }, +}); function RootLayout() { return ( diff --git a/client/src/routes/_sidebarLayout/index.tsx b/client/src/routes/_sidebarLayout/index.tsx index e23ff0f..9a8b7d8 100644 --- a/client/src/routes/_sidebarLayout/index.tsx +++ b/client/src/routes/_sidebarLayout/index.tsx @@ -13,18 +13,16 @@ export const Route = createFileRoute('/_sidebarLayout/')({ }, }); -function SectionCards() { - return ( -
- -
- ); -} - function Index() { return (
- + {/* Section Cards */} +
+ +
); }