feat(client): joined event list
Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
import type { EventInfo } from '../types';
|
import { useEvents } from '@/hooks/data/useEvents';
|
||||||
import PlaceholderImage from '@/assets/event-placeholder.png';
|
|
||||||
import { useGetEvents } from '@/hooks/data/useGetEvents';
|
|
||||||
import { Button } from '../../ui/button';
|
import { Button } from '../../ui/button';
|
||||||
import { DialogTrigger } from '../../ui/dialog';
|
import { DialogTrigger } from '../../ui/dialog';
|
||||||
import { EventJoinDialogContainer } from '../event-join.dialog.container';
|
import { EventJoinDialogContainer } from '../event-join.dialog.container';
|
||||||
import { KycDialogContainer } from '../kyc/kyc.dialog.container';
|
import { KycDialogContainer } from '../kyc/kyc.dialog.container';
|
||||||
|
import { toEventInfo } from '../types';
|
||||||
import { EventGridSkeleton } from './event-grid.skeleton';
|
import { EventGridSkeleton } from './event-grid.skeleton';
|
||||||
import { EventGridView } from './event-grid.view';
|
import { EventGridView } from './event-grid.view';
|
||||||
|
|
||||||
@@ -15,24 +14,14 @@ function JoinButton() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function EventGridContainer() {
|
export function EventGridContainer() {
|
||||||
const { data, isLoading } = useGetEvents();
|
const { data, isLoading } = useEvents();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
isLoading
|
isLoading
|
||||||
? <EventGridSkeleton />
|
? <EventGridSkeleton />
|
||||||
: (
|
: (
|
||||||
<EventGridView
|
<EventGridView
|
||||||
events={data.pages.flatMap(page => page.data ?? []).map(it => ({
|
events={data.pages.flatMap(page => page.data ?? []).map(toEventInfo)}
|
||||||
type: it.type! as EventInfo['type'],
|
|
||||||
eventId: it.event_id!,
|
|
||||||
isJoined: it.is_joined!,
|
|
||||||
requireKyc: it.enable_kyc!,
|
|
||||||
coverImage: it.thumbnail! || PlaceholderImage,
|
|
||||||
eventName: it.name!,
|
|
||||||
description: it.description!,
|
|
||||||
startTime: new Date(it.start_time!),
|
|
||||||
endTime: new Date(it.end_time!),
|
|
||||||
} satisfies EventInfo))}
|
|
||||||
footer={eventInfo => (eventInfo.isJoined
|
footer={eventInfo => (eventInfo.isJoined
|
||||||
? <Button className="w-full" disabled>已加入</Button>
|
? <Button className="w-full" disabled>已加入</Button>
|
||||||
: (
|
: (
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import type { EventInfo } from './types';
|
||||||
|
import { useJoinedEvents } from '@/hooks/data/useJoinedEvents';
|
||||||
|
import { isInDateRange } from '@/lib/utils';
|
||||||
|
import { Button } from '../ui/button';
|
||||||
|
import { EventGridSkeleton } from './event-grid/event-grid.skeleton';
|
||||||
|
import { EventGridView } from './event-grid/event-grid.view';
|
||||||
|
import { toEventInfo } from './types';
|
||||||
|
|
||||||
|
export function JoinedEventGridFooter({ event }: { event: EventInfo }) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-row justify-between w-full gap-4">
|
||||||
|
<Button className="flex-1" disabled={!isInDateRange(event.startTime, event.endTime)}>签到</Button>
|
||||||
|
<Button className="flex-1">查看详情</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function JoinedEventsContainer() {
|
||||||
|
const { data, isLoading } = useJoinedEvents();
|
||||||
|
|
||||||
|
return (
|
||||||
|
isLoading
|
||||||
|
? <EventGridSkeleton />
|
||||||
|
: (
|
||||||
|
<EventGridView
|
||||||
|
events={data.pages.flatMap(page => page.data ?? []).map(toEventInfo)}
|
||||||
|
footer={event => (
|
||||||
|
<JoinedEventGridFooter event={event} />
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import type { DataEventIndexDoc } from '@/client';
|
||||||
|
import PlaceholderImage from '@/assets/event-placeholder.png';
|
||||||
|
|
||||||
export interface EventInfo {
|
export interface EventInfo {
|
||||||
type: 'official' | 'party';
|
type: 'official' | 'party';
|
||||||
eventId: string;
|
eventId: string;
|
||||||
@@ -9,3 +12,17 @@ export interface EventInfo {
|
|||||||
startTime: Date;
|
startTime: Date;
|
||||||
endTime: Date;
|
endTime: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toEventInfo(raw: DataEventIndexDoc): EventInfo {
|
||||||
|
return {
|
||||||
|
type: raw.type! as EventInfo['type'],
|
||||||
|
eventId: raw.event_id!,
|
||||||
|
isJoined: raw.is_joined!,
|
||||||
|
requireKyc: raw.enable_kyc!,
|
||||||
|
coverImage: raw.thumbnail! || PlaceholderImage,
|
||||||
|
eventName: raw.name!,
|
||||||
|
description: raw.description!,
|
||||||
|
startTime: new Date(raw.start_time!),
|
||||||
|
endTime: new Date(raw.end_time!),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useInfiniteQuery } from '@tanstack/react-query';
|
|||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import { getEventListInfiniteOptions } from '@/client/@tanstack/react-query.gen';
|
import { getEventListInfiniteOptions } from '@/client/@tanstack/react-query.gen';
|
||||||
|
|
||||||
export function useGetEvents() {
|
export function useEvents() {
|
||||||
return useInfiniteQuery({
|
return useInfiniteQuery({
|
||||||
...getEventListInfiniteOptions({
|
...getEventListInfiniteOptions({
|
||||||
query: {},
|
query: {},
|
||||||
19
client/cms/src/hooks/data/useJoinedEvents.ts
Normal file
19
client/cms/src/hooks/data/useJoinedEvents.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { useInfiniteQuery } from '@tanstack/react-query';
|
||||||
|
import { isNil } from 'lodash-es';
|
||||||
|
import { getEventJoinedInfiniteOptions } from '@/client/@tanstack/react-query.gen';
|
||||||
|
|
||||||
|
export function useJoinedEvents() {
|
||||||
|
return useInfiniteQuery({
|
||||||
|
...getEventJoinedInfiniteOptions({
|
||||||
|
query: {},
|
||||||
|
}),
|
||||||
|
initialPageParam: 0,
|
||||||
|
getNextPageParam: (lastPage, allPages) => {
|
||||||
|
const currentData = lastPage?.data;
|
||||||
|
if (!isNil(currentData) && currentData.length === 20) {
|
||||||
|
return allPages.length * 20;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
IconCalendarClock,
|
||||||
IconCalendarEvent,
|
IconCalendarEvent,
|
||||||
IconDashboard,
|
IconDashboard,
|
||||||
IconUser,
|
IconUser,
|
||||||
@@ -16,6 +17,11 @@ export const navData = {
|
|||||||
url: '/events',
|
url: '/events',
|
||||||
icon: IconCalendarEvent,
|
icon: IconCalendarEvent,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '已加入的活动',
|
||||||
|
url: '/joined-events',
|
||||||
|
icon: IconCalendarClock,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
navSecondary: [
|
navSecondary: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,3 +27,8 @@ export function invalidateBlurry(id: string) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isInDateRange(start: Date, end: Date, target: Date = new Date()): boolean {
|
||||||
|
const time = target.getTime();
|
||||||
|
return time >= start.getTime() && time <= end.getTime();
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,9 +14,12 @@ import { Route as MagicLinkSentRouteImport } from './routes/magicLinkSent'
|
|||||||
import { Route as AuthorizeRouteImport } from './routes/authorize'
|
import { Route as AuthorizeRouteImport } from './routes/authorize'
|
||||||
import { Route as WorkbenchLayoutRouteImport } from './routes/_workbenchLayout'
|
import { Route as WorkbenchLayoutRouteImport } from './routes/_workbenchLayout'
|
||||||
import { Route as WorkbenchLayoutIndexRouteImport } from './routes/_workbenchLayout/index'
|
import { Route as WorkbenchLayoutIndexRouteImport } from './routes/_workbenchLayout/index'
|
||||||
|
import { Route as WorkbenchLayoutJoinedEventsRouteImport } from './routes/_workbenchLayout/joined-events'
|
||||||
import { Route as WorkbenchLayoutEventsRouteImport } from './routes/_workbenchLayout/events'
|
import { Route as WorkbenchLayoutEventsRouteImport } from './routes/_workbenchLayout/events'
|
||||||
import { Route as WorkbenchLayoutProfileIndexRouteImport } from './routes/_workbenchLayout/profile.index'
|
import { Route as WorkbenchLayoutProfileIndexRouteImport } from './routes/_workbenchLayout/profile/index'
|
||||||
import { Route as WorkbenchLayoutProfileUserIdRouteImport } from './routes/_workbenchLayout/profile.$userId'
|
import { Route as WorkbenchLayoutEventsIndexRouteImport } from './routes/_workbenchLayout/events/index'
|
||||||
|
import { Route as WorkbenchLayoutProfileUserIdRouteImport } from './routes/_workbenchLayout/profile/$userId'
|
||||||
|
import { Route as WorkbenchLayoutEventsEventIdRouteImport } from './routes/_workbenchLayout/events/$eventId'
|
||||||
|
|
||||||
const TokenRoute = TokenRouteImport.update({
|
const TokenRoute = TokenRouteImport.update({
|
||||||
id: '/token',
|
id: '/token',
|
||||||
@@ -42,6 +45,12 @@ const WorkbenchLayoutIndexRoute = WorkbenchLayoutIndexRouteImport.update({
|
|||||||
path: '/',
|
path: '/',
|
||||||
getParentRoute: () => WorkbenchLayoutRoute,
|
getParentRoute: () => WorkbenchLayoutRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
const WorkbenchLayoutJoinedEventsRoute =
|
||||||
|
WorkbenchLayoutJoinedEventsRouteImport.update({
|
||||||
|
id: '/joined-events',
|
||||||
|
path: '/joined-events',
|
||||||
|
getParentRoute: () => WorkbenchLayoutRoute,
|
||||||
|
} as any)
|
||||||
const WorkbenchLayoutEventsRoute = WorkbenchLayoutEventsRouteImport.update({
|
const WorkbenchLayoutEventsRoute = WorkbenchLayoutEventsRouteImport.update({
|
||||||
id: '/events',
|
id: '/events',
|
||||||
path: '/events',
|
path: '/events',
|
||||||
@@ -53,29 +62,46 @@ const WorkbenchLayoutProfileIndexRoute =
|
|||||||
path: '/profile/',
|
path: '/profile/',
|
||||||
getParentRoute: () => WorkbenchLayoutRoute,
|
getParentRoute: () => WorkbenchLayoutRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
const WorkbenchLayoutEventsIndexRoute =
|
||||||
|
WorkbenchLayoutEventsIndexRouteImport.update({
|
||||||
|
id: '/',
|
||||||
|
path: '/',
|
||||||
|
getParentRoute: () => WorkbenchLayoutEventsRoute,
|
||||||
|
} as any)
|
||||||
const WorkbenchLayoutProfileUserIdRoute =
|
const WorkbenchLayoutProfileUserIdRoute =
|
||||||
WorkbenchLayoutProfileUserIdRouteImport.update({
|
WorkbenchLayoutProfileUserIdRouteImport.update({
|
||||||
id: '/profile/$userId',
|
id: '/profile/$userId',
|
||||||
path: '/profile/$userId',
|
path: '/profile/$userId',
|
||||||
getParentRoute: () => WorkbenchLayoutRoute,
|
getParentRoute: () => WorkbenchLayoutRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
const WorkbenchLayoutEventsEventIdRoute =
|
||||||
|
WorkbenchLayoutEventsEventIdRouteImport.update({
|
||||||
|
id: '/$eventId',
|
||||||
|
path: '/$eventId',
|
||||||
|
getParentRoute: () => WorkbenchLayoutEventsRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof WorkbenchLayoutIndexRoute
|
'/': typeof WorkbenchLayoutIndexRoute
|
||||||
'/authorize': typeof AuthorizeRoute
|
'/authorize': typeof AuthorizeRoute
|
||||||
'/magicLinkSent': typeof MagicLinkSentRoute
|
'/magicLinkSent': typeof MagicLinkSentRoute
|
||||||
'/token': typeof TokenRoute
|
'/token': typeof TokenRoute
|
||||||
'/events': typeof WorkbenchLayoutEventsRoute
|
'/events': typeof WorkbenchLayoutEventsRouteWithChildren
|
||||||
|
'/joined-events': typeof WorkbenchLayoutJoinedEventsRoute
|
||||||
|
'/events/$eventId': typeof WorkbenchLayoutEventsEventIdRoute
|
||||||
'/profile/$userId': typeof WorkbenchLayoutProfileUserIdRoute
|
'/profile/$userId': typeof WorkbenchLayoutProfileUserIdRoute
|
||||||
|
'/events/': typeof WorkbenchLayoutEventsIndexRoute
|
||||||
'/profile/': typeof WorkbenchLayoutProfileIndexRoute
|
'/profile/': typeof WorkbenchLayoutProfileIndexRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/authorize': typeof AuthorizeRoute
|
'/authorize': typeof AuthorizeRoute
|
||||||
'/magicLinkSent': typeof MagicLinkSentRoute
|
'/magicLinkSent': typeof MagicLinkSentRoute
|
||||||
'/token': typeof TokenRoute
|
'/token': typeof TokenRoute
|
||||||
'/events': typeof WorkbenchLayoutEventsRoute
|
'/joined-events': typeof WorkbenchLayoutJoinedEventsRoute
|
||||||
'/': typeof WorkbenchLayoutIndexRoute
|
'/': typeof WorkbenchLayoutIndexRoute
|
||||||
|
'/events/$eventId': typeof WorkbenchLayoutEventsEventIdRoute
|
||||||
'/profile/$userId': typeof WorkbenchLayoutProfileUserIdRoute
|
'/profile/$userId': typeof WorkbenchLayoutProfileUserIdRoute
|
||||||
|
'/events': typeof WorkbenchLayoutEventsIndexRoute
|
||||||
'/profile': typeof WorkbenchLayoutProfileIndexRoute
|
'/profile': typeof WorkbenchLayoutProfileIndexRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
@@ -84,9 +110,12 @@ export interface FileRoutesById {
|
|||||||
'/authorize': typeof AuthorizeRoute
|
'/authorize': typeof AuthorizeRoute
|
||||||
'/magicLinkSent': typeof MagicLinkSentRoute
|
'/magicLinkSent': typeof MagicLinkSentRoute
|
||||||
'/token': typeof TokenRoute
|
'/token': typeof TokenRoute
|
||||||
'/_workbenchLayout/events': typeof WorkbenchLayoutEventsRoute
|
'/_workbenchLayout/events': typeof WorkbenchLayoutEventsRouteWithChildren
|
||||||
|
'/_workbenchLayout/joined-events': typeof WorkbenchLayoutJoinedEventsRoute
|
||||||
'/_workbenchLayout/': typeof WorkbenchLayoutIndexRoute
|
'/_workbenchLayout/': typeof WorkbenchLayoutIndexRoute
|
||||||
|
'/_workbenchLayout/events/$eventId': typeof WorkbenchLayoutEventsEventIdRoute
|
||||||
'/_workbenchLayout/profile/$userId': typeof WorkbenchLayoutProfileUserIdRoute
|
'/_workbenchLayout/profile/$userId': typeof WorkbenchLayoutProfileUserIdRoute
|
||||||
|
'/_workbenchLayout/events/': typeof WorkbenchLayoutEventsIndexRoute
|
||||||
'/_workbenchLayout/profile/': typeof WorkbenchLayoutProfileIndexRoute
|
'/_workbenchLayout/profile/': typeof WorkbenchLayoutProfileIndexRoute
|
||||||
}
|
}
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
@@ -97,16 +126,21 @@ export interface FileRouteTypes {
|
|||||||
| '/magicLinkSent'
|
| '/magicLinkSent'
|
||||||
| '/token'
|
| '/token'
|
||||||
| '/events'
|
| '/events'
|
||||||
|
| '/joined-events'
|
||||||
|
| '/events/$eventId'
|
||||||
| '/profile/$userId'
|
| '/profile/$userId'
|
||||||
|
| '/events/'
|
||||||
| '/profile/'
|
| '/profile/'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to:
|
to:
|
||||||
| '/authorize'
|
| '/authorize'
|
||||||
| '/magicLinkSent'
|
| '/magicLinkSent'
|
||||||
| '/token'
|
| '/token'
|
||||||
| '/events'
|
| '/joined-events'
|
||||||
| '/'
|
| '/'
|
||||||
|
| '/events/$eventId'
|
||||||
| '/profile/$userId'
|
| '/profile/$userId'
|
||||||
|
| '/events'
|
||||||
| '/profile'
|
| '/profile'
|
||||||
id:
|
id:
|
||||||
| '__root__'
|
| '__root__'
|
||||||
@@ -115,8 +149,11 @@ export interface FileRouteTypes {
|
|||||||
| '/magicLinkSent'
|
| '/magicLinkSent'
|
||||||
| '/token'
|
| '/token'
|
||||||
| '/_workbenchLayout/events'
|
| '/_workbenchLayout/events'
|
||||||
|
| '/_workbenchLayout/joined-events'
|
||||||
| '/_workbenchLayout/'
|
| '/_workbenchLayout/'
|
||||||
|
| '/_workbenchLayout/events/$eventId'
|
||||||
| '/_workbenchLayout/profile/$userId'
|
| '/_workbenchLayout/profile/$userId'
|
||||||
|
| '/_workbenchLayout/events/'
|
||||||
| '/_workbenchLayout/profile/'
|
| '/_workbenchLayout/profile/'
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
@@ -164,6 +201,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof WorkbenchLayoutIndexRouteImport
|
preLoaderRoute: typeof WorkbenchLayoutIndexRouteImport
|
||||||
parentRoute: typeof WorkbenchLayoutRoute
|
parentRoute: typeof WorkbenchLayoutRoute
|
||||||
}
|
}
|
||||||
|
'/_workbenchLayout/joined-events': {
|
||||||
|
id: '/_workbenchLayout/joined-events'
|
||||||
|
path: '/joined-events'
|
||||||
|
fullPath: '/joined-events'
|
||||||
|
preLoaderRoute: typeof WorkbenchLayoutJoinedEventsRouteImport
|
||||||
|
parentRoute: typeof WorkbenchLayoutRoute
|
||||||
|
}
|
||||||
'/_workbenchLayout/events': {
|
'/_workbenchLayout/events': {
|
||||||
id: '/_workbenchLayout/events'
|
id: '/_workbenchLayout/events'
|
||||||
path: '/events'
|
path: '/events'
|
||||||
@@ -178,6 +222,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof WorkbenchLayoutProfileIndexRouteImport
|
preLoaderRoute: typeof WorkbenchLayoutProfileIndexRouteImport
|
||||||
parentRoute: typeof WorkbenchLayoutRoute
|
parentRoute: typeof WorkbenchLayoutRoute
|
||||||
}
|
}
|
||||||
|
'/_workbenchLayout/events/': {
|
||||||
|
id: '/_workbenchLayout/events/'
|
||||||
|
path: '/'
|
||||||
|
fullPath: '/events/'
|
||||||
|
preLoaderRoute: typeof WorkbenchLayoutEventsIndexRouteImport
|
||||||
|
parentRoute: typeof WorkbenchLayoutEventsRoute
|
||||||
|
}
|
||||||
'/_workbenchLayout/profile/$userId': {
|
'/_workbenchLayout/profile/$userId': {
|
||||||
id: '/_workbenchLayout/profile/$userId'
|
id: '/_workbenchLayout/profile/$userId'
|
||||||
path: '/profile/$userId'
|
path: '/profile/$userId'
|
||||||
@@ -185,18 +236,42 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof WorkbenchLayoutProfileUserIdRouteImport
|
preLoaderRoute: typeof WorkbenchLayoutProfileUserIdRouteImport
|
||||||
parentRoute: typeof WorkbenchLayoutRoute
|
parentRoute: typeof WorkbenchLayoutRoute
|
||||||
}
|
}
|
||||||
|
'/_workbenchLayout/events/$eventId': {
|
||||||
|
id: '/_workbenchLayout/events/$eventId'
|
||||||
|
path: '/$eventId'
|
||||||
|
fullPath: '/events/$eventId'
|
||||||
|
preLoaderRoute: typeof WorkbenchLayoutEventsEventIdRouteImport
|
||||||
|
parentRoute: typeof WorkbenchLayoutEventsRoute
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface WorkbenchLayoutEventsRouteChildren {
|
||||||
|
WorkbenchLayoutEventsEventIdRoute: typeof WorkbenchLayoutEventsEventIdRoute
|
||||||
|
WorkbenchLayoutEventsIndexRoute: typeof WorkbenchLayoutEventsIndexRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
const WorkbenchLayoutEventsRouteChildren: WorkbenchLayoutEventsRouteChildren = {
|
||||||
|
WorkbenchLayoutEventsEventIdRoute: WorkbenchLayoutEventsEventIdRoute,
|
||||||
|
WorkbenchLayoutEventsIndexRoute: WorkbenchLayoutEventsIndexRoute,
|
||||||
|
}
|
||||||
|
|
||||||
|
const WorkbenchLayoutEventsRouteWithChildren =
|
||||||
|
WorkbenchLayoutEventsRoute._addFileChildren(
|
||||||
|
WorkbenchLayoutEventsRouteChildren,
|
||||||
|
)
|
||||||
|
|
||||||
interface WorkbenchLayoutRouteChildren {
|
interface WorkbenchLayoutRouteChildren {
|
||||||
WorkbenchLayoutEventsRoute: typeof WorkbenchLayoutEventsRoute
|
WorkbenchLayoutEventsRoute: typeof WorkbenchLayoutEventsRouteWithChildren
|
||||||
|
WorkbenchLayoutJoinedEventsRoute: typeof WorkbenchLayoutJoinedEventsRoute
|
||||||
WorkbenchLayoutIndexRoute: typeof WorkbenchLayoutIndexRoute
|
WorkbenchLayoutIndexRoute: typeof WorkbenchLayoutIndexRoute
|
||||||
WorkbenchLayoutProfileUserIdRoute: typeof WorkbenchLayoutProfileUserIdRoute
|
WorkbenchLayoutProfileUserIdRoute: typeof WorkbenchLayoutProfileUserIdRoute
|
||||||
WorkbenchLayoutProfileIndexRoute: typeof WorkbenchLayoutProfileIndexRoute
|
WorkbenchLayoutProfileIndexRoute: typeof WorkbenchLayoutProfileIndexRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
const WorkbenchLayoutRouteChildren: WorkbenchLayoutRouteChildren = {
|
const WorkbenchLayoutRouteChildren: WorkbenchLayoutRouteChildren = {
|
||||||
WorkbenchLayoutEventsRoute: WorkbenchLayoutEventsRoute,
|
WorkbenchLayoutEventsRoute: WorkbenchLayoutEventsRouteWithChildren,
|
||||||
|
WorkbenchLayoutJoinedEventsRoute: WorkbenchLayoutJoinedEventsRoute,
|
||||||
WorkbenchLayoutIndexRoute: WorkbenchLayoutIndexRoute,
|
WorkbenchLayoutIndexRoute: WorkbenchLayoutIndexRoute,
|
||||||
WorkbenchLayoutProfileUserIdRoute: WorkbenchLayoutProfileUserIdRoute,
|
WorkbenchLayoutProfileUserIdRoute: WorkbenchLayoutProfileUserIdRoute,
|
||||||
WorkbenchLayoutProfileIndexRoute: WorkbenchLayoutProfileIndexRoute,
|
WorkbenchLayoutProfileIndexRoute: WorkbenchLayoutProfileIndexRoute,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_workbenchLayout/events/$eventId')({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return <div>Hello "/_workbenchLayout/events/$eventId"!</div>;
|
||||||
|
}
|
||||||
14
client/cms/src/routes/_workbenchLayout/events/index.tsx
Normal file
14
client/cms/src/routes/_workbenchLayout/events/index.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import { EventGridContainer } from '@/components/events/event-grid/event-grid.container';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_workbenchLayout/events/')({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return (
|
||||||
|
<div className="py-4 px-6 md:gap-6 md:py-6 h-full">
|
||||||
|
<EventGridContainer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
client/cms/src/routes/_workbenchLayout/joined-events.tsx
Normal file
14
client/cms/src/routes/_workbenchLayout/joined-events.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import { JoinedEventsContainer } from '@/components/events/joined-events.containers';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_workbenchLayout/joined-events')({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return (
|
||||||
|
<div className="py-4 px-6 md:gap-6 md:py-6 h-full">
|
||||||
|
<JoinedEventsContainer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||||
import { EventGridSkeleton } from '@/components/events/event-grid/event-grid.skeleton';
|
import { EventGridSkeleton } from '@/components/events/event-grid/event-grid.skeleton';
|
||||||
import { EventGridView } from '@/components/events/event-grid/event-grid.view';
|
import { EventGridView } from '@/components/events/event-grid/event-grid.view';
|
||||||
|
import { JoinedEventGridFooter } from '@/components/events/joined-events.containers';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Skeleton as UiSkeleton } from '@/components/ui/skeleton';
|
import { Skeleton as UiSkeleton } from '@/components/ui/skeleton';
|
||||||
|
import { exampleMultiEvents } from './event.example';
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Events/EventGrid',
|
title: 'Events/EventGrid',
|
||||||
@@ -14,56 +16,18 @@ type Story = StoryObj<typeof meta>;
|
|||||||
|
|
||||||
export const Primary: Story = {
|
export const Primary: Story = {
|
||||||
args: {
|
args: {
|
||||||
events: [
|
events: exampleMultiEvents,
|
||||||
{
|
|
||||||
eventId: '1',
|
|
||||||
requireKyc: true,
|
|
||||||
isJoined: false,
|
|
||||||
type: 'official',
|
|
||||||
coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-watersplash.png?raw=true',
|
|
||||||
eventName: 'Nix CN Conference 26.05',
|
|
||||||
description: 'Event Description',
|
|
||||||
startTime: new Date('2026-06-13T04:00:00.000Z'),
|
|
||||||
endTime: new Date('2026-06-14T04:00:00.000Z'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
eventId: '2',
|
|
||||||
requireKyc: true,
|
|
||||||
isJoined: false,
|
|
||||||
type: 'official',
|
|
||||||
coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-moonscape.png?raw=true',
|
|
||||||
eventName: 'Nix CN Conference 26.05',
|
|
||||||
description: 'Event Description',
|
|
||||||
startTime: new Date('2026-06-13T04:00:00.000Z'),
|
|
||||||
endTime: new Date('2026-06-14T04:00:00.000Z'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
eventId: '3',
|
|
||||||
requireKyc: true,
|
|
||||||
isJoined: false,
|
|
||||||
type: 'official',
|
|
||||||
coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-nineish-catppuccin-latte.png?raw=true',
|
|
||||||
eventName: 'Nix CN Conference 26.05',
|
|
||||||
description: 'Event Description',
|
|
||||||
startTime: new Date('2026-06-13T04:00:00.000Z'),
|
|
||||||
endTime: new Date('2026-06-14T04:00:00.000Z'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
eventId: '4',
|
|
||||||
requireKyc: true,
|
|
||||||
isJoined: false,
|
|
||||||
type: 'official',
|
|
||||||
coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nixos-wallpaper-catppuccin-macchiato.png?raw=true',
|
|
||||||
eventName: 'Nix CN Conference 26.05',
|
|
||||||
description: 'Event Description',
|
|
||||||
startTime: new Date('2026-06-13T04:00:00.000Z'),
|
|
||||||
endTime: new Date('2026-06-14T04:00:00.000Z'),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
footer: () => <Button className="w-full">加入活动</Button>,
|
footer: () => <Button className="w-full">加入活动</Button>,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Joined: Story = {
|
||||||
|
args: {
|
||||||
|
events: exampleMultiEvents,
|
||||||
|
footer: event => <JoinedEventGridFooter event={event} />,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const Empty: Story = {
|
export const Empty: Story = {
|
||||||
decorators: [Story => <div className="h-screen"><Story /></div>],
|
decorators: [Story => <div className="h-screen"><Story /></div>],
|
||||||
args: {
|
args: {
|
||||||
|
|||||||
@@ -11,3 +11,50 @@ export const exampleEvent: EventInfo = {
|
|||||||
startTime: new Date('2026-06-13T04:00:00.000Z'),
|
startTime: new Date('2026-06-13T04:00:00.000Z'),
|
||||||
endTime: new Date('2026-06-14T04:00:00.000Z'),
|
endTime: new Date('2026-06-14T04:00:00.000Z'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const exampleMultiEvents: EventInfo[] = [
|
||||||
|
{
|
||||||
|
eventId: '1',
|
||||||
|
requireKyc: true,
|
||||||
|
isJoined: false,
|
||||||
|
type: 'official',
|
||||||
|
coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-watersplash.png?raw=true',
|
||||||
|
eventName: 'Nix CN Conference 26.05',
|
||||||
|
description: 'Event Description',
|
||||||
|
startTime: new Date('2026-06-13T04:00:00.000Z'),
|
||||||
|
endTime: new Date('2026-06-14T04:00:00.000Z'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
eventId: '2',
|
||||||
|
requireKyc: true,
|
||||||
|
isJoined: false,
|
||||||
|
type: 'official',
|
||||||
|
coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-moonscape.png?raw=true',
|
||||||
|
eventName: 'Nix CN Conference 26.05',
|
||||||
|
description: 'Event Description',
|
||||||
|
startTime: new Date('2026-06-13T04:00:00.000Z'),
|
||||||
|
endTime: new Date('2026-06-14T04:00:00.000Z'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
eventId: '3',
|
||||||
|
requireKyc: true,
|
||||||
|
isJoined: false,
|
||||||
|
type: 'official',
|
||||||
|
coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nix-wallpaper-nineish-catppuccin-latte.png?raw=true',
|
||||||
|
eventName: 'Nix CN Conference 26.05',
|
||||||
|
description: 'Event Description',
|
||||||
|
startTime: new Date('2026-06-13T04:00:00.000Z'),
|
||||||
|
endTime: new Date('2026-06-14T04:00:00.000Z'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
eventId: '4',
|
||||||
|
requireKyc: true,
|
||||||
|
isJoined: false,
|
||||||
|
type: 'official',
|
||||||
|
coverImage: 'https://github.com/NixOS/nixos-artwork/blob/master/wallpapers/nixos-wallpaper-catppuccin-macchiato.png?raw=true',
|
||||||
|
eventName: 'Nix CN Conference 26.05',
|
||||||
|
description: 'Event Description',
|
||||||
|
startTime: new Date('2026-06-13T04:00:00.000Z'),
|
||||||
|
endTime: new Date('2026-06-14T04:00:00.000Z'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user