feat: quiz

This commit is contained in:
gosangam
2026-10-15 19:40:28 +05:30
parent 3f3fa9a720
commit 111485a43e
20 changed files with 2178 additions and 224 deletions
+33 -24
View File
@@ -12,6 +12,7 @@
*/
import { useEffect, useState } from "react";
import { Can } from "@/components/staff-context";
import Image from "next/image";
import { toast } from "sonner";
import { rewardGifts, type GiftableReward } from "@/lib/api";
@@ -48,7 +49,9 @@ export default function RewardGiftsPage() {
: `Sent to ${granted} ${granted === 1 ? "devotee" : "devotees"}`,
);
} catch (err) {
toast.error(err instanceof Error ? err.message : "Could not send the gift");
toast.error(
err instanceof Error ? err.message : "Could not send the gift",
);
} finally {
setSending(null);
}
@@ -81,16 +84,18 @@ export default function RewardGiftsPage() {
Occasional gifts
</h1>
<p className="mt-1 text-sm text-muted-foreground">
Send a sticker to everyone, no streak required. It arrives wrapped
and opens with a celebration.
Send a sticker to everyone, no streak required. It arrives wrapped and
opens with a celebration.
</p>
</header>
<CustomGift
onCreated={(reward) =>
setCatalog((prev) => (prev ? [...prev, reward] : [reward]))
}
/>
<Can perm="rewards:write">
<CustomGift
onCreated={(reward) =>
setCatalog((prev) => (prev ? [...prev, reward] : [reward]))
}
/>
</Can>
{catalog === null ? (
<p className="text-sm text-muted-foreground">Loading…</p>
@@ -122,27 +127,31 @@ export default function RewardGiftsPage() {
{r.name}
</p>
<div className="mt-auto w-full space-y-1.5">
<button
type="button"
disabled={sending !== null}
onClick={() => send(r)}
className="w-full rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
>
{sending === r.key ? "Sending…" : "Send to everyone"}
</button>
{/* Seeded rewards have no delete: they would return on the
next seed run, having been taken from the galleries of
everyone who earned them. */}
{r.key.startsWith("custom_") && (
<Can perm="rewards:send">
<button
type="button"
disabled={sending !== null}
onClick={() => remove(r)}
className="w-full rounded-md border border-border px-3 py-1.5 text-xs text-muted-foreground hover:bg-muted disabled:opacity-50"
onClick={() => send(r)}
className="w-full rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
>
Delete
{sending === r.key ? "Sending…" : "Send to everyone"}
</button>
)}
</Can>
{/* Seeded rewards have no delete: they would return on the
next seed run, having been taken from the galleries of
everyone who earned them. */}
<Can perm="rewards:delete">
{r.key.startsWith("custom_") && (
<button
type="button"
disabled={sending !== null}
onClick={() => remove(r)}
className="w-full rounded-md border border-border px-3 py-1.5 text-xs text-muted-foreground hover:bg-muted disabled:opacity-50"
>
Delete
</button>
)}
</Can>
</div>
</li>
))}