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:
pradeepkumar
2026-03-20 12:43:23 +05:30
parent f71d47f3b7
commit 64f4234220
4 changed files with 69 additions and 47 deletions

View File

@@ -612,8 +612,8 @@ function ProfilesPageContent() {
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<MobileBackButton label="Back" fallbackHref="/user/dashboard" /> <MobileBackButton label="Back" fallbackHref="/user/dashboard" />
<div className="flex gap-6"> <div className="flex gap-6">
{/* Left Sidebar - hidden on mobile, sticky */} {/* Left Sidebar - hidden on mobile */}
<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"> <div className="hidden lg:block w-[220px] flex-shrink-0">
{/* Listing Type */} {/* Listing Type */}
<div className="mb-6"> <div className="mb-6">
<h2 className="font-fractul font-bold text-[14px] text-[#00293d] mb-3">Listing Type</h2> <h2 className="font-fractul font-bold text-[14px] text-[#00293d] mb-3">Listing Type</h2>
@@ -774,18 +774,18 @@ function ProfilesPageContent() {
</div> </div>
)} )}
{/* Profile Cards - nested scroll matching filter sidebar height */} {/* Profile Cards */}
{!loading && !error && agents.length > 0 && ( {!loading && !error && agents.length > 0 && (
<div className="overflow-y-auto scroll-smooth scrollbar-thin" style={{ maxHeight: 'calc(100vh - 220px)' }}> <div className="space-y-4">
<div className="space-y-4 pb-4">
{agents.map((profile) => ( {agents.map((profile) => (
<ProfileCard key={profile.id} profile={profile} resolvedAvatarUrl={avatarUrls[profile.id]} /> <ProfileCard key={profile.id} profile={profile} resolvedAvatarUrl={avatarUrls[profile.id]} />
))} ))}
</div> </div>
)}
{/* Pagination - sticky at bottom of scroll area */} {/* Pagination */}
{totalPages > 1 && ( {!loading && !error && totalPages > 1 && (
<div className="flex justify-center items-center gap-2 py-3 flex-wrap sticky bottom-0 bg-white/95 backdrop-blur-sm"> <div className="flex justify-center items-center gap-2 mt-8 flex-wrap">
<button <button
onClick={() => setCurrentPage(p => Math.max(1, p - 1))} onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
disabled={currentPage === 1} disabled={currentPage === 1}
@@ -806,8 +806,6 @@ function ProfilesPageContent() {
</div> </div>
)} )}
</div> </div>
)}
</div>
</div> </div>
</div> </div>

View File

@@ -6,6 +6,7 @@ import { useState, useEffect } from 'react';
import { CommonHeader } from '@/components/layout/CommonHeader'; import { CommonHeader } from '@/components/layout/CommonHeader';
import { Footer } from '@/components/layout/Footer'; import { Footer } from '@/components/layout/Footer';
import { cmsService } from '@/services/cms.service'; import { cmsService } from '@/services/cms.service';
import api from '@/services/api';
interface ContactDetails { interface ContactDetails {
title: string; title: string;
@@ -55,6 +56,8 @@ export default function ContactPage() {
const [contactDetails, setContactDetails] = useState<ContactDetails>(defaultContactDetails); const [contactDetails, setContactDetails] = useState<ContactDetails>(defaultContactDetails);
const [cta, setCta] = useState<ContactCta>(defaultCta); const [cta, setCta] = useState<ContactCta>(defaultCta);
const [isSubmitting, setIsSubmitting] = useState(false);
const [submitStatus, setSubmitStatus] = useState<'idle' | 'success' | 'error'>('idle');
useEffect(() => { useEffect(() => {
const loadCms = async () => { const loadCms = async () => {
@@ -73,10 +76,27 @@ export default function ContactPage() {
setFormData(prev => ({ ...prev, [name]: value })); setFormData(prev => ({ ...prev, [name]: value }));
}; };
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
// Handle form submission if (!formData.name.trim() || !formData.email.trim() || !formData.message.trim()) return;
console.log('Form submitted:', formData);
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 = () => { const handleCancel = () => {
@@ -188,19 +208,31 @@ export default function ContactPage() {
</div> </div>
{/* Buttons */} {/* 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"> <div className="flex items-center justify-center gap-4 pt-4">
<button <button
type="button" type="button"
onClick={handleCancel} 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 Cancel
</button> </button>
<button <button
type="submit" 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> </button>
</div> </div>
</form> </form>

View File

@@ -311,17 +311,8 @@ export function ProfileSettingsForm({
}); });
} }
// Update session name without causing a page refresh
try {
const fullName = `${formData.firstName} ${formData.lastName}`.trim();
await updateSession({
user: { name: fullName },
});
} catch {
// Session update can fail silently - profile is already saved
}
// Dispatch event to notify header and other components to refresh profile data // Dispatch event to notify header and other components to refresh profile data
// (Don't call updateSession as it can trigger a full page reload in next-auth v5)
window.dispatchEvent(new Event('profile-updated')); window.dispatchEvent(new Event('profile-updated'));
if (onSave) { if (onSave) {

View File

@@ -110,6 +110,7 @@ const publicEndpoints = [
'/agent-types', '/agent-types',
'/agents', '/agents',
'/cms', '/cms',
'/contact',
'/profile-fields/filterable', '/profile-fields/filterable',
'/stripe/plans', '/stripe/plans',
'/upload/presigned-download-url', '/upload/presigned-download-url',