Skip to content

Commit 5eee1f8

Browse files
domain validation FE (#415)
1 parent bacf36b commit 5eee1f8

2 files changed

Lines changed: 78 additions & 4 deletions

File tree

src/components/loginForms/recruiterSignup.tsx

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ const VALIDATION_MESSAGES = {
9898
MAX_VALUE: (max: number) => `Value must not exceed ${max}`,
9999
INVALID_YEAR: "Please enter a valid year",
100100
INVALID_SIZE: "Please enter a valid company size",
101+
DOMAINS_REQUIRED: "Please select at least one domain",
101102
};
102103

103104
interface ValidationErrors {
@@ -183,6 +184,14 @@ export default function RecruiterSignup() {
183184
loadData();
184185
}, []);
185186

187+
// Validation function for domains array
188+
const validateDomainsField = (domains: string[]): string => {
189+
if (createCompany && (!domains || domains.length === 0)) {
190+
return VALIDATION_MESSAGES.DOMAINS_REQUIRED;
191+
}
192+
return "";
193+
};
194+
186195
// Real-time validation functions
187196
const validateField = (field: string, value: string): string => {
188197
if (!value.trim() && isRequiredField(field)) {
@@ -291,7 +300,7 @@ export default function RecruiterSignup() {
291300
const isRequiredField = (field: string): boolean => {
292301
const requiredPersonalFields = ["name", "email", "contact", "designation"];
293302
const requiredCompanyFields = createCompany
294-
? ["companyName", "category", "line1", "city", "state", "country"]
303+
? ["companyName", "category", "line1", "city", "state", "country", "domains"]
295304
: ["companyId"];
296305

297306
return (
@@ -324,6 +333,11 @@ export default function RecruiterSignup() {
324333

325334
const handleDomainsChange = (value: string[]) => {
326335
setCompanyInfo((prev) => ({ ...prev, domains: value }));
336+
337+
// Real-time validation for domains
338+
const error = validateDomainsField(value);
339+
setValidationErrors((prev) => ({ ...prev, domains: error }));
340+
setTouched((prev) => ({ ...prev, domains: true }));
327341
};
328342

329343
const handleAddressChange = (field: string, value: string) => {
@@ -381,6 +395,13 @@ export default function RecruiterSignup() {
381395
isValid = false;
382396
}
383397
});
398+
399+
// Validate domains
400+
const domainsError = validateDomainsField(companyInfo.domains);
401+
if (domainsError) {
402+
errors.domains = domainsError;
403+
isValid = false;
404+
}
384405
} else {
385406
// Validate company selection
386407
if (!companyInfo.companyId) {
@@ -951,13 +972,20 @@ export default function RecruiterSignup() {
951972
</div>
952973
<div className="space-y-2">
953974
<Label className="text-sm font-medium text-gray-700">
954-
Domains
975+
Domains *
955976
</Label>
956977
<MultiSelect
957978
givenOptions={jaf?.domains || []}
958979
formData={companyInfo.domains}
959980
setFormData={handleDomainsChange}
981+
hasError={isFieldInvalid("domains")}
960982
/>
983+
{getFieldError("domains") && (
984+
<div className="flex items-center gap-1 text-red-500 text-sm">
985+
<AlertCircle className="h-3 w-3" />
986+
{getFieldError("domains")}
987+
</div>
988+
)}
961989
</div>
962990
</div>
963991

src/components/ui/multiselect.tsx

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import Select from "react-select";
22

3-
export const MultiSelect = ({ givenOptions, formData, setFormData }) => {
3+
interface MultiSelectProps {
4+
givenOptions: string[];
5+
formData: string[];
6+
setFormData: (data: string[]) => void;
7+
hasError?: boolean;
8+
}
9+
10+
export const MultiSelect = ({ givenOptions, formData, setFormData, hasError = false }: MultiSelectProps) => {
411
const handleChange = (selectedOptions) => {
512
setFormData(selectedOptions.map((option) => option.value));
613
};
@@ -15,13 +22,52 @@ export const MultiSelect = ({ givenOptions, formData, setFormData }) => {
1522
label: option,
1623
}));
1724

25+
const customStyles = {
26+
control: (provided, state) => ({
27+
...provided,
28+
borderColor: hasError ? '#ef4444' : state.isFocused ? '#3b82f6' : '#d1d5db',
29+
borderWidth: '1px',
30+
boxShadow: hasError
31+
? '0 0 0 1px #ef4444'
32+
: state.isFocused
33+
? '0 0 0 1px #3b82f6'
34+
: 'none',
35+
'&:hover': {
36+
borderColor: hasError ? '#ef4444' : '#3b82f6',
37+
},
38+
minHeight: '44px', // h-11 equivalent
39+
}),
40+
placeholder: (provided) => ({
41+
...provided,
42+
color: '#6b7280',
43+
}),
44+
multiValue: (provided) => ({
45+
...provided,
46+
backgroundColor: hasError ? '#fef2f2' : '#f3f4f6',
47+
borderColor: hasError ? '#fecaca' : '#e5e7eb',
48+
}),
49+
multiValueLabel: (provided) => ({
50+
...provided,
51+
color: hasError ? '#991b1b' : '#374151',
52+
}),
53+
multiValueRemove: (provided) => ({
54+
...provided,
55+
color: hasError ? '#991b1b' : '#6b7280',
56+
'&:hover': {
57+
backgroundColor: hasError ? '#fecaca' : '#e5e7eb',
58+
color: hasError ? '#7f1d1d' : '#374151',
59+
},
60+
}),
61+
};
62+
1863
return (
1964
<Select
2065
isMulti
2166
value={values}
2267
onChange={handleChange}
2368
options={options}
24-
className="w-full text-sm text-gray-800 bg-white border border-gray-200 rounded-lg focus:border-blue-500 focus:ring-blue-500 dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400"
69+
styles={customStyles}
70+
className="w-full text-sm"
2571
placeholder="Select multiple options..."
2672
/>
2773
);

0 commit comments

Comments
 (0)