Files
cozsweet-frontend-nextjs/src/app/tip/tip-success-view.tsx
T

152 lines
4.3 KiB
TypeScript

"use client";
import { useEffect, useRef, type CSSProperties } from "react";
import Link from "next/link";
import { Gift, Heart, Sparkles } from "lucide-react";
import { CharacterAvatar } from "@/app/_components";
import { MobileShell } from "@/app/_components/core";
import { TipProductImage } from "./tip-product-image";
import styles from "./tip-success-view.module.css";
const GENERIC_TIP_SUCCESS_MESSAGE =
"Thank you. Your gift made me smile.";
export interface TipSuccessViewProps {
characterName: string;
characterAvatar: string;
characterCover: string;
giftImageSources: readonly string[];
giftName: string;
isMessageLoading: boolean;
message: string | null;
messageError: string | null;
splashHref: string;
onRetryMessage: () => void;
onSendAgain: () => void;
}
export function TipSuccessView({
characterName,
characterAvatar,
characterCover,
giftImageSources,
giftName,
isMessageLoading,
message,
messageError,
splashHref,
onRetryMessage,
onSendAgain,
}: TipSuccessViewProps) {
const titleRef = useRef<HTMLHeadingElement>(null);
useEffect(() => {
titleRef.current?.focus({ preventScroll: true });
}, []);
return (
<MobileShell background="#fff7f0">
<main
className={styles.shell}
style={
{
"--tip-success-cover": `url("${characterCover}")`,
} as CSSProperties
}
>
<div className={styles.coverWash} aria-hidden="true" />
<div className={styles.glowOne} aria-hidden="true" />
<div className={styles.glowTwo} aria-hidden="true" />
<section
className={styles.card}
aria-live="polite"
aria-labelledby="tip-success-title"
>
<div className={styles.visual}>
<span className={styles.sparkleOne} aria-hidden="true">
<Sparkles size={22} strokeWidth={1.8} />
</span>
<span className={styles.sparkleTwo} aria-hidden="true">
<Heart size={17} fill="currentColor" strokeWidth={1.8} />
</span>
<div className={styles.avatarFrame}>
<CharacterAvatar
src={characterAvatar}
alt={characterName}
size="100%"
imageSize={112}
priority
/>
</div>
<div className={styles.coffeeFrame}>
<TipProductImage
key={giftName}
sources={giftImageSources}
alt={giftName}
className={styles.coffeeImage}
priority
/>
</div>
</div>
<p className={styles.eyebrow}>
<Gift size={15} aria-hidden="true" />
Gift received
</p>
<h1
ref={titleRef}
id="tip-success-title"
className={styles.title}
tabIndex={-1}
>
You made {characterName} smile.
</h1>
<div className={styles.copy}>
<p>
{message ??
(isMessageLoading
? "Your gift arrived. A thank-you note is on its way."
: GENERIC_TIP_SUCCESS_MESSAGE)}
</p>
</div>
{messageError ? (
<div className={styles.messageRetry}>
<p>We could not load the personal thank-you note.</p>
<button
type="button"
className={styles.retryAction}
disabled={isMessageLoading}
onClick={onRetryMessage}
>
{isMessageLoading ? "Retrying..." : "Retry message"}
</button>
</div>
) : null}
<div className={styles.actions}>
<button
type="button"
className={styles.primaryAction}
data-analytics-key="tip.send_again"
onClick={onSendAgain}
>
Send another gift
</button>
<Link
href={splashHref}
className={styles.secondaryAction}
data-analytics-key="tip.success_back_to_splash"
>
Back to {characterName}
</Link>
</div>
</section>
</main>
</MobileShell>
);
}