"use client"; /** * /reward-gifts — hand a sticker to everyone, outside the streak. * * These arrive wrapped: each devotee sees a blurred tile in their rewards * gallery, and opening it plays the same celebration a streak reward does. * Nothing is required of them to earn it. * * Sending is idempotent — a repeat reaches only accounts that don't already * hold the sticker — so a double click tops up rather than duplicating. */ import { useEffect, useState } from "react"; import Image from "next/image"; import { toast } from "sonner"; import { rewardGifts, type GiftableReward } from "@/lib/api"; export default function RewardGiftsPage() { const [catalog, setCatalog] = useState(null); const [sending, setSending] = useState(null); useEffect(() => { rewardGifts .catalog() .then(setCatalog) .catch(() => { toast.error("Could not load the reward catalog"); setCatalog([]); }); }, []); const send = async (reward: GiftableReward) => { if ( !window.confirm( `Send “${reward.name}” to every devotee? They'll see it wrapped in their gallery.`, ) ) { return; } setSending(reward.key); try { const { granted } = await rewardGifts.send(reward.key); toast.success( granted === 0 ? "Everyone already has this one" : `Sent to ${granted} ${granted === 1 ? "devotee" : "devotees"}`, ); } catch (err) { toast.error(err instanceof Error ? err.message : "Could not send the gift"); } finally { setSending(null); } }; return (

Occasional gifts

Send a sticker to everyone, no streak required. It arrives wrapped and opens with a celebration.

{catalog === null ? (

Loading…

) : catalog.length === 0 ? (

The reward catalog is empty.

) : (
    {catalog.map((r) => (
  • {r.name}

    {r.name}

  • ))}
)}
); }