refactor(forms): Enhance MultiSelect with controlled state and styling
This commit overhauls the `MultiSelect` component to improve its functionality, flexibility, and integration with form libraries. The component is now a controlled component, accepting a `value` prop and using the `onChange` handler to propagate updates. This allows for seamless integration with libraries like React Hook Form. Key changes include: - Added `value`, `disabled`, `active`, and `height` props for more granular control over the component's state and appearance. - Refactored styling logic to use the `cn` utility for cleaner conditional class management. - Simplified the internal JSX structure and SVGs for better readability and maintenance. - Updated the component's state management to correctly reflect the incoming `value` prop.
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
import { GlobeIcon, MoneyIcon } from "@/assets/icons";
|
||||
import InputGroup from "@/components/FormElements/InputGroup";
|
||||
import TagInput from "@/components/FormElements/InputGroup/tag-input";
|
||||
import { TextAreaGroup } from "@/components/FormElements/InputGroup/text-area";
|
||||
import MultiSelect from "@/components/FormElements/MultiSelect";
|
||||
import { Select } from "@/components/FormElements/select";
|
||||
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
|
||||
import FormFooter from "@/components/ui/FormFooter";
|
||||
@@ -17,12 +19,19 @@ interface IProps {
|
||||
}
|
||||
|
||||
const CreateCompany = ({ defaultValues, editMode, id }: IProps) => {
|
||||
const { errors, handleSubmit, onSubmit, register } =
|
||||
useCreateCompanyPresenter({
|
||||
editMode,
|
||||
defaultValues,
|
||||
id,
|
||||
});
|
||||
const {
|
||||
errors,
|
||||
handleSubmit,
|
||||
onSubmit,
|
||||
register,
|
||||
watch,
|
||||
setValue,
|
||||
companyCategories,
|
||||
} = useCreateCompanyPresenter({
|
||||
editMode,
|
||||
defaultValues,
|
||||
id,
|
||||
});
|
||||
return (
|
||||
<form
|
||||
className="grid grid-cols-1 items-start gap-9 rounded-xl bg-gray-1 p-10 dark:bg-gray-7 sm:grid-cols-2"
|
||||
@@ -458,35 +467,56 @@ const CreateCompany = ({ defaultValues, editMode, id }: IProps) => {
|
||||
)}
|
||||
</ShowcaseSection>
|
||||
<ShowcaseSection title="Tags" className="grid grid-cols-1 gap-5">
|
||||
<InputGroup
|
||||
<TagInput
|
||||
{...register("tags.keywords")}
|
||||
label="Keywords"
|
||||
name="tags.keywords"
|
||||
type="text"
|
||||
label="Keywords"
|
||||
placeholder="Enter Tag Keywords"
|
||||
register={register}
|
||||
setValue={setValue}
|
||||
watch={watch}
|
||||
/>
|
||||
{errors.tags?.keywords && (
|
||||
<p className="mt-1 text-sm text-red-500">
|
||||
{errors.tags.keywords.message}
|
||||
</p>
|
||||
)}
|
||||
<InputGroup
|
||||
<MultiSelect
|
||||
{...register("tags.categories")}
|
||||
label="Categories"
|
||||
value={watch("tags.categories")}
|
||||
name="tags.categories"
|
||||
type="text"
|
||||
placeholder="Enter Tag Categories"
|
||||
label="Categories"
|
||||
items={
|
||||
companyCategories
|
||||
? companyCategories?.data?.categories?.map((c) => {
|
||||
return {
|
||||
text: c.name,
|
||||
value: c.id,
|
||||
};
|
||||
})
|
||||
: []
|
||||
}
|
||||
placeholder="Please select categories"
|
||||
/>
|
||||
{errors.tags?.categories && (
|
||||
<p className="mt-1 text-sm text-red-500">
|
||||
{errors.tags.categories.message}
|
||||
</p>
|
||||
)}
|
||||
<InputGroup
|
||||
<TagInput
|
||||
{...register("tags.cpv_codes")}
|
||||
label="CPV codes"
|
||||
name="tags.cpv_codes"
|
||||
watch={watch}
|
||||
setValue={setValue}
|
||||
placeholder="Enter Tag CPV codes"
|
||||
/>
|
||||
|
||||
<TagInput
|
||||
{...register("tags.certifications")}
|
||||
label="Certifications"
|
||||
name="tags.certifications"
|
||||
watch={watch}
|
||||
setValue={setValue}
|
||||
placeholder="Enter Tag Certifications"
|
||||
/>
|
||||
|
||||
<TagInput
|
||||
{...register("tags.specializations")}
|
||||
label="Specializations"
|
||||
name="tags.specializations"
|
||||
type="text"
|
||||
watch={watch}
|
||||
setValue={setValue}
|
||||
placeholder="Enter Tag Specializations"
|
||||
/>
|
||||
{errors.tags?.specializations && (
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
"use client";
|
||||
import { useCreateCompany, useUpdateCompany } from "@/hooks/queries";
|
||||
import {
|
||||
useCompanyCategoriesQuery,
|
||||
useCreateCompany,
|
||||
useUpdateCompany,
|
||||
} from "@/hooks/queries";
|
||||
import { ICreateCompanyCredentials } from "@/lib/api";
|
||||
import { useIsMutating } from "@tanstack/react-query";
|
||||
import { useRouter } from "next/navigation";
|
||||
@@ -17,9 +21,24 @@ const useCreateCompanyPresenter = ({ defaultValues, editMode, id }: IProps) => {
|
||||
register,
|
||||
formState: { errors },
|
||||
handleSubmit,
|
||||
watch,
|
||||
setValue,
|
||||
reset,
|
||||
} = useForm<ICreateCompanyCredentials>({ mode: "onChange", defaultValues });
|
||||
} = useForm<ICreateCompanyCredentials>({
|
||||
mode: "onChange",
|
||||
defaultValues: {
|
||||
...defaultValues,
|
||||
tags: {
|
||||
...defaultValues?.tags,
|
||||
categories: defaultValues?.tags.categories.map((item) => ({
|
||||
value: item.id,
|
||||
text: item.name,
|
||||
})),
|
||||
},
|
||||
},
|
||||
});
|
||||
const router = useRouter();
|
||||
const { data: companyCategories } = useCompanyCategoriesQuery();
|
||||
const { mutate: createCompany, isPending: isCreating } = useCreateCompany();
|
||||
const { mutate: updateCompany, isPending: isUpdating } = useUpdateCompany(
|
||||
id as string,
|
||||
@@ -30,33 +49,6 @@ const useCreateCompanyPresenter = ({ defaultValues, editMode, id }: IProps) => {
|
||||
founded_year: data.founded_year ? +data.founded_year : 0,
|
||||
employee_count: data.employee_count ? +data.employee_count : 0,
|
||||
annual_revenue: data.annual_revenue ? +data.annual_revenue : 0,
|
||||
tags: {
|
||||
keywords: data.tags?.keywords
|
||||
? (data.tags.keywords as unknown as string)
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
: [],
|
||||
categories: data.tags?.categories
|
||||
? (data.tags.categories as unknown as string)
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
: [],
|
||||
specializations: data.tags?.specializations
|
||||
? (data.tags.specializations as unknown as string)
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
: [],
|
||||
certifications: data.tags?.certifications
|
||||
? (data.tags.certifications as unknown as string)
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
: [],
|
||||
cpv_codes: data.tags?.cpv_codes
|
||||
? (data.tags.cpv_codes as unknown as string)
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
: [],
|
||||
},
|
||||
};
|
||||
if (editMode) {
|
||||
updateCompany({
|
||||
@@ -80,7 +72,10 @@ const useCreateCompanyPresenter = ({ defaultValues, editMode, id }: IProps) => {
|
||||
isMutating,
|
||||
isCreating,
|
||||
isUpdating,
|
||||
router
|
||||
router,
|
||||
watch,
|
||||
setValue,
|
||||
companyCategories,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { GlobeIcon } from "@/assets/icons";
|
||||
import InputGroup from "@/components/FormElements/InputGroup";
|
||||
import MultiSelect from "@/components/FormElements/MultiSelect";
|
||||
import { Select } from "@/components/FormElements/select";
|
||||
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
|
||||
import { FormErrorMessages } from "@/constants/Texts";
|
||||
import { CreateCustomerCredentials } from "@/lib/api";
|
||||
import useCreateCustomerPresenter from "./useCreateCustomerPresenter";
|
||||
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
|
||||
import InputGroup from "@/components/FormElements/InputGroup";
|
||||
import { FormErrorMessages } from "@/constants/Texts";
|
||||
import { Select } from "@/components/FormElements/select";
|
||||
import MultiSelect from "@/components/FormElements/MultiSelect";
|
||||
import { GlobeIcon, UserIcon } from "@/assets/icons";
|
||||
|
||||
interface IProps {
|
||||
editMode?: boolean;
|
||||
|
||||
Reference in New Issue
Block a user