refactor: extract empty state and update basepath to /app/
Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
@@ -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,11 +23,9 @@ export function EventGridContainer() {
|
||||
} satisfies EventInfo));
|
||||
|
||||
return (
|
||||
<>
|
||||
{allEvents.length > 0 && (
|
||||
<EventGridView
|
||||
events={allEvents}
|
||||
assembleFooter={eventInfo => (eventInfo.isJoined
|
||||
footer={eventInfo => (eventInfo.isJoined
|
||||
? <Button className="w-full" disabled>已加入</Button>
|
||||
: (
|
||||
<KycDialogContainer eventIdToJoin={eventInfo.eventId}>
|
||||
@@ -40,20 +36,5 @@ export function EventGridContainer() {
|
||||
)
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{
|
||||
allEvents.length === 0 && (
|
||||
<Empty className="h-full">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<FileQuestionMark />
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>暂无活动</EmptyTitle>
|
||||
<EmptyDescription>前面的区域 以后再来探索吧</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
</Empty>
|
||||
)
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
16
client/cms/src/components/events/event-grid.empty.tsx
Normal file
16
client/cms/src/components/events/event-grid.empty.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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.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={assembleFooter(event)} />
|
||||
<EventCardView key={event.eventId} eventInfo={event} actionFooter={footer(event)} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{events.length === 0 && <EventGridEmpty />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
|
||||
export function configInternalApiClient() {
|
||||
client.setConfig({
|
||||
baseUrl: '/api/v1/',
|
||||
baseUrl: '/app/api/v1/',
|
||||
headers: {
|
||||
'X-Api-Version': 'latest',
|
||||
},
|
||||
|
||||
@@ -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' {
|
||||
|
||||
@@ -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" />,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(file
|
||||
|
||||
// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
|
||||
export default defineConfig({
|
||||
base: '/app/',
|
||||
plugins: [tanstackRouter({
|
||||
target: 'react',
|
||||
autoCodeSplitting: true,
|
||||
@@ -26,7 +27,7 @@ export default defineConfig({
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': 'http://10.0.0.10:8000',
|
||||
'/app/api': 'http://10.0.0.10:8000',
|
||||
},
|
||||
host: '0.0.0.0',
|
||||
port: 5173,
|
||||
|
||||
Reference in New Issue
Block a user