170 lines
5.3 KiB
TypeScript
170 lines
5.3 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
|
import { QrCode, Radio } from "lucide-react";
|
|
import { AgendaQrModal } from "../agenda/AgendaQrModal";
|
|
import { useBreakpoint } from "../../hooks/useBreakpoint";
|
|
import { useAppNav } from "../../contexts/AppNavContext";
|
|
import { eventsApi } from "../../../services/api/events";
|
|
import type { Event } from "../../../services/api/types";
|
|
|
|
const headerBtnBase: React.CSSProperties = {
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: "6px",
|
|
padding: "7px 14px",
|
|
borderRadius: "var(--radius-button)",
|
|
borderWidth: "1px",
|
|
borderStyle: "solid",
|
|
fontSize: "var(--text-sm)",
|
|
fontFamily: "var(--font-noto-sans)",
|
|
fontWeight: "var(--font-weight-medium)",
|
|
cursor: "pointer",
|
|
transition: "all 0.15s",
|
|
};
|
|
|
|
export function EventHomeHeaderActions() {
|
|
const { selectedEventId } = useAppNav();
|
|
const bp = useBreakpoint();
|
|
const isSmall = bp === "mobile" || bp === "tablet";
|
|
const [qrOpen, setQrOpen] = useState(false);
|
|
const [liveActive, setLiveActive] = useState(false);
|
|
const [qrEvent, setQrEvent] = useState<Event | null | undefined>(undefined);
|
|
|
|
useEffect(() => {
|
|
if (!qrOpen || !selectedEventId) {
|
|
setQrEvent(undefined);
|
|
return;
|
|
}
|
|
setQrEvent(undefined);
|
|
let cancelled = false;
|
|
void eventsApi.get(selectedEventId).then((res) => {
|
|
if (!cancelled) setQrEvent(res.data ?? null);
|
|
});
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [qrOpen, selectedEventId]);
|
|
|
|
function openQr() {
|
|
if (!selectedEventId) {
|
|
window.alert("Select an event from the sidebar first.");
|
|
return;
|
|
}
|
|
setQrOpen(true);
|
|
}
|
|
|
|
function toggleLive() {
|
|
if (!liveActive && !window.confirm("Start broadcasting this event as Live? All participants will be notified.")) {
|
|
return;
|
|
}
|
|
setLiveActive((v) => !v);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div style={{ display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap" }}>
|
|
<button
|
|
type="button"
|
|
onClick={openQr}
|
|
disabled={!selectedEventId}
|
|
style={{
|
|
...headerBtnBase,
|
|
borderColor: "var(--border)",
|
|
background: "var(--card)",
|
|
color: "var(--card-foreground)",
|
|
opacity: selectedEventId ? 1 : 0.55,
|
|
cursor: selectedEventId ? "pointer" : "not-allowed",
|
|
}}
|
|
onMouseEnter={(e) => {
|
|
if (!selectedEventId) return;
|
|
(e.currentTarget as HTMLElement).style.borderColor = "var(--primary)";
|
|
(e.currentTarget as HTMLElement).style.color = "var(--primary)";
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
(e.currentTarget as HTMLElement).style.borderColor = "var(--border)";
|
|
(e.currentTarget as HTMLElement).style.color = "var(--card-foreground)";
|
|
}}
|
|
>
|
|
<QrCode size={14} />
|
|
{isSmall ? "QR" : "Generate QR Code"}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={toggleLive}
|
|
style={{
|
|
...headerBtnBase,
|
|
borderColor: liveActive ? "var(--destructive)" : "var(--border)",
|
|
background: liveActive ? "var(--destructive)" : "var(--card)",
|
|
color: liveActive ? "var(--destructive-foreground)" : "var(--card-foreground)",
|
|
}}
|
|
onMouseEnter={(e) => {
|
|
if (liveActive) return;
|
|
(e.currentTarget as HTMLElement).style.borderColor = "var(--primary)";
|
|
(e.currentTarget as HTMLElement).style.color = "var(--primary)";
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
if (liveActive) return;
|
|
(e.currentTarget as HTMLElement).style.borderColor = "var(--border)";
|
|
(e.currentTarget as HTMLElement).style.color = "var(--card-foreground)";
|
|
}}
|
|
>
|
|
{liveActive ? (
|
|
<span
|
|
style={{
|
|
width: "7px",
|
|
height: "7px",
|
|
borderRadius: "50%",
|
|
background: "var(--destructive-foreground)",
|
|
display: "block",
|
|
}}
|
|
/>
|
|
) : (
|
|
<Radio size={14} />
|
|
)}
|
|
{liveActive ? "Stop Live" : isSmall ? "Go Live" : "Go Live"}
|
|
</button>
|
|
</div>
|
|
|
|
{qrOpen && selectedEventId && qrEvent !== undefined ? (
|
|
<AgendaQrModal
|
|
open
|
|
onClose={() => setQrOpen(false)}
|
|
kind="event"
|
|
joinCode={(qrEvent?.joinCode ?? "").trim()}
|
|
label={qrEvent?.name ?? "Event"}
|
|
/>
|
|
) : null}
|
|
|
|
{qrOpen && selectedEventId && qrEvent === undefined ? (
|
|
<div
|
|
role="status"
|
|
aria-live="polite"
|
|
style={{
|
|
position: "fixed",
|
|
inset: 0,
|
|
background: "rgba(0,0,0,0.45)",
|
|
zIndex: 120,
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
padding: "16px",
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
background: "var(--card)",
|
|
borderRadius: "var(--radius-card)",
|
|
padding: "24px 32px",
|
|
border: "1px solid var(--border)",
|
|
fontFamily: "var(--font-noto-sans)",
|
|
fontSize: "var(--text-sm)",
|
|
color: "var(--muted)",
|
|
}}
|
|
>
|
|
Loading event…
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
</>
|
|
);
|
|
}
|