diff --git a/src/components/ApplicationDetailsModal.tsx b/src/components/ApplicationDetailsModal.tsx index 15f3027..65f63e7 100644 --- a/src/components/ApplicationDetailsModal.tsx +++ b/src/components/ApplicationDetailsModal.tsx @@ -11,18 +11,65 @@ import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { VotingPanel } from "@/components/VotingPanel"; import { ApplicationVoteCharts } from "@/components/ApplicationVoteCharts"; -import { ExternalLink, Mail, Calendar, Clock, BookOpen, Users, GraduationCap, User, FileText, BarChart3 } from "lucide-react"; +import { ExternalLink, Mail, Calendar, Clock, BookOpen, Users, GraduationCap, User, FileText, BarChart3, ChevronLeft, ChevronRight } from "lucide-react"; import { usePermissions } from "@/hooks/usePermissions"; +import { useEffect } from "react"; interface ApplicationDetailsModalProps { application: Application | null; open: boolean; onOpenChange: (open: boolean) => void; onVoteSubmitted?: () => void; + onNavigateNext?: () => void; + onNavigatePrevious?: () => void; + canNavigateNext?: boolean; + canNavigatePrevious?: boolean; + currentIndex?: number; + totalCount?: number; } -export const ApplicationDetailsModal = ({ application, open, onOpenChange, onVoteSubmitted }: ApplicationDetailsModalProps) => { +export const ApplicationDetailsModal = ({ + application, + open, + onOpenChange, + onVoteSubmitted, + onNavigateNext, + onNavigatePrevious, + canNavigateNext = false, + canNavigatePrevious = false, + currentIndex, + totalCount +}: ApplicationDetailsModalProps) => { const { canVote, canViewVoteDetails } = usePermissions(); + + // Handle keyboard navigation + useEffect(() => { + if (!open) return; + + const handleKeyDown = (event: KeyboardEvent) => { + // Prevent navigation if user is typing in an input, textarea, or contenteditable element + const target = event.target as HTMLElement; + if ( + target instanceof HTMLInputElement || + target instanceof HTMLTextAreaElement || + target.contentEditable === 'true' + ) { + return; + } + + if (event.key === 'ArrowLeft' && canNavigatePrevious && onNavigatePrevious) { + event.preventDefault(); + onNavigatePrevious(); + } else if (event.key === 'ArrowRight' && canNavigateNext && onNavigateNext) { + event.preventDefault(); + onNavigateNext(); + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [open, canNavigateNext, canNavigatePrevious, onNavigateNext, onNavigatePrevious]); + if (!application) return null; const formatDate = (dateString: string) => { @@ -42,6 +89,34 @@ export const ApplicationDetailsModal = ({ application, open, onOpenChange, onVot return ( + {/* Navigation Arrows */} + {(canNavigatePrevious || canNavigateNext) && ( + <> + {canNavigatePrevious && ( + + )} + {canNavigateNext && ( + + )} + + )} +
@@ -51,9 +126,16 @@ export const ApplicationDetailsModal = ({ application, open, onOpenChange, onVot {application.rut}
- - ID: {application.id} - +
+ {currentIndex !== undefined && totalCount !== undefined && ( + + {currentIndex + 1} / {totalCount} + + )} + + ID: {application.id} + +
diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index 27bae8d..ce0ca11 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -18,6 +18,7 @@ export const Home = () => { const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [selectedApplication, setSelectedApplication] = useState(null); + const [selectedApplicationIndex, setSelectedApplicationIndex] = useState(-1); const [isModalOpen, setIsModalOpen] = useState(false); const [syncLoading, setSyncLoading] = useState(false); const [syncMessage, setSyncMessage] = useState(null); @@ -67,7 +68,9 @@ export const Home = () => { }, [user]); const handleCardClick = (application: Application) => { + const index = applications.findIndex(app => app.id === application.id); setSelectedApplication(application); + setSelectedApplicationIndex(index); setIsModalOpen(true); }; @@ -75,17 +78,50 @@ export const Home = () => { setIsModalOpen(open); if (!open) { setSelectedApplication(null); + setSelectedApplicationIndex(-1); + } + }; + + const handleNavigateNext = () => { + if (selectedApplicationIndex < applications.length - 1) { + const nextIndex = selectedApplicationIndex + 1; + setSelectedApplicationIndex(nextIndex); + setSelectedApplication(applications[nextIndex]); + } + }; + + const handleNavigatePrevious = () => { + if (selectedApplicationIndex > 0) { + const prevIndex = selectedApplicationIndex - 1; + setSelectedApplicationIndex(prevIndex); + setSelectedApplication(applications[prevIndex]); } }; const handleVoteSubmitted = () => { // Cuando se envía un voto, eliminar la aplicación de la lista if (selectedApplication) { - setApplications(prev => prev.filter(app => app.rut !== selectedApplication.rut)); + const newApplications = applications.filter(app => app.rut !== selectedApplication.rut); + setApplications(newApplications); setTotalApplications(prev => prev - 1); - // Cerrar el modal después de votar - setIsModalOpen(false); - setSelectedApplication(null); + + // Ajustar el índice después de eliminar + if (newApplications.length > 0) { + // El índice actual ahora apunta a la siguiente aplicación (porque removimos la actual) + // pero necesitamos validar que no exceda el límite + let newIndex = selectedApplicationIndex; + if (newIndex >= newApplications.length) { + // Si el índice está fuera de límites, ir a la última aplicación + newIndex = newApplications.length - 1; + } + setSelectedApplicationIndex(newIndex); + setSelectedApplication(newApplications[newIndex]); + } else { + // No hay más aplicaciones, cerrar el modal + setIsModalOpen(false); + setSelectedApplication(null); + setSelectedApplicationIndex(-1); + } } }; @@ -311,6 +347,12 @@ export const Home = () => { open={isModalOpen} onOpenChange={handleModalClose} onVoteSubmitted={handleVoteSubmitted} + onNavigateNext={handleNavigateNext} + onNavigatePrevious={handleNavigatePrevious} + canNavigateNext={selectedApplicationIndex < applications.length - 1} + canNavigatePrevious={selectedApplicationIndex > 0} + currentIndex={selectedApplicationIndex} + totalCount={applications.length} /> );