From 2ec7c53302cf84f07637cf4cba7238659bd5dda5 Mon Sep 17 00:00:00 2001 From: Mann Patel <130435633+Patel-Mann@users.noreply.github.com> Date: Sun, 15 Feb 2026 06:14:09 -0700 Subject: [PATCH] feat: working zip file --- frontend/src/api.js | 23 +++++-- frontend/src/components/AudioPostCard.jsx | 73 ++++++++++++++--------- 2 files changed, 63 insertions(+), 33 deletions(-) diff --git a/frontend/src/api.js b/frontend/src/api.js index b7f6f6a..dd85265 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -3,7 +3,7 @@ * Handles all communication with Flask API */ -const API_BASE_URL = 'http://localhost:5000/api'; +const API_BASE_URL= 'http://localhost:5000/api'; class ApiClient { constructor() { @@ -153,11 +153,24 @@ class ApiClient { return this.request(`/posts/${postId}/metadata`); } + // ==================== Export/Download ==================== + async exportPost(postId) { - const response = await fetch(`/api/posts/${postId}/download`, { method: "GET" }); - if (!response.ok) throw new Error(`Failed to download post: ${response.statusText}`); - return await response.blob(); // returns proper Blob ready for download -} + const response = await fetch(`${this.baseUrl}/posts/${postId}/download`, { + method: "GET", + }); + + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.error || `Failed to download post: ${response.statusText}`); + } + + // Get binary data + const buffer = await response.arrayBuffer(); + + // Convert to a Blob so the browser can download it + return new Blob([buffer], { type: "application/zip" }); + } // ==================== RAG Search ==================== diff --git a/frontend/src/components/AudioPostCard.jsx b/frontend/src/components/AudioPostCard.jsx index af684ae..a36b40d 100644 --- a/frontend/src/components/AudioPostCard.jsx +++ b/frontend/src/components/AudioPostCard.jsx @@ -1,4 +1,4 @@ -import { Play, Pause, Volume2, MoreVertical, Clock, ChevronDown, ChevronUp } from 'lucide-react' +import { Play, Pause, Volume2, MoreVertical, Clock, ChevronDown, ChevronUp, Download } from 'lucide-react' import { useState, useRef, useEffect } from 'react' import { api } from '../api' @@ -10,6 +10,7 @@ export default function AudioPostCard({ post }) { const [transcript, setTranscript] = useState(null) const [loadingTranscript, setLoadingTranscript] = useState(false) const [transcriptExpanded, setTranscriptExpanded] = useState(false) + const [downloading, setDownloading] = useState(false) const audioRef = useRef(null) // DEBUG: Log post data to console @@ -73,6 +74,29 @@ export default function AudioPostCard({ post }) { } } + const handleDownload = async () => { + if (downloading) return + + setDownloading(true) + try { + const zipBlob = await api.exportPost(post.post_id) + + const url = window.URL.createObjectURL(zipBlob) + const a = document.createElement("a") + a.href = url + a.download = `${post.title.replace(/[^a-zA-Z0-9]/g, "_")}_${post.post_id}.zip` + document.body.appendChild(a) + a.click() + a.remove() + window.URL.revokeObjectURL(url) + } catch (err) { + console.error("Failed to download post:", err) + alert(`Download failed: ${err.message}`) + } finally { + setDownloading(false) + } + } + const togglePlay = () => { if (!audioRef.current) return @@ -122,24 +146,6 @@ export default function AudioPostCard({ post }) { } } - const handleDownload = async () => { - try { - const zipBlob = await api.exportPost(post.post_id); - - const url = window.URL.createObjectURL(zipBlob); - const a = document.createElement("a"); - a.href = url; - a.download = `${post.title.replace(/\s+/g, "_")}.zip`; - document.body.appendChild(a); - a.click(); - a.remove(); - window.URL.revokeObjectURL(url); - } catch (err) { - console.error("Failed to download post:", err); - } - } - - const handleEnded = () => { setIsPlaying(false) setCurrentTime(0) @@ -174,15 +180,26 @@ export default function AudioPostCard({ post }) { - {post.status === "ready" && ( - -)} - + {post.status === 'ready' && ( + + )}