diff --git a/src/app/voluntometro/page.tsx b/src/app/voluntometro/page.tsx index 91687af0..da47ae4c 100644 --- a/src/app/voluntometro/page.tsx +++ b/src/app/voluntometro/page.tsx @@ -5,8 +5,7 @@ import { helpRequestService } from '@/lib/service'; export const dynamic = 'force-dynamic'; export default async function Voluntometro() { - const pueblos = await helpRequestService.getTodaysCountByTown(); - const count = await helpRequestService.getTodaysCount(); + const towns = await helpRequestService.getTodaysCountByTown(); const getFechaHoy = () => { const fecha = new Date(); @@ -17,23 +16,11 @@ export default async function Voluntometro() { }); }; - const getTopAndBottomPueblos = () => { - const sortedPueblos = [...pueblos].sort((a, b) => { - const volunteersDiffA = a.count - a.needHelp; - const volunteersDiffB = b.count - b.needHelp; - if (volunteersDiffA !== volunteersDiffB) { - return volunteersDiffB - volunteersDiffA; - } else { - return b.count - a.count; - } - }); + const totalOffers = towns.reduce((sum, pueblo) => sum + (pueblo.offers_last_24h ?? 0), 0); + const totalSolicitudes = towns.reduce((sum, pueblo) => sum + (pueblo.needs_last_24h ?? 0), 0); + + const sortedTowns = towns.sort((a, b) => (b.unassigned_needs ?? 0) - (a.unassigned_needs ?? 0)); - return { - top: sortedPueblos.slice(0, 2), - bottom: sortedPueblos.slice(-2).reverse(), - all: sortedPueblos.reverse(), - }; - }; return (
@@ -51,7 +38,7 @@ export default async function Voluntometro() {
-

{count.ofertas}+

+

{totalOffers}+

Nuevos voluntarios hoy

@@ -60,18 +47,19 @@ export default async function Voluntometro() {
-

{count.solicitudes}+

+

{totalSolicitudes}+

Nuevas solicitudes hoy

- {getTopAndBottomPueblos().all.map( - (pueblo) => - pueblo.needHelp > 0 && ( - - ), - )} + {sortedTowns.map((townSummary) => ( + + ))}
); diff --git a/src/components/TownCardInfo.tsx b/src/components/TownCardInfo.tsx index 291595c2..51800eca 100644 --- a/src/components/TownCardInfo.tsx +++ b/src/components/TownCardInfo.tsx @@ -1,42 +1,44 @@ 'use client'; import { useRouter } from 'next/navigation'; import React from 'react'; +import { TownSummary } from '@/types/Town'; type PuebloInfo = { - pueblo: { - id: number; - name: string; - count: number; - needHelp: string; - }; + townSummary: TownSummary; route: string; }; -export default function TownCardInfo({ pueblo, route }: PuebloInfo) { +export default function TownCardInfo({ townSummary, route }: PuebloInfo) { const router = useRouter(); return ( -
+
-

{pueblo.name}

+

{townSummary.town_name}

- {pueblo.count} + {townSummary.offers_last_24h} voluntarios
|
- {pueblo.needHelp} + {townSummary.needs_last_24h} solicitudes de ayuda
+
+
+ {townSummary.unassigned_needs} + solicitudes sin atender +
+
); diff --git a/src/lib/service.ts b/src/lib/service.ts index 31fd0bad..987de2f7 100644 --- a/src/lib/service.ts +++ b/src/lib/service.ts @@ -125,75 +125,20 @@ export const helpRequestService = { if (error) throw error; return data; }, - async getTodaysCount() { - const today = new Date().toISOString().split('T')[0]; - const supabase = await getSupabaseClient(); - const { count: solicitaCount, error: solicitaError } = await supabase - .from('help_requests') - .select('id', { count: 'exact' }) - .eq('type', 'necesita') - .gte('created_at', today) - .lte('created_at', `${today}T23:59:59.999Z`); - - const { count: ofreceCount, error: ofreceError } = await supabase - .from('help_requests') - .select('id', { count: 'exact' }) - .eq('type', 'ofrece') - .gte('created_at', today) - .lte('created_at', `${today}T23:59:59.999Z`); - - 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, - }; - }, async getTodaysCountByTown() { const supabase = await getSupabaseClient(); - const today = new Date().toISOString().split('T')[0]; - const { data: towns, error: townError } = await supabase.from('towns').select('id, name'); + const { data: towns, error: townError } = await supabase + .from('town_help_request_summary') + .select('*') + .or('offers_last_24h.gt.0,needs_last_24h.gt.0,unassigned_needs.gt.0'); if (townError) { console.log('Error fetching towns:', townError); throw townError; } - const { data, error } = await supabase - .from('help_requests') - .select('*') - .in('type', ['ofrece', 'necesita']) - .gte('created_at', today) - .lte('created_at', `${today}T23:59:59.999Z`); - - if (error) { - console.log('Error fetching help requests:', error); - throw error; - } - - const volunteersCount = new Map(); - const needHelpCount = new Map(); - - data.forEach((person) => { - const townId = person.town_id; - if (person.type === 'ofrece') { - volunteersCount.set(townId, (volunteersCount.get(townId) || 0) + 1); - } else if (person.type === 'necesita') { - needHelpCount.set(townId, (needHelpCount.get(townId) || 0) + 1); - } - }); - - return towns.map((town) => ({ - id: town.id, - name: town.name ?? 'N/A', - count: volunteersCount.get(town.id) || 0, - needHelp: needHelpCount.get(town.id) || 0, - })); + return towns; }, }; diff --git a/src/types/Town.ts b/src/types/Town.ts index 160382a6..1696fc8c 100644 --- a/src/types/Town.ts +++ b/src/types/Town.ts @@ -1,3 +1,5 @@ import { Database } from '@/types/database'; export type Town = Database['public']['Tables']['towns']['Row']; + +export type TownSummary = Database['public']['Views']['town_help_request_summary']['Row']; diff --git a/src/types/database.ts b/src/types/database.ts index a863b045..26cb238b 100644 --- a/src/types/database.ts +++ b/src/types/database.ts @@ -182,6 +182,7 @@ export type Database = { contact_info: string | null; coordinates: unknown | null; created_at: string | null; + crm_status: string | null; description: string | null; help_type: Database['public']['Enums']['help_type_enum'][] | null; id: number; @@ -189,6 +190,7 @@ export type Database = { location: string | null; longitude: number | null; name: string | null; + notes: string | null; number_of_people: number | null; other_help: string | null; people_needed: number | null; @@ -197,7 +199,6 @@ export type Database = { town_id: number | null; type: string | null; urgency: string | null; - crm_status: string | null; user_id: string | null; }; Insert: { @@ -206,6 +207,7 @@ export type Database = { contact_info?: string | null; coordinates?: unknown | null; created_at?: string | null; + crm_status?: string | null; description?: string | null; help_type?: Database['public']['Enums']['help_type_enum'][] | null; id?: number; @@ -213,6 +215,7 @@ export type Database = { location?: string | null; longitude?: number | null; name?: string | null; + notes?: string | null; number_of_people?: number | null; other_help?: string | null; people_needed?: number | null; @@ -229,6 +232,7 @@ export type Database = { contact_info?: string | null; coordinates?: unknown | null; created_at?: string | null; + crm_status?: string | null; description?: string | null; help_type?: Database['public']['Enums']['help_type_enum'][] | null; id?: number; @@ -236,6 +240,7 @@ export type Database = { location?: string | null; longitude?: number | null; name?: string | null; + notes?: string | null; number_of_people?: number | null; other_help?: string | null; people_needed?: number | null; @@ -247,6 +252,13 @@ export type Database = { user_id?: string | null; }; Relationships: [ + { + foreignKeyName: 'help_requests_town_id_fkey'; + columns: ['town_id']; + isOneToOne: false; + referencedRelation: 'town_help_request_summary'; + referencedColumns: ['town_id']; + }, { foreignKeyName: 'help_requests_town_id_fkey'; columns: ['town_id']; @@ -380,6 +392,7 @@ export type Database = { contact_info: string | null; coordinates: unknown | null; created_at: string | null; + crm_status: string | null; description: string | null; help_type: Database['public']['Enums']['help_type_enum'][] | null; id: number | null; @@ -387,6 +400,7 @@ export type Database = { location: string | null; longitude: number | null; name: string | null; + notes: string | null; number_of_people: number | null; other_help: string | null; people_needed: number | null; @@ -398,6 +412,13 @@ export type Database = { user_id: string | null; }; Relationships: [ + { + foreignKeyName: 'help_requests_town_id_fkey'; + columns: ['town_id']; + isOneToOne: false; + referencedRelation: 'town_help_request_summary'; + referencedColumns: ['town_id']; + }, { foreignKeyName: 'help_requests_town_id_fkey'; columns: ['town_id']; @@ -407,6 +428,16 @@ export type Database = { }, ]; }; + town_help_request_summary: { + Row: { + needs_last_24h: number | null; + offers_last_24h: number | null; + town_id: number | null; + town_name: string | null; + unassigned_needs: number | null; + }; + Relationships: []; + }; }; Functions: { [_ in never]: never; diff --git a/supabase/migrations/20241110204442_add view for voluntometro.sql b/supabase/migrations/20241110204442_add view for voluntometro.sql new file mode 100644 index 00000000..1f22a3a7 --- /dev/null +++ b/supabase/migrations/20241110204442_add view for voluntometro.sql @@ -0,0 +1,22 @@ +create view town_help_request_summary as +select + t.id as town_id, + t.name as town_name, + + -- Número de help_requests de type = "ofrece" en las últimas 24 horas + coalesce(sum(case when hr.type = 'ofrece' and hr.created_at >= now() - interval '24 hours' then 1 else 0 end), 0) as offers_last_24h, + + -- Número de help_requests de type = "necesita" en las últimas 24 horas + coalesce(sum(case when hr.type = 'necesita' and hr.created_at >= now() - interval '24 hours' then 1 else 0 end), 0) as needs_last_24h, + + -- Número de help_requests de type = "necesita" sin help_request_assignments + coalesce(sum(case when hr.type = 'necesita' and hr.status <> 'finished' and hra.help_request_id is null then 1 else 0 end), 0) as unassigned_needs + +from + towns t +left join + help_requests hr on t.id = hr.town_id +left join + help_request_assignments hra on hr.id = hra.help_request_id +group by + t.id, t.name; diff --git a/supabase/migrations/20241111161121_fix view with new fields.sql b/supabase/migrations/20241111161121_fix view with new fields.sql new file mode 100644 index 00000000..6c12ec9c --- /dev/null +++ b/supabase/migrations/20241111161121_fix view with new fields.sql @@ -0,0 +1,12 @@ +drop view if exists help_requests_with_assignment_count; + +create view help_requests_with_assignment_count as +select + hr.*, + coalesce(count(hra.id), 0) as assignments_count +from + help_requests hr +left join + help_request_assignments hra on hr.id = hra.help_request_id +group by + hr.id;