diff --git a/.gitignore b/.gitignore
index 43b28bba..00aba771 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,3 +61,6 @@ node_modules/
/playwright-report/
/blob-report/
/playwright/.cache/
+
+# Snaplet
+/.snaplet/
\ No newline at end of file
diff --git a/src/app/casos-activos/layout.js b/src/app/casos-activos/layout.js
deleted file mode 100644
index b23c4515..00000000
--- a/src/app/casos-activos/layout.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { supabase } from '@/lib/supabase/client';
-import TabNavigation from '@/components/TabNavigation';
-const getCount = async () => {
- const {
- data: solicitaData,
- count: solicitaCount,
- error: solicitaError,
- } = await supabase.from('help_requests').select('id', { count: 'exact' }).eq('type', 'necesita');
-
- const {
- data: ofreceData,
- count: ofreceCount,
- error: ofreceError,
- } = await supabase.from('help_requests').select('id', { count: 'exact' }).eq('type', 'ofrece');
-
- if (solicitaError) {
- throw new Error('Error fetching solicita:', solicitaError);
- }
- if (ofreceError) {
- throw new Error('Error fetching ofrece:', ofreceError);
- }
-
- return {
- solicitudes: solicitaCount || 0,
- ofertas: ofreceCount || 0,
- };
-};
-
-export default async function CasosActivosLayout({ children }) {
- const count = await getCount();
- return (
- <>
-
-
- {children}
-
- >
- );
-}
diff --git a/src/app/casos-activos/layout.tsx b/src/app/casos-activos/layout.tsx
new file mode 100644
index 00000000..85086a99
--- /dev/null
+++ b/src/app/casos-activos/layout.tsx
@@ -0,0 +1,41 @@
+import { createClient } from '@/lib/supabase/server';
+import TabNavigation from '@/components/TabNavigation';
+import { PropsWithChildren } from 'react';
+import { SupabaseClient } from '@supabase/supabase-js';
+import { Database } from '@/types/database';
+const getCount = async (supabase: SupabaseClient) => {
+ const { count: solicitaCount, error: solicitaError } = await supabase
+ .from('help_requests')
+ .select('id', { count: 'exact' })
+ .eq('type', 'necesita');
+
+ const { count: ofreceCount, error: ofreceError } = await supabase
+ .from('help_requests')
+ .select('id', { count: 'exact' })
+ .eq('type', 'ofrece');
+
+ if (solicitaError) {
+ throw new Error('Error fetching solicita:', solicitaError);
+ }
+ if (ofreceError) {
+ throw new Error('Error fetching ofrece:', ofreceError);
+ }
+
+ return {
+ solicitudes: solicitaCount || 0,
+ ofertas: ofreceCount || 0,
+ };
+};
+
+export default async function CasosActivosLayout({ children }: PropsWithChildren) {
+ const supabase = await createClient();
+ const count = await getCount(supabase);
+ return (
+ <>
+
+
+ {children}
+
+ >
+ );
+}
diff --git a/src/app/casos-activos/mapa/page.tsx b/src/app/casos-activos/mapa/page.tsx
index 64333c9e..23822f74 100644
--- a/src/app/casos-activos/mapa/page.tsx
+++ b/src/app/casos-activos/mapa/page.tsx
@@ -8,6 +8,8 @@ import { tiposAyudaOptions } from '@/helpers/constants';
import Map, { PinMapa } from '@/components/map/map';
import PickupPoint from '@/components/PickupPoint';
+export const dynamic = 'force-dynamic';
+
export default function MapaPage() {
return (
diff --git a/src/app/casos-activos/ofertas/page.js b/src/app/casos-activos/ofertas/page.tsx
similarity index 77%
rename from src/app/casos-activos/ofertas/page.js
rename to src/app/casos-activos/ofertas/page.tsx
index 3d7a58e7..d1b8f5de 100644
--- a/src/app/casos-activos/ofertas/page.js
+++ b/src/app/casos-activos/ofertas/page.tsx
@@ -1,13 +1,14 @@
'use client';
import { Suspense, useEffect, useState } from 'react';
-import { HeartHandshake } from 'lucide-react';
import { supabase } from '@/lib/supabase/client';
import Pagination from '@/components/Pagination';
import { tiposAyudaOptions } from '@/helpers/constants';
import { useRouter, useSearchParams } from 'next/navigation';
-import { useTowns } from '@/context/TownProvider';
import OfferCard from '@/components/OfferCard';
+import { HelpRequestData } from '@/types/Requests';
+
+export const dynamic = 'force-dynamic';
export default function OfertasPage() {
return (
@@ -18,26 +19,25 @@ export default function OfertasPage() {
}
function Ofertas() {
- const { towns } = useTowns();
const searchParams = useSearchParams();
const router = useRouter();
const {} = router;
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
- const [data, setData] = useState([]);
- const [currentPage, setCurrentPage] = useState(Number(searchParams.get('page')) || 1);
- const [currentCount, setCurrentCount] = useState(0);
+ const [data, setData] = useState([]);
+ const [currentPage, setCurrentPage] = useState(Number(searchParams.get('page')) || 1);
+ const [currentCount, setCurrentCount] = useState(0);
const itemsPerPage = 10;
- const numPages = (count) => {
+ const numPages = (count: number) => {
return Math.ceil(count / itemsPerPage) || 0;
};
- const updateFilter = (filter, value) => {
+ const updateFilter = (filter: 'ayuda' | 'page', value: string | number) => {
const params = new URLSearchParams(searchParams.toString());
- params.set(filter, value);
+ params.set(filter, value.toString());
router.push(`?${params.toString()}`);
};
@@ -45,7 +45,7 @@ function Ofertas() {
ayuda: searchParams.get('acepta') || 'todas',
});
- const changeDataFilter = (type, newFilter) => {
+ const changeDataFilter = (type: 'ayuda', newFilter: string) => {
setFiltroData((prev) => ({
...prev,
[type]: newFilter,
@@ -53,7 +53,7 @@ function Ofertas() {
updateFilter(type, newFilter);
};
- function changePage(newPage) {
+ function changePage(newPage: number) {
setCurrentPage(newPage);
updateFilter('page', newPage);
}
@@ -83,7 +83,7 @@ function Ofertas() {
setData([]);
} else {
setData(data || []);
- setCurrentCount(count);
+ setCurrentCount(count ?? 0);
}
} catch (err) {
console.log('Error general:', err);
@@ -136,21 +136,11 @@ function Ofertas() {
{data.length === 0 ? (
- No se encontraron solicitudes que coincidan con los filtros.
+ No se encontraron ofertas que coincidan con los filtros.
-
-
) : (
- data.map((caso) => )
+ data.map((caso) => )
)}
diff --git a/src/app/casos-activos/page.js b/src/app/casos-activos/page.js
deleted file mode 100644
index bf9d287e..00000000
--- a/src/app/casos-activos/page.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import CasosActivosLayout from './layout';
-import Solicitudes from './solicitudes/page';
-
-export default function CasosActivos() {
- return
;
-}
diff --git a/src/app/casos-activos/solicitudes/page.js b/src/app/casos-activos/solicitudes/page.tsx
similarity index 78%
rename from src/app/casos-activos/solicitudes/page.js
rename to src/app/casos-activos/solicitudes/page.tsx
index e1b8acf0..725493eb 100644
--- a/src/app/casos-activos/solicitudes/page.js
+++ b/src/app/casos-activos/solicitudes/page.tsx
@@ -1,18 +1,15 @@
'use client';
import { Suspense, useEffect, useState } from 'react';
-import { HeartHandshake } from 'lucide-react';
import { supabase } from '@/lib/supabase/client';
import SolicitudCard from '@/components/SolicitudCard';
import Pagination from '@/components/Pagination';
-import OfferHelp from '@/components/OfferHelp';
import { useRouter, useSearchParams } from 'next/navigation';
import { tiposAyudaOptions } from '@/helpers/constants';
-import Modal from '@/components/Modal';
-import { useModal } from '@/context/ModalProvider';
import { useTowns } from '@/context/TownProvider';
+import { HelpRequestData } from '@/types/Requests';
-const MODAL_NAME = 'solicitudes';
+export const dynamic = 'force-dynamic';
export default function SolicitudesPage() {
return (
@@ -23,29 +20,25 @@ export default function SolicitudesPage() {
}
function Solicitudes() {
- const { getTownById, towns } = useTowns();
+ const { towns } = useTowns();
const searchParams = useSearchParams();
const router = useRouter();
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
+ const [loading, setLoading] = useState
(true);
+ const [error, setError] = useState(null);
- const [data, setData] = useState([]);
- const [currentPage, setCurrentPage] = useState(Number(searchParams.get('page')) || 1);
- const [currentCount, setCurrentCount] = useState(0);
- const { toggleModal } = useModal();
+ const [data, setData] = useState([]);
+ const [currentPage, setCurrentPage] = useState(Number(searchParams.get('page')) || 1);
+ const [currentCount, setCurrentCount] = useState(0);
- const closeModal = () => {
- toggleModal(MODAL_NAME, false);
- };
const itemsPerPage = 10;
- const numPages = (count) => {
+ const numPages = (count: number) => {
return Math.ceil(count / itemsPerPage) || 0;
};
- const updateFilter = (filter, value) => {
+ const updateFilter = (filter: 'urgencia' | 'tipoAyuda' | 'pueblo' | 'page', value: string | number) => {
const params = new URLSearchParams(searchParams.toString());
- params.set(filter, value);
+ params.set(filter, value.toString());
router.push(`?${params.toString()}`);
};
@@ -55,7 +48,7 @@ function Solicitudes() {
pueblo: searchParams.get('pueblo') || 'todos',
});
- const changeDataFilter = (type, newFilter) => {
+ const changeDataFilter = (type: 'urgencia' | 'tipoAyuda' | 'pueblo', newFilter: string) => {
setFiltroData((prev) => ({
...prev,
[type]: newFilter,
@@ -63,7 +56,7 @@ function Solicitudes() {
updateFilter(type, newFilter);
};
- function changePage(newPage) {
+ function changePage(newPage: number) {
setCurrentPage(newPage);
updateFilter('page', newPage);
}
@@ -102,7 +95,7 @@ function Solicitudes() {
setData([]);
} else {
setData(data || []);
- setCurrentCount(count);
+ setCurrentCount(count ?? 0);
}
} catch (err) {
console.log('Error general:', err);
@@ -131,8 +124,6 @@ function Solicitudes() {
);
}
- const puebloSeleccionado = getTownById(Number(filtroData.pueblo));
-
return (
<>
{/* FILTROS */}
@@ -181,16 +172,6 @@ function Solicitudes() {
No se encontraron solicitudes que coincidan con los filtros.
-
-
) : (
data.map((caso) => )
@@ -199,10 +180,6 @@ function Solicitudes() {
-
-
-
-
>
);
}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 17213357..a2516ed5 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -5,7 +5,7 @@ import PhoneNumberDialog from '@/components/auth/PhoneNumberDialog';
import Image from 'next/image';
import { CallCenterLink } from '@/components/CallCenterLink';
-export default function Home() {
+export default async function Home() {
const emergencyNumbers = [
{ name: 'Emergencias', number: '112', description: 'Para situaciones de peligro inmediato' },
{ name: 'Policía Local', number: '092', description: 'Asistencia y seguridad local' },
@@ -132,7 +132,7 @@ export default function Home() {
title: 'Casos activos',
description: 'Observa los casos activos',
icon: AlertCircle,
- path: '/casos-activos',
+ path: '/casos-activos/solicitudes',
color: 'orange',
},
{
diff --git a/src/app/punto-recogida/page.js b/src/app/punto-recogida/page.tsx
similarity index 90%
rename from src/app/punto-recogida/page.js
rename to src/app/punto-recogida/page.tsx
index e61daec3..c0122674 100644
--- a/src/app/punto-recogida/page.js
+++ b/src/app/punto-recogida/page.tsx
@@ -1,11 +1,14 @@
'use client';
-import { useState, useCallback, useEffect } from 'react';
+import { useState, useCallback, useEffect, FormEvent } from 'react';
import { supabase } from '@/lib/supabase/client';
import { MapPin, Phone, Package, House, Contact, Megaphone } from 'lucide-react';
import AddressAutocomplete from '@/components/AddressAutocomplete';
import { isValidPhone } from '@/helpers/utils';
import { PhoneInput } from '@/components/PhoneInput';
+import { CollectionPointData, CollectionPointInsert } from '@/types/DataPoints';
+
+export const dynamic = 'force-dynamic';
export default function PuntosRecogida() {
const initialFormData = {
@@ -20,16 +23,16 @@ export default function PuntosRecogida() {
status: 'active',
};
- const [formData, setFormData] = useState(initialFormData);
+ const [formData, setFormData] = useState(initialFormData);
const [showForm, setShowForm] = useState(false);
const [loading, setLoading] = useState(false);
- const [collectionPoints, setCollectionPoints] = useState([]);
- const [error, setError] = useState(null);
+ const [collectionPoints, setCollectionPoints] = useState([]);
+ const [error, setError] = useState(null);
const [success, setSuccess] = useState(false);
const tiposAyuda = ['Alimentos', 'Agua', 'Ropa', 'Mantas', 'Medicamentos', 'Productos de higiene'];
- const handlePhoneChange = useCallback((phoneNumber) => {
+ const handlePhoneChange = useCallback((phoneNumber: string) => {
setFormData((formData) => ({ ...formData, contact_phone: phoneNumber }));
}, []);
@@ -52,20 +55,20 @@ export default function PuntosRecogida() {
}
}
- async function handleSubmit(e) {
+ async function handleSubmit(e: FormEvent) {
e.preventDefault();
setLoading(true);
setError(null);
try {
- const requiredFields = ['name', 'location', 'contact_phone'];
+ const requiredFields = ['name', 'location', 'contact_phone'] as const;
const missingFields = requiredFields.filter((field) => !formData[field]);
if (missingFields.length > 0) {
throw new Error('Por favor completa todos los campos obligatorios');
}
- if (!isValidPhone(formData.contact_phone)) {
+ if (!isValidPhone(formData.contact_phone ?? '')) {
alert('El teléfono de contacto no es válido.');
return;
}
@@ -92,7 +95,7 @@ export default function PuntosRecogida() {
setFormData(initialFormData);
setTimeout(() => setSuccess(false), 3000);
- } catch (error) {
+ } catch (error: any) {
console.error('Error al registrar punto de recogida:', error);
setError(error.message || 'Error al registrar el punto de recogida');
} finally {
@@ -208,7 +211,7 @@ export default function PuntosRecogida() {
setFormData({ ...formData, name: e.target.value })}
className="w-full p-2 border rounded"
required
@@ -217,7 +220,7 @@ export default function PuntosRecogida() {
{
+ onSelect={(address: any) => {
setFormData((prev) => ({
...prev,
location: address.fullAddress,
@@ -240,18 +243,18 @@ export default function PuntosRecogida() {
-
+
Necesidades urgentes
diff --git a/src/app/puntos-entrega/page.js b/src/app/puntos-entrega/page.tsx
similarity index 92%
rename from src/app/puntos-entrega/page.js
rename to src/app/puntos-entrega/page.tsx
index 10927da3..5ea18b2b 100644
--- a/src/app/puntos-entrega/page.js
+++ b/src/app/puntos-entrega/page.tsx
@@ -1,9 +1,10 @@
'use client';
-import { useState, useEffect } from 'react';
+import { useState, useEffect, FormEvent } from 'react';
import { supabase } from '@/lib/supabase/client';
import { Truck, MapPin, Phone, Mail, Calendar, Package } from 'lucide-react';
import AddressAutocomplete from '@/components/AddressAutocomplete';
+import { DeliveryPointData, DeliveryPointInsert, isCoordinates } from '@/types/DataPoints';
export default function PuntosEntrega() {
const initialFormData = {
@@ -21,12 +22,12 @@ export default function PuntosEntrega() {
status: 'active',
};
- const [formData, setFormData] = useState(initialFormData);
+ const [formData, setFormData] = useState(initialFormData);
const [showForm, setShowForm] = useState(false);
const [loading, setLoading] = useState(false);
- const [points, setPoints] = useState([]);
- const [error, setError] = useState(null);
- const [success, setSuccess] = useState(false);
+ const [points, setPoints] = useState([]);
+ const [error, setError] = useState(null);
+ const [success, setSuccess] = useState(false);
const vehicleTypes = ['Camión grande (>3500kg)', 'Camión mediano', 'Furgoneta grande', 'Furgoneta mediana', 'Otro'];
@@ -51,13 +52,13 @@ export default function PuntosEntrega() {
}
}
- async function handleSubmit(e) {
+ async function handleSubmit(e: FormEvent) {
e.preventDefault();
setLoading(true);
setError(null);
try {
- const requiredFields = ['name', 'location', 'contact_phone'];
+ const requiredFields = ['name', 'location', 'contact_phone'] as const;
const missingFields = requiredFields.filter((field) => !formData[field]);
if (missingFields.length > 0) {
@@ -67,7 +68,7 @@ export default function PuntosEntrega() {
const pointData = {
name: formData.name,
location: formData.location,
- city: formData.city || null,
+ city: formData.city,
contact_name: formData.contact_name || null,
contact_phone: formData.contact_phone,
contact_email: formData.contact_email || null,
@@ -75,8 +76,8 @@ export default function PuntosEntrega() {
cargo_type: formData.cargo_type || null,
schedule: formData.schedule || null,
additional_info: formData.additional_info || null,
- latitude: formData.coordinates?.lat ? parseFloat(formData.coordinates.lat) : null,
- longitude: formData.coordinates?.lon ? parseFloat(formData.coordinates.lon) : null,
+ latitude: isCoordinates(formData.coordinates) ? formData.coordinates.lat : null,
+ longitude: isCoordinates(formData.coordinates) ? formData.coordinates.lon : null,
status: 'active',
};
@@ -90,7 +91,7 @@ export default function PuntosEntrega() {
setFormData(initialFormData);
setTimeout(() => setSuccess(false), 3000);
- } catch (error) {
+ } catch (error: any) {
console.error('Error al registrar punto de entrega:', error);
setError(error.message || 'Error al registrar el punto de entrega');
} finally {
@@ -225,7 +226,7 @@ export default function PuntosEntrega() {
Dirección exacta *
{
+ onSelect={(address: any) => {
setFormData((prev) => ({
...prev,
location: address.fullAddress,
@@ -246,7 +247,7 @@ export default function PuntosEntrega() {
Tipo de vehículos