CoompanionApp/front/play/chat/ChatNewScreen.tsx

153 lines
4.5 KiB
TypeScript
Raw Permalink Normal View History

2026-02-03 13:48:56 +01:00
import React, { useMemo, useState } from "react";
import { Link } from "react-router-dom";
import type { SessionSnapshot } from "../../../shared/types";
import { useI18n } from "../i18n";
export default function ChatNewScreen({
session,
meId,
sessionId,
onCreate,
}: {
session: SessionSnapshot;
meId: string;
sessionId: string;
onCreate: (name: string, memberIds: string[]) => void;
}) {
const { t } = useI18n();
const [mode, setMode] = useState<"direct" | "group">("direct");
const [groupName, setGroupName] = useState("");
const [selected, setSelected] = useState<string[]>([]);
const [error, setError] = useState<string | null>(null);
const options = useMemo(
() => session.players.filter((player) => player.id !== meId),
[session.players, meId],
);
function resetSelection(nextMode: "direct" | "group") {
setMode(nextMode);
setSelected([]);
setError(null);
if (nextMode === "direct") {
setGroupName("");
}
}
function toggleMember(id: string) {
if (mode === "direct") {
setSelected([id]);
return;
}
setSelected((prev) =>
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id],
);
}
function handleCreate() {
if (mode === "direct") {
if (selected.length !== 1) {
setError(t("chat.error.direct"));
return;
}
onCreate(t("chat.direct"), selected);
return;
}
if (!groupName.trim()) {
setError(t("chat.error.groupName"));
return;
}
if (selected.length === 0) {
setError(t("chat.error.member"));
return;
}
onCreate(groupName.trim(), selected);
}
return (
<div className="play-shell chat-shell">
<div className="chat-screen chat-screen--new">
<header className="chat-screen-header">
<Link className="chat-back" to={`/play/${sessionId}/chat`}>
{t("chat.backChats")}
</Link>
<div className="chat-screen-title">
<h1>{t("chat.newTitle")}</h1>
<span>{t("chat.newSubtitle")}</span>
</div>
</header>
<section className="chat-new">
<div className="chat-toggle">
<button
type="button"
className={mode === "direct" ? "active" : ""}
onClick={() => resetSelection("direct")}
>
{t("chat.direct")}
</button>
<button
type="button"
className={mode === "group" ? "active" : ""}
onClick={() => resetSelection("group")}
>
{t("chat.group")}
</button>
</div>
{mode === "group" && (
<label className="chat-field">
<span>{t("chat.groupName")}</span>
<input
value={groupName}
onChange={(event) => setGroupName(event.target.value)}
placeholder={t("chat.groupPlaceholder")}
/>
</label>
)}
<div className="chat-members">
<h2>{t("chat.choosePlayers")}</h2>
{options.length === 0 ? (
<p className="helper">{t("chat.noPlayers")}</p>
) : (
<div className="chat-members-list">
{options.map((player) => {
const selectedNow = selected.includes(player.id);
return (
<label
key={player.id}
className={`chat-member ${selectedNow ? "selected" : ""}`}
>
<input
type={mode === "direct" ? "radio" : "checkbox"}
name="chat-member"
checked={selectedNow}
onChange={() => toggleMember(player.id)}
/>
<span className="chat-member-name">{player.name}</span>
<span className="chat-member-meta">
{player.role === "banker"
? t("common.banker")
: player.isDummy
? t("common.dummy")
: t("common.player")}
</span>
</label>
);
})}
</div>
)}
</div>
{error && <p className="chat-error">{error}</p>}
<button className="button" type="button" onClick={handleCreate}>
{t("chat.startChat")}
</button>
</section>
</div>
</div>
);
}