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 && (
)}
);
}