84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* The sticker drawer, opened from the composer.
|
|
*
|
|
* The collection is whatever the server says it is — rewards earned through
|
|
* sādhana plus stickers saved from a chat — so a sticker you were sent
|
|
* appears here the moment you keep it, with no client-side bookkeeping.
|
|
*
|
|
* Empty is a real state worth explaining: stickers are earned, so someone
|
|
* with none needs to know how to get one rather than seeing a blank sheet.
|
|
*/
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Image from "next/image";
|
|
import { ResponsiveDialog } from "@/components/chat/responsive-dialog";
|
|
import { chat, type Sticker } from "@/lib/chat";
|
|
|
|
export function StickerPicker({
|
|
onPick,
|
|
onClose,
|
|
}: {
|
|
onPick: (sticker: Sticker) => void;
|
|
onClose: () => void;
|
|
}) {
|
|
const [stickers, setStickers] = useState<Sticker[] | null>(null);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
chat
|
|
.stickers()
|
|
.then((s) => {
|
|
if (!cancelled) setStickers(s);
|
|
})
|
|
.catch(() => {
|
|
if (!cancelled) setStickers([]);
|
|
});
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, []);
|
|
|
|
return (
|
|
<ResponsiveDialog
|
|
title="Stickers"
|
|
description="Earned through sādhana, or saved from a chat."
|
|
onClose={onClose}
|
|
>
|
|
{stickers === null ? (
|
|
<p className="p-4 text-sm text-muted-foreground">Loading…</p>
|
|
) : stickers.length === 0 ? (
|
|
<p className="p-4 text-sm text-muted-foreground">
|
|
No stickers yet. Keep your sādhana streak — a sacred reward arrives
|
|
every 7 days — or save one someone sends you.
|
|
</p>
|
|
) : (
|
|
<div className="grid grid-cols-4 gap-2 p-4 sm:grid-cols-5">
|
|
{stickers.map((s) => (
|
|
<button
|
|
key={s.key}
|
|
type="button"
|
|
onClick={() => {
|
|
onPick(s);
|
|
onClose();
|
|
}}
|
|
title={s.name}
|
|
aria-label={s.name}
|
|
className="relative aspect-square rounded-lg p-1 transition-colors hover:bg-muted"
|
|
>
|
|
<Image
|
|
src={s.image_url}
|
|
alt=""
|
|
fill
|
|
sizes="80px"
|
|
className="object-contain p-1"
|
|
/>
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
</ResponsiveDialog>
|
|
);
|
|
}
|