feat: Implement replyTo for contact form emails and refine success/error message layout.
This commit is contained in:
@@ -71,6 +71,7 @@ export async function sendContactFormAction(formData: FormData) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const notificationResult = await sendEmail({
|
const notificationResult = await sendEmail({
|
||||||
|
replyTo: email,
|
||||||
subject: notificationSubject,
|
subject: notificationSubject,
|
||||||
html: notificationHtml,
|
html: notificationHtml,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -49,21 +49,28 @@ export default function RequestQuoteForm({ productName }: RequestQuoteFormProps)
|
|||||||
|
|
||||||
if (status === 'success') {
|
if (status === 'success') {
|
||||||
return (
|
return (
|
||||||
<div className="bg-accent/5 border border-accent/20 text-primary-dark p-4 rounded-xl text-center flex flex-col items-center animate-fade-in !mt-0">
|
<div className="bg-accent/5 border border-accent/20 text-primary-dark p-4 rounded-xl text-center animate-fade-in !mt-0 w-full">
|
||||||
<div className="w-10 h-10 bg-accent rounded-full flex items-center justify-center mx-auto mb-3 shadow-lg shadow-accent/20">
|
<div className="flex justify-center mb-3">
|
||||||
<svg
|
<div className="w-10 h-10 bg-accent rounded-full flex items-center justify-center shadow-lg shadow-accent/20">
|
||||||
className="w-5 h-5 text-primary-dark"
|
<svg
|
||||||
fill="none"
|
className="w-5 h-5 text-primary-dark"
|
||||||
stroke="currentColor"
|
fill="none"
|
||||||
viewBox="0 0 24 24"
|
stroke="currentColor"
|
||||||
>
|
viewBox="0 0 24 24"
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" />
|
>
|
||||||
</svg>
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={3}
|
||||||
|
d="M5 13l4 4L19 7"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-base font-extrabold mb-1 tracking-tight !mt-0 text-center">
|
<h3 className="text-base font-extrabold mb-1 tracking-tight !mt-0 text-center w-full">
|
||||||
{t('successTitle')}
|
{t('successTitle')}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-text-secondary text-xs leading-tight mb-4 !mt-0 text-center">
|
<p className="text-text-secondary text-xs leading-tight mb-4 !mt-0 text-center w-full">
|
||||||
{t('successDesc', { productName })}
|
{t('successDesc', { productName })}
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
@@ -80,24 +87,26 @@ export default function RequestQuoteForm({ productName }: RequestQuoteFormProps)
|
|||||||
|
|
||||||
if (status === 'error') {
|
if (status === 'error') {
|
||||||
return (
|
return (
|
||||||
<div className="bg-destructive/5 border border-destructive/20 text-destructive p-4 rounded-xl text-center flex flex-col items-center animate-fade-in !mt-0">
|
<div className="bg-destructive/5 border border-destructive/20 text-destructive p-4 rounded-xl text-center animate-fade-in !mt-0 w-full">
|
||||||
<div className="w-10 h-10 bg-destructive rounded-full flex items-center justify-center mx-auto mb-3 shadow-lg shadow-destructive/20">
|
<div className="flex justify-center mb-3">
|
||||||
<svg
|
<div className="w-10 h-10 bg-destructive rounded-full flex items-center justify-center shadow-lg shadow-destructive/20">
|
||||||
className="w-5 h-5 text-destructive-foreground"
|
<svg
|
||||||
fill="none"
|
className="w-5 h-5 text-destructive-foreground"
|
||||||
viewBox="0 0 24 24"
|
fill="none"
|
||||||
stroke="currentColor"
|
viewBox="0 0 24 24"
|
||||||
strokeWidth="3"
|
stroke="currentColor"
|
||||||
>
|
strokeWidth="3"
|
||||||
<circle cx="12" cy="12" r="10" />
|
>
|
||||||
<line x1="15" y1="9" x2="9" y2="15" />
|
<circle cx="12" cy="12" r="10" />
|
||||||
<line x1="9" y1="9" x2="15" y2="15" />
|
<line x1="15" y1="9" x2="9" y2="15" />
|
||||||
</svg>
|
<line x1="9" y1="9" x2="15" y2="15" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-base font-extrabold mb-1 tracking-tight !mt-0 text-destructive text-center">
|
<h3 className="text-base font-extrabold mb-1 tracking-tight !mt-0 text-destructive text-center w-full">
|
||||||
{t('errorTitle') || 'Submission Failed'}
|
{t('errorTitle') || 'Submission Failed'}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-destructive/80 text-xs leading-tight mb-4 !mt-0 text-center">
|
<p className="text-destructive/80 text-xs leading-tight mb-4 !mt-0 text-center w-full">
|
||||||
{t('errorDesc') || 'Something went wrong. Please try again.'}
|
{t('errorDesc') || 'Something went wrong. Please try again.'}
|
||||||
</p>
|
</p>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -27,16 +27,18 @@ function getTransporter() {
|
|||||||
|
|
||||||
interface SendEmailOptions {
|
interface SendEmailOptions {
|
||||||
to?: string | string[];
|
to?: string | string[];
|
||||||
|
replyTo?: string;
|
||||||
subject: string;
|
subject: string;
|
||||||
html: string;
|
html: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendEmail({ to, subject, html }: SendEmailOptions) {
|
export async function sendEmail({ to, replyTo, subject, html }: SendEmailOptions) {
|
||||||
const recipients = to || config.mail.recipients;
|
const recipients = to || config.mail.recipients;
|
||||||
|
|
||||||
const mailOptions = {
|
const mailOptions = {
|
||||||
from: config.mail.from,
|
from: config.mail.from,
|
||||||
to: recipients,
|
to: recipients,
|
||||||
|
replyTo,
|
||||||
subject,
|
subject,
|
||||||
html,
|
html,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user