From 414806734d6ea3844757c7ce0b967eca992aa2f6 Mon Sep 17 00:00:00 2001 From: Ardeman Date: Thu, 6 Mar 2025 05:46:25 +0800 Subject: [PATCH] feat: implement createNews API and integrate with content creation flow --- app/apis/admin/create-news.ts | 39 +++++++++++++++++++++ app/components/text-editor/index.tsx | 1 + app/pages/contents-create/index.tsx | 26 ++++++++------ app/routes/actions.admin.contents.create.ts | 13 ++++--- 4 files changed, 61 insertions(+), 18 deletions(-) create mode 100644 app/apis/admin/create-news.ts diff --git a/app/apis/admin/create-news.ts b/app/apis/admin/create-news.ts new file mode 100644 index 0000000..b10c73d --- /dev/null +++ b/app/apis/admin/create-news.ts @@ -0,0 +1,39 @@ +import { z } from 'zod' + +import { HttpServer } from '~/libs/http-server' +import type { TContentSchema } from '~/pages/contents-create' + +const newsResponseSchema = z.object({ + data: z.object({ + Message: z.string(), + }), +}) + +type TParameter = { + accessToken: string + payload: TContentSchema +} + +export const createNewsRequest = async (parameters: TParameter) => { + const { accessToken, payload } = parameters + try { + const { categories, tags, ...restPayload } = payload + const transformedPayload = { + ...restPayload, + categories: categories.map((category) => category?.code), + tags: tags?.map((tag) => tag?.code), + live_at: new Date(payload?.live_at).toISOString(), + } + if (transformedPayload.tags?.length === 0) { + delete transformedPayload.tags + } + const { data } = await HttpServer({ accessToken }).post( + '/api/news/create', + transformedPayload, + ) + return newsResponseSchema.parse(data) + } catch (error) { + // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject + return Promise.reject(error) + } +} diff --git a/app/components/text-editor/index.tsx b/app/components/text-editor/index.tsx index f6d883c..22d8cd0 100644 --- a/app/components/text-editor/index.tsx +++ b/app/components/text-editor/index.tsx @@ -84,6 +84,7 @@ export const TextEditor = >( types: ['heading', 'paragraph'], }), ], + immediatelyRender: false, content: watchContent, onUpdate: ({ editor }) => { setValue(name, editor.getHTML() as any) // eslint-disable-line @typescript-eslint/no-explicit-any diff --git a/app/pages/contents-create/index.tsx b/app/pages/contents-create/index.tsx index 5780c87..a525216 100644 --- a/app/pages/contents-create/index.tsx +++ b/app/pages/contents-create/index.tsx @@ -1,7 +1,7 @@ import { DevTool } from '@hookform/devtools' import { zodResolver } from '@hookform/resolvers/zod' import { useEffect, useState } from 'react' -import { useFetcher, useRouteLoaderData } from 'react-router' +import { useFetcher, useNavigate, useRouteLoaderData } from 'react-router' import { RemixFormProvider, useRemixForm } from 'remix-hook-form' import { z } from 'zod' @@ -27,16 +27,18 @@ export const contentSchema = z.object({ .refine((data) => !!data, { message: 'Please select a category', }), - tags: z.array( - z - .object({ - id: z.string(), - code: z.string(), - name: z.string(), - }) - .optional() - .nullable(), - ), + tags: z + .array( + z + .object({ + id: z.string(), + code: z.string(), + name: z.string(), + }) + .optional() + .nullable(), + ) + .optional(), title: z.string().min(1, { message: 'Judul is required', }), @@ -54,6 +56,7 @@ export type TContentSchema = z.infer export const CreateContentsPage = () => { const fetcher = useFetcher() + const navigate = useNavigate() const loaderData = useRouteLoaderData('routes/_admin.lg-admin') const categories = loaderData?.categoriesData const tags = loaderData?.tagsData @@ -77,6 +80,7 @@ export const CreateContentsPage = () => { return } + navigate('/lg-admin/contents') setDisabled(true) setError(undefined) // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/app/routes/actions.admin.contents.create.ts b/app/routes/actions.admin.contents.create.ts index ea7cfa7..4ecea2c 100644 --- a/app/routes/actions.admin.contents.create.ts +++ b/app/routes/actions.admin.contents.create.ts @@ -3,6 +3,7 @@ import { data } from 'react-router' import { getValidatedFormData } from 'remix-hook-form' import { XiorError } from 'xior' +import { createNewsRequest } from '~/apis/admin/create-news' import { handleCookie } from '~/libs/cookies' import { contentSchema, type TContentSchema } from '~/pages/contents-create' @@ -25,17 +26,15 @@ export const action = async ({ request }: Route.ActionArgs) => { return data({ success: false, errors, defaultValues }, { status: 400 }) } - // TODO: implement subscribe - console.log('payload', payload) // eslint-disable-line no-console - console.log('staffToken', staffToken) // eslint-disable-line no-console - - // const { data: userData } = await getUser({ - // accessToken: userToken, - // }) + const { data: newsData } = await createNewsRequest({ + accessToken: staffToken, + payload, + }) return data( { success: true, + newsData, }, { status: 200,