feat: implement comprehensive field validation logic and update UI components to enforce validation constraints
This commit is contained in:
@@ -7,6 +7,7 @@ import DynamicSection from './components/DynamicSection';
|
||||
import RepeatableSection, { RepeatableEntryData } from './components/RepeatableSection';
|
||||
import { profileSectionsService, ProfileSection, AgentTypeSectionsResponse } from '@/services/profile-sections.service';
|
||||
import { agentsService, AgentProfile, FieldValueInput } from '@/services/agents.service';
|
||||
import { validateFieldValue } from '@/utils/validateFieldValue';
|
||||
import { usersService } from '@/services/users.service';
|
||||
import { MobileBackButton } from '@/components/layout/MobileBackButton';
|
||||
|
||||
@@ -116,11 +117,37 @@ export default function EditProfilePage() {
|
||||
try {
|
||||
const fieldValuesResponse = await agentsService.getFieldValues();
|
||||
if (fieldValuesResponse.fieldValues) {
|
||||
// Build a lookup of current valid option values per enumerated-field slug
|
||||
const enumTypes = new Set(['CHECKBOX_GROUP', 'MULTI_SELECT', 'SELECT', 'RADIO']);
|
||||
const validOptionsBySlug = new Map<string, Set<string>>();
|
||||
sortedSections.forEach((section) => {
|
||||
const sectionFields = Array.isArray(section.fields) ? section.fields : [];
|
||||
sectionFields.forEach((field) => {
|
||||
if (!field?.slug || !enumTypes.has(field.fieldType)) return;
|
||||
const opts = Array.isArray(field.options) ? field.options : [];
|
||||
validOptionsBySlug.set(
|
||||
field.slug,
|
||||
new Set(opts.map((o: { value: string }) => String(o.value))),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
fieldValuesResponse.fieldValues.forEach(fv => {
|
||||
// Only set if value exists and is not null/undefined
|
||||
if (fv.value !== null && fv.value !== undefined) {
|
||||
initialData[fv.fieldSlug] = fv.value;
|
||||
if (fv.value === null || fv.value === undefined) return;
|
||||
let val: unknown = fv.value;
|
||||
// Strip orphan option values from stored arrays/strings so the form
|
||||
// never carries stale selections forward on the next save.
|
||||
const validValues = validOptionsBySlug.get(fv.fieldSlug);
|
||||
if (validValues) {
|
||||
if (Array.isArray(val)) {
|
||||
val = (val as unknown[])
|
||||
.filter((v) => validValues.has(String(v)))
|
||||
.filter((v, i, arr) => arr.indexOf(v) === i);
|
||||
} else if (typeof val === 'string' && !validValues.has(val)) {
|
||||
val = '';
|
||||
}
|
||||
}
|
||||
initialData[fv.fieldSlug] = val;
|
||||
});
|
||||
}
|
||||
} catch (fieldValueErr) {
|
||||
@@ -204,18 +231,12 @@ export default function EditProfilePage() {
|
||||
const entries = repeatableData[section.slug] || [{}];
|
||||
entries.forEach((entry, entryIndex) => {
|
||||
sectionFields.forEach(field => {
|
||||
if (field && field.isRequired && field.isActive && !field.isSearchableOnly) {
|
||||
const value = entry[field.slug];
|
||||
const isEmpty =
|
||||
value === undefined ||
|
||||
value === null ||
|
||||
value === '' ||
|
||||
(Array.isArray(value) && value.length === 0);
|
||||
|
||||
if (isEmpty) {
|
||||
if (field && field.isActive && !field.isSearchableOnly) {
|
||||
const err = validateFieldValue(field, entry[field.slug]);
|
||||
if (err) {
|
||||
if (!repErrors[section.slug]) repErrors[section.slug] = {};
|
||||
if (!repErrors[section.slug][entryIndex]) repErrors[section.slug][entryIndex] = {};
|
||||
repErrors[section.slug][entryIndex][field.slug] = `${field.name} is required`;
|
||||
repErrors[section.slug][entryIndex][field.slug] = err;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -223,16 +244,10 @@ export default function EditProfilePage() {
|
||||
} else {
|
||||
// Validate regular section fields
|
||||
sectionFields.forEach(field => {
|
||||
if (field && field.isRequired && field.isActive && !field.isSearchableOnly) {
|
||||
const value = formData[field.slug];
|
||||
const isEmpty =
|
||||
value === undefined ||
|
||||
value === null ||
|
||||
value === '' ||
|
||||
(Array.isArray(value) && value.length === 0);
|
||||
|
||||
if (isEmpty) {
|
||||
errors[field.slug] = `${field.name} is required`;
|
||||
if (field && field.isActive && !field.isSearchableOnly) {
|
||||
const err = validateFieldValue(field, formData[field.slug]);
|
||||
if (err) {
|
||||
errors[field.slug] = err;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user