refactor: extract empty state and update basepath to /app/
All checks were successful
Client CMS Check Build (NixCN CMS) TeamCity build finished
Backend Check Build (NixCN CMS) TeamCity build finished

Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
2026-02-06 20:41:50 +08:00
parent 0fc57ac637
commit 6411268090
7 changed files with 60 additions and 45 deletions

View File

@@ -1,10 +1,8 @@
import type { EventInfo } from './types';
import { FileQuestionMark } from 'lucide-react';
import PlaceholderImage from '@/assets/event-placeholder.png';
import { useGetEvents } from '@/hooks/data/useGetEvents';
import { Button } from '../ui/button';
import { DialogTrigger } from '../ui/dialog';
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '../ui/empty';
import { EventGridView } from './event-grid.view';
import { KycDialogContainer } from './kyc/kyc.dialog.container';
@@ -25,35 +23,18 @@ export function EventGridContainer() {
} satisfies EventInfo));
return (
<>
{allEvents.length > 0 && (
<EventGridView
events={allEvents}
assembleFooter={eventInfo => (eventInfo.isJoined
? <Button className="w-full" disabled></Button>
: (
<KycDialogContainer eventIdToJoin={eventInfo.eventId}>
<DialogTrigger asChild>
<Button className="w-full"></Button>
</DialogTrigger>
</KycDialogContainer>
)
)}
/>
)}
{
allEvents.length === 0 && (
<Empty className="h-full">
<EmptyHeader>
<EmptyMedia variant="icon">
<FileQuestionMark />
</EmptyMedia>
<EmptyTitle></EmptyTitle>
<EmptyDescription> </EmptyDescription>
</EmptyHeader>
</Empty>
<EventGridView
events={allEvents}
footer={eventInfo => (eventInfo.isJoined
? <Button className="w-full" disabled></Button>
: (
<KycDialogContainer eventIdToJoin={eventInfo.eventId}>
<DialogTrigger asChild>
<Button className="w-full"></Button>
</DialogTrigger>
</KycDialogContainer>
)
}
</>
)}
/>
);
}

View File

@@ -0,0 +1,16 @@
import { FileQuestionMark } from 'lucide-react';
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '../ui/empty';
export function EventGridEmpty() {
return (
<Empty className="h-full">
<EmptyHeader>
<EmptyMedia variant="icon">
<FileQuestionMark />
</EmptyMedia>
<EmptyTitle></EmptyTitle>
<EmptyDescription> </EmptyDescription>
</EmptyHeader>
</Empty>
);
}

View File

@@ -1,12 +1,18 @@
import type { EventInfo } from './types';
import { EventCardView } from './event-card.view';
import { EventGridEmpty } from './event-grid.empty';
export function EventGridView({ events, assembleFooter }: { events: EventInfo[]; assembleFooter: (event: EventInfo) => React.ReactNode }) {
export function EventGridView({ events, footer }: { events: EventInfo[]; footer: (event: EventInfo) => React.ReactNode }) {
return (
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4">
{events.map(event => (
<EventCardView key={event.eventId} eventInfo={event} actionFooter={assembleFooter(event)} />
))}
</div>
<>
{events.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4 h-full">
{events.map(event => (
<EventCardView key={event.eventId} eventInfo={event} actionFooter={footer(event)} />
))}
</div>
)}
{events.length === 0 && <EventGridEmpty />}
</>
);
}

View File

@@ -11,7 +11,7 @@ import {
export function configInternalApiClient() {
client.setConfig({
baseUrl: '/api/v1/',
baseUrl: '/app/api/v1/',
headers: {
'X-Api-Version': 'latest',
},

View File

@@ -3,7 +3,7 @@ import { createRouter } from '@tanstack/react-router';
import { routeTree } from '../routeTree.gen';
// Create a new router instance
export const router = createRouter({ routeTree });
export const router = createRouter({ routeTree, basepath: '/app/' });
// Register the router instance for type safety
declare module '@tanstack/react-router' {

View File

@@ -60,14 +60,25 @@ export const Primary: Story = {
endTime: new Date('2026-06-14T04:00:00.000Z'),
},
],
assembleFooter: () => <Button className="w-full"></Button>,
footer: () => <Button className="w-full"></Button>,
},
};
export const Skeleton: Story = {
export const Empty: Story = {
decorators: [Story => <div className="h-screen">{Story()}</div>],
args: {
events: [],
footer: () => <Button className="w-full"></Button>,
},
parameters: {
layout: 'fullscreen',
},
};
export const Loading: Story = {
render: () => <EventGridSkeleton />,
args: {
events: [],
assembleFooter: () => <UiSkeleton className="w-full" />,
footer: () => <UiSkeleton className="w-full" />,
},
};