feat: Implement contact form submission with API integration and status feedback, refactor user profiles page layout and scrolling, and remove updateSession call from profile settings.
This commit is contained in:
@@ -612,8 +612,8 @@ function ProfilesPageContent() {
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
<MobileBackButton label="Back" fallbackHref="/user/dashboard" />
|
||||
<div className="flex gap-6">
|
||||
{/* Left Sidebar - hidden on mobile, sticky */}
|
||||
<div className="hidden lg:block w-[220px] flex-shrink-0 self-start sticky top-6 max-h-[calc(100vh-48px)] overflow-y-auto scrollbar-thin">
|
||||
{/* Left Sidebar - hidden on mobile */}
|
||||
<div className="hidden lg:block w-[220px] flex-shrink-0">
|
||||
{/* Listing Type */}
|
||||
<div className="mb-6">
|
||||
<h2 className="font-fractul font-bold text-[14px] text-[#00293d] mb-3">Listing Type</h2>
|
||||
@@ -774,37 +774,35 @@ function ProfilesPageContent() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Profile Cards - nested scroll matching filter sidebar height */}
|
||||
{/* Profile Cards */}
|
||||
{!loading && !error && agents.length > 0 && (
|
||||
<div className="overflow-y-auto scroll-smooth scrollbar-thin" style={{ maxHeight: 'calc(100vh - 220px)' }}>
|
||||
<div className="space-y-4 pb-4">
|
||||
{agents.map((profile) => (
|
||||
<ProfileCard key={profile.id} profile={profile} resolvedAvatarUrl={avatarUrls[profile.id]} />
|
||||
))}
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
{agents.map((profile) => (
|
||||
<ProfileCard key={profile.id} profile={profile} resolvedAvatarUrl={avatarUrls[profile.id]} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Pagination - sticky at bottom of scroll area */}
|
||||
{totalPages > 1 && (
|
||||
<div className="flex justify-center items-center gap-2 py-3 flex-wrap sticky bottom-0 bg-white/95 backdrop-blur-sm">
|
||||
<button
|
||||
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
|
||||
disabled={currentPage === 1}
|
||||
className="px-4 py-2 rounded-[10px] border border-[#00293d]/20 font-serif text-[13px] text-[#00293d] disabled:opacity-50 disabled:cursor-not-allowed hover:border-[#00293d]/40 transition-colors"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<span className="px-4 py-2 font-serif text-[13px] text-[#00293d]">
|
||||
Page {currentPage} of {totalPages}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
|
||||
disabled={currentPage === totalPages}
|
||||
className="px-4 py-2 rounded-[10px] border border-[#00293d]/20 font-serif text-[13px] text-[#00293d] disabled:opacity-50 disabled:cursor-not-allowed hover:border-[#00293d]/40 transition-colors"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{/* Pagination */}
|
||||
{!loading && !error && totalPages > 1 && (
|
||||
<div className="flex justify-center items-center gap-2 mt-8 flex-wrap">
|
||||
<button
|
||||
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
|
||||
disabled={currentPage === 1}
|
||||
className="px-4 py-2 rounded-[10px] border border-[#00293d]/20 font-serif text-[13px] text-[#00293d] disabled:opacity-50 disabled:cursor-not-allowed hover:border-[#00293d]/40 transition-colors"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<span className="px-4 py-2 font-serif text-[13px] text-[#00293d]">
|
||||
Page {currentPage} of {totalPages}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
|
||||
disabled={currentPage === totalPages}
|
||||
className="px-4 py-2 rounded-[10px] border border-[#00293d]/20 font-serif text-[13px] text-[#00293d] disabled:opacity-50 disabled:cursor-not-allowed hover:border-[#00293d]/40 transition-colors"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useState, useEffect } from 'react';
|
||||
import { CommonHeader } from '@/components/layout/CommonHeader';
|
||||
import { Footer } from '@/components/layout/Footer';
|
||||
import { cmsService } from '@/services/cms.service';
|
||||
import api from '@/services/api';
|
||||
|
||||
interface ContactDetails {
|
||||
title: string;
|
||||
@@ -55,6 +56,8 @@ export default function ContactPage() {
|
||||
|
||||
const [contactDetails, setContactDetails] = useState<ContactDetails>(defaultContactDetails);
|
||||
const [cta, setCta] = useState<ContactCta>(defaultCta);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [submitStatus, setSubmitStatus] = useState<'idle' | 'success' | 'error'>('idle');
|
||||
|
||||
useEffect(() => {
|
||||
const loadCms = async () => {
|
||||
@@ -73,10 +76,27 @@ export default function ContactPage() {
|
||||
setFormData(prev => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
// Handle form submission
|
||||
console.log('Form submitted:', formData);
|
||||
if (!formData.name.trim() || !formData.email.trim() || !formData.message.trim()) return;
|
||||
|
||||
setIsSubmitting(true);
|
||||
setSubmitStatus('idle');
|
||||
try {
|
||||
await api.post('/contact', {
|
||||
name: formData.name.trim(),
|
||||
email: formData.email.trim(),
|
||||
phone: formData.phone.trim() || undefined,
|
||||
message: formData.message.trim(),
|
||||
});
|
||||
setSubmitStatus('success');
|
||||
setFormData({ name: '', phone: '', email: '', message: '' });
|
||||
setTimeout(() => setSubmitStatus('idle'), 5000);
|
||||
} catch {
|
||||
setSubmitStatus('error');
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@@ -188,19 +208,31 @@ export default function ContactPage() {
|
||||
</div>
|
||||
|
||||
{/* Buttons */}
|
||||
{submitStatus === 'success' && (
|
||||
<div className="bg-green-50 border border-green-200 rounded-[15px] p-3 text-center">
|
||||
<p className="font-serif text-[14px] text-green-700">Message sent successfully! We'll get back to you shortly.</p>
|
||||
</div>
|
||||
)}
|
||||
{submitStatus === 'error' && (
|
||||
<div className="bg-red-50 border border-red-200 rounded-[15px] p-3 text-center">
|
||||
<p className="font-serif text-[14px] text-red-700">Failed to send message. Please try again.</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center justify-center gap-4 pt-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCancel}
|
||||
className="w-[163px] h-[46px] border border-[#00293d]/10 rounded-[15px] font-fractul font-bold text-[14px] text-[#00293d] hover:bg-gray-50 transition-colors"
|
||||
disabled={isSubmitting}
|
||||
className="w-[163px] h-[46px] border border-[#00293d]/10 rounded-[15px] font-fractul font-bold text-[14px] text-[#00293d] hover:bg-gray-50 transition-colors disabled:opacity-50"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-[163px] h-[46px] bg-[#e58625] rounded-[15px] font-fractul font-bold text-[14px] text-[#00293d] hover:bg-[#d47720] transition-colors"
|
||||
disabled={isSubmitting}
|
||||
className="w-[163px] h-[46px] bg-[#e58625] rounded-[15px] font-fractul font-bold text-[14px] text-[#00293d] hover:bg-[#d47720] transition-colors disabled:opacity-50"
|
||||
>
|
||||
Send Message
|
||||
{isSubmitting ? 'Sending...' : 'Send Message'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user