From adba58780a8b775e213aea6ecda8f75a09fa0164 Mon Sep 17 00:00:00 2001 From: Ardeman Date: Sun, 2 Mar 2025 01:20:18 +0800 Subject: [PATCH] feat: add subscription selection to registration form and implement API for fetching subscriptions --- app/apis/common/get-subscriptions.ts | 23 ++++++++++ app/components/ui/select.tsx | 67 ++++++++++++++++++++++++++++ app/layouts/news/form-register.tsx | 25 +++++------ app/routes/_layout.tsx | 3 ++ 4 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 app/apis/common/get-subscriptions.ts create mode 100644 app/components/ui/select.tsx diff --git a/app/apis/common/get-subscriptions.ts b/app/apis/common/get-subscriptions.ts new file mode 100644 index 0000000..8e4824b --- /dev/null +++ b/app/apis/common/get-subscriptions.ts @@ -0,0 +1,23 @@ +import { z } from 'zod' + +import { HttpServer, type THttpServer } from '~/libs/http-server' + +const subscriptionSchema = z.object({ + data: z.array( + z.object({ + id: z.string(), + code: z.string(), + name: z.string(), + }), + ), +}) + +export const getSubscriptions = async (parameters?: THttpServer) => { + try { + const { data } = await HttpServer(parameters).get(`/api/subscribe-plan`) + return subscriptionSchema.parse(data) + } catch (error) { + // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject + return Promise.reject(error) + } +} diff --git a/app/components/ui/select.tsx b/app/components/ui/select.tsx new file mode 100644 index 0000000..d725faa --- /dev/null +++ b/app/components/ui/select.tsx @@ -0,0 +1,67 @@ +import { Field, Label, Select as HeadlessSelect } from '@headlessui/react' +import { type ComponentProps, type ReactNode } from 'react' +import { + get, + type FieldError, + type FieldValues, + type Path, + type RegisterOptions, +} from 'react-hook-form' +import { useRemixFormContext } from 'remix-hook-form' + +type TInputProperties = Omit< + ComponentProps<'select'>, + 'size' +> & { + id: string + label?: ReactNode + name: Path + rules?: RegisterOptions + placeholder?: string + options?: { + code: string + name: string + id: string + }[] +} + +export const Select = >( + properties: TInputProperties, +) => { + const { id, label, name, rules, disabled, placeholder, options, ...rest } = + properties + + const { + register, + formState: { errors }, + } = useRemixFormContext() + + const error: FieldError = get(errors, name) + + return ( + + + + + {options?.map((option) => ( + + ))} + + + ) +} diff --git a/app/layouts/news/form-register.tsx b/app/layouts/news/form-register.tsx index a2a9b48..f833e7c 100644 --- a/app/layouts/news/form-register.tsx +++ b/app/layouts/news/form-register.tsx @@ -1,12 +1,14 @@ import { zodResolver } from '@hookform/resolvers/zod' import { useEffect, useState } from 'react' -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 { Select } from '~/components/ui/select' import { useNewsContext } from '~/contexts/news' +import type { loader } from '~/routes/_layout' export const registerSchema = z .object({ @@ -14,6 +16,7 @@ export const registerSchema = z password: z.string().min(6, 'Kata sandi minimal 6 karakter'), rePassword: z.string().min(6, 'Kata sandi minimal 6 karakter'), phone: z.string().min(10, 'No telepon tidak valid'), + subscription: z.string().min(1, 'Pilih salah satu subscription'), }) .refine((field) => field.password === field.rePassword, { message: 'Kata sandi tidak sama', @@ -27,6 +30,7 @@ export const FormRegister = () => { const [error, setError] = useState() const [disabled, setDisabled] = useState(false) const fetcher = useFetcher() + const loaderData = useRouteLoaderData('routes/_layout') const formMethods = useRemixForm({ mode: 'onSubmit', @@ -89,18 +93,13 @@ export const FormRegister = () => { name="phone" /> - {/* Subscribe*/} - {/*
- - -
*/} +