1
0
Fork 0
polaris-task-force/src/components/frontend/minigames/blackjack/RenameDialogGuard.tsx
Z8MB1E 474aff734d feat(blackjack): add blackjack minigame with realtime table wiring
Engine, felt, controls, sounds, card skins, and dev popups; SSE events in the realtime hook, nav and command palette entries, stats migration, and the six blackjack test suites.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-14 15:38:05 -04:00

107 lines
3 KiB
TypeScript

"use client";
import { useState } from "react";
import { Pencil } from "lucide-react";
import { MAX_TABLE_NAME_LENGTH } from "@/lib/minigames/blackjack/constants";
import {
renameBlackjackTable,
type BlackjackSnapshot,
} from "@/app/(frontend)/minigames/blackjack/actions";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
interface RenameDialogGuardProps {
readonly canRename: boolean;
readonly tableId: string;
readonly currentName: string | null;
readonly onSnapshot: (snapshot: BlackjackSnapshot) => void;
}
export function RenameDialogGuard({
canRename,
tableId,
currentName,
onSnapshot,
}: RenameDialogGuardProps) {
const [open, setOpen] = useState(false);
const [value, setValue] = useState(currentName ?? "");
const [saving, setSaving] = useState(false);
const [error, setError] = useState<string | null>(null);
if (!canRename) return null;
const save = async () => {
setSaving(true);
setError(null);
try {
const result = await renameBlackjackTable(tableId, value);
if (!result.success || !result.data) {
setError(result.error ?? "Could not rename the table.");
return;
}
onSnapshot(result.data);
setOpen(false);
} catch (caught) {
setError(caught instanceof Error ? caught.message : "Could not rename the table.");
} finally {
setSaving(false);
}
};
return (
<Dialog
open={open}
onOpenChange={(next) => {
if (next) setValue(currentName ?? "");
setOpen(next);
}}
>
<DialogTrigger asChild>
<Button
type="button"
variant="ghost"
size="icon"
aria-label="Rename table"
title="Rename table"
>
<Pencil className="size-4" />
</Button>
</DialogTrigger>
<DialogContent className="max-w-sm rounded-none">
<DialogHeader>
<DialogTitle>Name this table</DialogTitle>
<DialogDescription>
The name shows in the lobby and at the table. Share links stay the same.
</DialogDescription>
</DialogHeader>
<Input
value={value}
onChange={(event) => setValue(event.target.value.slice(0, MAX_TABLE_NAME_LENGTH))}
placeholder="Friday night blackjack"
maxLength={MAX_TABLE_NAME_LENGTH}
aria-label="Table name"
onKeyDown={(event) => {
if (event.key === "Enter") void save();
}}
/>
{error && <p className="text-sm text-destructive">{error}</p>}
<DialogFooter>
<Button type="button" variant="outline" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button type="button" onClick={() => void save()} disabled={saving}>
{saving ? "Saving..." : "Save name"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}