From b7ac9428079bec8870d8e938170d9e48cda95948 Mon Sep 17 00:00:00 2001 From: Noa Virellia Date: Sun, 1 Feb 2026 14:26:35 +0800 Subject: [PATCH] feat(client): event list Signed-off-by: Noa Virellia --- client/cms/src/assets/event-placeholder.png | Bin 0 -> 20063 bytes .../src/client/@tanstack/react-query.gen.ts | 61 +++++- client/cms/src/client/index.ts | 4 +- client/cms/src/client/sdk.gen.ts | 44 +++- client/cms/src/client/types.gen.ts | 196 ++++++++++++++++++ client/cms/src/client/zod.gen.ts | 63 ++++++ .../components/events/event-card.skeleton.tsx | 40 ++++ .../event-card.view.tsx | 18 +- .../events/event-grid.container.tsx | 23 ++ .../components/events/event-grid.skeleton.tsx | 12 ++ .../src/components/events/event-grid.view.tsx | 12 ++ client/cms/src/components/events/types.ts | 9 + .../workbenchCards/card-skeleton.tsx | 9 - client/cms/src/hooks/data/useGetEvents.ts | 21 ++ client/cms/src/hooks/data/useJoinEvent.ts | 8 + .../src/routes/_workbenchLayout/events.tsx | 7 +- client/cms/src/stories/event-card.stories.ts | 21 -- .../src/stories/events/event-card.stories.tsx | 36 ++++ .../src/stories/events/event-grid.stories.tsx | 61 ++++++ .../stories/{ => layout}/sidebar.stories.tsx | 4 +- 20 files changed, 600 insertions(+), 49 deletions(-) create mode 100644 client/cms/src/assets/event-placeholder.png create mode 100644 client/cms/src/components/events/event-card.skeleton.tsx rename client/cms/src/components/{workbenchCards => events}/event-card.view.tsx (80%) create mode 100644 client/cms/src/components/events/event-grid.container.tsx create mode 100644 client/cms/src/components/events/event-grid.skeleton.tsx create mode 100644 client/cms/src/components/events/event-grid.view.tsx create mode 100644 client/cms/src/components/events/types.ts delete mode 100644 client/cms/src/components/workbenchCards/card-skeleton.tsx create mode 100644 client/cms/src/hooks/data/useGetEvents.ts create mode 100644 client/cms/src/hooks/data/useJoinEvent.ts delete mode 100644 client/cms/src/stories/event-card.stories.ts create mode 100644 client/cms/src/stories/events/event-card.stories.tsx create mode 100644 client/cms/src/stories/events/event-grid.stories.tsx rename client/cms/src/stories/{ => layout}/sidebar.stories.tsx (93%) diff --git a/client/cms/src/assets/event-placeholder.png b/client/cms/src/assets/event-placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..dc2c293833bcd447a9193a52e221e9b927210e44 GIT binary patch literal 20063 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 => query queryKey: getEventInfoQueryKey(options) }); +/** + * Join an Event + * + * Allows an authenticated user to join an event by providing the event ID. The user's role and state are initialized by the service. + */ +export const postEventJoinMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await postEventJoin({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + export const getEventListQueryKey = (options: Options) => createQueryKey('getEventList', options); /** @@ -292,6 +311,44 @@ export const getEventListInfiniteOptions = (options: Options) queryKey: getEventListInfiniteQueryKey(options) }); +/** + * Query KYC Status + * + * Checks the current state of a KYC session and updates local database if approved. + */ +export const postKycQueryMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await postKycQuery({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Create KYC Session + * + * Initializes a KYC process (CNRid or Passport) and returns the status or redirect URI. + */ +export const postKycSessionMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await postKycSession({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + export const getUserInfoQueryKey = (options?: Options) => createQueryKey('getUserInfo', options); /** diff --git a/client/cms/src/client/index.ts b/client/cms/src/client/index.ts index a9d11b0..a853517 100644 --- a/client/cms/src/client/index.ts +++ b/client/cms/src/client/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { getAuthRedirect, getEventCheckin, getEventCheckinQuery, getEventInfo, getEventList, getUserInfo, getUserInfoByUserId, getUserList, type Options, patchUserUpdate, postAuthExchange, postAuthMagic, postAuthRefresh, postAuthToken, postEventCheckinSubmit } from './sdk.gen'; -export type { ClientOptions, DataEventIndexDoc, DataUserIndexDoc, GetAuthRedirectData, GetAuthRedirectError, GetAuthRedirectErrors, GetEventCheckinData, GetEventCheckinError, GetEventCheckinErrors, GetEventCheckinQueryData, GetEventCheckinQueryError, GetEventCheckinQueryErrors, GetEventCheckinQueryResponse, GetEventCheckinQueryResponses, GetEventCheckinResponse, GetEventCheckinResponses, GetEventInfoData, GetEventInfoError, GetEventInfoErrors, GetEventInfoResponse, GetEventInfoResponses, GetEventListData, GetEventListError, GetEventListErrors, GetEventListResponse, GetEventListResponses, GetUserInfoByUserIdData, GetUserInfoByUserIdError, GetUserInfoByUserIdErrors, GetUserInfoByUserIdResponse, GetUserInfoByUserIdResponses, GetUserInfoData, GetUserInfoError, GetUserInfoErrors, GetUserInfoResponse, GetUserInfoResponses, GetUserListData, GetUserListError, GetUserListErrors, GetUserListResponse, GetUserListResponses, PatchUserUpdateData, PatchUserUpdateError, PatchUserUpdateErrors, PatchUserUpdateResponse, PatchUserUpdateResponses, PostAuthExchangeData, PostAuthExchangeError, PostAuthExchangeErrors, PostAuthExchangeResponse, PostAuthExchangeResponses, PostAuthMagicData, PostAuthMagicError, PostAuthMagicErrors, PostAuthMagicResponse, PostAuthMagicResponses, PostAuthRefreshData, PostAuthRefreshError, PostAuthRefreshErrors, PostAuthRefreshResponse, PostAuthRefreshResponses, PostAuthTokenData, PostAuthTokenError, PostAuthTokenErrors, PostAuthTokenResponse, PostAuthTokenResponses, PostEventCheckinSubmitData, PostEventCheckinSubmitError, PostEventCheckinSubmitErrors, PostEventCheckinSubmitResponse, PostEventCheckinSubmitResponses, ServiceAuthExchangeData, ServiceAuthExchangeResponse, ServiceAuthMagicData, ServiceAuthMagicResponse, ServiceAuthRefreshData, ServiceAuthTokenData, ServiceAuthTokenResponse, ServiceEventCheckinQueryResponse, ServiceEventCheckinResponse, ServiceEventCheckinSubmitData, ServiceUserUserInfoData, UtilsRespStatus } from './types.gen'; +export { getAuthRedirect, getEventCheckin, getEventCheckinQuery, getEventInfo, getEventList, getUserInfo, getUserInfoByUserId, getUserList, type Options, patchUserUpdate, postAuthExchange, postAuthMagic, postAuthRefresh, postAuthToken, postEventCheckinSubmit, postEventJoin, postKycQuery, postKycSession } from './sdk.gen'; +export type { ClientOptions, DataEventIndexDoc, DataUserIndexDoc, GetAuthRedirectData, GetAuthRedirectError, GetAuthRedirectErrors, GetEventCheckinData, GetEventCheckinError, GetEventCheckinErrors, GetEventCheckinQueryData, GetEventCheckinQueryError, GetEventCheckinQueryErrors, GetEventCheckinQueryResponse, GetEventCheckinQueryResponses, GetEventCheckinResponse, GetEventCheckinResponses, GetEventInfoData, GetEventInfoError, GetEventInfoErrors, GetEventInfoResponse, GetEventInfoResponses, GetEventListData, GetEventListError, GetEventListErrors, GetEventListResponse, GetEventListResponses, GetUserInfoByUserIdData, GetUserInfoByUserIdError, GetUserInfoByUserIdErrors, GetUserInfoByUserIdResponse, GetUserInfoByUserIdResponses, GetUserInfoData, GetUserInfoError, GetUserInfoErrors, GetUserInfoResponse, GetUserInfoResponses, GetUserListData, GetUserListError, GetUserListErrors, GetUserListResponse, GetUserListResponses, PatchUserUpdateData, PatchUserUpdateError, PatchUserUpdateErrors, PatchUserUpdateResponse, PatchUserUpdateResponses, PostAuthExchangeData, PostAuthExchangeError, PostAuthExchangeErrors, PostAuthExchangeResponse, PostAuthExchangeResponses, PostAuthMagicData, PostAuthMagicError, PostAuthMagicErrors, PostAuthMagicResponse, PostAuthMagicResponses, PostAuthRefreshData, PostAuthRefreshError, PostAuthRefreshErrors, PostAuthRefreshResponse, PostAuthRefreshResponses, PostAuthTokenData, PostAuthTokenError, PostAuthTokenErrors, PostAuthTokenResponse, PostAuthTokenResponses, PostEventCheckinSubmitData, PostEventCheckinSubmitError, PostEventCheckinSubmitErrors, PostEventCheckinSubmitResponse, PostEventCheckinSubmitResponses, PostEventJoinData, PostEventJoinError, PostEventJoinErrors, PostEventJoinResponse, PostEventJoinResponses, PostKycQueryData, PostKycQueryError, PostKycQueryErrors, PostKycQueryResponse, PostKycQueryResponses, PostKycSessionData, PostKycSessionError, PostKycSessionErrors, PostKycSessionResponse, PostKycSessionResponses, ServiceAuthExchangeData, ServiceAuthExchangeResponse, ServiceAuthMagicData, ServiceAuthMagicResponse, ServiceAuthRefreshData, ServiceAuthTokenData, ServiceAuthTokenResponse, ServiceEventCheckinQueryResponse, ServiceEventCheckinResponse, ServiceEventCheckinSubmitData, ServiceEventEventJoinData, ServiceKycKycQueryData, ServiceKycKycQueryResponse, ServiceKycKycSessionData, ServiceKycKycSessionResponse, ServiceUserUserInfoData, UtilsRespStatus } from './types.gen'; diff --git a/client/cms/src/client/sdk.gen.ts b/client/cms/src/client/sdk.gen.ts index fd54c66..475743d 100644 --- a/client/cms/src/client/sdk.gen.ts +++ b/client/cms/src/client/sdk.gen.ts @@ -2,7 +2,7 @@ import type { Client, Options as Options2, TDataShape } from './client'; import { client } from './client.gen'; -import type { GetAuthRedirectData, GetAuthRedirectErrors, GetEventCheckinData, GetEventCheckinErrors, GetEventCheckinQueryData, GetEventCheckinQueryErrors, GetEventCheckinQueryResponses, GetEventCheckinResponses, GetEventInfoData, GetEventInfoErrors, GetEventInfoResponses, GetEventListData, GetEventListErrors, GetEventListResponses, GetUserInfoByUserIdData, GetUserInfoByUserIdErrors, GetUserInfoByUserIdResponses, GetUserInfoData, GetUserInfoErrors, GetUserInfoResponses, GetUserListData, GetUserListErrors, GetUserListResponses, PatchUserUpdateData, PatchUserUpdateErrors, PatchUserUpdateResponses, PostAuthExchangeData, PostAuthExchangeErrors, PostAuthExchangeResponses, PostAuthMagicData, PostAuthMagicErrors, PostAuthMagicResponses, PostAuthRefreshData, PostAuthRefreshErrors, PostAuthRefreshResponses, PostAuthTokenData, PostAuthTokenErrors, PostAuthTokenResponses, PostEventCheckinSubmitData, PostEventCheckinSubmitErrors, PostEventCheckinSubmitResponses } from './types.gen'; +import type { GetAuthRedirectData, GetAuthRedirectErrors, GetEventCheckinData, GetEventCheckinErrors, GetEventCheckinQueryData, GetEventCheckinQueryErrors, GetEventCheckinQueryResponses, GetEventCheckinResponses, GetEventInfoData, GetEventInfoErrors, GetEventInfoResponses, GetEventListData, GetEventListErrors, GetEventListResponses, GetUserInfoByUserIdData, GetUserInfoByUserIdErrors, GetUserInfoByUserIdResponses, GetUserInfoData, GetUserInfoErrors, GetUserInfoResponses, GetUserListData, GetUserListErrors, GetUserListResponses, PatchUserUpdateData, PatchUserUpdateErrors, PatchUserUpdateResponses, PostAuthExchangeData, PostAuthExchangeErrors, PostAuthExchangeResponses, PostAuthMagicData, PostAuthMagicErrors, PostAuthMagicResponses, PostAuthRefreshData, PostAuthRefreshErrors, PostAuthRefreshResponses, PostAuthTokenData, PostAuthTokenErrors, PostAuthTokenResponses, PostEventCheckinSubmitData, PostEventCheckinSubmitErrors, PostEventCheckinSubmitResponses, PostEventJoinData, PostEventJoinErrors, PostEventJoinResponses, PostKycQueryData, PostKycQueryErrors, PostKycQueryResponses, PostKycSessionData, PostKycSessionErrors, PostKycSessionResponses } from './types.gen'; export type Options = Options2 & { /** @@ -116,6 +116,20 @@ export const postEventCheckinSubmit = (opt */ export const getEventInfo = (options: Options) => (options.client ?? client).get({ url: '/event/info', ...options }); +/** + * Join an Event + * + * Allows an authenticated user to join an event by providing the event ID. The user's role and state are initialized by the service. + */ +export const postEventJoin = (options: Options) => (options.client ?? client).post({ + url: '/event/join', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + /** * List Events * @@ -123,6 +137,34 @@ export const getEventInfo = (options: Opti */ export const getEventList = (options: Options) => (options.client ?? client).get({ url: '/event/list', ...options }); +/** + * Query KYC Status + * + * Checks the current state of a KYC session and updates local database if approved. + */ +export const postKycQuery = (options: Options) => (options.client ?? client).post({ + url: '/kyc/query', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Create KYC Session + * + * Initializes a KYC process (CNRid or Passport) and returns the status or redirect URI. + */ +export const postKycSession = (options: Options) => (options.client ?? client).post({ + url: '/kyc/session', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + /** * Get My User Information * diff --git a/client/cms/src/client/types.gen.ts b/client/cms/src/client/types.gen.ts index c59d21e..85a22d1 100644 --- a/client/cms/src/client/types.gen.ts +++ b/client/cms/src/client/types.gen.ts @@ -72,6 +72,42 @@ export type ServiceEventCheckinSubmitData = { checkin_code?: string; }; +export type ServiceEventEventJoinData = { + event_id?: string; + kyc_id?: string; +}; + +export type ServiceKycKycQueryData = { + kyc_id?: string; +}; + +export type ServiceKycKycQueryResponse = { + /** + * success | pending | failed + */ + status?: string; +}; + +export type ServiceKycKycSessionData = { + /** + * base64 json + */ + identity?: string; + /** + * cnrid | passport + */ + type?: string; +}; + +export type ServiceKycKycSessionResponse = { + kyc_id?: string; + redirect_uri?: string; + /** + * success | processing + */ + status?: string; +}; + export type ServiceUserUserInfoData = { allow_public?: boolean; avatar?: string; @@ -536,6 +572,66 @@ export type GetEventInfoResponses = { export type GetEventInfoResponse = GetEventInfoResponses[keyof GetEventInfoResponses]; +export type PostEventJoinData = { + /** + * Event Join Details (UserId and EventId are required) + */ + body: ServiceEventEventJoinData; + path?: never; + query?: never; + url: '/event/join'; +}; + +export type PostEventJoinErrors = { + /** + * Invalid Input or UUID Parse Failed + */ + 400: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; + /** + * Missing User ID / Unauthorized + */ + 401: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; + /** + * Unauthorized / Missing User ID + */ + 403: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; + /** + * Internal Server Error / Database Error + */ + 500: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; +}; + +export type PostEventJoinError = PostEventJoinErrors[keyof PostEventJoinErrors]; + +export type PostEventJoinResponses = { + /** + * Successfully joined the event + */ + 200: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; +}; + +export type PostEventJoinResponse = PostEventJoinResponses[keyof PostEventJoinResponses]; + export type GetEventListData = { body?: never; path?: never; @@ -592,6 +688,106 @@ export type GetEventListResponses = { export type GetEventListResponse = GetEventListResponses[keyof GetEventListResponses]; +export type PostKycQueryData = { + /** + * KYC query data (KycId) + */ + body: ServiceKycKycQueryData; + path?: never; + query?: never; + url: '/kyc/query'; +}; + +export type PostKycQueryErrors = { + /** + * Invalid UUID or input + */ + 400: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; + /** + * Unauthorized + */ + 403: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; + /** + * Internal Server Error + */ + 500: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; +}; + +export type PostKycQueryError = PostKycQueryErrors[keyof PostKycQueryErrors]; + +export type PostKycQueryResponses = { + /** + * Query processed (success/pending/failed) + */ + 200: UtilsRespStatus & { + data?: ServiceKycKycQueryResponse; + }; +}; + +export type PostKycQueryResponse = PostKycQueryResponses[keyof PostKycQueryResponses]; + +export type PostKycSessionData = { + /** + * KYC session data (Type and Base64 Identity) + */ + body: ServiceKycKycSessionData; + path?: never; + query?: never; + url: '/kyc/session'; +}; + +export type PostKycSessionErrors = { + /** + * Invalid input or decode failed + */ + 400: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; + /** + * Missing User ID + */ + 403: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; + /** + * Internal Server Error / KYC Service Error + */ + 500: UtilsRespStatus & { + data?: { + [key: string]: unknown; + }; + }; +}; + +export type PostKycSessionError = PostKycSessionErrors[keyof PostKycSessionErrors]; + +export type PostKycSessionResponses = { + /** + * Session created successfully + */ + 200: UtilsRespStatus & { + data?: ServiceKycKycSessionResponse; + }; +}; + +export type PostKycSessionResponse = PostKycSessionResponses[keyof PostKycSessionResponses]; + export type GetUserInfoData = { body?: never; path?: never; diff --git a/client/cms/src/client/zod.gen.ts b/client/cms/src/client/zod.gen.ts index 4b87cee..19c081d 100644 --- a/client/cms/src/client/zod.gen.ts +++ b/client/cms/src/client/zod.gen.ts @@ -70,6 +70,30 @@ export const zServiceEventCheckinSubmitData = z.object({ checkin_code: z.optional(z.string()) }); +export const zServiceEventEventJoinData = z.object({ + event_id: z.optional(z.string()), + kyc_id: z.optional(z.string()) +}); + +export const zServiceKycKycQueryData = z.object({ + kyc_id: z.optional(z.string()) +}); + +export const zServiceKycKycQueryResponse = z.object({ + status: z.optional(z.string()) +}); + +export const zServiceKycKycSessionData = z.object({ + identity: z.optional(z.string()), + type: z.optional(z.string()) +}); + +export const zServiceKycKycSessionResponse = z.object({ + kyc_id: z.optional(z.string()), + redirect_uri: z.optional(z.string()), + status: z.optional(z.string()) +}); + export const zServiceUserUserInfoData = z.object({ allow_public: z.optional(z.boolean()), avatar: z.optional(z.string()), @@ -210,6 +234,19 @@ export const zGetEventInfoResponse = zUtilsRespStatus.and(z.object({ data: z.optional(zDataEventIndexDoc) })); +export const zPostEventJoinData = z.object({ + body: zServiceEventEventJoinData, + path: z.optional(z.never()), + query: z.optional(z.never()) +}); + +/** + * Successfully joined the event + */ +export const zPostEventJoinResponse = zUtilsRespStatus.and(z.object({ + data: z.optional(z.record(z.string(), z.unknown())) +})); + export const zGetEventListData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), @@ -226,6 +263,32 @@ export const zGetEventListResponse = zUtilsRespStatus.and(z.object({ data: z.optional(z.array(zDataEventIndexDoc)) })); +export const zPostKycQueryData = z.object({ + body: zServiceKycKycQueryData, + path: z.optional(z.never()), + query: z.optional(z.never()) +}); + +/** + * Query processed (success/pending/failed) + */ +export const zPostKycQueryResponse = zUtilsRespStatus.and(z.object({ + data: z.optional(zServiceKycKycQueryResponse) +})); + +export const zPostKycSessionData = z.object({ + body: zServiceKycKycSessionData, + path: z.optional(z.never()), + query: z.optional(z.never()) +}); + +/** + * Session created successfully + */ +export const zPostKycSessionResponse = zUtilsRespStatus.and(z.object({ + data: z.optional(zServiceKycKycSessionResponse) +})); + export const zGetUserInfoData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), diff --git a/client/cms/src/components/events/event-card.skeleton.tsx b/client/cms/src/components/events/event-card.skeleton.tsx new file mode 100644 index 0000000..0a874c0 --- /dev/null +++ b/client/cms/src/components/events/event-card.skeleton.tsx @@ -0,0 +1,40 @@ +import { Calendar } from 'lucide-react'; +import { + Card, + CardAction, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@/components/ui/card'; +import { Badge } from '../ui/badge'; +import { Skeleton } from '../ui/skeleton'; + +export function EventCardSkeleton() { + return ( + +
+ + + + Official + + + + + + + + + + + + + + + + + ); +} diff --git a/client/cms/src/components/workbenchCards/event-card.view.tsx b/client/cms/src/components/events/event-card.view.tsx similarity index 80% rename from client/cms/src/components/workbenchCards/event-card.view.tsx rename to client/cms/src/components/events/event-card.view.tsx index 7bb21cf..3b5d5fd 100644 --- a/client/cms/src/components/workbenchCards/event-card.view.tsx +++ b/client/cms/src/components/events/event-card.view.tsx @@ -1,3 +1,4 @@ +import type { EventInfo } from './types'; import dayjs from 'dayjs'; import { Calendar } from 'lucide-react'; import { Badge } from '@/components/ui/badge'; @@ -10,16 +11,9 @@ import { CardHeader, CardTitle, } from '@/components/ui/card'; +import { Skeleton } from '../ui/skeleton'; -export function EventCardView({ type, coverImage, eventName, description, startTime, endTime }: - { - type: 'official' | 'party'; - coverImage: string; - eventName: string; - description: string; - startTime: Date; - endTime: Date; - }) { +export function EventCardView({ type, coverImage, eventName, description, startTime, endTime, onJoinEvent }: EventInfo) { const startDayJs = dayjs(startTime); const endDayJs = dayjs(endTime); return ( @@ -30,6 +24,9 @@ export function EventCardView({ type, coverImage, eventName, description, startT alt="Event cover" className="relative z-20 aspect-video w-full object-cover rounded-t-xl" /> + {type === 'official' ? Official : Party} @@ -42,10 +39,9 @@ export function EventCardView({ type, coverImage, eventName, description, startT {description} - - + ); diff --git a/client/cms/src/components/events/event-grid.container.tsx b/client/cms/src/components/events/event-grid.container.tsx new file mode 100644 index 0000000..e0e981f --- /dev/null +++ b/client/cms/src/components/events/event-grid.container.tsx @@ -0,0 +1,23 @@ +import type { EventInfo } from './types'; +import PlaceholderImage from '@/assets/event-placeholder.png'; +import { useGetEvents } from '@/hooks/data/useGetEvents'; +import { useJoinEvent } from '@/hooks/data/useJoinEvent'; +import { EventGridView } from './event-grid.view'; + +export function EventGridContainer() { + const { data, isLoading } = useGetEvents(); + const { mutate } = useJoinEvent(); + const allEvents: EventInfo[] = isLoading + ? [] + : data.pages.flatMap(page => page.data!).map(it => ({ + type: it.type! as EventInfo['type'], + coverImage: it.thumbnail! || PlaceholderImage, + eventName: it.name!, + description: it.description!, + startTime: new Date(it.start_time!), + endTime: new Date(it.end_time!), + onJoinEvent: () => mutate({ body: { event_id: it.event_id } }), + } satisfies EventInfo)); + + return ; +} diff --git a/client/cms/src/components/events/event-grid.skeleton.tsx b/client/cms/src/components/events/event-grid.skeleton.tsx new file mode 100644 index 0000000..7c0046a --- /dev/null +++ b/client/cms/src/components/events/event-grid.skeleton.tsx @@ -0,0 +1,12 @@ +import { EventCardSkeleton } from './event-card.skeleton'; + +export function EventGridSkeleton() { + return ( +
+ {Array.from({ length: 8 }).map((_, i) => ( + // eslint-disable-next-line react/no-array-index-key + + ))} +
+ ); +} diff --git a/client/cms/src/components/events/event-grid.view.tsx b/client/cms/src/components/events/event-grid.view.tsx new file mode 100644 index 0000000..79c90c1 --- /dev/null +++ b/client/cms/src/components/events/event-grid.view.tsx @@ -0,0 +1,12 @@ +import type { EventInfo } from './types'; +import { EventCardView } from './event-card.view'; + +export function EventGridView({ events }: { events: EventInfo[] }) { + return ( +
+ {events.map(event => ( + + ))} +
+ ); +} diff --git a/client/cms/src/components/events/types.ts b/client/cms/src/components/events/types.ts new file mode 100644 index 0000000..22f52de --- /dev/null +++ b/client/cms/src/components/events/types.ts @@ -0,0 +1,9 @@ +export interface EventInfo { + type: 'official' | 'party'; + coverImage: string; + eventName: string; + description: string; + startTime: Date; + endTime: Date; + onJoinEvent: () => void; +} diff --git a/client/cms/src/components/workbenchCards/card-skeleton.tsx b/client/cms/src/components/workbenchCards/card-skeleton.tsx deleted file mode 100644 index 007b499..0000000 --- a/client/cms/src/components/workbenchCards/card-skeleton.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Skeleton } from '../ui/skeleton'; - -export function CardSkeleton() { - return ( - - ); -} diff --git a/client/cms/src/hooks/data/useGetEvents.ts b/client/cms/src/hooks/data/useGetEvents.ts new file mode 100644 index 0000000..4e02244 --- /dev/null +++ b/client/cms/src/hooks/data/useGetEvents.ts @@ -0,0 +1,21 @@ +import { useInfiniteQuery } from '@tanstack/react-query'; +import { isNil } from 'lodash-es'; +import { getEventListInfiniteOptions } from '@/client/@tanstack/react-query.gen'; + +const LIMIT = 12; + +export function useGetEvents() { + return useInfiniteQuery({ + ...getEventListInfiniteOptions({ + query: { limit: String(LIMIT), offset: String(0) }, + }), + initialPageParam: '0', + getNextPageParam: (lastPage, allPages) => { + const currentData = lastPage?.data; + if (!isNil(currentData) && currentData.length === LIMIT) { + return String(allPages.length * LIMIT); + } + return undefined; + }, + }); +} diff --git a/client/cms/src/hooks/data/useJoinEvent.ts b/client/cms/src/hooks/data/useJoinEvent.ts new file mode 100644 index 0000000..ae273ac --- /dev/null +++ b/client/cms/src/hooks/data/useJoinEvent.ts @@ -0,0 +1,8 @@ +import { useMutation } from '@tanstack/react-query'; +import { postEventJoinMutation } from '@/client/@tanstack/react-query.gen'; + +export function useJoinEvent() { + return useMutation({ + ...postEventJoinMutation(), + }); +} diff --git a/client/cms/src/routes/_workbenchLayout/events.tsx b/client/cms/src/routes/_workbenchLayout/events.tsx index 22bd0b1..79e31d1 100644 --- a/client/cms/src/routes/_workbenchLayout/events.tsx +++ b/client/cms/src/routes/_workbenchLayout/events.tsx @@ -1,9 +1,14 @@ import { createFileRoute } from '@tanstack/react-router'; +import { EventGridContainer } from '@/components/events/event-grid.container'; export const Route = createFileRoute('/_workbenchLayout/events')({ component: RouteComponent, }); function RouteComponent() { - return
Hello "/_sidebarLayout/events"!
; + return ( +
+ +
+ ); } diff --git a/client/cms/src/stories/event-card.stories.ts b/client/cms/src/stories/event-card.stories.ts deleted file mode 100644 index 6a6017b..0000000 --- a/client/cms/src/stories/event-card.stories.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react-vite'; -import { EventCardView } from '@/components/workbenchCards/event-card.view'; - -const meta = { - title: 'Cards/EventCard', - component: EventCardView, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Primary: Story = { - args: { - 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: "2026-06-13T04:00:00.000Z", - endTime: "2026-06-14T04:00:00.000Z", - }, -}; diff --git a/client/cms/src/stories/events/event-card.stories.tsx b/client/cms/src/stories/events/event-card.stories.tsx new file mode 100644 index 0000000..9180224 --- /dev/null +++ b/client/cms/src/stories/events/event-card.stories.tsx @@ -0,0 +1,36 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { EventCardSkeleton } from '@/components/events/event-card.skeleton'; +import { EventCardView } from '@/components/events/event-card.view'; + +const meta = { + title: 'Events/EventCard', + component: EventCardView, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + 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'), + onJoinEvent: () => { }, + }, +}; + +export const Loading: Story = { + render: () => , + args: { + type: 'official', + coverImage: '', + eventName: '', + description: '', + startTime: new Date(0), + endTime: new Date(0), + onJoinEvent: () => { }, + }, +}; diff --git a/client/cms/src/stories/events/event-grid.stories.tsx b/client/cms/src/stories/events/event-grid.stories.tsx new file mode 100644 index 0000000..bb63feb --- /dev/null +++ b/client/cms/src/stories/events/event-grid.stories.tsx @@ -0,0 +1,61 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { EventGridSkeleton } from '@/components/events/event-grid.skeleton'; +import { EventGridView } from '@/components/events/event-grid.view'; + +const meta = { + title: 'Events/EventGrid', + component: EventGridView, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + events: [ + { + 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'), + onJoinEvent: () => { }, + }, + { + 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'), + onJoinEvent: () => { }, + }, + { + 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'), + onJoinEvent: () => { }, + }, + { + 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'), + onJoinEvent: () => { }, + }, + ], + }, +}; + +export const Skeleton: Story = { + render: () => , + args: { + events: [], + }, +}; diff --git a/client/cms/src/stories/sidebar.stories.tsx b/client/cms/src/stories/layout/sidebar.stories.tsx similarity index 93% rename from client/cms/src/stories/sidebar.stories.tsx rename to client/cms/src/stories/layout/sidebar.stories.tsx index 0cab568..ac2aeac 100644 --- a/client/cms/src/stories/sidebar.stories.tsx +++ b/client/cms/src/stories/layout/sidebar.stories.tsx @@ -4,10 +4,10 @@ import { NavUserSkeleton } from '@/components/sidebar/nav-user.skeletion'; import { NavUserView } from '@/components/sidebar/nav-user.view'; import { SidebarProvider } from '@/components/ui/sidebar'; import { navData } from '@/lib/navData'; -import { user } from './exampleUser'; +import { user } from '../exampleUser'; const meta = { - title: 'Navigation/Sidebar', + title: 'Layout/Sidebar', component: AppSidebar, decorators: [ Story => (