From d765d92df745a2ed815d5ebb7104b020eeedff38 Mon Sep 17 00:00:00 2001 From: Ardeman Date: Fri, 7 Mar 2025 09:04:11 +0800 Subject: [PATCH] feat: refactor API response schemas for improve consistency --- app/apis/admin/get-news.ts | 23 +++++++++-------------- app/apis/admin/get-staff.ts | 4 ++-- app/apis/common/get-categories.ts | 12 ++++++------ app/apis/common/get-subscriptions.ts | 4 ++-- app/apis/common/get-tags.ts | 10 +++++----- app/apis/news/get-user.ts | 6 +++--- app/apis/news/login-user.ts | 2 +- app/apis/news/register-user.ts | 8 +------- app/layouts/news/header-menu-mobile.tsx | 4 ++-- app/pages/dashboard-contents/index.tsx | 13 +++++++------ app/utils/render.tsx | 4 ++-- 11 files changed, 40 insertions(+), 50 deletions(-) diff --git a/app/apis/admin/get-news.ts b/app/apis/admin/get-news.ts index eecfd14..6426a0b 100644 --- a/app/apis/admin/get-news.ts +++ b/app/apis/admin/get-news.ts @@ -1,6 +1,7 @@ import { z } from 'zod' -import { categorySchema } from '~/apis/common/get-categories' +import { categoryResponseSchema } from '~/apis/common/get-categories' +import { tagResponseSchema } from '~/apis/common/get-tags' import { HttpServer, type THttpServer } from '~/libs/http-server' const authorSchema = z.object({ @@ -8,18 +9,12 @@ const authorSchema = z.object({ name: z.string(), profile_picture: z.string(), }) -const newsSchema = z.object({ +const newsResponseSchema = z.object({ id: z.string(), title: z.string(), content: z.string(), - categories: z.array(categorySchema), - tags: z.array( - z.object({ - id: z.string(), - name: z.string(), - code: z.string(), - }), - ), + categories: z.array(categoryResponseSchema), + tags: z.array(tagResponseSchema), is_premium: z.boolean(), slug: z.string(), featured_image: z.string(), @@ -29,16 +24,16 @@ const newsSchema = z.object({ updated_at: z.string(), author: authorSchema, }) -const dataSchema = z.object({ - data: z.array(newsSchema), +const dataResponseSchema = z.object({ + data: z.array(newsResponseSchema), }) -export type TNewsSchema = z.infer +export type TNewsResponse = z.infer export const getNews = async (parameters: THttpServer) => { try { const { data } = await HttpServer(parameters).get(`/api/news`) - return dataSchema.parse(data) + return dataResponseSchema.parse(data) } catch (error) { // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.reject(error) diff --git a/app/apis/admin/get-staff.ts b/app/apis/admin/get-staff.ts index fc414b7..90db341 100644 --- a/app/apis/admin/get-staff.ts +++ b/app/apis/admin/get-staff.ts @@ -2,7 +2,7 @@ import { z } from 'zod' import { HttpServer, type THttpServer } from '~/libs/http-server' -const staffSchema = z.object({ +const staffResponseSchema = z.object({ data: z.object({ id: z.string(), email: z.string(), @@ -14,7 +14,7 @@ const staffSchema = z.object({ export const getStaff = async (parameters: THttpServer) => { try { const { data } = await HttpServer(parameters).get(`/api/staff/profile`) - return staffSchema.parse(data) + return staffResponseSchema.parse(data) } catch (error) { // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.reject(error) diff --git a/app/apis/common/get-categories.ts b/app/apis/common/get-categories.ts index fd4cca1..c074cee 100644 --- a/app/apis/common/get-categories.ts +++ b/app/apis/common/get-categories.ts @@ -2,22 +2,22 @@ import { z } from 'zod' import { HttpServer, type THttpServer } from '~/libs/http-server' -export const categorySchema = z.object({ +export const categoryResponseSchema = z.object({ id: z.string(), name: z.string(), code: z.string(), }) -const categoriesSchema = z.object({ - data: z.array(categorySchema), +const categoriesResponseSchema = z.object({ + data: z.array(categoryResponseSchema), }) -export type TCategorySchema = z.infer -export type TCategoriesSchema = z.infer +export type TCategoryResponse = z.infer +export type TCategoriesResponse = z.infer export const getCategories = async (parameters?: THttpServer) => { try { const { data } = await HttpServer(parameters).get(`/api/category`) - return categoriesSchema.parse(data) + return categoriesResponseSchema.parse(data) } catch (error) { // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.reject(error) diff --git a/app/apis/common/get-subscriptions.ts b/app/apis/common/get-subscriptions.ts index 8e4824b..35caf74 100644 --- a/app/apis/common/get-subscriptions.ts +++ b/app/apis/common/get-subscriptions.ts @@ -2,7 +2,7 @@ import { z } from 'zod' import { HttpServer, type THttpServer } from '~/libs/http-server' -const subscriptionSchema = z.object({ +const subscriptionResponseSchema = z.object({ data: z.array( z.object({ id: z.string(), @@ -15,7 +15,7 @@ const subscriptionSchema = z.object({ export const getSubscriptions = async (parameters?: THttpServer) => { try { const { data } = await HttpServer(parameters).get(`/api/subscribe-plan`) - return subscriptionSchema.parse(data) + return subscriptionResponseSchema.parse(data) } catch (error) { // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.reject(error) diff --git a/app/apis/common/get-tags.ts b/app/apis/common/get-tags.ts index ea61719..75d6ea2 100644 --- a/app/apis/common/get-tags.ts +++ b/app/apis/common/get-tags.ts @@ -2,21 +2,21 @@ import { z } from 'zod' import { HttpServer, type THttpServer } from '~/libs/http-server' -const tagSchema = z.object({ +export const tagResponseSchema = z.object({ id: z.string(), code: z.string(), name: z.string(), }) -const tagsSchema = z.object({ - data: z.array(tagSchema), +const tagsResponseSchema = z.object({ + data: z.array(tagResponseSchema), }) -export type TTagSchema = z.infer +export type TTagResponse = z.infer export const getTags = async (parameters?: THttpServer) => { try { const { data } = await HttpServer(parameters).get(`/api/tag`) - return tagsSchema.parse(data) + return tagsResponseSchema.parse(data) } catch (error) { // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.reject(error) diff --git a/app/apis/news/get-user.ts b/app/apis/news/get-user.ts index 6e53448..f223388 100644 --- a/app/apis/news/get-user.ts +++ b/app/apis/news/get-user.ts @@ -2,7 +2,7 @@ import { z } from 'zod' import { HttpServer, type THttpServer } from '~/libs/http-server' -const userSchema = z.object({ +const userResponseSchema = z.object({ data: z.object({ id: z.string(), email: z.string(), @@ -23,12 +23,12 @@ const userSchema = z.object({ }), }) -export type TUser = z.infer +export type TUserResponse = z.infer export const getUser = async (parameters: THttpServer) => { try { const { data } = await HttpServer(parameters).get(`/api/user/profile`) - return userSchema.parse(data) + return userResponseSchema.parse(data) } catch (error) { // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.reject(error) diff --git a/app/apis/news/login-user.ts b/app/apis/news/login-user.ts index a25b0ff..d536481 100644 --- a/app/apis/news/login-user.ts +++ b/app/apis/news/login-user.ts @@ -3,7 +3,7 @@ import { z } from 'zod' import { type TLoginSchema } from '~/layouts/news/form-login' import { HttpServer } from '~/libs/http-server' -const loginResponseSchema = z.object({ +export const loginResponseSchema = z.object({ data: z.object({ token: z.string(), }), diff --git a/app/apis/news/register-user.ts b/app/apis/news/register-user.ts index fa2ed66..be65868 100644 --- a/app/apis/news/register-user.ts +++ b/app/apis/news/register-user.ts @@ -1,13 +1,7 @@ -import { z } from 'zod' - import type { TRegisterSchema } from '~/layouts/news/form-register' import { HttpServer } from '~/libs/http-server' -const loginResponseSchema = z.object({ - data: z.object({ - token: z.string(), - }), -}) +import { loginResponseSchema } from './login-user' export const userRegisterRequest = async (payload: TRegisterSchema) => { try { diff --git a/app/layouts/news/header-menu-mobile.tsx b/app/layouts/news/header-menu-mobile.tsx index faa2453..7d2ae38 100644 --- a/app/layouts/news/header-menu-mobile.tsx +++ b/app/layouts/news/header-menu-mobile.tsx @@ -1,7 +1,7 @@ import { useState } from 'react' import { Link, useFetcher, useRouteLoaderData } from 'react-router' -import type { TCategoriesSchema } from '~/apis/common/get-categories' +import type { TCategoriesResponse } from '~/apis/common/get-categories' import { CloseIcon } from '~/components/icons/close' import { MenuIcon } from '~/components/icons/menu' import { Button } from '~/components/ui/button' @@ -10,7 +10,7 @@ import { HeaderSearch } from '~/layouts/news/header-search' import type { loader } from '~/routes/_layout' type THeaderMenuMobile = { - menu?: TCategoriesSchema['data'] + menu?: TCategoriesResponse['data'] } export default function HeaderMenuMobile(properties: THeaderMenuMobile) { diff --git a/app/pages/dashboard-contents/index.tsx b/app/pages/dashboard-contents/index.tsx index 5434bc3..d01a442 100644 --- a/app/pages/dashboard-contents/index.tsx +++ b/app/pages/dashboard-contents/index.tsx @@ -2,9 +2,9 @@ import DT from 'datatables.net-dt' import DataTable from 'datatables.net-react' import { Link, useRouteLoaderData } from 'react-router' -import type { TNewsSchema } from '~/apis/admin/get-news' -import type { TCategorySchema } from '~/apis/common/get-categories' -import type { TTagSchema } from '~/apis/common/get-tags' +import type { TNewsResponse } from '~/apis/admin/get-news' +import type { TCategoryResponse } from '~/apis/common/get-categories' +import type { TTagResponse } from '~/apis/common/get-tags' import { Button } from '~/components/ui/button' import { UiTable } from '~/components/ui/table' import { TitleDashboard } from '~/components/ui/title-dashboard' @@ -55,14 +55,15 @@ export const ContentsPage = () => { ] const dataSlot = { 1: (value: string) => formatDate(value), - 2: (_value: unknown, _type: unknown, data: TNewsSchema) => ( + 2: (_value: unknown, _type: unknown, data: TNewsResponse) => (
{data.author.name}
ID: {data.id.slice(0, 8)}
), - 4: (value: TCategorySchema[]) => value.map((item) => item.name).join(', '), - 5: (value: TTagSchema[]) => value.map((item) => item.name).join(', '), + 4: (value: TCategoryResponse[]) => + value.map((item) => item.name).join(', '), + 5: (value: TTagResponse[]) => value.map((item) => item.name).join(', '), 6: (value: string) => value ? (
diff --git a/app/utils/render.tsx b/app/utils/render.tsx index 267b30b..8fb11f5 100644 --- a/app/utils/render.tsx +++ b/app/utils/render.tsx @@ -1,13 +1,13 @@ import type { MouseEventHandler } from 'react' import { Link } from 'react-router' -import type { TUser } from '~/apis/news/get-user' +import type { TUserResponse } from '~/apis/news/get-user' type TGetPremiumAttribute = { isPremium?: boolean slug: string onClick: MouseEventHandler - userData?: TUser['data'] + userData?: TUserResponse['data'] } export const getPremiumAttribute = (parameters: TGetPremiumAttribute) => {