Files
frontend/src/app/(agent)/agent/edit/components/DynamicSection.tsx

141 lines
4.9 KiB
TypeScript

'use client';
import React from 'react';
import Image from 'next/image';
import { ProfileSection } from '@/services/profile-sections.service';
import DynamicField from './DynamicField';
// Map section slugs to icon paths
const sectionIcons: Record<string, string> = {
'basic-information': '/assets/icons/basic-information-icon.svg',
'contact-information': '/assets/icons/email-orange-icon.svg',
'location': '/assets/icons/location-orange-icon.svg',
'professional-info': '/assets/icons/certification-icon.svg',
'specialization': '/assets/icons/home-icon.svg',
'experience': '/assets/icons/star-icon.svg',
'availability': '/assets/icons/availability-clock-icon.svg',
'biography': '/assets/icons/bio-icon.svg',
'attached-documents': '/assets/icons/attachment-icon.svg',
'hobbies': '/assets/icons/heart-icon.svg',
'testimonials': '/assets/icons/quote-icon.svg',
'certification': '/assets/icons/certification-icon.svg',
};
// Map icon names (from database) to icon paths
const iconNameToPath: Record<string, string> = {
'star': '/assets/icons/star-icon.svg',
'home': '/assets/icons/home-icon.svg',
'location': '/assets/icons/location-orange-icon.svg',
'heart': '/assets/icons/heart-icon.svg',
'clock': '/assets/icons/availability-clock-icon.svg',
'user': '/assets/icons/basic-information-icon.svg',
'email': '/assets/icons/email-orange-icon.svg',
'phone': '/assets/icons/phone-orange-icon.svg',
'document': '/assets/icons/attachment-icon.svg',
'certificate': '/assets/icons/certification-icon.svg',
'certification': '/assets/icons/certification-icon.svg',
'quote': '/assets/icons/quote-icon.svg',
'bio': '/assets/icons/bio-icon.svg',
'professional': '/assets/icons/professional-icon.svg',
'wallet': '/assets/icons/wallet-icon.svg',
'chart': '/assets/icons/chart-icon.svg',
'dollar': '/assets/icons/dollar-icon.svg',
'calendar': '/assets/icons/calendar-icon.svg',
};
// Default icon for sections without a specific icon
const defaultIcon = '/assets/icons/professional-icon.svg';
// Helper to check if a string is an emoji
const isEmojiString = (str: string): boolean => {
// Emoji regex pattern - matches most common emojis
const emojiRegex = /^[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]/u;
return emojiRegex.test(str);
};
interface DynamicSectionProps {
section: ProfileSection;
formData: Record<string, unknown>;
onChange: (fieldSlug: string, value: unknown) => void;
errors?: Record<string, string>;
}
export default function DynamicSection({ section, formData, onChange, errors }: DynamicSectionProps) {
// Determine icon source
let iconPath: string = defaultIcon;
let isEmoji = false;
if (section.icon) {
if (section.icon.startsWith('/') || section.icon.startsWith('http')) {
// It's a valid URL path
iconPath = section.icon;
} else if (isEmojiString(section.icon)) {
// It's an emoji
isEmoji = true;
} else if (iconNameToPath[section.icon.toLowerCase()]) {
// It's an icon name like "star", "home", etc.
iconPath = iconNameToPath[section.icon.toLowerCase()];
} else {
// Fallback to slug mapping or default
iconPath = sectionIcons[section.slug] || defaultIcon;
}
} else {
// No icon set, use slug mapping or default
iconPath = sectionIcons[section.slug] || defaultIcon;
}
// Sort fields by sortOrder
const sortedFields = [...(section.fields || [])].sort((a, b) => a.sortOrder - b.sortOrder);
const activeFields = sortedFields.filter(f => f.isActive && !f.isSearchableOnly);
if (activeFields.length === 0) {
return null;
}
return (
<div
id={section.slug}
className="bg-white rounded-[20px] p-6 shadow-[0px_10px_20px_rgba(217,217,217,0.5)] scroll-mt-[100px]"
>
{/* Section Header */}
<div className="flex items-center gap-3 mb-6">
<div className="w-[40px] h-[40px] flex items-center justify-center">
{isEmoji ? (
<span className="text-2xl">{section.icon}</span>
) : (
<Image
src={iconPath}
alt={section.name}
width={24}
height={24}
className="object-contain"
/>
)}
</div>
<div>
<h2 className="text-[18px] font-bold font-serif text-[#00293D]">
{section.name}
{section.isRequired && <span className="text-red-500 ml-1">*</span>}
</h2>
{section.description && (
<p className="text-[12px] text-gray-500">{section.description}</p>
)}
</div>
</div>
{/* Section Fields */}
<div className="space-y-4">
{activeFields.map((field) => (
<DynamicField
key={field.id}
field={field}
value={formData[field.slug]}
onChange={onChange}
error={errors?.[field.slug]}
/>
))}
</div>
</div>
);
}