import { useEffect, useRef, useState } from "react"; import { X, Smartphone, Check, Copy, Image as ImageIcon, Film, Music } from "lucide-react"; import { useStore, type VideoAsset } from "../store"; // "Scan to upload from your phone": mints a short-lived, project-scoped link on the server, shows its // QR code, then polls for files the phone sends — adding each to the project's asset library live. export function PhoneUploadModal({ open, onClose }: { open: boolean; onClose: () => void }) { const projectId = useStore((s) => s.projectId); const projectName = useStore((s) => s.projectName); const addAsset = useStore((s) => s.addAsset); const [qr, setQr] = useState(null); const [url, setUrl] = useState(""); const [err, setErr] = useState(""); const [received, setReceived] = useState([]); const [copied, setCopied] = useState(false); const tokenRef = useRef(null); const seen = useRef>(new Set()); useEffect(() => { if (!open || !projectId) return; let stop = false; let timer: ReturnType | undefined; setQr(null); setUrl(""); setErr(""); setReceived([]); setCopied(false); seen.current = new Set(); tokenRef.current = null; (async () => { try { const res = await fetch("/api/uplink", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ projectId }) }); const d = await res.json(); if (!res.ok || !d.token) throw new Error(d.error || "couldn't create an upload link"); if (stop) return; tokenRef.current = d.token; setQr(d.qr); setUrl(d.url); const poll = async () => { if (stop || !tokenRef.current) return; try { const r = await fetch("/api/uplink/" + tokenRef.current); if (r.ok) { const j = await r.json(); for (const a of (j.assets || []) as VideoAsset[]) { if (!seen.current.has(a.id)) { seen.current.add(a.id); addAsset(a); setReceived((prev) => [a, ...prev]); } } } } catch { /* keep polling */ } if (!stop) timer = setTimeout(poll, 2500); }; timer = setTimeout(poll, 2500); } catch (e) { if (!stop) setErr(String((e as Error)?.message || e)); } })(); return () => { stop = true; if (timer) clearTimeout(timer); }; }, [open, projectId, addAsset]); if (!open) return null; const kindIcon = (k?: string) => (k === "image" ? ImageIcon : k === "audio" ? Music : Film); return (
e.stopPropagation()}>
Upload from your phone
Files land in {projectName}
{err ? (
{err}
) : ( <>
{qr ? Scan to upload :
Generating link…
}

Scan with your phone camera, then pick photos or videos.
Phone must be on the same Wi-Fi. Link expires in 30 min.

{url && ( )} )}
{received.length ? `${received.length} file${received.length === 1 ? "" : "s"} received` : "Waiting for uploads…"}
{received.length === 0 ? (
Anything you send appears here and in My Assets automatically.
) : (
{received.map((a) => { const Icon = kindIcon(a.kind); return (
{a.label}
); })}
)}
); }