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
+ })}
+
+
+
+
+ )}
)}