Files
crm-calls/calls/frontend/src/Guest.tsx

61 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Гостевая страница /g/<токен>: имя → сессия гостя (без прав модератора) → звонок.
import { useCallback, useEffect, useState } from "react";
import { api } from "./api";
import { CallWithSession } from "./Call";
import { Icon } from "./Icon";
const NAME_KEY = "calls_guest_name_v1";
export function GuestPage({ token }: { token: string }) {
const sessionKey = "calls_guest_session_v1:" + token.slice(0, 12);
const [state, setState] = useState<"checking" | "ok" | "bad">("checking");
const [name, setName] = useState(() => { try { return localStorage.getItem(NAME_KEY) ?? ""; } catch { return ""; } });
const [session, setSession] = useState<string | null>(() => sessionStorage.getItem(sessionKey));
const [err, setErr] = useState("");
const [busy, setBusy] = useState(false);
useEffect(() => {
if (session) return;
api.guestCheck(token).then(() => setState("ok")).catch(() => setState("bad"));
}, [token, session]);
const join = async () => {
const n = name.trim();
if (!n) { setErr("Вкажіть ім'я"); return; }
setBusy(true); setErr("");
try {
const r = await api.guestJoin(token, n);
try { localStorage.setItem(NAME_KEY, n); } catch { /* без сховища */ }
sessionStorage.setItem(sessionKey, r.session);
setSession(r.session);
} catch (e) {
if ((e as { status?: number }).status === 404) setState("bad");
else setErr((e as Error).message);
} finally { setBusy(false); }
};
const lost = useCallback((m: string) => { sessionStorage.removeItem(sessionKey); setSession(null); setErr(m); }, [sessionKey]);
if (session) return <CallWithSession session={session} onSessionLost={lost} />;
return (
<main id="main"><div className="page">
<div className="head"><div><h1>Дзвінок</h1><div className="sub">Запрошення від <b>CRM Tvorymo</b></div></div></div>
{state === "checking" && <div className="empty">Перевірка посилання…</div>}
{state === "bad" && <div className="pcard"><div className="t">Посилання недійсне або застаріло.<small>Попросіть того, хто вас запросив, надіслати нове посилання.</small></div></div>}
{state === "ok" && <div className="pcard">
<div className="f">
<label htmlFor="gname">Ваше ім'я</label>
<div className="in big">
<input id="gname" value={name} maxLength={60} autoComplete="name" autoFocus
onChange={(e) => setName(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") void join(); }} />
</div>
{err && <div className="err">{err}</div>}
</div>
<div className="row wrap mt-14">
<button className="btn gold" disabled={busy} onClick={() => void join()}><Icon name="video" />Приєднатися</button>
</div>
</div>}
</div></main>
);
}