diff --git a/src/app/casos-activos/mapa/page.tsx b/src/app/casos-activos/mapa/page.tsx index 9e738f68..b59e5e55 100644 --- a/src/app/casos-activos/mapa/page.tsx +++ b/src/app/casos-activos/mapa/page.tsx @@ -7,10 +7,8 @@ import { useRouter, useSearchParams } from 'next/navigation'; import { tiposAyudaOptions } from '@/helpers/constants'; import Map, { PinMapa } from '@/components/map/map'; import PickupPoint from '@/components/PickupPoint'; -import { useTowns } from '@/context/TownProvider'; export default function Mapa() { - const towns = useTowns(); const searchParams = useSearchParams(); const router = useRouter(); @@ -47,7 +45,7 @@ export default function Mapa() { latitude: request.latitude ?? 0, longitude: request.longitude ?? 0, id: request.id, - popup: , + popup: , }; } @@ -107,7 +105,7 @@ export default function Mapa() { } fetchData(); - }, [filtroData, towns]); + }, [filtroData]); if (loading) { return ( diff --git a/src/app/casos-activos/ofertas/page.js b/src/app/casos-activos/ofertas/page.js index 4dc1df3b..c2a78d1b 100644 --- a/src/app/casos-activos/ofertas/page.js +++ b/src/app/casos-activos/ofertas/page.js @@ -6,11 +6,11 @@ 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 { useTowns } from '@/context/TownProvider'; +import OfferCard from '@/components/OfferCard'; export default function Ofertas() { - const towns = useTowns(); + const { towns } = useTowns(); const searchParams = useSearchParams(); const router = useRouter(); diff --git a/src/app/casos-activos/solicitudes/page.js b/src/app/casos-activos/solicitudes/page.js index 5a86151e..99853cba 100644 --- a/src/app/casos-activos/solicitudes/page.js +++ b/src/app/casos-activos/solicitudes/page.js @@ -15,7 +15,7 @@ import { useTowns } from '@/context/TownProvider'; const MODAL_NAME = 'solicitudes'; export default function Solicitudes() { - const towns = useTowns(); + const { getTownById, towns } = useTowns(); const searchParams = useSearchParams(); const router = useRouter(); @@ -123,6 +123,8 @@ export default function Solicitudes() { ); } + const puebloSeleccionado = getTownById(Number(filtroData.pueblo)); + return ( <> {/* FILTROS */} @@ -179,14 +181,11 @@ export default function Solicitudes() { className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600 flex items-center gap-2 whitespace-nowrap" > - Ofrecer ayuda{' '} - {filtroData.pueblo === 'todos' - ? '' - : ' a ' + towns.find((town) => town.id === Number(filtroData.pueblo))?.name} + Ofrecer ayuda {filtroData.pueblo === 'todos' ? '' : ' a ' + getTownById(Number(filtroData.pueblo))?.name} ) : ( - data.map((caso) => ) + data.map((caso) => ) )}
@@ -194,11 +193,7 @@ export default function Solicitudes() {
- town.id === Number(filtroData.pueblo))?.name} - onClose={closeModal} - isModal={true} - /> + ); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index bac0251c..48aa29c9 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,10 +2,8 @@ import './globals.css'; import 'leaflet/dist/leaflet.css'; import SidebarLayout from '@/components/layout/SidebarLayout'; import { ModalProvider } from '@/context/ModalProvider'; -import { TownsProvider } from '@/context/TownProvider'; import { createClient } from '@/lib/supabase/server'; import { SessionProvider } from '@/context/SessionProvider'; -import { townsService } from '@/lib/service'; import { Toaster } from 'sonner'; import { PropsWithChildren } from 'react'; import { QueryClientProvider } from '@/context/QueryClientProvider'; @@ -23,18 +21,15 @@ const getSession = async () => { export default async function RootLayout({ children }: PropsWithChildren) { const session = await getSession(); - const towns = await townsService.getTowns(); return ( - - - {children} - - + + {children} + diff --git a/src/app/oferta/[id]/page.js b/src/app/oferta/[id]/page.js index ed95e8d0..80de85ca 100644 --- a/src/app/oferta/[id]/page.js +++ b/src/app/oferta/[id]/page.js @@ -3,15 +3,15 @@ import { useEffect, useState } from 'react'; import { useParams } from 'next/navigation'; import { supabase } from '@/lib/supabase/client'; import { ArrowLeft } from 'lucide-react'; -import OfferCard from '../../../components/OfferCard'; -import { useTowns } from '../../../context/TownProvider'; +import OfferCard from '@/components/OfferCard'; +import { useTowns } from '@/context/TownProvider'; export default function CasoDetalle() { const params = useParams(); const { id } = params; const [caso, setCaso] = useState(null); const [loading, setLoading] = useState(true); - const towns = useTowns(); + const { towns } = useTowns(); useEffect(() => { async function fetchCaso() { const { data, error } = await supabase.from('help_requests').select('*').eq('id', id).single(); diff --git a/src/app/ofertas/page.js b/src/app/ofertas/page.js index 3b8087ef..a3fac973 100644 --- a/src/app/ofertas/page.js +++ b/src/app/ofertas/page.js @@ -6,9 +6,9 @@ import { supabase } from '@/lib/supabase/client'; import Pagination from '@/components/Pagination'; import { useRouter, useSearchParams } from 'next/navigation'; import { tiposAyudaOptions } from '@/helpers/constants'; -import { useTowns } from '../../context/TownProvider'; -import { useSession } from '../../context/SessionProvider'; -import OfferCard from '../../components/OfferCard'; +import { useTowns } from '@/context/TownProvider'; +import { useSession } from '@/context/SessionProvider'; +import OfferCard from '@/components/OfferCard'; import Link from 'next/link'; export default function ListaSolicitudes() { @@ -23,7 +23,7 @@ export default function ListaSolicitudes() { const [data, setData] = useState([]); const [currentPage, setCurrentPage] = useState(Number(searchParams.get('page')) || 1); const [currentCount, setCurrentCount] = useState(0); - const towns = useTowns(); + const { towns } = useTowns(); const itemsPerPage = 10; const numPages = (count) => { diff --git a/src/app/solicitar-ayuda/_components/Form/FormContainer.tsx b/src/app/solicitar-ayuda/_components/Form/FormContainer.tsx index 620ac2e1..43971f3c 100644 --- a/src/app/solicitar-ayuda/_components/Form/FormContainer.tsx +++ b/src/app/solicitar-ayuda/_components/Form/FormContainer.tsx @@ -1,6 +1,6 @@ 'use client'; -import React, { FormEvent, useCallback, useEffect, useMemo, useState } from 'react'; +import React, { FormEvent, useCallback, useMemo, useState } from 'react'; import { FormRenderer } from './FormRenderer'; import { FormData, Status } from '../types'; @@ -49,14 +49,6 @@ export function FormContainer() { email: session?.user?.user_metadata?.email || '', }); - useEffect(() => { - console.log('Component mounted'); - }, []); - - useEffect(() => { - console.log('formData changed: ', formData); - }, [formData]); - const [status, setStatus] = useState({ isSubmitting: false, error: null, @@ -180,7 +172,6 @@ export function FormContainer() { } : null, })); - console.log('address: ', address); }, []); const handlePhoneChange = useCallback((phoneNumber: string) => { @@ -191,11 +182,7 @@ export function FormContainer() { }, []); const handleHelpTypeChange: React.ChangeEventHandler = useCallback((event) => { - const { id, name, value, checked } = event.target; - console.log('id: ', id); - console.log('name: ', name); - console.log('value: ', value); - console.log('checked: ', checked); + const { id, checked } = event.target; setFormData((formData) => { const prevHelp = formData.tiposDeAyuda; diff --git a/src/app/solicitud/page.js b/src/app/solicitud/page.js deleted file mode 100644 index 861953ab..00000000 --- a/src/app/solicitud/page.js +++ /dev/null @@ -1,21 +0,0 @@ -import { ArrowLeft } from 'lucide-react'; -import Link from 'next/link'; - -export default function Solicitud() { - return ( -
-
- - - Volver - -
-
-

No se encontró la solicitud.

-
-
- ); -} diff --git a/src/app/solicitud/[id]/page.js b/src/app/solicitudes/[id]/page.tsx similarity index 65% rename from src/app/solicitud/[id]/page.js rename to src/app/solicitudes/[id]/page.tsx index 44548753..0b3d313d 100644 --- a/src/app/solicitud/[id]/page.js +++ b/src/app/solicitudes/[id]/page.tsx @@ -1,37 +1,31 @@ 'use client'; -import { useEffect, useState } from 'react'; -import { useParams } from 'next/navigation'; -import { supabase } from '@/lib/supabase/client'; import { ArrowLeft } from 'lucide-react'; import SolicitudCard from '@/components/SolicitudCard'; -import { useTowns } from '../../../context/TownProvider'; +import { useQuery } from '@tanstack/react-query'; +import { HelpRequestData } from '@/types/Requests'; +import { helpRequestService } from '@/lib/service'; +import { useParams } from 'next/navigation'; export default function CasoDetalle() { - const params = useParams(); - const { id } = params; - const [caso, setCaso] = useState(null); - const towns = useTowns(); - const [loading, setLoading] = useState(true); - useEffect(() => { - async function fetchCaso() { - const { data, error } = await supabase.from('help_requests').select('*').eq('id', id).single(); - if (error) { - console.error('Error fetching caso:', error); - } else { - setCaso(data); - } - setLoading(false); - } - fetchCaso(); - }, [id]); - if (loading) { + const { id } = useParams<{ id: string }>(); + + const { + data: request, + isLoading, + error, + } = useQuery({ + queryKey: ['help_requests', { id: id }], + queryFn: () => helpRequestService.getOne(Number(id)), + }); + + if (isLoading) { return (
); } - if (!caso) { + if (error || request === undefined) { return (
@@ -60,7 +54,7 @@ export default function CasoDetalle() { Volver
- +
); } diff --git a/src/app/solicitudes/editar/[id]/page.js b/src/app/solicitudes/editar/[id]/page.js deleted file mode 100644 index 060cce30..00000000 --- a/src/app/solicitudes/editar/[id]/page.js +++ /dev/null @@ -1,40 +0,0 @@ -import { createClient } from '@/lib/supabase/server'; -import RequestHelp from '@/components/RequestHelp'; -import Unauthorized from '../../../../components/Unauthorized'; - -const getRequest = async (id) => { - const supabase = await createClient(); - const { data: session, sessionError } = await supabase.auth.getUser(); - if (sessionError || !session?.user) { - return 'unauthorized'; - } - const { data, error } = await supabase - .from('help_requests') - .select('*') - .eq('id', id) - .eq('type', 'necesita') - .contains('additional_info', { email: session.user.email }) - .single(); - if (error) { - throw new Error(error); - } - return data; -}; - -export default async function EditarSolicitud({ params }) { - const { id } = await params; - const request = await getRequest(id); - if (request === 'unauthorized') { - return ; - } - return ( - - ); -} diff --git a/src/app/solicitudes/editar/[id]/page.tsx b/src/app/solicitudes/editar/[id]/page.tsx new file mode 100644 index 00000000..58c5d879 --- /dev/null +++ b/src/app/solicitudes/editar/[id]/page.tsx @@ -0,0 +1,26 @@ +import { PageProps } from '.next/types/app/page'; +import RequestHelp from '@/components/RequestHelp'; +import Unauthorized from '@/components/Unauthorized'; +import { helpRequestService } from '@/lib/service'; +import { createClient } from '@/lib/supabase/server'; + +export default async function EditarSolicitud({ params }: PageProps) { + const { id } = await params; + const supabase = await createClient(); + const { data: session } = await supabase.auth.getUser(); + if (session.user === null) { + return ; + } + const request = await helpRequestService.getOne(Number(id)); + + return ( + + ); +} diff --git a/src/app/solicitudes/page.tsx b/src/app/solicitudes/page.tsx index 6f43df0a..72eb04e4 100644 --- a/src/app/solicitudes/page.tsx +++ b/src/app/solicitudes/page.tsx @@ -2,7 +2,6 @@ import { Search } from 'lucide-react'; import SolicitudCard from '@/components/SolicitudCard'; -import { useTowns } from '@/context/TownProvider'; import { useSession } from '@/context/SessionProvider'; import Link from 'next/link'; import { useQuery } from '@tanstack/react-query'; @@ -11,7 +10,6 @@ import { helpRequestService } from '@/lib/service'; export default function ListaSolicitudes() { const session = useSession(); - const towns = useTowns(); const userId = session.user?.id; const { @@ -58,16 +56,7 @@ export default function ListaSolicitudes() { ) : ( - requests.map((caso) => ( - - )) + requests.map((caso) => ) )} diff --git a/src/components/AsignarSolicitudButton.tsx b/src/components/AsignarSolicitudButton.tsx index c0ae3f30..fabc1921 100644 --- a/src/components/AsignarSolicitudButton.tsx +++ b/src/components/AsignarSolicitudButton.tsx @@ -1,7 +1,7 @@ 'use client'; import { useSession } from '@/context/SessionProvider'; -import { HelpRequestAssignmentData, HelpRequestData, HelpRequestAdditionalInfo } from '@/types/Requests'; +import { HelpRequestAssignmentData, HelpRequestData } from '@/types/Requests'; import { helpRequestService } from '@/lib/service'; import { MouseEvent } from 'react'; import { Spinner } from '@/components/Spinner'; @@ -18,7 +18,7 @@ type AsignarSolicitudButtonProps = { export default function AsignarSolicitudButton({ helpRequest }: AsignarSolicitudButtonProps) { const { toggleModal } = useModal(); const session = useSession(); - + const userId = session.user?.id; const MODAL_NAME = `Solicitud-${helpRequest.id}`; const { @@ -43,6 +43,7 @@ export default function AsignarSolicitudButton({ helpRequest }: AsignarSolicitud }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['help_request_assignments'] }); + queryClient.invalidateQueries({ queryKey: ['help_requests', { user_id: userId, type: 'necesita' }] }); }, onError: (e) => { console.error('Error al asignarte a la petición de ayuda', e); @@ -58,6 +59,7 @@ export default function AsignarSolicitudButton({ helpRequest }: AsignarSolicitud }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['help_request_assignments'] }); + queryClient.invalidateQueries({ queryKey: ['help_requests', { user_id: userId, type: 'necesita' }] }); }, onError: (e) => { console.error('Error al asignarte a la petición de ayuda', e); @@ -96,7 +98,7 @@ export default function AsignarSolicitudButton({ helpRequest }: AsignarSolicitud ); // Verifica el email dentro de additional_info utilizando un casting y encadenamiento opcional - if ((helpRequest.additional_info as HelpRequestAdditionalInfo)?.email === session.user.email) return null; + if (helpRequest.user_id === session.user.id) return null; return ( <> diff --git a/src/components/OfferHelp.js b/src/components/OfferHelp.js index aafaf0b9..ac321a58 100644 --- a/src/components/OfferHelp.js +++ b/src/components/OfferHelp.js @@ -24,7 +24,7 @@ export default function OfferHelp({ redirect = '/casos-activos/ofertas', submitType = 'create', }) { - const towns = useTowns(); + const { towns } = useTowns(); const session = useSession(); const router = useRouter(); diff --git a/src/components/RequestHelp.js b/src/components/RequestHelp.js index 31e42ad1..bba68518 100644 --- a/src/components/RequestHelp.js +++ b/src/components/RequestHelp.js @@ -20,7 +20,7 @@ export default function RequestHelp({ id, redirect = '/casos-activos/solicitudes', }) { - const towns = useTowns(); + const { towns } = useTowns(); const router = useRouter(); const session = useSession(); const userId = session.user?.id; diff --git a/src/components/SolicitudCard.tsx b/src/components/SolicitudCard.tsx index 22851897..9d2db443 100644 --- a/src/components/SolicitudCard.tsx +++ b/src/components/SolicitudCard.tsx @@ -1,39 +1,27 @@ -import { AlertTriangle, Calendar, MapPin, MapPinned, Megaphone, Phone, Users } from 'lucide-react'; +import { AlertTriangle, MapPin, MapPinned, Megaphone, Phone, Users } from 'lucide-react'; import { tiposAyudaOptions } from '@/helpers/constants'; import Link from 'next/link'; import { useSession } from '@/context/SessionProvider'; -import { HelpRequestAdditionalInfo, HelpRequestData, HelpRequestAssignmentData } from '@/types/Requests'; -import { Town } from '@/types/Town'; +import { HelpRequestAdditionalInfo, HelpRequestData } from '@/types/Requests'; import AsignarSolicitudButton from '@/components/AsignarSolicitudButton'; import SolicitudHelpCount from '@/components/SolicitudHelpCount'; import PhoneInfo from '@/components/PhoneInfo.js'; +import { useTowns } from '@/context/TownProvider'; type SolicitudCardProps = { caso: HelpRequestData; - towns: Town[]; - isHref?: boolean; - button?: SolicitudCardButton; - isEdit?: boolean; + showLink?: boolean; + showEdit?: boolean; }; -type SolicitudCardButton = { - text: string; - link: string; -}; - -export default function SolicitudCard({ - caso, - towns, - isHref = true, - button = { text: 'Ver solicitud', link: '/solicitud/' }, - isEdit = false, -}: SolicitudCardProps) { +export default function SolicitudCard({ caso, showLink = true, showEdit = false }: SolicitudCardProps) { const session = useSession(); - + const { getTownById } = useTowns(); const additionalInfo = caso.additional_info as HelpRequestAdditionalInfo; - const special_situations = 'special_situations' in additionalInfo ? additionalInfo.special_situations : undefined; - const email = 'email' in additionalInfo ? additionalInfo.email : undefined; + const isMyRequest = session.user?.id && session.user.id === caso.user_id; + const canEdit = isMyRequest; //TODO: support admin editing + return (
@@ -92,8 +80,7 @@ export default function SolicitudCard({
- Pueblo:{' '} - {towns.find((town) => town.id === caso.town_id)?.name || ''} + Pueblo: {getTownById(caso.town_id)?.name || ''}
)} @@ -172,22 +159,20 @@ export default function SolicitudCard({
- {session && session.user && session.user.email && session.user.email === email && !isEdit && ( + {canEdit && showEdit && ( Editar )} - {isHref && ( + {showLink && ( - {button.text} + Ver solicitud )} diff --git a/src/context/TownProvider.tsx b/src/context/TownProvider.tsx index 1e7ede0e..d7c5922b 100644 --- a/src/context/TownProvider.tsx +++ b/src/context/TownProvider.tsx @@ -1,16 +1,20 @@ 'use client'; -import React, { createContext, ReactNode, useContext } from 'react'; + +import { useQuery } from '@tanstack/react-query'; +import { townService } from '@/lib/service'; import { Town } from '@/types/Town'; -const TownsContext = createContext([]); +export const useTowns = () => { + const { + data: towns, + isLoading, + error, + } = useQuery({ + queryKey: ['towns'], + queryFn: () => townService.getTowns(), + }); -type TownsProviderProps = { - children: ReactNode; - towns: Town[]; -}; + const getTownById = (id: number) => towns?.find((t) => t.id === id); -export const TownsProvider: React.FC = ({ children, towns }) => { - return {children}; + return { towns: towns ?? [], isLoading, error, getTownById }; }; - -export const useTowns = () => useContext(TownsContext); diff --git a/src/helpers/format.js b/src/helpers/format.js index 2f96a9cc..d156714d 100644 --- a/src/helpers/format.js +++ b/src/helpers/format.js @@ -1,7 +1,7 @@ import SolicitudCard from '@/components/SolicitudCard'; import ReactDOMServer from 'react-dom/server'; -export const getMarkerBySolicitud = (solicitud, towns) => { +export const getMarkerBySolicitud = (solicitud) => { // TODO think if possible getLatLng from a given location if (!solicitud.latitude || !solicitud.longitude) { return null; @@ -10,7 +10,7 @@ export const getMarkerBySolicitud = (solicitud, towns) => { return { id: solicitud.id, coordinates: [solicitud.longitude, solicitud.latitude], - descriptionHTML: getMarkerDescriptionBySolicitudAndTowns(solicitud, towns), + descriptionHTML: getMarkerDescriptionBySolicitudAndTowns(solicitud), color: getMarkerColorBySolicitud(solicitud), width: '400px', }; @@ -28,8 +28,10 @@ export const getMarkerColorBySolicitud = (solicitud) => { return '#000000'; } }; -export const getMarkerDescriptionBySolicitudAndTowns = (solicitud, towns) => { - return ReactDOMServer.renderToString(); +export const getMarkerDescriptionBySolicitudAndTowns = (solicitud) => { + return ReactDOMServer.renderToString( + , + ); }; export const getMarkerByPuntoDeRecogida = (ptoDeRecogida) => { diff --git a/src/lib/service.ts b/src/lib/service.ts index 9d17ac96..f0aebddf 100644 --- a/src/lib/service.ts +++ b/src/lib/service.ts @@ -21,6 +21,17 @@ export const helpRequestService = { if (error) throw error; return data; }, + async getOne(id: number) { + const supabase = await getSupabaseClient(); + const { data, error } = await supabase + .from('help_requests') + .select('*') + .eq('id', id) + .eq('type', 'necesita') + .single(); + if (error) throw error; + return data; + }, async getRequestsByUser(user_id: string | undefined) { if (user_id === undefined) return []; @@ -88,6 +99,12 @@ export const townService = { async create(townName: string) { return await supabase.from('towns').insert({ name: townName }).select('id'); }, + async getTowns() { + const supabase = await getSupabaseClient(); + const { data, error } = await supabase.from('towns').select(); + if (error) throw error; + return data; + }, async createIfNotExists(townName: string) { const response = await this.getByName(townName); if (response.error) return response; @@ -217,15 +234,6 @@ export const mapService = { }, }; -export const townsService = { - async getTowns() { - const supabase = await getSupabaseClient(); - const { data, error } = await supabase.from('towns').select(); - if (error) throw error; - return data; - }, -}; - // Add this function to test the connection export const testSupabaseConnection = async () => { try { diff --git a/src/lib/supabase/middleware.ts b/src/lib/supabase/middleware.ts index 9814ec19..03a11751 100644 --- a/src/lib/supabase/middleware.ts +++ b/src/lib/supabase/middleware.ts @@ -29,21 +29,8 @@ export async function updateSession(request: NextRequest) { // supabase.auth.getUser(). A simple mistake could make it very hard to debug // issues with users being randomly logged out. - const { - data: { user }, - } = await supabase.auth.getUser(); const url = request.nextUrl.clone(); - if ( - !user && - (request.nextUrl.pathname.startsWith('/ofertas') || request.nextUrl.pathname.startsWith('/solicitudes')) - ) { - // no user, no access to their offers or requests. Redirect to log in - - url.pathname = '/auth'; - return NextResponse.redirect(url); - } - if (request.nextUrl.pathname === '/casos-activos') { url.pathname = '/casos-activos/solicitudes'; return NextResponse.redirect(url);