diff --git a/backend/__pycache__/api_routes.cpython-311.pyc b/backend/__pycache__/api_routes.cpython-311.pyc index 2a83a73..c0aa6cc 100644 Binary files a/backend/__pycache__/api_routes.cpython-311.pyc and b/backend/__pycache__/api_routes.cpython-311.pyc differ diff --git a/backend/__pycache__/db_queries.cpython-311.pyc b/backend/__pycache__/db_queries.cpython-311.pyc index f2f0aa7..1ae39bc 100644 Binary files a/backend/__pycache__/db_queries.cpython-311.pyc and b/backend/__pycache__/db_queries.cpython-311.pyc differ diff --git a/backend/api_routes.py b/backend/api_routes.py index 8bfb42c..4575134 100644 --- a/backend/api_routes.py +++ b/backend/api_routes.py @@ -868,19 +868,18 @@ def api_delete_post(post_id: int): return _error("You don't have permission to delete this post.", 403) try: + add_audit_log({ + "user_id": user_id, + "action": "post.deleted", + "details": json.dumps({"deleted_post_id": post_id, "title": post.get("title")}) + }) + delete_rag_chunks(post_id) delete_archive_files(post_id) delete_metadata(post_id) delete_rights(post_id) delete_audio_post(post_id) - add_audit_log({ - "post_id": post_id, - "user_id": user_id, - "action": "post.deleted", - "details": json.dumps({"title": post.get("title")}) - }) - return jsonify({"message": "Post deleted successfully", "post_id": post_id}) except Exception as e: diff --git a/backend/uploads/00ce7e87-614d-44f7-a300-0ac8fb4af2bd_data.m4a b/backend/uploads/00ce7e87-614d-44f7-a300-0ac8fb4af2bd_data.m4a new file mode 100644 index 0000000..38e5740 Binary files /dev/null and b/backend/uploads/00ce7e87-614d-44f7-a300-0ac8fb4af2bd_data.m4a differ diff --git a/backend/uploads/28b3ced4-4174-4555-ad9c-cb0adff1fbba_harvard.wav b/backend/uploads/28b3ced4-4174-4555-ad9c-cb0adff1fbba_harvard.wav new file mode 100644 index 0000000..b05ec79 Binary files /dev/null and b/backend/uploads/28b3ced4-4174-4555-ad9c-cb0adff1fbba_harvard.wav differ diff --git a/frontend/public/Logo.png b/frontend/public/Logo.png new file mode 100644 index 0000000..6ca06f6 Binary files /dev/null and b/frontend/public/Logo.png differ diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index d48ffae..e8b5ddf 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -61,6 +61,7 @@ export default function App() { localStorage.removeItem('voicevault_user') setShowLogin(true) setActiveTab('feed') + setViewingPostId(null) } const handleSearch = async (query) => { @@ -91,9 +92,15 @@ export default function App() { setViewingPostId(null) } + const handleTabChange = (tab) => { + setActiveTab(tab) + setViewingPostId(null) + } + const handlePostCreated = () => { // Switch to feed after creating a post setActiveTab('feed') + setViewingPostId(null) } const handleUserUpdate = (updatedUser) => { @@ -202,11 +209,16 @@ export default function App() { // Main App return ( -
+
+<<<<<<< HEAD
+ +======= +
+>>>>>>> cd657f37cf76773d9dd6ad7a0cdbe05e19a9eced
{renderPage()} diff --git a/frontend/src/api.js b/frontend/src/api.js index bdb09d8..9cbc904 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -27,13 +27,16 @@ class ApiClient { try { const response = await fetch(url, config); - const data = await response.json(); + const contentType = response.headers.get('content-type') || ''; + const isJson = contentType.includes('application/json'); + const data = isJson ? await response.json() : null; if (!response.ok) { - throw new Error(data.error || 'Request failed'); + const fallbackError = `Request failed with status ${response.status}`; + throw new Error((data && data.error) || fallbackError); } - return data; + return data || {}; } catch (error) { console.error('API Error:', error); throw error; @@ -87,14 +90,16 @@ class ApiClient { method: 'POST', body: formData, // Don't set Content-Type, let browser set it with boundary }); - - const data = await response.json(); + const contentType = response.headers.get('content-type') || ''; + const isJson = contentType.includes('application/json'); + const data = isJson ? await response.json() : null; if (!response.ok) { - throw new Error(data.error || 'Upload failed'); + const fallbackError = `Upload failed with status ${response.status}`; + throw new Error((data && data.error) || fallbackError); } - return data; + return data || {}; } catch (error) { console.error('Upload Error:', error); throw error; @@ -144,10 +149,6 @@ class ApiClient { }); } - async getPostMetadata(postId) { - return this.request(`/posts/${postId}/metadata`); - } - async getAudioUrl(postId, expiresIn = 3600) { return this.request(`/posts/${postId}/audio?expires_in=${expiresIn}`); } diff --git a/frontend/src/components/EditPostModal.jsx b/frontend/src/components/EditPostModal.jsx index 3d941f4..9594ef9 100644 --- a/frontend/src/components/EditPostModal.jsx +++ b/frontend/src/components/EditPostModal.jsx @@ -28,8 +28,8 @@ export default function EditPostModal({ post, user, onClose, onSave }) { visibility } - await api.editPost(post.post_id, updates) - onSave?.() + const updatedPost = await api.editPost(post.post_id, updates) + onSave?.(updatedPost) onClose() } catch (err) { setError(err.message || 'Failed to update post') diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/Header.jsx index c4ae9c6..5f96b8b 100644 --- a/frontend/src/components/Header.jsx +++ b/frontend/src/components/Header.jsx @@ -23,10 +23,15 @@ export default function Header({ onSearch, onLogout, onNavigateToSearch }) {
{/* Left: Logo */}
-
- +
+ {/* - + */} + VoiceVault Logo

VoiceVault

diff --git a/frontend/src/pages/History.jsx b/frontend/src/pages/History.jsx index 7cf626c..e432d79 100644 --- a/frontend/src/pages/History.jsx +++ b/frontend/src/pages/History.jsx @@ -40,7 +40,7 @@ export default function History({ user, onViewPost }) { try { await api.deletePost(postId, user.user_id) // Remove from local state immediately - setPosts(posts.filter(p => p.post_id !== postId)) + setPosts((prev) => prev.filter((p) => p.post_id !== postId)) } catch (err) { alert('Failed to delete post: ' + err.message) } finally { @@ -58,8 +58,15 @@ export default function History({ user, onViewPost }) { setEditingPost(post) } - const handleSaveEdit = () => { - // Refresh the list after edit + const handleSaveEdit = (updatedPost) => { + if (updatedPost && updatedPost.post_id) { + setPosts((prev) => + prev.map((post) => + post.post_id === updatedPost.post_id ? { ...post, ...updatedPost } : post + ) + ) + return + } fetchHistory() } diff --git a/frontend/src/pages/PostDetail.jsx b/frontend/src/pages/PostDetail.jsx index cfafa34..dd575b5 100644 --- a/frontend/src/pages/PostDetail.jsx +++ b/frontend/src/pages/PostDetail.jsx @@ -16,6 +16,7 @@ export default function PostDetail({ postId, user, onBack }) { const [volume, setVolume] = useState(1) const [downloading, setDownloading] = useState(false) const audioRef = useRef(null) + const [audioSrc, setAudioSrc] = useState(null) useEffect(() => { if (postId) { @@ -34,6 +35,8 @@ export default function PostDetail({ postId, user, onBack }) { // Load audio URL if available if (postData.audio_url && audioRef.current) { + setPost(postData) + setAudioSrc(postData.audio_url) audioRef.current.src = postData.audio_url audioRef.current.load() } @@ -290,12 +293,14 @@ export default function PostDetail({ postId, user, onBack }) {