diff --git a/README.md b/README.md index b276f6a..6b5d5a1 100644 --- a/README.md +++ b/README.md @@ -360,6 +360,54 @@ UPDATE checklists SET max_score = ( MIT License - Uso libre para proyectos comerciales y personales +## 📝 Control de Versiones + +### Instrucciones para commits de Git + +**IMPORTANTE**: Siempre incluir la versión actualizada en los mensajes de commit. + +Formato recomendado: +```bash +git add . +git commit -m "tipo: descripción del cambio + +- Detalle 1 +- Detalle 2 +- Frontend vX.X.XX / Backend vX.X.XX" +``` + +Tipos de commit: +- `feat`: Nueva funcionalidad +- `fix`: Corrección de bugs +- `refactor`: Refactorización de código +- `style`: Cambios de formato/estilo +- `docs`: Actualización de documentación +- `perf`: Mejoras de rendimiento +- `test`: Añadir o actualizar tests + +**Ejemplo real**: +```bash +git add . +git commit -m "feat: Add pagination (10 items/page) to all main tabs + +- Pagination for Inspections, Checklists, and Reports +- Auto-reset on filter changes +- Smart page navigation with ellipsis +- Result counters showing X-Y of Z items +- Frontend v1.0.64" +``` + +### Versionado + +Seguir **Semantic Versioning** (MAJOR.MINOR.PATCH): +- **MAJOR**: Cambios incompatibles en la API +- **MINOR**: Nueva funcionalidad compatible con versiones anteriores +- **PATCH**: Correcciones de bugs + +Ubicación de versiones: +- Frontend: `frontend/package.json` → `"version": "X.X.XX"` +- Backend: `backend/app/main.py` → `version="X.X.XX"` en FastAPI app + ## 🆘 Soporte Para problemas o preguntas: diff --git a/frontend/package.json b/frontend/package.json index c22cfd9..a445ef9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "checklist-frontend", "private": true, - "version": "1.0.63", + "version": "1.0.64", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 36aefd6..06a8638 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1735,6 +1735,8 @@ function ChecklistsTab({ checklists, user, onChecklistCreated, onStartInspection const [mechanics, setMechanics] = useState([]) const [searchTerm, setSearchTerm] = useState('') const [aiModeFilter, setAiModeFilter] = useState('all') // all, off, optional, required + const [currentPage, setCurrentPage] = useState(1) + const itemsPerPage = 10 const [formData, setFormData] = useState({ name: '', description: '', @@ -1783,6 +1785,17 @@ function ChecklistsTab({ checklists, user, onChecklistCreated, onStartInspection return matchesSearch && matchesAiMode }) + // Calcular paginación + const totalPages = Math.ceil(filteredChecklists.length / itemsPerPage) + const startIndex = (currentPage - 1) * itemsPerPage + const endIndex = startIndex + itemsPerPage + const paginatedChecklists = filteredChecklists.slice(startIndex, endIndex) + + // Reset a página 1 cuando cambian los filtros + useEffect(() => { + setCurrentPage(1) + }, [searchTerm, aiModeFilter]) + const handleCreate = async (e) => { e.preventDefault() setCreating(true) @@ -1969,7 +1982,7 @@ function ChecklistsTab({ checklists, user, onChecklistCreated, onStartInspection {/* Contador de resultados */}
- Mostrando {filteredChecklists.length} de {checklists.length} checklists + Mostrando {startIndex + 1}-{Math.min(endIndex, filteredChecklists.length)} de {filteredChecklists.length} checklists
)} @@ -2010,7 +2023,8 @@ function ChecklistsTab({ checklists, user, onChecklistCreated, onStartInspection ) : ( - filteredChecklists.map((checklist) => ( + <> + {paginatedChecklists.map((checklist) => (
{/* Logo del Checklist */} @@ -2110,7 +2124,58 @@ function ChecklistsTab({ checklists, user, onChecklistCreated, onStartInspection
- )) + ))} + + {/* Controles de paginación */} + {filteredChecklists.length > itemsPerPage && ( +
+ + +
+ {[...Array(totalPages)].map((_, index) => { + const page = index + 1 + // Mostrar solo páginas cercanas a la actual + if ( + page === 1 || + page === totalPages || + (page >= currentPage - 1 && page <= currentPage + 1) + ) { + return ( + + ) + } else if (page === currentPage - 2 || page === currentPage + 2) { + return ... + } + return null + })} +
+ + +
+ )} + )} {/* Modal Gestionar Preguntas */} @@ -3173,6 +3238,8 @@ function InspectionsTab({ inspections, user, onUpdate }) { const [selectedInspection, setSelectedInspection] = useState(null) const [searchTerm, setSearchTerm] = useState('') const [statusFilter, setStatusFilter] = useState('all') // all, completed, draft + const [currentPage, setCurrentPage] = useState(1) + const itemsPerPage = 10 // Filtrar inspecciones const filteredInspections = inspections.filter(inspection => { @@ -3192,6 +3259,17 @@ function InspectionsTab({ inspections, user, onUpdate }) { return matchesSearch && matchesStatus }) + // Calcular paginación + const totalPages = Math.ceil(filteredInspections.length / itemsPerPage) + const startIndex = (currentPage - 1) * itemsPerPage + const endIndex = startIndex + itemsPerPage + const paginatedInspections = filteredInspections.slice(startIndex, endIndex) + + // Reset a página 1 cuando cambian los filtros + useEffect(() => { + setCurrentPage(1) + }, [searchTerm, statusFilter]) + if (inspections.length === 0) { return (
@@ -3231,7 +3309,7 @@ function InspectionsTab({ inspections, user, onUpdate }) { {/* Contador de resultados */}
- Mostrando {filteredInspections.length} de {inspections.length} inspecciones + Mostrando {startIndex + 1}-{Math.min(endIndex, filteredInspections.length)} de {filteredInspections.length} inspecciones
@@ -3251,7 +3329,7 @@ function InspectionsTab({ inspections, user, onUpdate }) { ) : (
- {filteredInspections.map((inspection) => ( + {paginatedInspections.map((inspection) => (
@@ -3296,6 +3374,56 @@ function InspectionsTab({ inspections, user, onUpdate }) {
)} + {/* Controles de paginación */} + {filteredInspections.length > itemsPerPage && ( +
+ + +
+ {[...Array(totalPages)].map((_, index) => { + const page = index + 1 + // Mostrar solo páginas cercanas a la actual + if ( + page === 1 || + page === totalPages || + (page >= currentPage - 1 && page <= currentPage + 1) + ) { + return ( + + ) + } else if (page === currentPage - 2 || page === currentPage + 2) { + return ... + } + return null + })} +
+ + +
+ )} + {/* Modal de Detalle */} {selectedInspection && ( { setLoading(true) setAppliedFilters(filters) + setCurrentPage(1) // Reset a página 1 al aplicar filtros await Promise.all([loadDashboard(filters), loadInspections(filters)]) setLoading(false) } @@ -5207,6 +5338,12 @@ function ReportsTab({ user }) { {inspections.length > 0 && (

📝 Inspecciones Recientes

+ + {/* Información de paginación */} +
+ Mostrando {((currentPage - 1) * itemsPerPage) + 1}-{Math.min(currentPage * itemsPerPage, inspections.length)} de {inspections.length} inspecciones +
+
@@ -5222,7 +5359,7 @@ function ReportsTab({ user }) { - {inspections.slice(0, 20).map((inspection) => ( + {inspections.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage).map((inspection) => (
{new Date(inspection.started_at).toLocaleDateString()} @@ -5286,6 +5423,57 @@ function ReportsTab({ user }) {
+ + {/* Controles de paginación */} + {inspections.length > itemsPerPage && ( +
+ + +
+ {[...Array(Math.ceil(inspections.length / itemsPerPage))].map((_, index) => { + const page = index + 1 + const totalPages = Math.ceil(inspections.length / itemsPerPage) + // Mostrar solo páginas cercanas a la actual + if ( + page === 1 || + page === totalPages || + (page >= currentPage - 1 && page <= currentPage + 1) + ) { + return ( + + ) + } else if (page === currentPage - 2 || page === currentPage + 2) { + return ... + } + return null + })} +
+ + +
+ )}
)}