feat: Add agent network feature with invitation cards and sidebar, and revamp agent edit availability UI to include office hours and contact methods.
This commit is contained in:
@@ -8,13 +8,19 @@ interface FormCheckboxProps {
|
|||||||
|
|
||||||
export function FormCheckbox({ label, checked, onChange }: FormCheckboxProps) {
|
export function FormCheckbox({ label, checked, onChange }: FormCheckboxProps) {
|
||||||
return (
|
return (
|
||||||
<label className="flex items-center gap-2 cursor-pointer">
|
<label className="flex items-center gap-3 cursor-pointer">
|
||||||
<input
|
<div
|
||||||
type="checkbox"
|
onClick={() => onChange(!checked)}
|
||||||
checked={checked}
|
className={`w-[22px] h-[22px] rounded-[5px] border border-[#00293D]/20 flex items-center justify-center transition-colors ${
|
||||||
onChange={(e) => onChange(e.target.checked)}
|
checked ? 'bg-[#E58625] border-[#E58625]' : 'bg-white'
|
||||||
className="w-4 h-4 rounded border-[#00293D]/30 text-[#E58625] focus:ring-[#E58625] focus:ring-offset-0 accent-[#E58625]"
|
}`}
|
||||||
/>
|
>
|
||||||
|
{checked && (
|
||||||
|
<svg width="12" height="10" viewBox="0 0 12 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1 5L4.5 8.5L11 1" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<span className="text-[14px] font-serif text-[#00293D]">{label}</span>
|
<span className="text-[14px] font-serif text-[#00293D]">{label}</span>
|
||||||
</label>
|
</label>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -100,8 +100,11 @@ const initialFormData = {
|
|||||||
{ name: 'Certified Residential Specialist (CRS)', org: 'Residential Real Estate Council' },
|
{ name: 'Certified Residential Specialist (CRS)', org: 'Residential Real Estate Council' },
|
||||||
],
|
],
|
||||||
availability: {
|
availability: {
|
||||||
type: 'Full Time Weekend',
|
officeHours: ['MON-FRI 8am-6pm', 'Sat 10am-2pm'],
|
||||||
workFrom: 'Work from Method',
|
contactMethod: {
|
||||||
|
email: true,
|
||||||
|
call: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,6 +113,7 @@ export default function EditProfilePage() {
|
|||||||
const [formData, setFormData] = useState(initialFormData);
|
const [formData, setFormData] = useState(initialFormData);
|
||||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const [stateInput, setStateInput] = useState('');
|
const [stateInput, setStateInput] = useState('');
|
||||||
|
const [officeHoursInput, setOfficeHoursInput] = useState('');
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
router.push('/agent/dashboard');
|
router.push('/agent/dashboard');
|
||||||
@@ -140,6 +144,31 @@ export default function EditProfilePage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAddOfficeHours = (value: string) => {
|
||||||
|
const trimmedValue = value.trim();
|
||||||
|
if (trimmedValue && !formData.availability.officeHours.includes(trimmedValue)) {
|
||||||
|
updateField('availability', {
|
||||||
|
...formData.availability,
|
||||||
|
officeHours: [...formData.availability.officeHours, trimmedValue],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setOfficeHoursInput('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOfficeHoursKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ',') {
|
||||||
|
e.preventDefault();
|
||||||
|
handleAddOfficeHours(officeHoursInput);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveOfficeHours = (hour: string) => {
|
||||||
|
updateField('availability', {
|
||||||
|
...formData.availability,
|
||||||
|
officeHours: formData.availability.officeHours.filter((h) => h !== hour),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-6 h-[calc(100vh-180px)]">
|
<div className="flex gap-6 h-[calc(100vh-180px)]">
|
||||||
{/* Left Sidebar - Quick Links */}
|
{/* Left Sidebar - Quick Links */}
|
||||||
@@ -596,32 +625,66 @@ export default function EditProfilePage() {
|
|||||||
{/* Availability */}
|
{/* Availability */}
|
||||||
<div className="bg-white rounded-[15px] border border-[#00293D]/20 shadow-[0px_10px_20px_#D9D9D9] p-6">
|
<div className="bg-white rounded-[15px] border border-[#00293D]/20 shadow-[0px_10px_20px_#D9D9D9] p-6">
|
||||||
<FormSection id="availability" icon="/assets/icons/availability-clock-icon.svg" title="Availability">
|
<FormSection id="availability" icon="/assets/icons/availability-clock-icon.svg" title="Availability">
|
||||||
<div className="flex flex-col md:flex-row gap-4">
|
<div className="flex flex-col lg:flex-row gap-6">
|
||||||
<FormSelect
|
{/* Typical Office Hours */}
|
||||||
label="Availability"
|
<div className="flex-1">
|
||||||
value={formData.availability.type}
|
<label className="block text-[14px] font-semibold text-[#00293D] font-serif mb-2">
|
||||||
onChange={(value) =>
|
Typical Office Hours
|
||||||
updateField('availability', { ...formData.availability, type: value })
|
</label>
|
||||||
}
|
<div className="flex items-center gap-2 h-[40px] px-4 border border-[#00293D]/20 rounded-[15px]">
|
||||||
options={[
|
{formData.availability.officeHours.map((hour) => (
|
||||||
{ value: 'Full Time Weekend', label: 'Full Time Weekend' },
|
<span
|
||||||
{ value: 'Part Time', label: 'Part Time' },
|
key={hour}
|
||||||
{ value: 'Weekdays Only', label: 'Weekdays Only' },
|
className="inline-flex items-center gap-1 text-[14px] font-semibold font-serif text-[#00293D]"
|
||||||
]}
|
>
|
||||||
|
{hour}
|
||||||
|
<button
|
||||||
|
onClick={() => handleRemoveOfficeHours(hour)}
|
||||||
|
className="text-[#00293d]/50 hover:text-[#E58625] transition-colors ml-1"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={officeHoursInput}
|
||||||
|
onChange={(e) => setOfficeHoursInput(e.target.value)}
|
||||||
|
onKeyDown={handleOfficeHoursKeyDown}
|
||||||
|
placeholder={formData.availability.officeHours.length === 0 ? "Add office hours" : ""}
|
||||||
|
className="flex-1 h-full text-[14px] font-serif text-[#00293D] placeholder:text-[#00293D]/40 focus:outline-none bg-transparent"
|
||||||
/>
|
/>
|
||||||
<FormSelect
|
</div>
|
||||||
label="Work From Method"
|
</div>
|
||||||
value={formData.availability.workFrom}
|
|
||||||
onChange={(value) =>
|
{/* Preferred Contact Method */}
|
||||||
updateField('availability', { ...formData.availability, workFrom: value })
|
<div className="lg:w-[250px]">
|
||||||
|
<label className="block text-[14px] font-semibold text-[#00293D] font-serif mb-2">
|
||||||
|
Preferred Contact Method
|
||||||
|
</label>
|
||||||
|
<div className="flex items-center gap-6 h-[40px]">
|
||||||
|
<FormCheckbox
|
||||||
|
label="Email"
|
||||||
|
checked={formData.availability.contactMethod.email}
|
||||||
|
onChange={(checked) =>
|
||||||
|
updateField('availability', {
|
||||||
|
...formData.availability,
|
||||||
|
contactMethod: { ...formData.availability.contactMethod, email: checked },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
options={[
|
|
||||||
{ value: 'Work from Method', label: 'Work from Method' },
|
|
||||||
{ value: 'Remote', label: 'Remote' },
|
|
||||||
{ value: 'In Office', label: 'In Office' },
|
|
||||||
{ value: 'Hybrid', label: 'Hybrid' },
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
|
<FormCheckbox
|
||||||
|
label="Call"
|
||||||
|
checked={formData.availability.contactMethod.call}
|
||||||
|
onChange={(checked) =>
|
||||||
|
updateField('availability', {
|
||||||
|
...formData.availability,
|
||||||
|
contactMethod: { ...formData.availability.contactMethod, call: checked },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user