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