153 lines
4.5 KiB
TypeScript
153 lines
4.5 KiB
TypeScript
|
|
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>
|
||
|
|
);
|
||
|
|
}
|