import React, { useState, useEffect } from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import type { Presentation } from '../../types/presentation.ts'; import type { Theme } from '../../types/theme.ts'; import { getPresentationById } from '../../utils/presentationStorage.ts'; import { getTheme } from '../../themes/index.ts'; import { loggers } from '../../utils/logger.ts'; import './PresentationViewer.css'; export const PresentationViewer: React.FC = () => { const { presentationId, slideNumber } = useParams<{ presentationId: string; slideNumber: string; }>(); const navigate = useNavigate(); const [presentation, setPresentation] = useState(null); const [theme, setTheme] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const currentSlideIndex = slideNumber ? parseInt(slideNumber, 10) - 1 : 0; useEffect(() => { const loadPresentationAndTheme = async () => { if (!presentationId) { setError('No presentation ID provided'); setLoading(false); return; } try { setLoading(true); // Load presentation const presentationData = await getPresentationById(presentationId); if (!presentationData) { setError(`Presentation not found: ${presentationId}`); return; } setPresentation(presentationData); // Load theme const themeData = await getTheme(presentationData.metadata.theme); if (!themeData) { setError(`Theme not found: ${presentationData.metadata.theme}`); return; } setTheme(themeData); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load presentation'); } finally { setLoading(false); } }; loadPresentationAndTheme(); }, [presentationId]); const goToSlide = (slideIndex: number) => { if (!presentation) return; const slideNum = slideIndex + 1; navigate(`/presentations/${presentationId}/view/slides/${slideNum}`); }; const goToPreviousSlide = () => { if (currentSlideIndex > 0) { goToSlide(currentSlideIndex - 1); } }; const goToNextSlide = () => { if (presentation && currentSlideIndex < presentation.slides.length - 1) { goToSlide(currentSlideIndex + 1); } }; const editPresentation = () => { if (!presentation) return; const slideNum = Math.max(1, currentSlideIndex + 1); navigate(`/presentations/${presentationId}/edit/slides/${slideNum}`); }; const enterPresentationMode = () => { // TODO: Implement full-screen presentation mode loggers.ui.info('Full-screen presentation mode requested - feature to be implemented'); }; if (loading) { return (
Loading presentation...
); } if (error) { return (

Error Loading Presentation

{error}

← Back to Themes
); } if (!presentation || !theme) { return (

Presentation Not Found

The requested presentation could not be found.

← Back to Themes
); } const currentSlide = presentation.slides[currentSlideIndex]; const totalSlides = presentation.slides.length; return (
← Back

{presentation.metadata.name}

{presentation.metadata.description && (

{presentation.metadata.description}

)}
Theme: {theme.name} {totalSlides === 0 ? 'No slides' : `Slide ${currentSlideIndex + 1} of ${totalSlides}`}
{totalSlides === 0 ? (

This presentation is empty

Switch to edit mode to add slides

) : ( <>
{currentSlide ? (

Slide {currentSlideIndex + 1}

Layout: {currentSlide.layoutId}

{/* TODO: Render actual slide content based on layout */}

Slide content will be rendered here

Layout: {currentSlide.layoutId}

Content slots: {Object.keys(currentSlide.content).length}

{currentSlide.notes && (

Notes:

{currentSlide.notes}

)}
) : (

Invalid slide number

)}
{presentation.slides.map((slide, index) => ( ))}
)}
); };