ui: download pptx

This commit is contained in:
Krishav Raj Singh 2025-08-25 06:27:50 +05:30
parent aacc6549fb
commit 92cc53bf08
2 changed files with 56 additions and 7 deletions

View File

@ -46,6 +46,7 @@ interface FullScreenPresentationViewerProps {
sandboxUrl?: string; sandboxUrl?: string;
initialSlide?: number; initialSlide?: number;
onPDFDownload?: (setIsDownloadingPDF: (isDownloading: boolean) => void) => void; onPDFDownload?: (setIsDownloadingPDF: (isDownloading: boolean) => void) => void;
onPPTXDownload?: (setIsDownloadingPPTX: (isDownloading: boolean) => void) => void;
} }
export function FullScreenPresentationViewer({ export function FullScreenPresentationViewer({
@ -55,6 +56,7 @@ export function FullScreenPresentationViewer({
sandboxUrl, sandboxUrl,
initialSlide = 1, initialSlide = 1,
onPDFDownload, onPDFDownload,
onPPTXDownload,
}: FullScreenPresentationViewerProps) { }: FullScreenPresentationViewerProps) {
const [metadata, setMetadata] = useState<PresentationMetadata | null>(null); const [metadata, setMetadata] = useState<PresentationMetadata | null>(null);
const [currentSlide, setCurrentSlide] = useState(initialSlide); const [currentSlide, setCurrentSlide] = useState(initialSlide);
@ -65,6 +67,7 @@ export function FullScreenPresentationViewer({
const [showControls, setShowControls] = useState(true); const [showControls, setShowControls] = useState(true);
const [showEditor, setShowEditor] = useState(false); const [showEditor, setShowEditor] = useState(false);
const [isDownloadingPDF, setIsDownloadingPDF] = useState(false); const [isDownloadingPDF, setIsDownloadingPDF] = useState(false);
const [isDownloadingPPTX, setIsDownloadingPPTX] = useState(false);
// Create a stable refresh timestamp when metadata changes (like PresentationViewer) // Create a stable refresh timestamp when metadata changes (like PresentationViewer)
const refreshTimestamp = useMemo(() => Date.now(), [metadata]); const refreshTimestamp = useMemo(() => Date.now(), [metadata]);
@ -418,7 +421,7 @@ export function FullScreenPresentationViewer({
className="h-8 w-8 p-0" className="h-8 w-8 p-0"
title="Export presentation" title="Export presentation"
> >
{isDownloadingPDF ? ( {(isDownloadingPDF || isDownloadingPPTX) ? (
<Loader2 className="h-3.5 w-3.5 animate-spin" /> <Loader2 className="h-3.5 w-3.5 animate-spin" />
) : ( ) : (
<Download className="h-3.5 w-3.5" /> <Download className="h-3.5 w-3.5" />
@ -430,7 +433,7 @@ export function FullScreenPresentationViewer({
<FileText className="h-4 w-4 mr-2" /> <FileText className="h-4 w-4 mr-2" />
PDF PDF
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem className="cursor-pointer"> <DropdownMenuItem className="cursor-pointer" onClick={() => onPPTXDownload(setIsDownloadingPPTX)}>
<Presentation className="h-4 w-4 mr-2" /> <Presentation className="h-4 w-4 mr-2" />
PPTX PPTX
</DropdownMenuItem> </DropdownMenuItem>

View File

@ -79,6 +79,7 @@ export function PresentationViewer({
const [isFullScreenOpen, setIsFullScreenOpen] = useState(false); const [isFullScreenOpen, setIsFullScreenOpen] = useState(false);
const [fullScreenInitialSlide, setFullScreenInitialSlide] = useState<number | null>(null); const [fullScreenInitialSlide, setFullScreenInitialSlide] = useState<number | null>(null);
const [isDownloadingPDF, setIsDownloadingPDF] = useState(false); const [isDownloadingPDF, setIsDownloadingPDF] = useState(false);
const [isDownloadingPPTX, setIsDownloadingPPTX] = useState(false);
// Extract presentation info from tool data // Extract presentation info from tool data
const { toolResult } = extractToolData(toolContent); const { toolResult } = extractToolData(toolContent);
@ -505,6 +506,36 @@ export function PresentationViewer({
} }
}; };
const downloadPresentationAsPPTX = async (sandboxUrl: string, presentationName: string): Promise<void> => {
try {
const response = await fetch(`${sandboxUrl}/presentation/convert-to-pptx`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
presentation_path: `/workspace/presentations/${presentationName}`,
download: true
})
});
if (!response.ok) {
throw new Error('Failed to download PPTX');
}
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${presentationName}.pptx`;
a.click();
window.URL.revokeObjectURL(url);
} catch (error) {
console.error('Error downloading PPTX:', error);
toast.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
};
const handlePDFDownload = useCallback(async (setIsDownloadingPDF: (isDownloading: boolean) => void) => { const handlePDFDownload = useCallback(async (setIsDownloadingPDF: (isDownloading: boolean) => void) => {
@ -520,6 +551,20 @@ export function PresentationViewer({
} }
}, [project?.sandbox?.sandbox_url, extractedPresentationName]); }, [project?.sandbox?.sandbox_url, extractedPresentationName]);
const handlePPTXDownload = useCallback(async (setIsDownloadingPPTX: (isDownloading: boolean) => void) => {
if (!project?.sandbox?.sandbox_url || !extractedPresentationName) return;
setIsDownloadingPPTX(true);
try{
await downloadPresentationAsPPTX(project.sandbox.sandbox_url, extractedPresentationName);
} catch (error) {
console.error('Error downloading PPTX:', error);
} finally {
setIsDownloadingPPTX(false);
}
}, [project?.sandbox?.sandbox_url, extractedPresentationName]);
return ( return (
<Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card"> <Card className="gap-0 flex border shadow-none border-t border-b-0 border-x-0 p-0 rounded-none flex-col h-full overflow-hidden bg-card">
<CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2"> <CardHeader className="h-14 bg-zinc-50/80 dark:bg-zinc-900/80 backdrop-blur-sm border-b p-2 px-4 space-y-2">
@ -560,7 +605,7 @@ export function PresentationViewer({
className="h-8 w-8 p-0" className="h-8 w-8 p-0"
title="Export presentation" title="Export presentation"
> >
{isDownloadingPDF ? ( {(isDownloadingPDF || isDownloadingPPTX) ? (
<Loader2 className="h-3.5 w-3.5 animate-spin" /> <Loader2 className="h-3.5 w-3.5 animate-spin" />
) : ( ) : (
<Download className="h-3.5 w-3.5" /> <Download className="h-3.5 w-3.5" />
@ -571,16 +616,15 @@ export function PresentationViewer({
<DropdownMenuItem <DropdownMenuItem
onClick={() => handlePDFDownload(setIsDownloadingPDF)} onClick={() => handlePDFDownload(setIsDownloadingPDF)}
className="cursor-pointer" className="cursor-pointer"
disabled={isDownloadingPPTX}
> >
<FileText className="h-4 w-4 mr-2" /> <FileText className="h-4 w-4 mr-2" />
PDF PDF
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
onClick={() => { onClick={() => handlePPTXDownload(setIsDownloadingPPTX)}
// TODO: Implement PPTX export
console.log('Export as PPTX');
}}
className="cursor-pointer" className="cursor-pointer"
disabled={isDownloadingPDF}
> >
<Presentation className="h-4 w-4 mr-2" /> <Presentation className="h-4 w-4 mr-2" />
PPTX PPTX
@ -591,6 +635,7 @@ export function PresentationViewer({
console.log('Export to Google Slides'); console.log('Export to Google Slides');
}} }}
className="cursor-pointer" className="cursor-pointer"
disabled={isDownloadingPDF || isDownloadingPPTX}
> >
<ExternalLink className="h-4 w-4 mr-2" /> <ExternalLink className="h-4 w-4 mr-2" />
Google Slides Google Slides
@ -781,6 +826,7 @@ export function PresentationViewer({
sandboxUrl={project?.sandbox?.sandbox_url} sandboxUrl={project?.sandbox?.sandbox_url}
initialSlide={fullScreenInitialSlide || visibleSlide || currentSlideNumber || slides[0]?.number || 1} initialSlide={fullScreenInitialSlide || visibleSlide || currentSlideNumber || slides[0]?.number || 1}
onPDFDownload={handlePDFDownload} onPDFDownload={handlePDFDownload}
onPPTXDownload={handlePPTXDownload}
/> />
</Card> </Card>
); );