From ca2dbece3e98392d6b56ccfd9d859569712b62b1 Mon Sep 17 00:00:00 2001 From: desartstudio95 Date: Thu, 7 May 2026 00:29:57 +0200 Subject: [PATCH] feat: Enhance testimonial display and admin management Introduce a horizontal scrolling carousel for testimonials on the landing page. Update the admin dashboard to fetch and display existing testimonials, enabling their management. --- src/components/AdminDashboard.tsx | 48 +++++++++++++++++++++++++++++-- src/components/LandingPage.tsx | 22 +++++++++----- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/components/AdminDashboard.tsx b/src/components/AdminDashboard.tsx index cc080df..7c6efbe 100644 --- a/src/components/AdminDashboard.tsx +++ b/src/components/AdminDashboard.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { Users, ShieldCheck, Search, Loader2 } from 'lucide-react'; import { cn } from '../lib/utils'; -import { collection, onSnapshot, doc, updateDoc, addDoc } from 'firebase/firestore'; +import { collection, onSnapshot, doc, updateDoc, addDoc, deleteDoc, query, orderBy } from 'firebase/firestore'; import { db, handleFirestoreError, OperationType, auth } from '../lib/firebase'; import { ImageUploader } from './ImageUploader'; @@ -18,6 +18,7 @@ interface UserProfile { export const AdminDashboard: React.FC = () => { const [users, setUsers] = useState([]); + const [testimonials, setTestimonials] = useState([]); const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(''); const [testUser, setTestUser] = useState(''); @@ -62,7 +63,17 @@ export const AdminDashboard: React.FC = () => { setLoading(false); }); - return () => unsub(); + const q = query(collection(db, 'testimonials'), orderBy('timestamp', 'desc')); + const unsubTestimonials = onSnapshot(q, (snapshot) => { + setTestimonials(snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }))); + }, (error) => { + console.error("Testimonials fetch error:", error); + }); + + return () => { + unsub(); + unsubTestimonials(); + }; }, []); const handleToggleApproval = async (userId: string, currentStatus: boolean) => { @@ -106,6 +117,17 @@ export const AdminDashboard: React.FC = () => { } }; + const handleDeleteTestimonial = async (id: string) => { + if (!confirm('Tem certeza que deseja remover este resultado?')) return; + try { + await deleteDoc(doc(db, 'testimonials', id)); + alert('Resultado removido com sucesso!'); + } catch (err) { + console.error("Failed to delete testimonial", err); + alert('Erro ao remover resultado.'); + } + }; + const filteredUsers = users.filter(user => user.email?.toLowerCase().includes(searchTerm.toLowerCase()) || user.name?.toLowerCase().includes(searchTerm.toLowerCase()) @@ -164,6 +186,28 @@ export const AdminDashboard: React.FC = () => { + {testimonials.length > 0 && ( +
+

Resultados Postados

+
+ {testimonials.map(t => ( +
+ {t.imageUrls && t.imageUrls.length > 0 && ( + Result + )} +

"{t.text}"

+

— {t.userName}

+
+ +
+
+ ))} +
+
+ )} + {loading ? (
diff --git a/src/components/LandingPage.tsx b/src/components/LandingPage.tsx index 645ba4a..1ec279c 100644 --- a/src/components/LandingPage.tsx +++ b/src/components/LandingPage.tsx @@ -276,16 +276,24 @@ export const LandingPage: React.FC = ({ onGetStarted, onViewPl

Resultados

-
+ {testimonials.length > 0 ? ( +
{testimonials.map((t, i) => ( -
- {t.imageUrls && t.imageUrls.map((url: string, index: number) => ( - {`Resultado +
+ {t.imageUrls && t.imageUrls.length > 0 && ( +
+ {t.imageUrls.map((url: string, index: number) => ( + {`Resultado ))} -

{t.text}
– **{t.userName.split('@')[0]}**

-
+
+ )} +

"{t.text}"
– {t.userName.split('@')[0]}

+
))} -
+
+ ) : ( +

Nenhum resultado postado ainda.

+ )}