242 lines
14 KiB
JavaScript
242 lines
14 KiB
JavaScript
import React, { useState } from 'react';
|
|
import { Head, useForm, Link } from '@inertiajs/react';
|
|
import EmployerLayout from '../../Layouts/EmployerLayout';
|
|
import { useTranslation } from '../../lib/LanguageContext';
|
|
import {
|
|
User,
|
|
Mail,
|
|
Phone,
|
|
MapPin,
|
|
Home,
|
|
Camera,
|
|
Save,
|
|
XCircle,
|
|
ArrowLeft,
|
|
Compass
|
|
} from 'lucide-react';
|
|
import { toast } from 'sonner';
|
|
|
|
export default function ProfileEdit({ employerProfile }) {
|
|
const { t } = useTranslation();
|
|
|
|
const { data, setData, post, processing, errors } = useForm({
|
|
name: employerProfile?.name || '',
|
|
email: employerProfile?.email || '',
|
|
phone: employerProfile?.phone || '',
|
|
address: employerProfile?.address || '',
|
|
property_type: employerProfile?.property_type || '',
|
|
profile_photo: null,
|
|
});
|
|
|
|
const [photoPreview, setPhotoPreview] = useState(employerProfile?.profile_photo_url || null);
|
|
|
|
const handlePhotoChange = (e) => {
|
|
const file = e.target.files[0];
|
|
if (file) {
|
|
setData('profile_photo', file);
|
|
setPhotoPreview(URL.createObjectURL(file));
|
|
}
|
|
};
|
|
|
|
const handleSubmit = (e) => {
|
|
e.preventDefault();
|
|
|
|
post('/employer/profile/update', {
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
toast.success(t('profile_updated_successfully', 'Profile updated successfully!'));
|
|
},
|
|
onError: (errs) => {
|
|
toast.error(t('profile_update_failed', 'Failed to update profile'), {
|
|
description: Object.values(errs)[0] || t('check_form_fields', 'Please check the form fields.')
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
return (
|
|
<EmployerLayout title={t('edit_profile', 'Edit Profile')}>
|
|
<Head title={`${t('edit_profile', 'Edit Profile')} - ${t('employer_portal', 'Employer Portal')}`} />
|
|
|
|
<div className="max-w-3xl mx-auto pb-16 space-y-8 select-none animate-in fade-in duration-500">
|
|
{/* Back Link */}
|
|
<div className="flex items-center">
|
|
<Link
|
|
href="/employer/profile"
|
|
className="text-slate-450 hover:text-[#185FA5] flex items-center gap-2 text-xs font-black uppercase tracking-wider transition-colors group"
|
|
>
|
|
<ArrowLeft className="w-4 h-4 transition-transform group-hover:-translate-x-1" />
|
|
<span>{t('back_to_profile', 'Back to Profile')}</span>
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Edit Form Card */}
|
|
<div className="bg-white rounded-3xl border border-slate-200 shadow-sm overflow-hidden">
|
|
{/* Header Banner Accent */}
|
|
<div className="h-28 bg-gradient-to-r from-[#185FA5] to-[#2d7ad6] relative">
|
|
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top_right,rgba(255,255,255,0.1),transparent)] pointer-events-none" />
|
|
<div className="absolute -bottom-6 left-8 flex items-center gap-2 text-white/5 select-none">
|
|
<Compass className="w-20 h-20 stroke-[0.5]" />
|
|
</div>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="px-8 pb-8 pt-4 space-y-8 relative">
|
|
|
|
{/* Profile Photo Floating Container */}
|
|
<div className="flex flex-col sm:flex-row items-center gap-6 p-6 bg-slate-50 rounded-2xl border border-slate-150 -mt-14 relative z-10">
|
|
<div className="relative group">
|
|
<div className="w-20 h-20 rounded-2xl bg-white p-1 border border-slate-200 shadow-md overflow-hidden">
|
|
{photoPreview ? (
|
|
<img
|
|
src={photoPreview}
|
|
alt="Preview"
|
|
className="w-full h-full rounded-xl object-cover"
|
|
/>
|
|
) : (
|
|
<div className="w-full h-full rounded-xl bg-[#185FA5]/10 text-[#185FA5] flex items-center justify-center font-black text-3xl">
|
|
{data.name?.charAt(0) || 'U'}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<label className="absolute -bottom-2 -right-2 p-2 bg-[#185FA5] text-white rounded-xl shadow-lg hover:bg-[#144f8a] cursor-pointer transition-colors border border-white">
|
|
<Camera className="w-4 h-4" />
|
|
<input
|
|
type="file"
|
|
accept="image/*"
|
|
onChange={handlePhotoChange}
|
|
className="hidden"
|
|
/>
|
|
</label>
|
|
</div>
|
|
<div className="space-y-1 text-center sm:text-left flex-1">
|
|
<h4 className="text-xs font-black text-slate-800 uppercase tracking-wide">{t('profile_avatar', 'Profile Photo')}</h4>
|
|
<p className="text-[10px] text-slate-400 font-bold uppercase tracking-wider">
|
|
{t('avatar_rules', 'Upload high-resolution avatar. Max 10MB.')}
|
|
</p>
|
|
</div>
|
|
{errors.profile_photo && (
|
|
<p className="text-xs text-red-500 mt-1">{errors.profile_photo}</p>
|
|
)}
|
|
</div>
|
|
|
|
{/* Fields Grid */}
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6 pt-4">
|
|
{/* Full Name */}
|
|
<div className="space-y-2">
|
|
<label className="text-xs font-black text-slate-500 uppercase tracking-tighter ml-1">
|
|
{t('full_name', 'Full Name')}
|
|
</label>
|
|
<div className="relative">
|
|
<User className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
|
|
<input
|
|
type="text"
|
|
value={data.name}
|
|
onChange={(e) => setData('name', e.target.value)}
|
|
className="w-full pl-12 pr-4 py-3 bg-slate-50 border border-slate-150 rounded-2xl text-xs font-bold focus:ring-2 focus:ring-blue-100 focus:bg-white transition-all outline-none"
|
|
required
|
|
/>
|
|
</div>
|
|
{errors.name && <p className="text-xs text-red-500 mt-1">{errors.name}</p>}
|
|
</div>
|
|
|
|
{/* Email */}
|
|
<div className="space-y-2">
|
|
<label className="text-xs font-black text-slate-500 uppercase tracking-tighter ml-1">
|
|
{t('email_address', 'Email Address')}
|
|
</label>
|
|
<div className="relative">
|
|
<Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
|
|
<input
|
|
type="email"
|
|
value={data.email}
|
|
onChange={(e) => setData('email', e.target.value)}
|
|
className="w-full pl-12 pr-4 py-3 bg-slate-50 border border-slate-150 rounded-2xl text-xs font-bold focus:ring-2 focus:ring-blue-100 focus:bg-white transition-all outline-none"
|
|
required
|
|
/>
|
|
</div>
|
|
{errors.email && <p className="text-xs text-red-500 mt-1">{errors.email}</p>}
|
|
</div>
|
|
|
|
{/* Phone */}
|
|
<div className="space-y-2">
|
|
<label className="text-xs font-black text-slate-500 uppercase tracking-tighter ml-1">
|
|
{t('phone_number', 'Phone Number')}
|
|
</label>
|
|
<div className="relative">
|
|
<Phone className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
|
|
<input
|
|
type="text"
|
|
value={data.phone}
|
|
onChange={(e) => setData('phone', e.target.value)}
|
|
className="w-full pl-12 pr-4 py-3 bg-slate-50 border border-slate-150 rounded-2xl text-xs font-bold focus:ring-2 focus:ring-blue-100 focus:bg-white transition-all outline-none"
|
|
required
|
|
/>
|
|
</div>
|
|
{errors.phone && <p className="text-xs text-red-500 mt-1">{errors.phone}</p>}
|
|
</div>
|
|
|
|
{/* Property Type */}
|
|
<div className="space-y-2">
|
|
<label className="text-xs font-black text-slate-500 uppercase tracking-tighter ml-1">
|
|
{t('property_type', 'Property Type')}
|
|
</label>
|
|
<div className="relative">
|
|
<Home className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
|
|
<select
|
|
value={data.property_type}
|
|
onChange={(e) => setData('property_type', e.target.value)}
|
|
className="w-full pl-12 pr-4 py-3 bg-slate-50 border border-slate-150 rounded-2xl text-xs font-bold focus:ring-2 focus:ring-blue-100 focus:bg-white transition-all outline-none cursor-pointer"
|
|
>
|
|
<option value="">{t('select_property_type', 'Select Property Type')}</option>
|
|
<option value="Villa">{t('villa', 'Villa')}</option>
|
|
<option value="Apartment">{t('apartment', 'Apartment')}</option>
|
|
<option value="Penthouse">{t('penthouse', 'Penthouse')}</option>
|
|
<option value="Townhouse">{t('townhouse', 'Townhouse')}</option>
|
|
</select>
|
|
</div>
|
|
{errors.property_type && <p className="text-xs text-red-500 mt-1">{errors.property_type}</p>}
|
|
</div>
|
|
|
|
{/* Address */}
|
|
<div className="space-y-2 sm:col-span-2">
|
|
<label className="text-xs font-black text-slate-500 uppercase tracking-tighter ml-1">
|
|
{t('address', 'Address')}
|
|
</label>
|
|
<div className="relative">
|
|
<MapPin className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
|
|
<input
|
|
type="text"
|
|
value={data.address}
|
|
onChange={(e) => setData('address', e.target.value)}
|
|
className="w-full pl-12 pr-4 py-3 bg-slate-50 border border-slate-150 rounded-2xl text-xs font-bold focus:ring-2 focus:ring-blue-100 focus:bg-white transition-all outline-none"
|
|
/>
|
|
</div>
|
|
{errors.address && <p className="text-xs text-red-500 mt-1">{errors.address}</p>}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Form Action Controls */}
|
|
<div className="pt-6 border-t border-slate-100 flex flex-col sm:flex-row items-center justify-end gap-4">
|
|
<Link
|
|
href="/employer/profile"
|
|
className="w-full sm:w-auto px-6 py-3.5 border border-slate-200 hover:bg-slate-50 text-slate-650 rounded-2xl text-xs font-black uppercase tracking-wider text-center transition-colors outline-none"
|
|
>
|
|
{t('cancel', 'Cancel')}
|
|
</Link>
|
|
|
|
<button
|
|
type="submit"
|
|
disabled={processing}
|
|
className="w-full sm:w-auto bg-[#185FA5] hover:bg-[#144f8a] text-white px-8 py-3.5 rounded-2xl text-xs font-black uppercase tracking-wider flex items-center justify-center space-x-2 transition-all shadow-md shadow-blue-200/50"
|
|
>
|
|
<Save className="w-4 h-4" />
|
|
<span>{t('save_changes', 'Save Changes')}</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</EmployerLayout>
|
|
);
|
|
}
|