diff --git a/app/apis/admin/update-profile.ts b/app/apis/admin/update-profile.ts new file mode 100644 index 0000000..e6723d9 --- /dev/null +++ b/app/apis/admin/update-profile.ts @@ -0,0 +1,28 @@ +import { z } from 'zod' + +import type { TProfileSchema } from '~/layouts/admin/dialog-profile' +import { HttpServer, type THttpServer } from '~/libs/http-server' + +const updateProfileResponseSchema = z.object({ + data: z.object({ + Message: z.string(), + }), +}) + +type TParameter = { + payload: TProfileSchema +} & THttpServer + +export const updateProfileRequest = async (parameters: TParameter) => { + const { payload, ...restParameters } = parameters + try { + const { data } = await HttpServer(restParameters).put( + '/api/staff/update', + payload, + ) + return updateProfileResponseSchema.parse(data) + } catch (error) { + // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject + return Promise.reject(error) + } +} diff --git a/app/layouts/admin/dialog-profile.tsx b/app/layouts/admin/dialog-profile.tsx index c712580..5cb9024 100644 --- a/app/layouts/admin/dialog-profile.tsx +++ b/app/layouts/admin/dialog-profile.tsx @@ -1,29 +1,47 @@ -import { Dialog, DialogBackdrop, DialogPanel } from '@headlessui/react' +import { + Dialog, + DialogBackdrop, + DialogPanel, + DialogTitle, +} from '@headlessui/react' import { zodResolver } from '@hookform/resolvers/zod' import { useEffect } from 'react' import toast from 'react-hot-toast' -import { useFetcher } from 'react-router' +import { useFetcher, useRouteLoaderData } from 'react-router' import { RemixFormProvider, useRemixForm } from 'remix-hook-form' import { z } from 'zod' +import { Button } from '~/components/ui/button' +import { Input } from '~/components/ui/input' +import { InputFile } from '~/components/ui/input-file' import { useAdminContext } from '~/contexts/admin' +import type { loader } from '~/routes/_admin.lg-admin' -const profileSchema = z.object({ +export const profileSchema = z.object({ name: z.string().min(1, 'Name is required'), - email: z.string().email('Invalid email address'), - profile_picture: z.string().optional(), + email: z.string().email('Email is invalid'), + profile_picture: z.string().url({ + message: 'URL must be valid', + }), }) -type TProfileSchema = z.infer +export type TProfileSchema = z.infer export const DialogProfile = () => { const { editProfile, setEditProfile } = useAdminContext() + const loaderData = useRouteLoaderData('routes/_admin.lg-admin') + const { staffData } = loaderData || {} const fetcher = useFetcher() const formMethods = useRemixForm({ mode: 'onSubmit', fetcher, resolver: zodResolver(profileSchema), + values: { + name: staffData?.name || '', + email: staffData?.email || '', + profile_picture: staffData?.profile_picture || '', + }, }) const { handleSubmit } = formMethods @@ -57,16 +75,49 @@ export const DialogProfile = () => {
+ + Update Profile + + > + + + + +
diff --git a/app/layouts/admin/dialog-upload.tsx b/app/layouts/admin/dialog-upload.tsx index 05deeee..674d572 100644 --- a/app/layouts/admin/dialog-upload.tsx +++ b/app/layouts/admin/dialog-upload.tsx @@ -99,7 +99,7 @@ export const DialogUpload = () => {
{ const { staffToken: accessToken } = await handleCookie(request) diff --git a/app/routes/actions.admin.advertisements.update.ts b/app/routes/actions.admin.advertisements.update.ts index 094a35c..3da4686 100644 --- a/app/routes/actions.admin.advertisements.update.ts +++ b/app/routes/actions.admin.advertisements.update.ts @@ -7,7 +7,7 @@ import { updateAdsRequest } from '~/apis/admin/update-ads' import { handleCookie } from '~/libs/cookies' import { adsSchema, type TAdsSchema } from '~/pages/form-advertisements' -import type { Route } from './+types/actions.admin.advertisements.create' +import type { Route } from './+types/actions.admin.advertisements.update' export const action = async ({ request }: Route.ActionArgs) => { const { staffToken: accessToken } = await handleCookie(request) diff --git a/app/routes/actions.admin.profile.ts b/app/routes/actions.admin.profile.ts new file mode 100644 index 0000000..9dd4a7a --- /dev/null +++ b/app/routes/actions.admin.profile.ts @@ -0,0 +1,67 @@ +import { zodResolver } from '@hookform/resolvers/zod' +import { data } from 'react-router' +import { getValidatedFormData } from 'remix-hook-form' +import { XiorError } from 'xior' + +import { updateProfileRequest } from '~/apis/admin/update-profile' +import { + profileSchema, + type TProfileSchema, +} from '~/layouts/admin/dialog-profile' +import { handleCookie } from '~/libs/cookies' + +import type { Route } from './+types/actions.admin.profile' + +export const action = async ({ request }: Route.ActionArgs) => { + const { staffToken: accessToken } = await handleCookie(request) + try { + const { + errors, + data: payload, + receivedValues: defaultValues, + } = await getValidatedFormData( + request, + zodResolver(profileSchema), + false, + ) + + if (errors) { + return data({ success: false, errors, defaultValues }, { status: 400 }) + } + + const { data: profileData } = await updateProfileRequest({ + accessToken, + payload, + }) + + return data( + { + success: true, + profileData, + }, + { + 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 }, + ) + } +} diff --git a/app/routes/actions.admin.subscribe-plan.delete.$id.ts b/app/routes/actions.admin.subscribe-plan.delete.$id.ts index 1728fb1..08008b9 100644 --- a/app/routes/actions.admin.subscribe-plan.delete.$id.ts +++ b/app/routes/actions.admin.subscribe-plan.delete.$id.ts @@ -4,7 +4,7 @@ import { XiorError } from 'xior' import { deleteSubscribePlanRequest } from '~/apis/admin/delete-subscribe-plan' import { handleCookie } from '~/libs/cookies' -import type { Route } from './+types/actions.admin.advertisements.create' +import type { Route } from './+types/actions.admin.subscribe-plan.delete.$id' export const action = async ({ request, params }: Route.ActionArgs) => { const { staffToken: accessToken } = await handleCookie(request) diff --git a/app/routes/actions.admin.tags.delete.$id.ts b/app/routes/actions.admin.tags.delete.$id.ts index e113cdc..0557ced 100644 --- a/app/routes/actions.admin.tags.delete.$id.ts +++ b/app/routes/actions.admin.tags.delete.$id.ts @@ -4,7 +4,7 @@ import { XiorError } from 'xior' import { deleteTagsRequest } from '~/apis/admin/delete-tags' import { handleCookie } from '~/libs/cookies' -import type { Route } from './+types/actions.admin.advertisements.create' +import type { Route } from './+types/actions.admin.tags.delete.$id' export const action = async ({ request, params }: Route.ActionArgs) => { const { staffToken: accessToken } = await handleCookie(request)