3801073fd7
This commit introduces several enhancements to form components and user experience across the application. - **Sign-in Form:** - Implemented a loading state using `useIsMutating` from TanStack Query. - The username and password fields are now disabled during the login process to prevent concurrent submissions. - The "Sign in" button displays a spinner while the mutation is pending, providing clear visual feedback. - **Assign to Company Modal:** - Refactored the modal to use `react-hook-form` for more robust state management and validation. - The form submission button is now disabled while the assignment request is in progress. - **Tag Input Component:** - Added a new `shouldAddWithSpace` prop to allow creating tags by pressing the space bar, increasing the component's flexibility. - **Header:** - Corrected the image path for the mobile header logo to display the correct icon.
537 lines
17 KiB
TypeScript
537 lines
17 KiB
TypeScript
"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";
|
|
import { PHONE_REGEX } from "@/constants/regex";
|
|
import { FormErrorMessages } from "@/constants/Texts";
|
|
import { ICreateCompanyCredentials } from "@/lib/api/types/Company";
|
|
import useCreateCompanyPresenter from "./useCreateCompanyPresenter";
|
|
|
|
interface IProps {
|
|
editMode?: boolean;
|
|
defaultValues?: ICreateCompanyCredentials;
|
|
id?: string;
|
|
}
|
|
|
|
const CreateCompany = ({ defaultValues, editMode, id }: IProps) => {
|
|
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"
|
|
onSubmit={handleSubmit(onSubmit)}
|
|
>
|
|
<div className="flex flex-col gap-9">
|
|
<ShowcaseSection
|
|
title="Company Information"
|
|
className="flex flex-col gap-5"
|
|
>
|
|
<InputGroup
|
|
{...register("name", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: {
|
|
value: 2,
|
|
message: FormErrorMessages.minLength(2),
|
|
},
|
|
maxLength: {
|
|
value: 200,
|
|
message: FormErrorMessages.maxLength(200),
|
|
},
|
|
})}
|
|
label="Name"
|
|
name="name"
|
|
required
|
|
type="text"
|
|
placeholder="Enter Company Name"
|
|
/>
|
|
{errors.name && (
|
|
<p className="mt-1 text-sm text-red-500">{errors.name.message}</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("email", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
pattern: {
|
|
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
message: FormErrorMessages.invalidEmail,
|
|
},
|
|
})}
|
|
label="Email"
|
|
name="email"
|
|
required
|
|
type="email"
|
|
placeholder="Enter Company Email"
|
|
/>
|
|
{errors.email && (
|
|
<p className="mt-1 text-sm text-red-500">{errors.email.message}</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("phone", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: {
|
|
value: 10,
|
|
message: FormErrorMessages.minLength(10),
|
|
},
|
|
maxLength: {
|
|
value: 20,
|
|
message: FormErrorMessages.maxLength(20),
|
|
},
|
|
pattern: {
|
|
value: PHONE_REGEX,
|
|
message: FormErrorMessages.invalidPattern,
|
|
},
|
|
})}
|
|
label="Phone"
|
|
name="phone"
|
|
required
|
|
type="tel"
|
|
placeholder="Enter Company Phone"
|
|
/>
|
|
{errors.phone && (
|
|
<p className="mt-1 text-sm text-red-500">{errors.phone.message}</p>
|
|
)}
|
|
<Select
|
|
{...register("type", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
})}
|
|
name="type"
|
|
label="Company type"
|
|
required
|
|
items={[
|
|
{ value: "private", label: "Private" },
|
|
{ value: "public", label: "Public" },
|
|
{ value: "government", label: "Government" },
|
|
{ value: "ngo", label: "NGO" },
|
|
{ value: "startup", label: "Startup" },
|
|
]}
|
|
defaultValue="Private"
|
|
prefixIcon={<GlobeIcon />}
|
|
/>
|
|
{errors.type && (
|
|
<p className="mt-1 text-sm text-red-500">{errors.type.message}</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("registration_number", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: { value: 5, message: FormErrorMessages.minLength(5) },
|
|
maxLength: {
|
|
value: 50,
|
|
message: FormErrorMessages.maxLength(50),
|
|
},
|
|
})}
|
|
label="Registration Number"
|
|
name="registration_number"
|
|
type="text"
|
|
required
|
|
placeholder="Enter Registration Number"
|
|
/>
|
|
{errors.registration_number && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.registration_number.message}
|
|
</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("tax_id", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: { value: 5, message: FormErrorMessages.minLength(5) },
|
|
maxLength: {
|
|
value: 50,
|
|
message: FormErrorMessages.maxLength(50),
|
|
},
|
|
})}
|
|
label="Tax id"
|
|
name="tax_id"
|
|
type="text"
|
|
required
|
|
placeholder="Enter Tax id"
|
|
/>
|
|
{errors.tax_id && (
|
|
<p className="mt-1 text-sm text-red-500">{errors.tax_id.message}</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("industry", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: { value: 2, message: FormErrorMessages.minLength(2) },
|
|
maxLength: {
|
|
value: 100,
|
|
message: FormErrorMessages.maxLength(100),
|
|
},
|
|
})}
|
|
label="Industry"
|
|
name="industry"
|
|
type="text"
|
|
required
|
|
placeholder="Enter Industry"
|
|
/>
|
|
{errors.industry && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.industry.message}
|
|
</p>
|
|
)}
|
|
<TextAreaGroup
|
|
label="Description"
|
|
{...register("description", {
|
|
minLength: {
|
|
value: 10,
|
|
message: FormErrorMessages.minLength(10),
|
|
},
|
|
maxLength: {
|
|
value: 1000,
|
|
message: FormErrorMessages.maxLength(1000),
|
|
},
|
|
})}
|
|
name="description"
|
|
placeholder="Enter Description"
|
|
/>
|
|
{errors.description && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.description.message}
|
|
</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("website", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: { value: 2, message: FormErrorMessages.minLength(2) },
|
|
maxLength: {
|
|
value: 100,
|
|
message: FormErrorMessages.maxLength(100),
|
|
},
|
|
})}
|
|
label="Website"
|
|
required
|
|
name="website"
|
|
type="url"
|
|
placeholder="Enter Company Website"
|
|
/>
|
|
{errors.website && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.website.message}
|
|
</p>
|
|
)}
|
|
</ShowcaseSection>
|
|
|
|
<ShowcaseSection title="Settings" className="grid grid-cols-1 gap-5">
|
|
<Select
|
|
{...register("language")}
|
|
name="language"
|
|
label="Language"
|
|
items={[
|
|
{ value: "en", label: "EN" },
|
|
{ value: "ar", label: "AR" },
|
|
{ value: "fr", label: "FR" },
|
|
{ value: "es", label: "ES" },
|
|
{ value: "de", label: "DE" },
|
|
{ value: "zh", label: "ZH" },
|
|
{ value: "jEna", label: "jEna" },
|
|
{ value: "ko", label: "KO" },
|
|
]}
|
|
defaultValue="en"
|
|
prefixIcon={<GlobeIcon />}
|
|
/>
|
|
{errors.language && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.language.message}
|
|
</p>
|
|
)}
|
|
<Select
|
|
{...register("currency")}
|
|
name="currency"
|
|
label="Currency"
|
|
items={[
|
|
{ label: "USD", value: "USD" },
|
|
{ label: "EUR", value: "EUR" },
|
|
{ label: "GBP", value: "GBP" },
|
|
{ label: "JPY", value: "JPY" },
|
|
{ label: "CAD", value: "CAD" },
|
|
{ label: "AUD", value: "AUD" },
|
|
{ label: "CHF", value: "CHF" },
|
|
{ label: "CNY", value: "CNY" },
|
|
{ label: "INR", value: "INR" },
|
|
{ label: "BRL", value: "BRL" },
|
|
]}
|
|
defaultValue="en"
|
|
prefixIcon={<MoneyIcon />}
|
|
/>
|
|
{errors.currency && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.currency.message}
|
|
</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("timezone", {
|
|
minLength: { value: 3, message: FormErrorMessages.minLength(3) },
|
|
maxLength: {
|
|
value: 50,
|
|
message: FormErrorMessages.maxLength(50),
|
|
},
|
|
})}
|
|
label="Timezone"
|
|
name="timezone"
|
|
type="text"
|
|
placeholder="Enter Timezone"
|
|
/>
|
|
{errors.timezone && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.timezone.message}
|
|
</p>
|
|
)}
|
|
</ShowcaseSection>
|
|
</div>
|
|
<div className="flex flex-col gap-9">
|
|
<ShowcaseSection
|
|
title="Business Information"
|
|
className="grid grid-cols-1 gap-5"
|
|
>
|
|
<InputGroup
|
|
{...register("employee_count", {
|
|
min: { value: 1, message: FormErrorMessages.min(1) },
|
|
max: { value: 100000, message: FormErrorMessages.max(100000) },
|
|
})}
|
|
label="Employee Count"
|
|
name="employee_count"
|
|
type="number"
|
|
placeholder="Enter Employee Count"
|
|
/>
|
|
{errors.employee_count && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.employee_count.message}
|
|
</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("annual_revenue", {
|
|
min: { value: 0, message: FormErrorMessages.min(0) },
|
|
max: {
|
|
value: 999999999999,
|
|
message: FormErrorMessages.max(999999999999),
|
|
},
|
|
})}
|
|
label="Annual Revenue"
|
|
name="annual_revenue"
|
|
type="number"
|
|
placeholder="Enter Annual Revenue"
|
|
/>
|
|
{errors.annual_revenue && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.annual_revenue.message}
|
|
</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("founded_year", {
|
|
min: { value: 1800, message: FormErrorMessages.min(1800) },
|
|
max: {
|
|
value: 2100,
|
|
message: FormErrorMessages.max(2100),
|
|
},
|
|
})}
|
|
label="Founded Year"
|
|
name="founded_year"
|
|
type="number"
|
|
placeholder="Enter Founded Year"
|
|
/>
|
|
{errors.founded_year && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.founded_year.message}
|
|
</p>
|
|
)}
|
|
</ShowcaseSection>
|
|
<ShowcaseSection title="Address" className="grid grid-cols-1 gap-5">
|
|
<InputGroup
|
|
{...register("address.street", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: {
|
|
value: 5,
|
|
message: FormErrorMessages.minLength(5),
|
|
},
|
|
maxLength: {
|
|
value: 200,
|
|
message: FormErrorMessages.maxLength(200),
|
|
},
|
|
})}
|
|
label="Street"
|
|
name="address.street"
|
|
required
|
|
type="text"
|
|
placeholder="Enter Street"
|
|
/>
|
|
{errors.address?.street && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.address.street.message}
|
|
</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("address.city", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: {
|
|
value: 2,
|
|
message: FormErrorMessages.minLength(2),
|
|
},
|
|
maxLength: {
|
|
value: 100,
|
|
message: FormErrorMessages.maxLength(100),
|
|
},
|
|
})}
|
|
label="City"
|
|
required
|
|
name="address.city"
|
|
type="text"
|
|
placeholder="Enter City"
|
|
/>
|
|
{errors.address?.city && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.address.city.message}
|
|
</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("address.state", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: {
|
|
value: 2,
|
|
message: FormErrorMessages.minLength(2),
|
|
},
|
|
maxLength: {
|
|
value: 100,
|
|
message: FormErrorMessages.maxLength(100),
|
|
},
|
|
})}
|
|
label="State"
|
|
name="address.state"
|
|
type="text"
|
|
required
|
|
placeholder="Enter State"
|
|
/>
|
|
{errors.address?.state && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.address.state.message}
|
|
</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("address.postal_code", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: {
|
|
value: 3,
|
|
message: FormErrorMessages.minLength(3),
|
|
},
|
|
maxLength: {
|
|
value: 20,
|
|
message: FormErrorMessages.maxLength(20),
|
|
},
|
|
})}
|
|
label="Postal code"
|
|
name="address.postal_code"
|
|
type="text"
|
|
required
|
|
placeholder="Enter Postal code"
|
|
/>
|
|
{errors.address?.postal_code && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.address.postal_code.message}
|
|
</p>
|
|
)}
|
|
<InputGroup
|
|
{...register("address.country", {
|
|
required: { message: FormErrorMessages.required, value: true },
|
|
minLength: {
|
|
value: 2,
|
|
message: FormErrorMessages.minLength(2),
|
|
},
|
|
maxLength: {
|
|
value: 100,
|
|
message: FormErrorMessages.maxLength(100),
|
|
},
|
|
})}
|
|
label="Country"
|
|
name="address.country"
|
|
type="text"
|
|
required
|
|
placeholder="Enter Country"
|
|
/>
|
|
{errors.address?.country && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.address.country.message}
|
|
</p>
|
|
)}
|
|
</ShowcaseSection>
|
|
<ShowcaseSection title="Tags" className="grid grid-cols-1 gap-5">
|
|
<TagInput
|
|
{...register("tags.keywords")}
|
|
name="tags.keywords"
|
|
label="Keywords"
|
|
placeholder="Enter Tag Keywords"
|
|
register={register}
|
|
setValue={setValue}
|
|
watch={watch}
|
|
/>
|
|
<MultiSelect
|
|
{...register("tags.categories")}
|
|
value={watch("tags.categories")}
|
|
name="tags.categories"
|
|
label="Categories"
|
|
items={
|
|
companyCategories
|
|
? companyCategories?.data?.categories?.map((c) => {
|
|
return {
|
|
text: c.name,
|
|
value: c.id,
|
|
};
|
|
})
|
|
: []
|
|
}
|
|
placeholder="Please select categories"
|
|
/>
|
|
<TagInput
|
|
{...register("tags.cpv_codes")}
|
|
label="CPV codes"
|
|
name="tags.cpv_codes"
|
|
shouldAddWithSpace
|
|
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"
|
|
watch={watch}
|
|
setValue={setValue}
|
|
placeholder="Enter Tag Specializations"
|
|
/>
|
|
{errors.tags?.specializations && (
|
|
<p className="mt-1 text-sm text-red-500">
|
|
{errors.tags.specializations.message}
|
|
</p>
|
|
)}
|
|
</ShowcaseSection>
|
|
</div>
|
|
|
|
<FormFooter />
|
|
</form>
|
|
);
|
|
};
|
|
|
|
export default CreateCompany;
|