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:
pradeepkumar
2026-01-18 23:13:56 +05:30
parent 7d5de4aa93
commit 74fe46335f
2 changed files with 104 additions and 35 deletions

View File

@@ -8,13 +8,19 @@ interface FormCheckboxProps {
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]"
/>
<label className="flex items-center gap-3 cursor-pointer">
<div
onClick={() => onChange(!checked)}
className={`w-[22px] h-[22px] rounded-[5px] border border-[#00293D]/20 flex items-center justify-center transition-colors ${
checked ? 'bg-[#E58625] border-[#E58625]' : 'bg-white'
}`}
>
{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>
</label>
);

View File

@@ -100,8 +100,11 @@ const initialFormData = {
{ name: 'Certified Residential Specialist (CRS)', org: 'Residential Real Estate Council' },
],
availability: {
type: 'Full Time Weekend',
workFrom: 'Work from Method',
officeHours: ['MON-FRI 8am-6pm', 'Sat 10am-2pm'],
contactMethod: {
email: true,
call: false,
},
},
};
@@ -110,6 +113,7 @@ export default function EditProfilePage() {
const [formData, setFormData] = useState(initialFormData);
const scrollContainerRef = useRef<HTMLDivElement>(null);
const [stateInput, setStateInput] = useState('');
const [officeHoursInput, setOfficeHoursInput] = useState('');
const handleCancel = () => {
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 (
<div className="flex gap-6 h-[calc(100vh-180px)]">
{/* Left Sidebar - Quick Links */}
@@ -596,32 +625,66 @@ export default function EditProfilePage() {
{/* Availability */}
<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">
<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 className="flex flex-col lg:flex-row gap-6">
{/* Typical Office Hours */}
<div className="flex-1">
<label className="block text-[14px] font-semibold text-[#00293D] font-serif mb-2">
Typical Office Hours
</label>
<div className="flex items-center gap-2 h-[40px] px-4 border border-[#00293D]/20 rounded-[15px]">
{formData.availability.officeHours.map((hour) => (
<span
key={hour}
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"
/>
</div>
</div>
{/* Preferred Contact Method */}
<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 },
})
}
/>
<FormCheckbox
label="Call"
checked={formData.availability.contactMethod.call}
onChange={(checked) =>
updateField('availability', {
...formData.availability,
contactMethod: { ...formData.availability.contactMethod, call: checked },
})
}
/>
</div>
</div>
</div>
</FormSection>
</div>