From 9745fff8532225d731f2cd7cd85d8230e1e0d247 Mon Sep 17 00:00:00 2001 From: "fredy.siswanto" Date: Wed, 19 Mar 2025 17:15:46 +0700 Subject: [PATCH] feat: add delete functionality for news articles with confirmation dialog --- app/apis/admin/delete-contents.ts | 28 ++++++++++ app/pages/dashboard-contents/index.tsx | 51 ++++++++++++++----- .../actions.admin.contents.delete.$id.ts | 48 +++++++++++++++++ 3 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 app/apis/admin/delete-contents.ts create mode 100644 app/routes/actions.admin.contents.delete.$id.ts diff --git a/app/apis/admin/delete-contents.ts b/app/apis/admin/delete-contents.ts new file mode 100644 index 0000000..e240ea6 --- /dev/null +++ b/app/apis/admin/delete-contents.ts @@ -0,0 +1,28 @@ +import { z } from 'zod' + +import { HttpServer, type THttpServer } from '~/libs/http-server' +import type { TContentSchema } from '~/pages/form-contents' + +const deleteContentsResponseSchema = z.object({ + data: z.object({ + Message: z.string(), + }), +}) + +type TParameters = { + id: TContentSchema['id'] +} & THttpServer + +export const deleteContentsRequest = async (parameters: TParameters) => { + const { id, ...restParameters } = parameters + try { + const { data } = await HttpServer(restParameters).delete( + `/api/news/${id}/delete`, + ) + + return deleteContentsResponseSchema.parse(data) + } catch (error) { + // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject + return Promise.reject(error) + } +} diff --git a/app/pages/dashboard-contents/index.tsx b/app/pages/dashboard-contents/index.tsx index 057c574..b5fd093 100644 --- a/app/pages/dashboard-contents/index.tsx +++ b/app/pages/dashboard-contents/index.tsx @@ -1,10 +1,17 @@ +import { + PencilSquareIcon, + PlusIcon, + TrashIcon, +} from '@heroicons/react/24/solid' import DT, { type Config, type ConfigColumns } from 'datatables.net-dt' import DataTable, { type DataTableSlots } from 'datatables.net-react' +import { useState } from 'react' import { Link, useRouteLoaderData } from 'react-router' import type { TCategoryResponse } from '~/apis/common/get-categories' -import type { TAuthorResponse } from '~/apis/common/get-news' +import type { TAuthorResponse, TNewsResponse } from '~/apis/common/get-news' import type { TTagResponse } from '~/apis/common/get-tags' +import { DialogDelete } from '~/components/dialog/delete' import { Button } from '~/components/ui/button' import { UiTable } from '~/components/ui/table' import { TitleDashboard } from '~/components/ui/title-dashboard' @@ -15,7 +22,7 @@ export const ContentsPage = () => { const loaderData = useRouteLoaderData( 'routes/_admin.lg-admin._dashboard.contents._index', ) - + const [selectedContent, setSelectedContent] = useState() DataTable.use(DT) const dataTable = loaderData?.newsData?.sort( @@ -81,15 +88,26 @@ export const ContentsPage = () => { Normal ), - 7: (value: string) => ( - + 7: (value: string, _type: unknown, data: TNewsResponse) => ( +
+ + +
), } const dataOptions: Config = { @@ -110,7 +128,7 @@ export const ContentsPage = () => { size="lg" className="text-md h-[42px] px-4" > - Buat Artikel + Buat Artikel @@ -121,6 +139,15 @@ export const ContentsPage = () => { options={dataOptions} title="Daftar Artikel" /> + + setSelectedContent(undefined)} + title="Artikel" + fetcherAction={`/actions/admin/contents/delete/${selectedContent?.id}`} + > +

{selectedContent?.title}

+
) } diff --git a/app/routes/actions.admin.contents.delete.$id.ts b/app/routes/actions.admin.contents.delete.$id.ts new file mode 100644 index 0000000..765a887 --- /dev/null +++ b/app/routes/actions.admin.contents.delete.$id.ts @@ -0,0 +1,48 @@ +import { data } from 'react-router' +import { XiorError } from 'xior' + +import { deleteContentsRequest } from '~/apis/admin/delete-contents' +import { handleCookie } from '~/libs/cookies' + +import type { Route } from './+types/actions.admin.contents.delete.$id' + +export const action = async ({ request, params }: Route.ActionArgs) => { + const { staffToken: accessToken } = await handleCookie(request) + const { id } = params + try { + const { data: newsData } = await deleteContentsRequest({ + accessToken, + id, + }) + + return data( + { + success: true, + newsData, + }, + { + status: 200, + statusText: 'OK', + }, + ) + } catch (error) { + if (error instanceof XiorError) { + return data( + { + success: false, + message: error?.response?.data?.error?.message || error.message, + }, + { + status: error?.response?.status || 500, + }, + ) + } + return data( + { + success: false, + message: 'Internal server error', + }, + { status: 500 }, + ) + } +}