fix
This commit is contained in:
@@ -4,6 +4,7 @@ import { useState, useRef, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { QuickLinks } from './components';
|
||||
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';
|
||||
|
||||
@@ -19,7 +20,10 @@ export default function EditProfilePage() {
|
||||
|
||||
// Form data keyed by field slug
|
||||
const [formData, setFormData] = useState<Record<string, unknown>>({});
|
||||
// Repeatable sections data keyed by section slug
|
||||
const [repeatableData, setRepeatableData] = useState<Record<string, RepeatableEntryData[]>>({});
|
||||
const [formErrors, setFormErrors] = useState<Record<string, string>>({});
|
||||
const [repeatableErrors, setRepeatableErrors] = useState<Record<string, Record<string, Record<string, string>>>>({});
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
// Fetch agent profile and sections on mount
|
||||
@@ -96,6 +100,7 @@ export default function EditProfilePage() {
|
||||
// Fetch existing field values from the API
|
||||
try {
|
||||
const fieldValuesResponse = await agentsService.getFieldValues();
|
||||
console.log('Field values from API:', fieldValuesResponse.fieldValues);
|
||||
if (fieldValuesResponse.fieldValues) {
|
||||
fieldValuesResponse.fieldValues.forEach(fv => {
|
||||
// Only set if value exists and is not null/undefined
|
||||
@@ -109,8 +114,30 @@ export default function EditProfilePage() {
|
||||
console.log('No existing field values found, using defaults');
|
||||
}
|
||||
|
||||
console.log('initialData after field values:', initialData);
|
||||
|
||||
setFormData(initialData);
|
||||
|
||||
// Initialize repeatable sections data
|
||||
const initialRepeatableData: Record<string, RepeatableEntryData[]> = {};
|
||||
sortedSections.forEach(section => {
|
||||
if (section.isRepeatable) {
|
||||
// Check if there's existing data for this section (stored as `${sectionSlug}_entries`)
|
||||
const entriesKey = `${section.slug}_entries`;
|
||||
console.log(`Checking repeatable section: ${section.slug}, entriesKey: ${entriesKey}`);
|
||||
const existingEntries = initialData[entriesKey];
|
||||
console.log(`Existing entries for ${entriesKey}:`, existingEntries);
|
||||
if (Array.isArray(existingEntries) && existingEntries.length > 0) {
|
||||
initialRepeatableData[section.slug] = existingEntries as RepeatableEntryData[];
|
||||
} else {
|
||||
// Initialize with one empty entry
|
||||
initialRepeatableData[section.slug] = [{}];
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log('initialRepeatableData:', initialRepeatableData);
|
||||
setRepeatableData(initialRepeatableData);
|
||||
|
||||
} catch (err: unknown) {
|
||||
console.error('Failed to fetch data:', err);
|
||||
|
||||
@@ -139,32 +166,69 @@ export default function EditProfilePage() {
|
||||
try {
|
||||
setIsSaving(true);
|
||||
setFormErrors({});
|
||||
setRepeatableErrors({});
|
||||
|
||||
// Validate required fields
|
||||
// Validate required fields for regular sections
|
||||
const errors: Record<string, string> = {};
|
||||
sections.forEach(section => {
|
||||
section.fields?.forEach(field => {
|
||||
if (field.isRequired && field.isActive && !field.isSearchableOnly) {
|
||||
const value = formData[field.slug];
|
||||
const isEmpty =
|
||||
value === undefined ||
|
||||
value === null ||
|
||||
value === '' ||
|
||||
(Array.isArray(value) && value.length === 0);
|
||||
const repErrors: Record<string, Record<string, Record<string, string>>> = {};
|
||||
|
||||
if (isEmpty) {
|
||||
errors[field.slug] = `${field.name} is required`;
|
||||
sections.forEach(section => {
|
||||
if (section.isRepeatable) {
|
||||
// Validate repeatable section entries
|
||||
const entries = repeatableData[section.slug] || [{}];
|
||||
entries.forEach((entry, entryIndex) => {
|
||||
section.fields?.forEach(field => {
|
||||
if (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 (!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`;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Validate regular section fields
|
||||
section.fields?.forEach(field => {
|
||||
if (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 (Object.keys(errors).length > 0) {
|
||||
const hasErrors = Object.keys(errors).length > 0;
|
||||
const hasRepeatableErrors = Object.keys(repErrors).length > 0;
|
||||
|
||||
if (hasErrors || hasRepeatableErrors) {
|
||||
setFormErrors(errors);
|
||||
setRepeatableErrors(repErrors);
|
||||
// Scroll to first error
|
||||
const firstErrorField = Object.keys(errors)[0];
|
||||
const errorElement = document.querySelector(`[data-field-slug="${firstErrorField}"]`);
|
||||
errorElement?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
if (hasErrors) {
|
||||
const firstErrorField = Object.keys(errors)[0];
|
||||
const errorElement = document.querySelector(`[data-field-slug="${firstErrorField}"]`);
|
||||
errorElement?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
} else if (hasRepeatableErrors) {
|
||||
const firstSection = Object.keys(repErrors)[0];
|
||||
const sectionElement = document.getElementById(firstSection);
|
||||
sectionElement?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -174,6 +238,21 @@ export default function EditProfilePage() {
|
||||
value: value as string | number | boolean | string[] | Record<string, unknown> | null,
|
||||
}));
|
||||
|
||||
// Add repeatable section data as a special field value
|
||||
Object.entries(repeatableData).forEach(([sectionSlug, entries]) => {
|
||||
// Filter out empty entries (entries with no filled fields)
|
||||
const nonEmptyEntries = entries.filter(entry =>
|
||||
Object.values(entry).some(v => v !== undefined && v !== null && v !== '')
|
||||
);
|
||||
|
||||
if (nonEmptyEntries.length > 0) {
|
||||
fieldValues.push({
|
||||
fieldSlug: `${sectionSlug}_entries`,
|
||||
value: nonEmptyEntries,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Save field values to API
|
||||
await agentsService.saveFieldValues(fieldValues);
|
||||
|
||||
@@ -198,6 +277,18 @@ export default function EditProfilePage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleRepeatableChange = (sectionSlug: string, entries: RepeatableEntryData[]) => {
|
||||
setRepeatableData(prev => ({ ...prev, [sectionSlug]: entries }));
|
||||
// Clear errors for this section when modified
|
||||
if (repeatableErrors[sectionSlug]) {
|
||||
setRepeatableErrors(prev => {
|
||||
const newErrors = { ...prev };
|
||||
delete newErrors[sectionSlug];
|
||||
return newErrors;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-[calc(100vh-180px)]">
|
||||
@@ -256,15 +347,25 @@ export default function EditProfilePage() {
|
||||
)}
|
||||
|
||||
{/* Dynamic Sections */}
|
||||
{sections.map((section) => (
|
||||
<DynamicSection
|
||||
key={section.id}
|
||||
section={section}
|
||||
formData={formData}
|
||||
onChange={handleFieldChange}
|
||||
errors={formErrors}
|
||||
/>
|
||||
))}
|
||||
{sections.map((section) =>
|
||||
section.isRepeatable ? (
|
||||
<RepeatableSection
|
||||
key={section.id}
|
||||
section={section}
|
||||
entries={repeatableData[section.slug] || [{}]}
|
||||
onChange={handleRepeatableChange}
|
||||
errors={repeatableErrors[section.slug]}
|
||||
/>
|
||||
) : (
|
||||
<DynamicSection
|
||||
key={section.id}
|
||||
section={section}
|
||||
formData={formData}
|
||||
onChange={handleFieldChange}
|
||||
errors={formErrors}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
|
||||
{/* Empty State */}
|
||||
{sections.length === 0 && !loading && (
|
||||
|
||||
Reference in New Issue
Block a user