File size: 3,427 Bytes
37c6e09 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { Download } from "lucide-react";
import { API_BASE } from "../../api/client";
interface ShareData {
output_filename: string;
segment_filename: string | null;
created_at: string;
}
export default function SharedView() {
const { shareId } = useParams<{ shareId: string }>();
const [imageUrl, setImageUrl] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!shareId) {
setError("ID de sesión inválido");
setLoading(false);
return;
}
fetch(`${API_BASE}/api/share/${shareId}`)
.then((res) => {
if (!res.ok) throw new Error("Sesión compartida no encontrada o expirada");
return res.json() as Promise<ShareData>;
})
.then((data) => {
setImageUrl(`${API_BASE}/seg/image/${data.output_filename}`);
})
.catch((err: Error) => setError(err.message))
.finally(() => setLoading(false));
}, [shareId]);
const handleDownload = async () => {
if (!imageUrl) return;
const res = await fetch(imageUrl);
const blob = await res.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `hyper-reality-${shareId}.jpg`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
};
if (loading) {
return (
<div className="flex items-center justify-center h-screen bg-gray-950 text-white text-sm">
Cargando diseño compartido...
</div>
);
}
if (error) {
return (
<div className="flex flex-col items-center justify-center h-screen bg-gray-950 gap-3">
<p className="text-red-400 text-sm">{error}</p>
<p className="text-gray-500 text-xs">
Este enlace puede haber expirado. Los diseños compartidos se mantienen mientras el servidor esté activo.
</p>
</div>
);
}
return (
<div className="flex flex-col h-screen bg-gray-950">
{/* Header */}
<div className="flex items-center justify-between px-5 py-3 bg-white shadow-sm shrink-0">
<span className="text-[#0047AB] font-bold text-base tracking-tight">
Hyper Reality Visualizer
</span>
<button
onClick={handleDownload}
className="flex items-center gap-2 px-4 py-2 bg-[#0047AB] text-white rounded-full text-sm font-medium hover:bg-[#003a94] transition-colors"
>
<Download className="w-4 h-4" />
Descargar
</button>
</div>
{/* Image */}
<div className="flex-1 flex items-center justify-center p-6 min-h-0">
{imageUrl && (
<img
src={imageUrl}
alt="Diseño de habitación compartido"
className="max-h-full max-w-full object-contain rounded-xl shadow-2xl"
/>
)}
</div>
{/* Footer */}
<div className="text-center py-3 text-gray-500 text-xs shrink-0">
Diseñado con{" "}
<a
href="https://hyperrealitycompany.com"
target="_blank"
rel="noopener noreferrer"
className="text-[#4a7fd4] hover:underline"
>
Hyper Reality Visualizer
</a>
</div>
</div>
);
}
|