diff --git a/dashboards/admin-web/src/app/(dashboard)/feedback/page.tsx b/dashboards/admin-web/src/app/(dashboard)/feedback/page.tsx index 8b4e49b1..4706134c 100644 --- a/dashboards/admin-web/src/app/(dashboard)/feedback/page.tsx +++ b/dashboards/admin-web/src/app/(dashboard)/feedback/page.tsx @@ -1,7 +1,7 @@ 'use client'; -import { useState, useEffect } from 'react'; -import { useRouter } from 'next/navigation'; +import Image from 'next/image'; +import { useCallback, useEffect, useState } from 'react'; import { Search, MessageSquare, @@ -26,12 +26,7 @@ import { TableHeader, TableRow, } from '@/components/ui/table'; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog'; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Select, SelectContent, @@ -94,22 +89,22 @@ export default function FeedbackPage() { const [lightboxOpen, setLightboxOpen] = useState(false); const { toast } = useToast(); - useEffect(() => { - fetchFeedback(); - }, []); - - async function fetchFeedback() { + const fetchFeedback = useCallback(async () => { try { const res = await fetch('/api/feedback'); if (!res.ok) throw new Error('Failed to fetch'); const data = await res.json(); setFeedback(data.items || []); - } catch (err) { + } catch { toast({ title: 'Error', description: 'Failed to load feedback', variant: 'error' }); } finally { setLoading(false); } - } + }, [toast]); + + useEffect(() => { + fetchFeedback(); + }, [fetchFeedback]); async function viewScreenshot(feedbackId: string) { try { @@ -118,7 +113,7 @@ export default function FeedbackPage() { const data = await res.json(); setScreenshotUrl(data.url); setLightboxOpen(true); - } catch (err) { + } catch { toast({ title: 'Error', description: 'Failed to load screenshot', variant: 'error' }); } } @@ -130,7 +125,7 @@ export default function FeedbackPage() { if (!res.ok) throw new Error('Failed to delete'); toast({ title: 'Success', description: 'Screenshot deleted' }); fetchFeedback(); - } catch (err) { + } catch { toast({ title: 'Error', description: 'Failed to delete screenshot', variant: 'error' }); } } @@ -140,7 +135,7 @@ export default function FeedbackPage() { const res = await fetch(`/api/feedback/${feedbackId}/screenshot`); if (!res.ok) throw new Error('Failed to fetch screenshot'); const data = await res.json(); - + // Create temporary link to download const link = document.createElement('a'); link.href = data.url; @@ -148,19 +143,21 @@ export default function FeedbackPage() { document.body.appendChild(link); link.click(); document.body.removeChild(link); - } catch (err) { + } catch { toast({ title: 'Error', description: 'Failed to download screenshot', variant: 'error' }); } } - const filteredFeedback = feedback.filter((f) => { - const matchesSearch = f.title.toLowerCase().includes(search.toLowerCase()) || - f.body?.toLowerCase().includes(search.toLowerCase()); + const filteredFeedback = feedback.filter(f => { + const matchesSearch = + f.title.toLowerCase().includes(search.toLowerCase()) || + f.body?.toLowerCase().includes(search.toLowerCase()); const matchesType = typeFilter === 'all' || f.type === typeFilter; const matchesStatus = statusFilter === 'all' || f.status === statusFilter; - const matchesScreenshot = screenshotFilter === 'all' || - (screenshotFilter === 'has' && f.screenshotBlobPath) || - (screenshotFilter === 'none' && !f.screenshotBlobPath); + const matchesScreenshot = + screenshotFilter === 'all' || + (screenshotFilter === 'has' && f.screenshotBlobPath) || + (screenshotFilter === 'none' && !f.screenshotBlobPath); return matchesSearch && matchesType && matchesStatus && matchesScreenshot; }); @@ -169,7 +166,9 @@ export default function FeedbackPage() {
View and manage user-submitted feedback with screenshots
++ View and manage user-submitted feedback with screenshots +