import { callAction } from "@agent-native/core/client/hooks"; import { useT } from "@agent-native/core/client/i18n"; import { isInAgentEmbed, postNavigate, } from "@agent-native/core/client/navigation"; import { IconExternalLink } from "@tabler/icons-react"; import { useEffect, useState } from "react"; import { useSearchParams } from "react-router"; import SlideRenderer from "@/components/deck/SlideRenderer"; import type { Slide } from "@/context/DeckContext"; import messages from "@/i18n/en-US"; import type { AspectRatio } from "@/lib/aspect-ratios"; export function meta() { return [{ title: messages.raw.slidePreviewTitle }]; } function SlideError({ message }: { message: string }) { const t = useT(); return (
{t("raw.slideUnavailable")}
{message}
); } export default function SlideRoute() { const t = useT(); const [params] = useSearchParams(); const deckId = params.get("deckId"); const slideNumberParam = params.get("slideNumber"); const slideIndexParam = params.get("slideIndex"); const [slide, setSlide] = useState(null); const [aspectRatio, setAspectRatio] = useState( undefined, ); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); const slideNumber = slideNumberParam !== null ? parseInt(slideNumberParam, 10) : null; const slideIndex = slideNumber !== null ? slideNumber - 1 : slideIndexParam !== null ? parseInt(slideIndexParam, 10) : 0; const inEmbed = isInAgentEmbed(); useEffect(() => { if (!deckId) { setError("Missing deckId parameter."); setLoading(false); return; } if ( slideNumberParam !== null && (slideNumber === null || isNaN(slideNumber) || slideNumber < 1) ) { setError("slideNumber must be a positive 1-based number."); setLoading(false); return; } if (slideIndexParam !== null && isNaN(slideIndex)) { setError("slideIndex must be a number."); setLoading(false); return; } callAction<{ slides?: Slide[]; aspectRatio?: AspectRatio }>( "get-deck", { id: deckId }, { method: "GET" }, ) .then((deck) => { const slides: Slide[] = deck.slides ?? []; if (slides.length === 0) { throw new Error("This deck has no slides."); } const idx = Math.max(0, Math.min(slideIndex, slides.length - 1)); setSlide(slides[idx]); setAspectRatio(deck.aspectRatio); setLoading(false); }) .catch((err: unknown) => { const status = (err as { status?: number } | undefined)?.status; if (status === 404) { setError("Deck not found."); } else if (status !== undefined) { setError(`Failed to load deck (HTTP ${status}).`); } else { setError( err instanceof Error ? err.message : t("raw.couldNotLoadSlide"), ); } setLoading(false); }); }, [deckId, slideIndex, slideIndexParam, slideNumber, slideNumberParam, t]); if (loading) { return
; } if (error || !slide) { return ; } function handleOpenInApp() { postNavigate(`/deck/${deckId}/present?slide=${slideIndex + 1}`); } return (
{inEmbed && ( )}
); }