diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx index 37fc7873..92a38c1d 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationPage.tsx @@ -18,13 +18,9 @@ import { } from "../hooks"; import { PresentationPageProps } from "../types"; import LoadingState from "./LoadingState"; -import { useRouter, useSearchParams } from "next/navigation"; const PresentationPage: React.FC = ({ presentation_id }) => { - const router = useRouter(); - const searchParams = useSearchParams(); - const isPresentMode = searchParams.get("mode") === "present"; - const stream = searchParams.get("stream"); + // State management const [loading, setLoading] = useState(true); const [selectedSlide, setSelectedSlide] = useState(0); @@ -51,6 +47,14 @@ const PresentationPage: React.FC = ({ presentation_id }) setError ); + const { + isPresentMode, + stream, + handleSlideClick, + toggleFullscreen, + handlePresentExit, + handleSlideChange, + } = usePresentationNavigation(presentation_id, selectedSlide, setSelectedSlide, setIsFullscreen); // Initialize streaming usePresentationStreaming( @@ -63,46 +67,12 @@ const PresentationPage: React.FC = ({ presentation_id }) + const onSlideChange = (newSlide: number) => { handleSlideChange(newSlide, presentationData); }; - const handleSlideClick = useCallback((index: number) => { - console.log("handleSlideClick", index); - const slideElement = document.getElementById(`slide-${index}`); - if (slideElement) { - slideElement.scrollIntoView({ - behavior: "smooth", - block: "center", - }); - setSelectedSlide(index); - } - }, [setSelectedSlide]); - const toggleFullscreen = useCallback(() => { - if (!document.fullscreenElement) { - document.documentElement.requestFullscreen(); - setIsFullscreen(true); - } else { - document.exitFullscreen(); - setIsFullscreen(false); - } - }, [setIsFullscreen]); - - const handlePresentExit = useCallback(() => { - setIsFullscreen(false); - router.push(`/presentation?id=${presentation_id}`); - }, [router, presentation_id, setIsFullscreen]); - - const handleSlideChange = useCallback((newSlide: number, presentationData: any) => { - if (newSlide >= 0 && newSlide < presentationData?.slides.length!) { - setSelectedSlide(newSlide); - router.push( - `/presentation?id=${presentation_id}&mode=present&slide=${newSlide}`, - { scroll: false } - ); - } - }, [router, presentation_id, setSelectedSlide]); // Presentation Mode View if (isPresentMode) { @@ -110,7 +80,6 @@ const PresentationPage: React.FC = ({ presentation_id }) { - setMouseDownTime(Date.now()); - }; + const handleClick = (e: React.MouseEvent) => { + const now = Date.now(); - const handleMouseUp = () => { - const mouseUpTime = Date.now(); - const timeDiff = mouseUpTime - mouseDownTime; + // Debounce clicks - only allow one click every 300ms + if (now - lastClickTime.current < 300) { + return; + } - // If the mouse was down for less than 200ms, consider it a click - if (timeDiff < 200 && !isDragging) { + // Only trigger click if not dragging + if (!isDragging) { + lastClickTime.current = now; onSlideClick(slide.index); } }; @@ -48,8 +49,7 @@ export function SortableListItem({ slide, index, selectedSlide, onSlideClick }: style={style} {...attributes} {...listeners} - onMouseDown={handleMouseDown} - onMouseUp={handleMouseUp} + onClick={handleClick} className={`p-3 cursor-pointer ring-0 border-[3px] rounded-lg slide-box ${selectedSlide === index ? ' border-[#5141e5] ' diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/SortableSlide.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/SortableSlide.tsx index 14bc87b4..5e6ac054 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/SortableSlide.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/SortableSlide.tsx @@ -1,7 +1,7 @@ import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; import { Slide } from '../../types/slide'; -import { useState } from 'react'; +import { useRef } from 'react'; interface SortableSlideProps { slide: Slide; @@ -12,7 +12,7 @@ interface SortableSlideProps { } export function SortableSlide({ slide, index, selectedSlide, onSlideClick, renderSlideContent }: SortableSlideProps) { - const [mouseDownTime, setMouseDownTime] = useState(0); + const lastClickTime = useRef(0); const { attributes, @@ -29,20 +29,17 @@ export function SortableSlide({ slide, index, selectedSlide, onSlideClick, rende opacity: isDragging ? 0.5 : 1 }; - const handleMouseDown = () => { - console.log("mouse down"); - setMouseDownTime(Date.now()); - }; + const handleClick = (e: React.MouseEvent) => { + const now = Date.now(); - const handleMouseUp = () => { - console.log("mouse up"); - const mouseUpTime = Date.now(); - const timeDiff = mouseUpTime - mouseDownTime; - console.log("timeDiff", timeDiff); + // Debounce clicks - only allow one click every 300ms + if (now - lastClickTime.current < 300) { + return; + } - // If the mouse was down for less than 300ms, consider it a click - if (timeDiff < 300 && !isDragging) { - console.log("clicked"); + // Only trigger click if not dragging + if (!isDragging) { + lastClickTime.current = now; onSlideClick(slide.index); } }; @@ -53,9 +50,7 @@ export function SortableSlide({ slide, index, selectedSlide, onSlideClick, rende style={style} {...attributes} {...listeners} - onMouseDown={handleMouseDown} - onMouseUp={handleMouseUp} - + onClick={handleClick} className={` cursor-pointer border-[3px] relative p-1 shadow-lg rounded-md transition-all duration-200 ${selectedSlide === index ? ' border-[#5141e5]' : 'border-gray-300' }`} >