diff --git a/src/app/casos-activos/solicitudes/page.js b/src/app/casos-activos/solicitudes/page.js index e1b8acf0..277d60cd 100644 --- a/src/app/casos-activos/solicitudes/page.js +++ b/src/app/casos-activos/solicitudes/page.js @@ -1,6 +1,6 @@ 'use client'; -import { Suspense, useEffect, useState } from 'react'; +import { useEffect, useState, useCallback, useMemo, Suspense } from 'react'; import { HeartHandshake } from 'lucide-react'; import { supabase } from '@/lib/supabase/client'; import SolicitudCard from '@/components/SolicitudCard'; @@ -11,9 +11,15 @@ import { tiposAyudaOptions } from '@/helpers/constants'; import Modal from '@/components/Modal'; import { useModal } from '@/context/ModalProvider'; import { useTowns } from '@/context/TownProvider'; +import { Toggle } from '@/components/Toggle'; const MODAL_NAME = 'solicitudes'; +const itemsPerPage = 10; +const numPages = (count) => { + return Math.ceil(count / itemsPerPage) || 0; +}; + export default function SolicitudesPage() { return ( @@ -35,38 +41,46 @@ function Solicitudes() { const [currentCount, setCurrentCount] = useState(0); const { toggleModal } = useModal(); - const closeModal = () => { + const closeModal = useCallback(() => { toggleModal(MODAL_NAME, false); - }; - const itemsPerPage = 10; - const numPages = (count) => { - return Math.ceil(count / itemsPerPage) || 0; - }; - - const updateFilter = (filter, value) => { - const params = new URLSearchParams(searchParams.toString()); - params.set(filter, value); - router.push(`?${params.toString()}`); - }; + }, [toggleModal]); + + const updateFilter = useCallback( + (filter, value) => { + const params = new URLSearchParams(searchParams.toString()); + params.set(filter, value); + router.push(`?${params.toString()}`); + }, + [searchParams, router], + ); const [filtroData, setFiltroData] = useState({ urgencia: searchParams.get('urgencia') || 'todas', tipoAyuda: searchParams.get('tipoAyuda') || 'todas', pueblo: searchParams.get('pueblo') || 'todos', + soloSinVoluntarios: searchParams.get('soloSinVoluntarios') || true, }); - const changeDataFilter = (type, newFilter) => { - setFiltroData((prev) => ({ - ...prev, - [type]: newFilter, - })); - updateFilter(type, newFilter); - }; - - function changePage(newPage) { - setCurrentPage(newPage); - updateFilter('page', newPage); - } + const changeDataFilter = useCallback( + (type, newFilter) => { + setFiltroData((prev) => ({ + ...prev, + [type]: newFilter, + })); + updateFilter(type, newFilter); + }, + [updateFilter, setFiltroData], + ); + + const changePage = useCallback( + (newPage) => { + setCurrentPage(newPage); + updateFilter('page', newPage); + }, + [updateFilter], + ); + + const handleToggleChange = useCallback((e) => changeDataFilter('soloSinVoluntarios', e.target.checked), []); useEffect(() => { async function fetchData() { @@ -91,6 +105,12 @@ function Solicitudes() { if (filtroData.urgencia !== 'todas') { query.eq('urgency', filtroData.urgencia); } + + // Solo agregar filtro si es true + if (!!filtroData.soloSinVoluntarios) { + query.eq('asignees_count', 0); + } + query.neq('status', 'finished'); // Ejecutar la consulta con paginación const { data, count, error } = await query @@ -115,6 +135,8 @@ function Solicitudes() { fetchData(); }, [filtroData, currentPage]); + const puebloSeleccionado = useMemo(() => getTownById(Number(filtroData.pueblo)), [filtroData, getTownById]); + if (loading) { return (
@@ -131,48 +153,57 @@ function Solicitudes() { ); } - const puebloSeleccionado = getTownById(Number(filtroData.pueblo)); - return ( <> {/* FILTROS */}
-

Filtros

-
- - - +
+
+
+

Filtros

+
+ + + +
+
+ +
diff --git a/src/components/Toggle.tsx b/src/components/Toggle.tsx new file mode 100644 index 00000000..77960d80 --- /dev/null +++ b/src/components/Toggle.tsx @@ -0,0 +1,33 @@ +import React from 'react'; + +type ToggleProps = { handleChange: React.ChangeEventHandler; checked: boolean; label: string }; + +export const Toggle = ({ checked, handleChange, label }: ToggleProps) => { + return ( +
+ +
+ + +
+
+ ); +}; diff --git a/src/lib/service.ts b/src/lib/service.ts index fa45eb17..186e0ebb 100644 --- a/src/lib/service.ts +++ b/src/lib/service.ts @@ -65,14 +65,48 @@ export const helpRequestService = { async assign(requestData: HelpRequestAssignmentInsert) { const { data, error } = await supabase.from('help_request_assignments').insert([requestData]).select(); - if (error) throw error; + + const { data: linkedRequestData, error: errorGettingLinkedData } = await supabase + .from('help_requests') + .select('*') + .eq('id', requestData.help_request_id); + if (errorGettingLinkedData) throw errorGettingLinkedData; + if (!linkedRequestData) throw new Error('No se puede encontrar esta tarea'); + + const { error: errorUpdatingAssigneesCount } = await supabase + .from('help_requests') + .update({ asignees_count: linkedRequestData[0].asignees_count + 1 }); + if (errorUpdatingAssigneesCount) throw errorUpdatingAssigneesCount; + return data[0]; }, async unassign(id: number) { - const { error } = await supabase.from('help_request_assignments').delete().eq('id', id); + const { data, error: errorFindingRow } = await supabase.from('help_request_assignments').select('*').eq('id', id); + if (errorFindingRow || !data) { + throw new Error('No se puede encontrar la tarea'); + } - if (error) throw error; + const requestId = data[0].help_request_id; + + const { error: errorDeletingAssignment } = await supabase.from('help_request_assignments').delete().eq('id', id); + if (errorDeletingAssignment) throw errorDeletingAssignment; + + const { data: linkedRequestData, error: errorGettingLinkedData } = await supabase + .from('help_requests') + .select('*') + .eq('id', requestId); + + if (errorGettingLinkedData) throw errorGettingLinkedData; + if (!linkedRequestData) throw new Error('No se puede encontrar esta tarea'); + + const { asignees_count } = linkedRequestData[0]; + const newNumberAssignees = asignees_count <= 0 ? 0 : asignees_count - 1; + + const { error: errorUpdatingAssigneesCount } = await supabase + .from('help_requests') + .update({ asignees_count: newNumberAssignees }); + if (errorUpdatingAssigneesCount) throw errorUpdatingAssigneesCount; }, async getByType(type: any) { diff --git a/src/types/database.ts b/src/types/database.ts index 2a181cf2..5a137a4a 100644 --- a/src/types/database.ts +++ b/src/types/database.ts @@ -171,6 +171,7 @@ export type Database = { help_requests: { Row: { additional_info: Json | null; + asignees_count: number; contact_info: string | null; coordinates: unknown | null; created_at: string | null; @@ -192,6 +193,7 @@ export type Database = { }; Insert: { additional_info?: Json | null; + asignees_count?: number; contact_info?: string | null; coordinates?: unknown | null; created_at?: string | null; @@ -213,6 +215,7 @@ export type Database = { }; Update: { additional_info?: Json | null; + asignees_count?: number; contact_info?: string | null; coordinates?: unknown | null; created_at?: string | null; diff --git a/supabase/config.toml b/supabase/config.toml index a79ce9fc..6aa978b8 100644 --- a/supabase/config.toml +++ b/supabase/config.toml @@ -45,7 +45,7 @@ enabled = true # Specifies an ordered list of seed files to load during db reset. # Supports glob patterns relative to supabase directory. For example: # sql_paths = ['./seeds/*.sql', '../project-src/seeds/*-load-testing.sql'] -sql_paths = ['./seed.sql'] +sql_paths = ['./towns.sql', './help_requests.sql'] [realtime] enabled = true diff --git a/supabase/help_requests.sql b/supabase/help_requests.sql new file mode 100644 index 00000000..a37856da --- /dev/null +++ b/supabase/help_requests.sql @@ -0,0 +1,11 @@ +INSERT INTO "public"."help_requests" ("id","created_at","type","name","location","description","urgency","number_of_people","contact_info","additional_info","status","resources","latitude","longitude","help_type","people_needed","town_id","other_help") +VALUES ('10851', '2024-11-07 18:31:47.83578+00', 'necesita', 'Rocío', '46200, P', 'Lorem Ipsum', 'alta', '1', '123456789', '{"email": "ptesting@gmail.com", "consent": true, "special_situations": null}', 'active', null, '39.1', '-0.4', '{"alojamiento"}', '1', '17', null), +('10852', '2024-11-07 18:31:47.83578+00', 'necesita', 'Rocío', '46200, P', 'Lorem Ipsum', 'alta', '1', '123456789', '{"email": "ptesting@gmail.com", "consent": true, "special_situations": null}', 'active', null, '39.1', '-0.4', '{"alojamiento"}', '1', '17', null), +('10853', '2024-11-07 18:31:47.83578+00', 'necesita', 'Rocío', '46200, P', 'Lorem Ipsum', 'alta', '1', '123456789', '{"email": "ptesting@gmail.com", "consent": true, "special_situations": null}', 'active', null, '39.1', '-0.4', '{"alojamiento"}', '1', '17', null), +('10854', '2024-11-07 18:31:47.83578+00', 'necesita', 'Rocío', '46200, P', 'Me traslado desde r con l', 'alta', '1', '123456789', '{"email": "ptesting@gmail.com", "consent": true, "special_situations": null}', 'active', null, '39.1', '-0.4', '{"alojamiento"}', '1', '17', null), +('10855', '2024-11-07 18:31:47.83578+00', 'necesita', 'Rocío', '46200, P', 'Me traslado desde r con l', 'alta', '1', '123456789', '{"email": "ptesting@gmail.com", "consent": true, "special_situations": null}', 'active', null, '39.1', '-0.4', '{"alojamiento"}', '1', '17', null), +('10856', '2024-11-07 18:31:47.83578+00', 'necesita', 'Rocío', '46200, P', 'Me traslado desde r con l', 'alta', '1', '123456789', '{"email": "ptesting@gmail.com", "consent": true, "special_situations": null}', 'active', null, '39.1', '-0.4', '{"alojamiento"}', '1', '17', null), +('10857', '2024-11-07 18:31:47.83578+00', 'necesita', 'Rocío', '46200, P', 'Me traslado desde r con l', 'alta', '1', '123456789', '{"email": "ptesting@gmail.com", "consent": true, "special_situations": null}', 'active', null, '39.1', '-0.4', '{"alojamiento"}', '1', '17', null), +('10858', '2024-11-07 18:31:47.83578+00', 'necesita', 'Rocío', '46200, P', 'Me traslado desde r con l', 'alta', '1', '123456789', '{"email": "ptesting@gmail.com", "consent": true, "special_situations": null}', 'active', null, '39.1', '-0.4', '{"alojamiento"}', '1', '17', null), +('10859', '2024-11-07 18:31:47.83578+00', 'necesita', 'Rocío', '46200, P', 'Me traslado desde r con l', 'alta', '1', '123456789', '{"email": "ptesting@gmail.com", "consent": true, "special_situations": null}', 'active', null, '39.1', '-0.4', '{"alojamiento"}', '1', '17', null), +('10860', '2024-11-07 18:31:47.83578+00', 'necesita', 'Rocío', '46200, P', 'Me traslado desde r con l', 'alta', '1', '123456789', '{"email": "ptesting@gmail.com", "consent": true, "special_situations": null}', 'active', null, '39.1', '-0.4', '{"alojamiento"}', '1', '17', null); \ No newline at end of file diff --git a/supabase/migrations/20241107201532_add-number-of-volunteers-in-each-request.sql b/supabase/migrations/20241107201532_add-number-of-volunteers-in-each-request.sql new file mode 100644 index 00000000..b9becac8 --- /dev/null +++ b/supabase/migrations/20241107201532_add-number-of-volunteers-in-each-request.sql @@ -0,0 +1 @@ +alter table "public"."help_requests" add column "asignees_count" smallint not null default '0'::smallint; \ No newline at end of file diff --git a/supabase/migrations/20241108083517_populate_assignments_data.sql b/supabase/migrations/20241108083517_populate_assignments_data.sql new file mode 100644 index 00000000..8c5fb791 --- /dev/null +++ b/supabase/migrations/20241108083517_populate_assignments_data.sql @@ -0,0 +1,6 @@ +UPDATE "public"."help_requests" +SET "asignees_count" = ( + SELECT COUNT(*) + FROM "public"."help_request_assignments" + WHERE "public"."help_request_assignments"."help_request_id" = "public"."help_requests"."id" +); \ No newline at end of file diff --git a/supabase/seed.sql b/supabase/towns.sql similarity index 100% rename from supabase/seed.sql rename to supabase/towns.sql