feat: Implement agent profile editing page with new form components, icons, and dashboard integration.
This commit is contained in:
86
src/app/(agent)/agent/edit/components/FileUpload.tsx
Normal file
86
src/app/(agent)/agent/edit/components/FileUpload.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
'use client';
|
||||
|
||||
import Image from 'next/image';
|
||||
import { useRef } from 'react';
|
||||
|
||||
interface FileUploadProps {
|
||||
onFileSelect: (files: FileList) => void;
|
||||
acceptedTypes?: string;
|
||||
maxSize?: string;
|
||||
}
|
||||
|
||||
export function FileUpload({ onFileSelect, acceptedTypes = '.pdf,.doc,.docx,.jpg,.png', maxSize = '5MB' }: FileUploadProps) {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleClick = () => {
|
||||
fileInputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files && e.target.files.length > 0) {
|
||||
onFileSelect(e.target.files);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrop = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
||||
onFileSelect(e.dataTransfer.files);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragOver = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={handleClick}
|
||||
onDrop={handleDrop}
|
||||
onDragOver={handleDragOver}
|
||||
className="border-2 border-dashed border-[#00293D]/20 rounded-[10px] p-6 text-center cursor-pointer hover:border-[#E58625]/50 transition-colors"
|
||||
>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept={acceptedTypes}
|
||||
onChange={handleChange}
|
||||
className="hidden"
|
||||
multiple
|
||||
/>
|
||||
<p className="text-[14px] font-serif text-[#00293D]/70 mb-2">
|
||||
Drag and drop files here or click to upload files to provide documentation or verification for licensing credentials.
|
||||
</p>
|
||||
<p className="text-[12px] font-serif text-[#00293D]/50">
|
||||
{acceptedTypes.split(',').join(', ')} and more are accepted
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-4 px-6 py-2 bg-[#E58625] text-white text-[14px] font-semibold font-serif rounded-full hover:bg-[#E58625]/90 transition-colors"
|
||||
>
|
||||
Upload
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface AttachedFileProps {
|
||||
fileName: string;
|
||||
onRemove: () => void;
|
||||
}
|
||||
|
||||
export function AttachedFile({ fileName, onRemove }: AttachedFileProps) {
|
||||
return (
|
||||
<div className="flex items-center justify-between p-3 bg-gray-50 rounded-[10px]">
|
||||
<div className="flex items-center gap-2">
|
||||
<Image src="/assets/icons/document-icon.svg" alt="Document" width={20} height={20} />
|
||||
<span className="text-[14px] font-serif text-[#00293D]">{fileName}</span>
|
||||
</div>
|
||||
<button onClick={onRemove} className="text-[#00293D]/50 hover:text-red-500 transition-colors">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 4L4 12M4 4L12 12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
21
src/app/(agent)/agent/edit/components/FormCheckbox.tsx
Normal file
21
src/app/(agent)/agent/edit/components/FormCheckbox.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
'use client';
|
||||
|
||||
interface FormCheckboxProps {
|
||||
label: string;
|
||||
checked: boolean;
|
||||
onChange: (checked: boolean) => void;
|
||||
}
|
||||
|
||||
export function FormCheckbox({ label, checked, onChange }: FormCheckboxProps) {
|
||||
return (
|
||||
<label className="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
onChange={(e) => onChange(e.target.checked)}
|
||||
className="w-4 h-4 rounded border-[#00293D]/30 text-[#E58625] focus:ring-[#E58625] focus:ring-offset-0 accent-[#E58625]"
|
||||
/>
|
||||
<span className="text-[14px] font-serif text-[#00293D]">{label}</span>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
28
src/app/(agent)/agent/edit/components/FormInput.tsx
Normal file
28
src/app/(agent)/agent/edit/components/FormInput.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
'use client';
|
||||
|
||||
interface FormInputProps {
|
||||
label: string;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
placeholder?: string;
|
||||
type?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function FormInput({ label, value, onChange, placeholder, type = 'text', disabled }: FormInputProps) {
|
||||
return (
|
||||
<div className="flex-1">
|
||||
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-1">
|
||||
{label}
|
||||
</label>
|
||||
<input
|
||||
type={type}
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
disabled={disabled}
|
||||
className="w-full px-4 py-3 border border-[#00293D]/20 rounded-[10px] text-[14px] font-serif text-[#00293D] placeholder:text-[#00293D]/40 focus:outline-none focus:border-[#E58625] disabled:bg-gray-50 disabled:text-[#00293D]/50"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
34
src/app/(agent)/agent/edit/components/FormSection.tsx
Normal file
34
src/app/(agent)/agent/edit/components/FormSection.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
'use client';
|
||||
|
||||
import Image from 'next/image';
|
||||
|
||||
interface FormSectionProps {
|
||||
id: string;
|
||||
icon: string;
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
onEdit?: () => void;
|
||||
showEdit?: boolean;
|
||||
}
|
||||
|
||||
export function FormSection({ id, icon, title, children, onEdit, showEdit }: FormSectionProps) {
|
||||
return (
|
||||
<div id={id} className="scroll-mt-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Image src={icon} alt={title} width={20} height={20} />
|
||||
<h3 className="text-[16px] font-bold text-[#00293D] font-fractul">{title}</h3>
|
||||
</div>
|
||||
{showEdit && onEdit && (
|
||||
<button
|
||||
onClick={onEdit}
|
||||
className="flex items-center gap-1 text-[#E58625] text-[12px] font-medium font-serif hover:underline"
|
||||
>
|
||||
<span>+ Edit</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
41
src/app/(agent)/agent/edit/components/FormSelect.tsx
Normal file
41
src/app/(agent)/agent/edit/components/FormSelect.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
'use client';
|
||||
|
||||
interface FormSelectProps {
|
||||
label: string;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
options: { value: string; label: string }[];
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export function FormSelect({ label, value, onChange, options, placeholder }: FormSelectProps) {
|
||||
return (
|
||||
<div className="flex-1">
|
||||
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-1">
|
||||
{label}
|
||||
</label>
|
||||
<select
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
className="w-full px-4 py-3 border border-[#00293D]/20 rounded-[10px] text-[14px] font-serif text-[#00293D] focus:outline-none focus:border-[#E58625] bg-white appearance-none cursor-pointer"
|
||||
style={{
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2300293D'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'right 12px center',
|
||||
backgroundSize: '16px',
|
||||
}}
|
||||
>
|
||||
{placeholder && (
|
||||
<option value="" disabled>
|
||||
{placeholder}
|
||||
</option>
|
||||
)}
|
||||
{options.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
35
src/app/(agent)/agent/edit/components/FormTextarea.tsx
Normal file
35
src/app/(agent)/agent/edit/components/FormTextarea.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
'use client';
|
||||
|
||||
interface FormTextareaProps {
|
||||
label?: string;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
placeholder?: string;
|
||||
rows?: number;
|
||||
maxLength?: number;
|
||||
}
|
||||
|
||||
export function FormTextarea({ label, value, onChange, placeholder, rows = 4, maxLength }: FormTextareaProps) {
|
||||
return (
|
||||
<div className="flex-1">
|
||||
{label && (
|
||||
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-1">
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<textarea
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
rows={rows}
|
||||
maxLength={maxLength}
|
||||
className="w-full px-4 py-3 border border-[#00293D]/20 rounded-[10px] text-[14px] font-serif text-[#00293D] placeholder:text-[#00293D]/40 focus:outline-none focus:border-[#E58625] resize-none"
|
||||
/>
|
||||
{maxLength && (
|
||||
<p className="text-right text-[12px] text-[#00293D]/50 font-serif mt-1">
|
||||
{value.length}/{maxLength}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
54
src/app/(agent)/agent/edit/components/QuickLinks.tsx
Normal file
54
src/app/(agent)/agent/edit/components/QuickLinks.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
const links = [
|
||||
{ id: 'basic-info', label: 'Basic Information' },
|
||||
{ id: 'contact-info', label: 'Contact Information' },
|
||||
{ id: 'professional-types', label: 'Professional Types' },
|
||||
{ id: 'upload-documents', label: 'Upload Documents' },
|
||||
{ id: 'licensing-areas', label: 'Licensing & Areas' },
|
||||
{ id: 'biography', label: 'Biography' },
|
||||
{ id: 'expertise', label: 'Expertise' },
|
||||
{ id: 'years-business', label: 'Years In Business' },
|
||||
{ id: 'areas-expertise-years', label: 'Areas in expertise & Years' },
|
||||
{ id: 'contracts-closed', label: 'Contracts Closed' },
|
||||
{ id: 'price-point', label: 'Price Point' },
|
||||
{ id: 'specialization', label: 'Specialization' },
|
||||
{ id: 'hobbies', label: 'Hobbies' },
|
||||
{ id: 'certifications', label: 'Certifications' },
|
||||
{ id: 'availability', label: 'Availability' },
|
||||
];
|
||||
|
||||
export function QuickLinks() {
|
||||
const [activeLink, setActiveLink] = useState('basic-info');
|
||||
|
||||
const scrollToSection = (id: string) => {
|
||||
setActiveLink(id);
|
||||
const element = document.getElementById(id);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<h3 className="text-[16px] font-bold text-[#00293D] font-fractul mb-4">Quick Links</h3>
|
||||
<nav className="space-y-1">
|
||||
{links.map((link) => (
|
||||
<button
|
||||
key={link.id}
|
||||
onClick={() => scrollToSection(link.id)}
|
||||
className={`block w-full text-left px-3 py-2 rounded-lg text-[14px] font-serif transition-colors ${
|
||||
activeLink === link.id
|
||||
? 'text-[#E58625] font-semibold bg-[#E58625]/5'
|
||||
: 'text-[#00293D] hover:bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
{link.label}
|
||||
</button>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
58
src/app/(agent)/agent/edit/components/TagInput.tsx
Normal file
58
src/app/(agent)/agent/edit/components/TagInput.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
interface TagInputProps {
|
||||
tags: string[];
|
||||
onChange: (tags: string[]) => void;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export function TagInput({ tags, onChange, placeholder = 'Add tag...' }: TagInputProps) {
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.key === 'Enter' && inputValue.trim()) {
|
||||
e.preventDefault();
|
||||
if (!tags.includes(inputValue.trim())) {
|
||||
onChange([...tags, inputValue.trim()]);
|
||||
}
|
||||
setInputValue('');
|
||||
}
|
||||
};
|
||||
|
||||
const removeTag = (tagToRemove: string) => {
|
||||
onChange(tags.filter((tag) => tag !== tagToRemove));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="border border-[#00293D]/20 rounded-[10px] p-3">
|
||||
<div className="flex flex-wrap gap-2 mb-2">
|
||||
{tags.map((tag) => (
|
||||
<span
|
||||
key={tag}
|
||||
className="inline-flex items-center gap-1 px-3 py-1 bg-[#00293D]/5 rounded-full text-[14px] font-serif text-[#00293D]"
|
||||
>
|
||||
{tag}
|
||||
<button
|
||||
onClick={() => removeTag(tag)}
|
||||
className="text-[#00293D]/50 hover:text-[#00293D] ml-1"
|
||||
>
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 3L3 9M3 3L9 9" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={placeholder}
|
||||
className="w-full text-[14px] font-serif text-[#00293D] placeholder:text-[#00293D]/40 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
8
src/app/(agent)/agent/edit/components/index.ts
Normal file
8
src/app/(agent)/agent/edit/components/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export { QuickLinks } from './QuickLinks';
|
||||
export { FormSection } from './FormSection';
|
||||
export { FormInput } from './FormInput';
|
||||
export { FormCheckbox } from './FormCheckbox';
|
||||
export { FormTextarea } from './FormTextarea';
|
||||
export { FormSelect } from './FormSelect';
|
||||
export { FileUpload, AttachedFile } from './FileUpload';
|
||||
export { TagInput } from './TagInput';
|
||||
631
src/app/(agent)/agent/edit/page.tsx
Normal file
631
src/app/(agent)/agent/edit/page.tsx
Normal file
@@ -0,0 +1,631 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import Image from 'next/image';
|
||||
import {
|
||||
QuickLinks,
|
||||
FormSection,
|
||||
FormInput,
|
||||
FormCheckbox,
|
||||
FormTextarea,
|
||||
FormSelect,
|
||||
FileUpload,
|
||||
AttachedFile,
|
||||
TagInput,
|
||||
} from './components';
|
||||
|
||||
// Initial form data - in production this would come from API
|
||||
const initialFormData = {
|
||||
firstName: 'Brian',
|
||||
lastName: 'Neeland',
|
||||
email: 'brian@requestnetwork.com',
|
||||
phone: '+9195003837493',
|
||||
professionalTypes: {
|
||||
firstTime: true,
|
||||
solo: false,
|
||||
team: false,
|
||||
},
|
||||
attachedDocuments: ['Brian_Photo_1_Blue_Coat.pdf'],
|
||||
state: 'Colorado',
|
||||
licensedAreas: ['Colorado Springs', 'Monument'],
|
||||
expertiseYears: [
|
||||
{ area: 'Colorado', years: '10 yrs' },
|
||||
{ area: 'Falcon', years: '10 yrs' },
|
||||
],
|
||||
biography: "Brian brings eight years of hands-on experience helping clients confidently buy, sell, and invest in real estate. He combines strong analytical skills with deep market knowledge to identify the right opportunities and guide clients through every step of the process. With a data-driven approach and clear communication, Brian ensures smooth transactions and informed decisions tailored to each client's goals.",
|
||||
testimonialHighlight: "The most amazing experience I've had as a real estate professional is helping a family secure their dream home and seeing their happiness when they received the keys.",
|
||||
expertise: ['Buyers', 'Sellers', 'Divorce', 'Luxury', 'Retirement', 'Historical', 'Condo', 'Rural'],
|
||||
yearsInBusiness: {
|
||||
totalYears: '10 Years',
|
||||
totalTransactions: '100+',
|
||||
},
|
||||
contractsClosed: {
|
||||
lessThan10: false,
|
||||
between10And25: false,
|
||||
between26And50: true,
|
||||
between51And75: false,
|
||||
moreThan75: false,
|
||||
},
|
||||
pricePoint: {
|
||||
under100k: false,
|
||||
between100kAnd200k: false,
|
||||
between200kAnd400k: true,
|
||||
between400kAnd600k: true,
|
||||
between600kAnd800k: false,
|
||||
between800kAnd1m: false,
|
||||
above1m: false,
|
||||
},
|
||||
specialization: {
|
||||
clientLocalization: {
|
||||
local: true,
|
||||
national: false,
|
||||
international: false,
|
||||
},
|
||||
clientTypeWorkedWith: {
|
||||
firstTimeBuyer: true,
|
||||
firstTimeSeller: false,
|
||||
},
|
||||
propertyType: {
|
||||
sfr: true,
|
||||
condo: false,
|
||||
luxury: false,
|
||||
townhome: false,
|
||||
commercial: false,
|
||||
},
|
||||
transactionType: {
|
||||
relocation: true,
|
||||
probate: false,
|
||||
taxLien: false,
|
||||
traditional: false,
|
||||
newConstruction: false,
|
||||
},
|
||||
loanType: {
|
||||
conventional: true,
|
||||
fha: false,
|
||||
va: false,
|
||||
usda: false,
|
||||
reverse: false,
|
||||
},
|
||||
lifestyleSpecialties: {
|
||||
boating: true,
|
||||
horses: false,
|
||||
rv: false,
|
||||
automotive: false,
|
||||
aviation: false,
|
||||
},
|
||||
},
|
||||
hobbies: ['Boating', 'Horses'],
|
||||
certifications: [
|
||||
{ name: 'Certified Residential Specialist (CRS)', org: 'Residential Real Estate Council' },
|
||||
],
|
||||
availability: {
|
||||
type: 'Full Time Weekend',
|
||||
workFrom: 'Work from Method',
|
||||
},
|
||||
};
|
||||
|
||||
export default function EditProfilePage() {
|
||||
const router = useRouter();
|
||||
const [formData, setFormData] = useState(initialFormData);
|
||||
|
||||
const handleCancel = () => {
|
||||
router.push('/agent/dashboard');
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
// In production, this would save to API
|
||||
console.log('Saving form data:', formData);
|
||||
router.push('/agent/dashboard');
|
||||
};
|
||||
|
||||
const updateField = (field: string, value: any) => {
|
||||
setFormData((prev) => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex gap-6">
|
||||
{/* Left Sidebar - Quick Links */}
|
||||
<div className="w-[220px] flex-shrink-0 hidden lg:block">
|
||||
<div className="sticky top-6">
|
||||
<QuickLinks />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
<div className="flex-1 space-y-6">
|
||||
{/* Basic Information */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="basic-info" icon="/assets/icons/user-icon.svg" title="Basic Information">
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<FormInput
|
||||
label="First Name"
|
||||
value={formData.firstName}
|
||||
onChange={(value) => updateField('firstName', value)}
|
||||
placeholder="Enter first name"
|
||||
/>
|
||||
<FormInput
|
||||
label="Last Name"
|
||||
value={formData.lastName}
|
||||
onChange={(value) => updateField('lastName', value)}
|
||||
placeholder="Enter last name"
|
||||
/>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Contact Information */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="contact-info" icon="/assets/icons/contact-icon.svg" title="Contact Information">
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<FormInput
|
||||
label="Email Address"
|
||||
value={formData.email}
|
||||
onChange={(value) => updateField('email', value)}
|
||||
placeholder="Enter email"
|
||||
type="email"
|
||||
/>
|
||||
<FormInput
|
||||
label="Phone Number"
|
||||
value={formData.phone}
|
||||
onChange={(value) => updateField('phone', value)}
|
||||
placeholder="Enter phone"
|
||||
type="tel"
|
||||
/>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Professional Types */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="professional-types" icon="/assets/icons/professional-icon.svg" title="Professional Types">
|
||||
<div className="flex flex-wrap gap-6">
|
||||
<FormCheckbox
|
||||
label="First Time"
|
||||
checked={formData.professionalTypes.firstTime}
|
||||
onChange={(checked) =>
|
||||
updateField('professionalTypes', { ...formData.professionalTypes, firstTime: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="Solo"
|
||||
checked={formData.professionalTypes.solo}
|
||||
onChange={(checked) =>
|
||||
updateField('professionalTypes', { ...formData.professionalTypes, solo: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="Team"
|
||||
checked={formData.professionalTypes.team}
|
||||
onChange={(checked) =>
|
||||
updateField('professionalTypes', { ...formData.professionalTypes, team: checked })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Upload Documents */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="upload-documents" icon="/assets/icons/upload-icon.svg" title="Upload Documents">
|
||||
<FileUpload onFileSelect={(files) => console.log('Files selected:', files)} />
|
||||
|
||||
{/* Attached Documents */}
|
||||
{formData.attachedDocuments.length > 0 && (
|
||||
<div className="mt-6">
|
||||
<h4 className="text-[14px] font-semibold text-[#00293D] font-fractul mb-3 flex items-center gap-2">
|
||||
<Image src="/assets/icons/attachment-icon.svg" alt="Attached" width={16} height={16} />
|
||||
Attached Documents
|
||||
</h4>
|
||||
<div className="space-y-2">
|
||||
{formData.attachedDocuments.map((doc, idx) => (
|
||||
<AttachedFile
|
||||
key={idx}
|
||||
fileName={doc}
|
||||
onRemove={() => {
|
||||
const newDocs = [...formData.attachedDocuments];
|
||||
newDocs.splice(idx, 1);
|
||||
updateField('attachedDocuments', newDocs);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Licensing & Areas */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="licensing-areas" icon="/assets/icons/location-icon.svg" title="Licensing & Areas">
|
||||
<div className="space-y-4">
|
||||
<FormSelect
|
||||
label="State Licensed"
|
||||
value={formData.state}
|
||||
onChange={(value) => updateField('state', value)}
|
||||
options={[
|
||||
{ value: 'Colorado', label: 'Colorado' },
|
||||
{ value: 'Texas', label: 'Texas' },
|
||||
{ value: 'California', label: 'California' },
|
||||
]}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-2">
|
||||
Licensed Areas
|
||||
</label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{formData.licensedAreas.map((area) => (
|
||||
<span
|
||||
key={area}
|
||||
className="inline-flex items-center px-3 h-[28px] rounded-[15px] text-[14px] font-medium font-serif border-[0.7px] border-[#00293d] text-[#00293d]"
|
||||
>
|
||||
{area}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<label className="text-[12px] font-medium text-[#00293D]/70 font-serif">
|
||||
Expertise Years
|
||||
</label>
|
||||
<button className="text-[#E58625] text-[12px] font-medium font-serif">+ Edit</button>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{formData.expertiseYears.map((item, idx) => (
|
||||
<span
|
||||
key={idx}
|
||||
className="inline-flex items-center px-3 h-[28px] rounded-[15px] text-[14px] font-medium font-serif border-[0.7px] border-[#00293d] text-[#00293d]"
|
||||
>
|
||||
{item.area} - {item.years}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Biography */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="biography" icon="/assets/icons/bio-icon.svg" title="Biography">
|
||||
<div className="space-y-4">
|
||||
<FormTextarea
|
||||
value={formData.biography}
|
||||
onChange={(value) => updateField('biography', value)}
|
||||
placeholder="Write your biography..."
|
||||
rows={5}
|
||||
maxLength={500}
|
||||
/>
|
||||
<FormTextarea
|
||||
label="Write a few sentences that explain yourself and also a good memorable thought."
|
||||
value={formData.testimonialHighlight}
|
||||
onChange={(value) => updateField('testimonialHighlight', value)}
|
||||
placeholder="Write your memorable experience..."
|
||||
rows={3}
|
||||
maxLength={250}
|
||||
/>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Expertise */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="expertise" icon="/assets/icons/expertise-icon.svg" title="Expertise">
|
||||
<TagInput
|
||||
tags={formData.expertise}
|
||||
onChange={(tags) => updateField('expertise', tags)}
|
||||
placeholder="Add expertise..."
|
||||
/>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Years In Business */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="years-business" icon="/assets/icons/business-icon.svg" title="Years In Business">
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<FormInput
|
||||
label="Total Years"
|
||||
value={formData.yearsInBusiness.totalYears}
|
||||
onChange={(value) =>
|
||||
updateField('yearsInBusiness', { ...formData.yearsInBusiness, totalYears: value })
|
||||
}
|
||||
/>
|
||||
<FormInput
|
||||
label="Total Transactions"
|
||||
value={formData.yearsInBusiness.totalTransactions}
|
||||
onChange={(value) =>
|
||||
updateField('yearsInBusiness', { ...formData.yearsInBusiness, totalTransactions: value })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Areas in expertise & Years */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection
|
||||
id="areas-expertise-years"
|
||||
icon="/assets/icons/areas-icon.svg"
|
||||
title="Areas in expertise & Years"
|
||||
showEdit
|
||||
onEdit={() => console.log('Edit areas')}
|
||||
>
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<FormSelect
|
||||
label="Select State"
|
||||
value={formData.state}
|
||||
onChange={(value) => updateField('state', value)}
|
||||
options={[
|
||||
{ value: 'Colorado', label: 'Colorado' },
|
||||
{ value: 'Texas', label: 'Texas' },
|
||||
]}
|
||||
/>
|
||||
<FormSelect
|
||||
label="Select Years"
|
||||
value="10"
|
||||
onChange={() => {}}
|
||||
options={[
|
||||
{ value: '5', label: '5 Years' },
|
||||
{ value: '10', label: '10 Years' },
|
||||
{ value: '15', label: '15 Years' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Contracts Closed */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="contracts-closed" icon="/assets/icons/contract-icon.svg" title="Contracts Closed">
|
||||
<div className="space-y-3">
|
||||
<FormCheckbox
|
||||
label="< 10"
|
||||
checked={formData.contractsClosed.lessThan10}
|
||||
onChange={(checked) =>
|
||||
updateField('contractsClosed', { ...formData.contractsClosed, lessThan10: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="10 to 25"
|
||||
checked={formData.contractsClosed.between10And25}
|
||||
onChange={(checked) =>
|
||||
updateField('contractsClosed', { ...formData.contractsClosed, between10And25: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="26 to 50"
|
||||
checked={formData.contractsClosed.between26And50}
|
||||
onChange={(checked) =>
|
||||
updateField('contractsClosed', { ...formData.contractsClosed, between26And50: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="51 to 75"
|
||||
checked={formData.contractsClosed.between51And75}
|
||||
onChange={(checked) =>
|
||||
updateField('contractsClosed', { ...formData.contractsClosed, between51And75: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="75+"
|
||||
checked={formData.contractsClosed.moreThan75}
|
||||
onChange={(checked) =>
|
||||
updateField('contractsClosed', { ...formData.contractsClosed, moreThan75: checked })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Price Point */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="price-point" icon="/assets/icons/price-icon.svg" title="Price Point">
|
||||
<div className="space-y-3">
|
||||
<FormCheckbox
|
||||
label="Under $100K"
|
||||
checked={formData.pricePoint.under100k}
|
||||
onChange={(checked) =>
|
||||
updateField('pricePoint', { ...formData.pricePoint, under100k: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="$100K – $200K"
|
||||
checked={formData.pricePoint.between100kAnd200k}
|
||||
onChange={(checked) =>
|
||||
updateField('pricePoint', { ...formData.pricePoint, between100kAnd200k: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="$200K – $400K"
|
||||
checked={formData.pricePoint.between200kAnd400k}
|
||||
onChange={(checked) =>
|
||||
updateField('pricePoint', { ...formData.pricePoint, between200kAnd400k: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="$400K – $600K"
|
||||
checked={formData.pricePoint.between400kAnd600k}
|
||||
onChange={(checked) =>
|
||||
updateField('pricePoint', { ...formData.pricePoint, between400kAnd600k: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="$600K – $800K"
|
||||
checked={formData.pricePoint.between600kAnd800k}
|
||||
onChange={(checked) =>
|
||||
updateField('pricePoint', { ...formData.pricePoint, between600kAnd800k: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="$800K – $1M"
|
||||
checked={formData.pricePoint.between800kAnd1m}
|
||||
onChange={(checked) =>
|
||||
updateField('pricePoint', { ...formData.pricePoint, between800kAnd1m: checked })
|
||||
}
|
||||
/>
|
||||
<FormCheckbox
|
||||
label="$1M and above"
|
||||
checked={formData.pricePoint.above1m}
|
||||
onChange={(checked) =>
|
||||
updateField('pricePoint', { ...formData.pricePoint, above1m: checked })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Specialization */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="specialization" icon="/assets/icons/specialization-icon.svg" title="Specialization">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{/* Client Localization */}
|
||||
<div>
|
||||
<h4 className="text-[14px] font-semibold text-[#00293D] font-fractul mb-3">Client Localization</h4>
|
||||
<div className="space-y-2">
|
||||
<FormCheckbox label="Local" checked={formData.specialization.clientLocalization.local} onChange={() => {}} />
|
||||
<FormCheckbox label="National" checked={formData.specialization.clientLocalization.national} onChange={() => {}} />
|
||||
<FormCheckbox label="International" checked={formData.specialization.clientLocalization.international} onChange={() => {}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Client Type Worked With */}
|
||||
<div>
|
||||
<h4 className="text-[14px] font-semibold text-[#00293D] font-fractul mb-3">Client Type Worked With</h4>
|
||||
<div className="space-y-2">
|
||||
<FormCheckbox label="First Time Buyer" checked={formData.specialization.clientTypeWorkedWith.firstTimeBuyer} onChange={() => {}} />
|
||||
<FormCheckbox label="First Time Seller" checked={formData.specialization.clientTypeWorkedWith.firstTimeSeller} onChange={() => {}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Property Type */}
|
||||
<div>
|
||||
<h4 className="text-[14px] font-semibold text-[#00293D] font-fractul mb-3">Property Type</h4>
|
||||
<div className="space-y-2">
|
||||
<FormCheckbox label="SFR" checked={formData.specialization.propertyType.sfr} onChange={() => {}} />
|
||||
<FormCheckbox label="Condo" checked={formData.specialization.propertyType.condo} onChange={() => {}} />
|
||||
<FormCheckbox label="Luxury" checked={formData.specialization.propertyType.luxury} onChange={() => {}} />
|
||||
<FormCheckbox label="Townhome" checked={formData.specialization.propertyType.townhome} onChange={() => {}} />
|
||||
<FormCheckbox label="Commercial" checked={formData.specialization.propertyType.commercial} onChange={() => {}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Transaction Type */}
|
||||
<div>
|
||||
<h4 className="text-[14px] font-semibold text-[#00293D] font-fractul mb-3">Transaction Type</h4>
|
||||
<div className="space-y-2">
|
||||
<FormCheckbox label="Relocation" checked={formData.specialization.transactionType.relocation} onChange={() => {}} />
|
||||
<FormCheckbox label="Probate" checked={formData.specialization.transactionType.probate} onChange={() => {}} />
|
||||
<FormCheckbox label="Tax Lien" checked={formData.specialization.transactionType.taxLien} onChange={() => {}} />
|
||||
<FormCheckbox label="Traditional" checked={formData.specialization.transactionType.traditional} onChange={() => {}} />
|
||||
<FormCheckbox label="New Construction" checked={formData.specialization.transactionType.newConstruction} onChange={() => {}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Loan Type */}
|
||||
<div>
|
||||
<h4 className="text-[14px] font-semibold text-[#00293D] font-fractul mb-3">Loan Type</h4>
|
||||
<div className="space-y-2">
|
||||
<FormCheckbox label="Conventional" checked={formData.specialization.loanType.conventional} onChange={() => {}} />
|
||||
<FormCheckbox label="FHA" checked={formData.specialization.loanType.fha} onChange={() => {}} />
|
||||
<FormCheckbox label="VA" checked={formData.specialization.loanType.va} onChange={() => {}} />
|
||||
<FormCheckbox label="USDA" checked={formData.specialization.loanType.usda} onChange={() => {}} />
|
||||
<FormCheckbox label="Reverse" checked={formData.specialization.loanType.reverse} onChange={() => {}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Lifestyle Specialties */}
|
||||
<div>
|
||||
<h4 className="text-[14px] font-semibold text-[#00293D] font-fractul mb-3">Lifestyle Specialties</h4>
|
||||
<div className="space-y-2">
|
||||
<FormCheckbox label="Boating" checked={formData.specialization.lifestyleSpecialties.boating} onChange={() => {}} />
|
||||
<FormCheckbox label="Horses" checked={formData.specialization.lifestyleSpecialties.horses} onChange={() => {}} />
|
||||
<FormCheckbox label="RV" checked={formData.specialization.lifestyleSpecialties.rv} onChange={() => {}} />
|
||||
<FormCheckbox label="Automotive" checked={formData.specialization.lifestyleSpecialties.automotive} onChange={() => {}} />
|
||||
<FormCheckbox label="Aviation" checked={formData.specialization.lifestyleSpecialties.aviation} onChange={() => {}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Special Interests & Hobbies */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="hobbies" icon="/assets/icons/hobbies-icon.svg" title="Special Interests & Hobbies">
|
||||
<TagInput
|
||||
tags={formData.hobbies}
|
||||
onChange={(tags) => updateField('hobbies', tags)}
|
||||
placeholder="Add hobby..."
|
||||
/>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Certifications */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="certifications" icon="/assets/icons/certification-icon.svg" title="Professional Info">
|
||||
<p className="text-[12px] font-medium text-[#00293D]/70 font-serif mb-3">Certifications / Designations</p>
|
||||
<div className="space-y-2">
|
||||
{formData.certifications.map((cert, idx) => (
|
||||
<div key={idx} className="p-3 bg-gray-50 rounded-[10px]">
|
||||
<p className="text-[14px] font-semibold text-[#00293D] font-serif">{cert.name}</p>
|
||||
<p className="text-[12px] text-[#00293D]/70 font-serif">{cert.org}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Availability */}
|
||||
<div className="bg-white rounded-[20px] p-6">
|
||||
<FormSection id="availability" icon="/assets/icons/availability-clock-icon.svg" title="Availability">
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<FormSelect
|
||||
label="Availability"
|
||||
value={formData.availability.type}
|
||||
onChange={(value) =>
|
||||
updateField('availability', { ...formData.availability, type: value })
|
||||
}
|
||||
options={[
|
||||
{ value: 'Full Time Weekend', label: 'Full Time Weekend' },
|
||||
{ value: 'Part Time', label: 'Part Time' },
|
||||
{ value: 'Weekdays Only', label: 'Weekdays Only' },
|
||||
]}
|
||||
/>
|
||||
<FormSelect
|
||||
label="Work From Method"
|
||||
value={formData.availability.workFrom}
|
||||
onChange={(value) =>
|
||||
updateField('availability', { ...formData.availability, workFrom: value })
|
||||
}
|
||||
options={[
|
||||
{ value: 'Work from Method', label: 'Work from Method' },
|
||||
{ value: 'Remote', label: 'Remote' },
|
||||
{ value: 'In Office', label: 'In Office' },
|
||||
{ value: 'Hybrid', label: 'Hybrid' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex justify-end gap-4 pb-6">
|
||||
<button
|
||||
onClick={handleCancel}
|
||||
className="px-8 py-3 border border-[#00293D]/20 rounded-full text-[14px] font-semibold font-serif text-[#00293D] hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={handleSave}
|
||||
className="px-8 py-3 bg-[#E58625] rounded-full text-[14px] font-semibold font-serif text-white hover:bg-[#E58625]/90 transition-colors"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user