From b286d0a8c29fad18d3072aa018f5d127c4453b9d Mon Sep 17 00:00:00 2001 From: yuwol Date: Fri, 17 May 2024 15:47:22 +0900 Subject: [PATCH] :sparkles: Add notification types and fetchers --- src/lib/api/notification.ts | 23 +++++++++++++++++++ src/lib/queries/notification.ts | 25 +++++++++++++++++++++ src/types/index.ts | 2 ++ src/types/notification.ts | 40 +++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 src/lib/api/notification.ts create mode 100644 src/lib/queries/notification.ts create mode 100644 src/types/notification.ts diff --git a/src/lib/api/notification.ts b/src/lib/api/notification.ts new file mode 100644 index 0000000..9aaef21 --- /dev/null +++ b/src/lib/api/notification.ts @@ -0,0 +1,23 @@ +import { client } from "@/lib/axios"; +import { notificationSchema, paginationSchema } from "@/types"; + +export type GetNotificationsOptions = { + page?: number; + unread?: boolean; +}; + +export const getNotifications = async (options?: GetNotificationsOptions) => { + const notifications = ( + await client.get("notifications/", { + params: { + page: options?.page, + is_read: options?.unread === undefined ? undefined : !options.unread, + }, + }) + ).data; + return paginationSchema(notificationSchema).parse(notifications); +}; + +export const readNotification = async (id: number) => { + await client.post(`notifications/${id}/read/`); +}; diff --git a/src/lib/queries/notification.ts b/src/lib/queries/notification.ts new file mode 100644 index 0000000..bcdb7e0 --- /dev/null +++ b/src/lib/queries/notification.ts @@ -0,0 +1,25 @@ +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; + +import { + type GetNotificationsOptions, + getNotifications, + readNotification, +} from "@/lib/api/notification"; + +const NOTIFICATION_QUERY_KEY = "notifications"; + +export const useNotifications = (options?: GetNotificationsOptions) => + useQuery({ + queryKey: [NOTIFICATION_QUERY_KEY, options], + queryFn: () => getNotifications(options), + }); + +export const useReadNotification = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: readNotification, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: [NOTIFICATION_QUERY_KEY] }); + }, + }); +}; diff --git a/src/types/index.ts b/src/types/index.ts index 36fb992..c02d0a5 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1 +1,3 @@ export * from "./board"; +export * from "./notification"; +export * from "./pagination"; diff --git a/src/types/notification.ts b/src/types/notification.ts new file mode 100644 index 0000000..4751101 --- /dev/null +++ b/src/types/notification.ts @@ -0,0 +1,40 @@ +import { z } from "zod"; + +import { NameType } from "@/constants/enum"; + +const baseSchema = z.object({ + id: z.number(), + createdAt: z.coerce.date(), + title: z.string(), + content: z.string(), + isRead: z.boolean(), + relatedArticle: z.object({ + id: z.number(), + createdAt: z.coerce.date(), + createdBy: z.number(), + title: z.string(), + nameType: z.nativeEnum(NameType), + parentBoard: z.number(), + parentTopic: z.number().nullable(), + }), +}); +const commentNotificationSchema = baseSchema + .extend({ + type: z.literal("article_commented"), + relatedComment: z.null(), + }) + .transform(({ type, ...data }) => ({ type: "comment" as const, ...data })); +const replyNotificationSchema = baseSchema + .extend({ + type: z.literal("comment_commented"), + relatedComment: z.object({ + id: z.number(), + createdAt: z.coerce.date(), + createdBy: z.number(), + content: z.string(), + nameType: z.nativeEnum(NameType), + }), + }) + .transform(({ type, ...data }) => ({ type: "reply" as const, ...data })); +export const notificationSchema = z.union([commentNotificationSchema, replyNotificationSchema]); +export type Notification = z.infer;