diff --git a/app/apis/news/register-user.ts b/app/apis/news/register-user.ts index 7c6ab16..fa2ed66 100644 --- a/app/apis/news/register-user.ts +++ b/app/apis/news/register-user.ts @@ -14,7 +14,7 @@ export const userRegisterRequest = async (payload: TRegisterSchema) => { const { subscribe_plan, ...restPayload } = payload const transformedPayload = { ...restPayload, - subscribe_plan_id: subscribe_plan, + subscribe_plan_id: subscribe_plan.id, } const { data } = await HttpServer().post( '/api/user/register', diff --git a/app/components/ui/combobox.tsx b/app/components/ui/combobox.tsx new file mode 100644 index 0000000..402f125 --- /dev/null +++ b/app/components/ui/combobox.tsx @@ -0,0 +1,115 @@ +import { + Field, + Label, + Combobox as HeadlessCombobox, + ComboboxInput, + ComboboxButton, + ComboboxOptions, + ComboboxOption, +} from '@headlessui/react' +import { CheckIcon, ChevronDownIcon } from '@heroicons/react/20/solid' +import { useState, type ComponentProps, type ReactNode } from 'react' +import { + get, + type FieldError, + type FieldValues, + type Path, + type RegisterOptions, + Controller, +} from 'react-hook-form' +import { useRemixFormContext } from 'remix-hook-form' +import { twMerge } from 'tailwind-merge' + +type TComboboxOption = { + code: string + name: string + id: string +} + +type TInputProperties = ComponentProps< + typeof HeadlessCombobox +> & { + id: string + label?: ReactNode + name: Path + rules?: RegisterOptions + placeholder?: string + options?: TComboboxOption[] +} + +export const Combobox = >( + properties: TInputProperties, +) => { + const { id, label, name, rules, disabled, placeholder, options, ...rest } = + properties + const { + control, + formState: { errors }, + } = useRemixFormContext() + const [query, setQuery] = useState('') + const filteredOptions = + query === '' + ? options + : options?.filter((option) => + option.name.toLowerCase().includes(query.toLowerCase()), + ) + + const error: FieldError = get(errors, name) + + return ( + + + ( + +
+ option?.name} + onChange={(event) => setQuery(event.target.value)} + className="focus:inheriten h-[42px] w-full rounded-md border border-[#DFDFDF] p-2" + /> + + + +
+ + {filteredOptions?.map((person) => ( + + +
{person.name}
+
+ ))} +
+
+ )} + /> +
+ ) +} diff --git a/app/layouts/news/form-register.tsx b/app/layouts/news/form-register.tsx index 1cb8e86..7b639fc 100644 --- a/app/layouts/news/form-register.tsx +++ b/app/layouts/news/form-register.tsx @@ -1,3 +1,4 @@ +import { DevTool } from '@hookform/devtools' import { zodResolver } from '@hookform/resolvers/zod' import { useEffect, useState } from 'react' import { useFetcher, useRouteLoaderData } from 'react-router' @@ -5,8 +6,8 @@ import { RemixFormProvider, useRemixForm } from 'remix-hook-form' import { z } from 'zod' import { Button } from '~/components/ui/button' +import { Combobox } from '~/components/ui/combobox' import { Input } from '~/components/ui/input' -import { Select } from '~/components/ui/select' import { useNewsContext } from '~/contexts/news' import type { loader } from '~/routes/_layout' @@ -16,7 +17,17 @@ 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'), - subscribe_plan: z.string().min(1, 'Pilih salah satu subscription'), + subscribe_plan: z + .object({ + id: z.string(), + code: z.string(), + name: z.string(), + }) + .optional() + .nullable() + .refine((data) => !!data, { + message: 'Please select a subscription', + }), }) .refine((field) => field.password === field.rePassword, { message: 'Kata sandi tidak sama', @@ -40,7 +51,7 @@ export const FormRegister = () => { resolver: zodResolver(registerSchema), }) - const { handleSubmit } = formMethods + const { handleSubmit, control } = formMethods useEffect(() => { if (!fetcher.data?.success) { @@ -96,7 +107,7 @@ export const FormRegister = () => { name="phone" /> -