ifixkart-storefront/app/feedback/page.tsx

280 lines
11 KiB
TypeScript

'use client';
import React, { FormEvent, useEffect, useMemo, useState } from 'react';
import Link from 'next/link';
import { CheckCircle2, Lightbulb, MessageSquare, Star, TriangleAlert } from 'lucide-react';
import { AnnouncementBar } from '@/layout/AnnouncementBar';
import { Header } from '@/layout/Header';
import { Navbar } from '@/layout/Navbar';
import { Footer } from '@/layout/Footer';
import { StickyHeaderSpacer } from '@/components/StickyHeaderSpacer';
import { FloatingButtons } from '@/components/FloatingButtons';
import {
storefrontService,
type FooterInfo,
type StorefrontSettings,
MOCK_FOOTER_INFO,
} from '@/services/api/storefrontService';
import { buildFeedbackPage } from '@/lib/feedbackContent';
const HIGHLIGHT_ICONS = {
idea: Lightbulb,
issue: TriangleAlert,
praise: MessageSquare,
} as const;
const fieldClass =
'w-full px-3 py-2.5 bg-white border border-[#e5e5e5] rounded-lg text-[13px] text-[#222] outline-none focus:border-primary transition-colors';
const labelClass = 'block text-[12px] font-bold text-[#1E293B] mb-1.5';
export default function FeedbackPage() {
const [footer, setFooter] = useState<FooterInfo>(MOCK_FOOTER_INFO);
const [settings, setSettings] = useState<StorefrontSettings>({ store_name: 'iFixKart' });
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [topic, setTopic] = useState('suggestion');
const [orderNo, setOrderNo] = useState('');
const [rating, setRating] = useState(0);
const [message, setMessage] = useState('');
const [submitted, setSubmitted] = useState(false);
useEffect(() => {
let cancelled = false;
Promise.all([
storefrontService.getFooterInfo(),
storefrontService.getSettings(),
]).then(([info, store]) => {
if (cancelled) return;
if (info) setFooter(info);
if (store) setSettings(store);
});
return () => {
cancelled = true;
};
}, []);
const storeName = settings.store_name || 'iFixKart';
const supportEmail = footer.email || 'support@ifixkart.com';
const doc = useMemo(() => buildFeedbackPage(storeName), [storeName]);
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
const topicLabel = doc.topics.find((t) => t.id === topic)?.label || topic;
const body = [
`Name: ${name}`,
`Email: ${email}`,
`Topic: ${topicLabel}`,
orderNo ? `Order / job: ${orderNo}` : '',
rating ? `Rating: ${rating} / 5` : '',
'',
message,
]
.filter((line) => line !== '')
.join('\n');
const href = `mailto:${supportEmail}?subject=${encodeURIComponent(
`${storeName} feedback — ${topicLabel}`
)}&body=${encodeURIComponent(body)}`;
window.location.href = href;
setSubmitted(true);
};
return (
<div className="min-h-screen bg-[#F8F9FB] text-[#1E293B] flex flex-col font-sans">
<AnnouncementBar />
<Header />
<StickyHeaderSpacer />
<Navbar />
<main className="flex-grow py-10 pb-20">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-[900px]">
<h1 className="text-[28px] md:text-[32px] font-bold text-[#1E293B]">
{doc.heading}
</h1>
<p className="text-[14px] text-gray-500 mt-2 max-w-2xl">{doc.intro}</p>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 mt-8">
{doc.highlights.map((item) => {
const Icon =
HIGHLIGHT_ICONS[item.id as keyof typeof HIGHLIGHT_ICONS] || MessageSquare;
return (
<div
key={item.id}
className="bg-white border border-gray-200 rounded-xl p-5"
>
<div className="w-10 h-10 rounded-lg bg-primary/10 text-primary flex items-center justify-center mb-3">
<Icon className="w-5 h-5" />
</div>
<h2 className="text-[16px] font-bold text-[#1E293B]">{item.title}</h2>
<p className="text-[13px] text-gray-500 mt-1 leading-relaxed">
{item.detail}
</p>
</div>
);
})}
</div>
<article className="mt-8 bg-white border border-gray-200 rounded-xl overflow-hidden">
<div className="p-6 md:p-8">
{submitted ? (
<div className="py-6 text-center">
<CheckCircle2 className="w-10 h-10 text-primary mx-auto mb-3" />
<h2 className="text-[20px] font-bold text-[#1E293B]">Thanks for the feedback</h2>
<p className="text-[14px] text-gray-600 mt-2 max-w-md mx-auto leading-relaxed">
Your mail app should open with the message ready to send to {supportEmail}.
If it did not, copy your note and email us directly.
</p>
<button
type="button"
onClick={() => {
setSubmitted(false);
setMessage('');
}}
className="mt-6 text-[13px] font-semibold text-primary hover:underline cursor-pointer"
>
Send another message
</button>
</div>
) : (
<form onSubmit={handleSubmit} className="space-y-4">
<h2 className="text-[16px] font-bold text-[#1E293B] mb-1">Send a message</h2>
<p className="text-[13px] text-gray-500 mb-4">
Fields marked with * are required.
</p>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label htmlFor="fb-name" className={labelClass}>
Name *
</label>
<input
id="fb-name"
required
value={name}
onChange={(e) => setName(e.target.value)}
className={fieldClass}
autoComplete="name"
/>
</div>
<div>
<label htmlFor="fb-email" className={labelClass}>
Email *
</label>
<input
id="fb-email"
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
className={fieldClass}
autoComplete="email"
/>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label htmlFor="fb-topic" className={labelClass}>
Topic *
</label>
<select
id="fb-topic"
required
value={topic}
onChange={(e) => setTopic(e.target.value)}
className={`${fieldClass} cursor-pointer`}
>
{doc.topics.map((t) => (
<option key={t.id} value={t.id}>
{t.label}
</option>
))}
</select>
</div>
<div>
<label htmlFor="fb-order" className={labelClass}>
Order or job ID
</label>
<input
id="fb-order"
value={orderNo}
onChange={(e) => setOrderNo(e.target.value)}
className={fieldClass}
placeholder="Optional"
/>
</div>
</div>
<div>
<p className={labelClass}>How was your experience?</p>
<div className="flex items-center gap-1">
{[1, 2, 3, 4, 5].map((stars) => (
<button
key={stars}
type="button"
aria-label={`${stars} star${stars === 1 ? '' : 's'}`}
onClick={() => setRating(rating === stars ? 0 : stars)}
className="p-0.5 cursor-pointer"
>
<Star
size={22}
className={
stars <= rating
? 'fill-amber-400 text-amber-400'
: 'text-gray-200'
}
/>
</button>
))}
</div>
</div>
<div>
<label htmlFor="fb-message" className={labelClass}>
Message *
</label>
<textarea
id="fb-message"
required
rows={6}
value={message}
onChange={(e) => setMessage(e.target.value)}
className={`${fieldClass} resize-y min-h-[140px]`}
placeholder="Tell us what happened or what we should improve."
/>
</div>
<button
type="submit"
className="w-full sm:w-auto px-6 py-3 bg-primary text-white text-[14px] font-semibold rounded-lg hover:brightness-95 cursor-pointer"
>
Send feedback
</button>
</form>
)}
<p className="text-[13px] text-gray-500 mt-8 pt-6 border-t border-gray-100">
For a return or payment issue, use{' '}
<Link href="/returns" className="text-primary font-semibold hover:underline">
Returns
</Link>{' '}
or{' '}
<Link href="/payments" className="text-primary font-semibold hover:underline">
Payments
</Link>
. Need answers first?{' '}
<Link href="/help" className="text-primary font-semibold hover:underline">
Help Center
</Link>
</p>
</div>
</article>
</div>
</main>
<Footer />
<FloatingButtons />
</div>
);
}