diff --git a/package-lock.json b/package-lock.json
index 5614eae9..ff0a56ce 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,13 +12,15 @@
"@react-google-maps/api": "^2.20.3",
"@supabase/ssr": "^0.5.1",
"@supabase/supabase-js": "^2.46.1",
+ "@tanstack/react-query": "^5.59.19",
"deck.gl": "^9.0.34",
"leaflet": "^1.9.4",
"lucide-react": "^0.454.0",
"maplibre-gl": "^4.7.1",
"next": "15.0.2",
"react": "^18.3.1",
- "react-dom": "^18.3.1"
+ "react-dom": "^18.3.1",
+ "sonner": "^1.7.0"
},
"devDependencies": {
"@types/node": "^22.8.7",
@@ -1291,6 +1293,32 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@tanstack/query-core": {
+ "version": "5.59.20",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.59.20.tgz",
+ "integrity": "sha512-e8vw0lf7KwfGe1if4uPFhvZRWULqHjFcz3K8AebtieXvnMOz5FSzlZe3mTLlPuUBcydCnBRqYs2YJ5ys68wwLg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
+ "node_modules/@tanstack/react-query": {
+ "version": "5.59.20",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.59.20.tgz",
+ "integrity": "sha512-Zly0egsK0tFdfSbh5/mapSa+Zfc3Et0Zkar7Wo5sQkFzWyB3p3uZWOHR2wrlAEEV2L953eLuDBtbgFvMYiLvUw==",
+ "license": "MIT",
+ "dependencies": {
+ "@tanstack/query-core": "5.59.20"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19"
+ }
+ },
"node_modules/@turf/boolean-clockwise": {
"version": "5.1.5",
"license": "MIT",
@@ -6021,6 +6049,16 @@
"version": "0.6.1",
"license": "MIT"
},
+ "node_modules/sonner": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.7.0.tgz",
+ "integrity": "sha512-W6dH7m5MujEPyug3lpI2l3TC3Pp1+LTgK0Efg+IHDrBbtEjyCmCHHo6yfNBOsf1tFZ6zf+jceWwB38baC8yO9g==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
+ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ }
+ },
"node_modules/sortablejs": {
"version": "1.15.3",
"license": "MIT",
diff --git a/package.json b/package.json
index 219112dc..51a26afc 100644
--- a/package.json
+++ b/package.json
@@ -15,13 +15,15 @@
"@react-google-maps/api": "^2.20.3",
"@supabase/ssr": "^0.5.1",
"@supabase/supabase-js": "^2.46.1",
+ "@tanstack/react-query": "^5.59.19",
"deck.gl": "^9.0.34",
"leaflet": "^1.9.4",
"lucide-react": "^0.454.0",
"maplibre-gl": "^4.7.1",
"next": "15.0.2",
"react": "^18.3.1",
- "react-dom": "^18.3.1"
+ "react-dom": "^18.3.1",
+ "sonner": "^1.7.0"
},
"devDependencies": {
"@types/node": "^22.8.7",
@@ -32,9 +34,9 @@
"eslint-config-prettier": "^9.1.0",
"postcss": "^8",
"prettier": "3.3.3",
+ "supabase": "^1.215.0",
"tailwindcss": "^3.4.1",
- "typescript": "^5.6.3",
- "supabase": "^1.215.0"
+ "typescript": "^5.6.3"
},
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee"
}
diff --git a/src/app/layout.js b/src/app/layout.tsx
similarity index 50%
rename from src/app/layout.js
rename to src/app/layout.tsx
index ff84eee2..3513c0bf 100644
--- a/src/app/layout.js
+++ b/src/app/layout.tsx
@@ -2,19 +2,18 @@ import './globals.css';
import 'leaflet/dist/leaflet.css';
import EmergencyLayout from '@/components/layout/EmergencyLayout';
import { EmergencyProvider } from '@/context/EmergencyProvider';
-import { TownsProvider } from '../context/TownProvider';
+import { TownsProvider } from '@/context/TownProvider';
import { createClient } from '@/lib/supabase/server';
-import { SessionProvider } from '../context/SessionProvider';
+import { SessionProvider } from '@/context/SessionProvider';
+import { townsService } from '@/lib/service';
+import { Toaster } from 'sonner';
+import { PropsWithChildren } from 'react';
+import { QueryClientProvider } from '@/context/QueryClientProvider';
export const metadata = {
title: 'Ajuda Dana - Sistema de Coordinación',
description: 'Sistema de coordinación para emergencias en la Comunidad Valenciana',
};
-const getTowns = async () => {
- const supabase = await createClient();
- const { data, error } = await supabase.from('towns').select('id, name');
- return data;
-};
const getSession = async () => {
const supabase = await createClient();
@@ -22,18 +21,21 @@ const getSession = async () => {
return data;
};
-export default async function RootLayout({ children }) {
+export default async function RootLayout({ children }: PropsWithChildren) {
const session = await getSession();
- const towns = await getTowns();
+ const towns = await townsService.getTowns();
return (
+
-
-
- {children}
-
-
+
+
+
+ {children}
+
+
+
diff --git a/src/components/AsignarSolicitudButton.tsx b/src/components/AsignarSolicitudButton.tsx
new file mode 100644
index 00000000..bdda3d70
--- /dev/null
+++ b/src/components/AsignarSolicitudButton.tsx
@@ -0,0 +1,104 @@
+'use client';
+
+import { useSession } from '@/context/SessionProvider';
+import { HelpRequestAssignmentData, HelpRequestData } from '@/types/Requests';
+import { helpRequestService } from '@/lib/service';
+import { MouseEvent } from 'react';
+import { Spinner } from '@/components/Spinner';
+import Link from 'next/link';
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { toast } from 'sonner';
+
+type AsignarSolicitudButtonProps = {
+ helpRequest: HelpRequestData;
+};
+
+export default function AsignarSolicitudButton({ helpRequest }: AsignarSolicitudButtonProps) {
+ const session = useSession();
+
+ const {
+ data: assignments,
+ isLoading,
+ error,
+ } = useQuery({
+ queryKey: ['help_request_assignments', { id: helpRequest.id }],
+ queryFn: () => helpRequestService.getAssignments(helpRequest.id),
+ });
+
+ const queryClient = useQueryClient();
+
+ const assignMutation = useMutation({
+ mutationFn: async () => {
+ if (!session.user) return;
+ await helpRequestService.assign({
+ help_request_id: helpRequest.id,
+ user_id: session.user.id,
+ phone_number: session.user.user_metadata.telefono!,
+ });
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['help_request_assignments'] });
+ },
+ onError: (e) => {
+ console.error('Error al asignarte a la petición de ayuda', e);
+ toast.error('Error al asignarte :(');
+ },
+ });
+
+ const unassignMutation = useMutation({
+ mutationFn: async () => {
+ if (!session.user) return;
+ if (!userAssignment) return;
+ await helpRequestService.unassign(userAssignment.id);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['help_request_assignments'] });
+ },
+ onError: (e) => {
+ console.error('Error al asignarte a la petición de ayuda', e);
+ toast.error('Error al asignarte :(');
+ },
+ });
+
+ async function handleSubmit(e: MouseEvent) {
+ e.preventDefault();
+ assignMutation.mutate();
+ }
+ async function handleCancel(e: MouseEvent) {
+ e.preventDefault();
+ unassignMutation.mutate();
+ }
+
+ if (isLoading) return ;
+ if (error || assignments === undefined) return <>>;
+
+ const userAssignment = assignments.find((x) => x.user_id === session.user?.id);
+ const userIsAssigned = !!userAssignment;
+
+ if (!session || !session.user)
+ return (
+
+ Quiero ayudar
+
+ );
+
+ return (
+ <>
+ {userIsAssigned ? (
+
+ ) : (
+
+ )}
+ >
+ );
+}
diff --git a/src/components/SolicitudCard.js b/src/components/SolicitudCard.tsx
similarity index 78%
rename from src/components/SolicitudCard.js
rename to src/components/SolicitudCard.tsx
index a3b44e9b..12a8bc17 100644
--- a/src/components/SolicitudCard.js
+++ b/src/components/SolicitudCard.tsx
@@ -1,16 +1,38 @@
import { AlertTriangle, Calendar, MapPin, MapPinned, Megaphone, Phone, Users } from 'lucide-react';
import { tiposAyudaOptions } from '@/helpers/constants';
import Link from 'next/link';
-import { useSession } from '../context/SessionProvider';
+import { useSession } from '@/context/SessionProvider';
+import { HelpRequestAdditionalInfo, HelpRequestData } from '@/types/Requests';
+import { Town } from '@/types/Town';
+import AsignarSolicitudButton from '@/components/AsignarSolicitudButton';
+import SolicitudHelpCount from '@/components/SolicitudHelpCount';
+
+type SolicitudCardProps = {
+ caso: HelpRequestData;
+ towns: Town[];
+ isHref?: boolean;
+ button?: SolicitudCardButton;
+ isEdit?: boolean;
+};
+
+type SolicitudCardButton = {
+ text: string;
+ link: string;
+};
export default function SolicitudCard({
caso,
- isHref,
+ towns,
+ isHref = true,
button = { text: 'Ver solicitud', link: '/solicitud/' },
isEdit = false,
- towns,
-}) {
+}: SolicitudCardProps) {
const session = useSession();
+
+ 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;
return (
<>
+
Referencia: {caso.id}
@@ -55,7 +78,7 @@ export default function SolicitudCard({
- Pueblo: {towns[caso.town_id - 1].name || ''}
+ Pueblo: {towns[caso.town_id - 1]?.name || ''}
)}
@@ -69,9 +92,9 @@ export default function SolicitudCard({
Fecha:{' '}
- {new Date(caso.created_at).toLocaleDateString() +
+ {new Date(caso.created_at!).toLocaleDateString() +
' ' +
- new Date(caso.created_at).toLocaleTimeString([], {
+ new Date(caso.created_at!).toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
})}
@@ -127,10 +150,10 @@ export default function SolicitudCard({
)}
- {caso.additional_info?.special_situations && (
+ {special_situations && (
Situaciones especiales:
-
{caso.additional_info.special_situations}
+
{special_situations}
)}
{caso.number_of_people && (
@@ -143,20 +166,16 @@ export default function SolicitudCard({
)}
- {session &&
- session.user &&
- session.user.email &&
- session.user.email === caso.additional_info.email &&
- !isEdit && (
-
- Editar
-
- )}
+ {session && session.user && session.user.email && session.user.email === email && !isEdit && (
+
+ Editar
+
+ )}
{isHref && (
)}
+
diff --git a/src/components/SolicitudHelpCount.tsx b/src/components/SolicitudHelpCount.tsx
new file mode 100644
index 00000000..cb9846d4
--- /dev/null
+++ b/src/components/SolicitudHelpCount.tsx
@@ -0,0 +1,33 @@
+import { HelpRequestAssignmentData } from '@/types/Requests';
+import { useQuery } from '@tanstack/react-query';
+import { helpRequestService } from '@/lib/service';
+import { Spinner } from '@/components/Spinner';
+
+type SolicitudHelpCountProps = {
+ id: number;
+};
+
+export default function SolicitudHelpCount({ id }: SolicitudHelpCountProps) {
+ const {
+ data: assignments,
+ isLoading,
+ error,
+ } = useQuery({
+ queryKey: ['help_request_assignments', { id: id }],
+ queryFn: () => helpRequestService.getAssignments(id),
+ });
+
+ if (isLoading) return ;
+
+ if (error || assignments === undefined) return <>>;
+
+ const volunteers = assignments.length;
+
+ return (
+
+ Voluntarios: {volunteers}
+
+ );
+}
diff --git a/src/components/Spinner.tsx b/src/components/Spinner.tsx
new file mode 100644
index 00000000..db435f18
--- /dev/null
+++ b/src/components/Spinner.tsx
@@ -0,0 +1,8 @@
+export function Spinner() {
+ return (
+
+ );
+}
diff --git a/src/components/layout/EmergencyLayout.js b/src/components/layout/EmergencyLayout.tsx
similarity index 87%
rename from src/components/layout/EmergencyLayout.js
rename to src/components/layout/EmergencyLayout.tsx
index 7962a634..e7f3e4e1 100644
--- a/src/components/layout/EmergencyLayout.js
+++ b/src/components/layout/EmergencyLayout.tsx
@@ -1,12 +1,11 @@
-// components/layout/EmergencyLayout.js
-
'use client';
-import { useState, useEffect } from 'react';
+import { useState, useEffect, PropsWithChildren } from 'react';
+// @ts-ignore
import Sidebar from './Sidebar';
import Footer from './Footer';
-export default function EmergencyLayout({ children }) {
+export default function EmergencyLayout({ children }: PropsWithChildren) {
const [isSidebarOpen, setIsSidebarOpen] = useState(true); // Por defecto abierto
useEffect(() => {
diff --git a/src/components/layout/Footer.js b/src/components/layout/Footer.tsx
similarity index 100%
rename from src/components/layout/Footer.js
rename to src/components/layout/Footer.tsx
diff --git a/src/components/map/map.tsx b/src/components/map/map.tsx
index f93ec317..c2dcfcbf 100644
--- a/src/components/map/map.tsx
+++ b/src/components/map/map.tsx
@@ -54,7 +54,7 @@ const Map: FC = ({ center = [0, 0], zoom = 2, markers = [] }) => {
className: 'map-popup',
maxWidth: `${markerData.width}px`,
anchor: 'left',
- }).setHTML(markerData.descriptionHTML)
+ }).setHTML(markerData.descriptionHTML),
)
.addTo(mapRef.current!);
diff --git a/src/context/EmergencyProvider.js b/src/context/EmergencyProvider.js
deleted file mode 100644
index d1e9226e..00000000
--- a/src/context/EmergencyProvider.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use client';
-
-import React, { createContext, useContext, useState } from 'react';
-
-const EmergencyContext = createContext(undefined);
-
-export const EmergencyProvider = ({ children }) => {
- const [showModal, setShowModal] = useState(false);
-
- const toggleModal = (force) => setShowModal((prev) => (force !== undefined ? force : !prev));
-
- return {children};
-};
-
-export const useModal = () => {
- const context = useContext(EmergencyContext);
- if (!context) {
- throw new Error('useModal must be used within an EmergencyProvider');
- }
- return context;
-};
diff --git a/src/context/EmergencyProvider.tsx b/src/context/EmergencyProvider.tsx
new file mode 100644
index 00000000..fcd02baa
--- /dev/null
+++ b/src/context/EmergencyProvider.tsx
@@ -0,0 +1,30 @@
+'use client';
+
+import React, { createContext, ReactNode, useContext, useState } from 'react';
+
+const EmergencyContext = createContext({ showModal: false, toggleModal: () => {} });
+
+type EmergencyCtx = {
+ showModal: boolean;
+ toggleModal: (force: boolean) => void;
+};
+
+type SessionProviderProps = {
+ children: ReactNode;
+};
+
+export const EmergencyProvider: React.FC = ({ children }) => {
+ const [showModal, setShowModal] = useState(false);
+
+ const toggleModal = (force: boolean) => setShowModal((prev) => (force !== undefined ? force : !prev));
+
+ return {children};
+};
+
+export const useModal = () => {
+ const context = useContext(EmergencyContext);
+ if (!context) {
+ throw new Error('useModal must be used within an EmergencyProvider');
+ }
+ return context;
+};
diff --git a/src/context/QueryClientProvider.tsx b/src/context/QueryClientProvider.tsx
new file mode 100644
index 00000000..d52a1c08
--- /dev/null
+++ b/src/context/QueryClientProvider.tsx
@@ -0,0 +1,10 @@
+'use client';
+
+import { PropsWithChildren, useState } from 'react';
+import { QueryClient, QueryClientProvider as TanstackQueryClientProvider } from '@tanstack/react-query';
+
+export const QueryClientProvider = ({ children }: PropsWithChildren) => {
+ const [client] = useState(new QueryClient());
+
+ return {children};
+};
diff --git a/src/context/SessionProvider.js b/src/context/SessionProvider.js
deleted file mode 100644
index 561a1f24..00000000
--- a/src/context/SessionProvider.js
+++ /dev/null
@@ -1,10 +0,0 @@
-'use client';
-import { createContext, useContext } from 'react';
-
-const SessionContext = createContext();
-
-export const SessionProvider = ({ children, session }) => {
- return {children};
-};
-
-export const useSession = () => useContext(SessionContext);
diff --git a/src/context/SessionProvider.tsx b/src/context/SessionProvider.tsx
new file mode 100644
index 00000000..c94f7344
--- /dev/null
+++ b/src/context/SessionProvider.tsx
@@ -0,0 +1,18 @@
+'use client';
+import React, { createContext, ReactNode, useContext } from 'react';
+import { User } from '@supabase/auth-js';
+
+const SessionContext = createContext({ user: null });
+
+type UserSession = { user: User } | { user: null };
+
+type SessionProviderProps = {
+ children: ReactNode;
+ session: UserSession;
+};
+
+export const SessionProvider: React.FC = ({ children, session }) => {
+ return {children};
+};
+
+export const useSession = () => useContext(SessionContext);
diff --git a/src/context/TownProvider.js b/src/context/TownProvider.js
deleted file mode 100644
index f0b6e6cb..00000000
--- a/src/context/TownProvider.js
+++ /dev/null
@@ -1,10 +0,0 @@
-'use client';
-import { createContext, useContext } from 'react';
-
-const TownsContext = createContext();
-
-export const TownsProvider = ({ children, towns }) => {
- return {children};
-};
-
-export const useTowns = () => useContext(TownsContext);
diff --git a/src/context/TownProvider.tsx b/src/context/TownProvider.tsx
new file mode 100644
index 00000000..1e7ede0e
--- /dev/null
+++ b/src/context/TownProvider.tsx
@@ -0,0 +1,16 @@
+'use client';
+import React, { createContext, ReactNode, useContext } from 'react';
+import { Town } from '@/types/Town';
+
+const TownsContext = createContext([]);
+
+type TownsProviderProps = {
+ children: ReactNode;
+ towns: Town[];
+};
+
+export const TownsProvider: React.FC = ({ children, towns }) => {
+ return {children};
+};
+
+export const useTowns = () => useContext(TownsContext);
diff --git a/src/helpers/constants.js b/src/helpers/constants.ts
similarity index 88%
rename from src/helpers/constants.js
rename to src/helpers/constants.ts
index 99eee37b..431ddc2f 100644
--- a/src/helpers/constants.js
+++ b/src/helpers/constants.ts
@@ -7,11 +7,12 @@ export const tiposAyudaOptions = {
medica: 'Asistencia médica',
psicologico: 'Apoyo psicológico',
logistico: 'Apoyo logístico',
+ otros: 'Ayuda general',
};
export const tiposAyudaAcepta = ['Alimentos', 'Ropa', 'Mantas', 'Agua', 'Productos de higiene', 'Medicamentos'];
-export const mapToIdAndLabel = (data) => {
+export const mapToIdAndLabel = (data: any) => {
return Object.keys(data).map((key) => ({
id: key,
label: data[key],
diff --git a/src/lib/service.ts b/src/lib/service.ts
index ef45cfda..f551a2db 100644
--- a/src/lib/service.ts
+++ b/src/lib/service.ts
@@ -1,5 +1,6 @@
import { supabase } from './supabase/client';
-import { HelpRequestAssignmentData, HelpRequestData } from '@/types/Requests';
+import { HelpRequestAssignmentInsert, HelpRequestData, HelpRequestUpdate } from '@/types/Requests';
+import { createClient } from '@/lib/supabase/server';
export const helpRequestService = {
async createRequest(requestData: HelpRequestData) {
@@ -8,7 +9,7 @@ export const helpRequestService = {
if (error) throw error;
return data[0];
},
- async editRequest(requestData: any, id: any) {
+ async editRequest(requestData: HelpRequestUpdate, id: number) {
const { data, error } = await supabase.from('help_requests').update(requestData).eq('id', id).select();
if (error) throw error;
return data;
@@ -20,12 +21,24 @@ export const helpRequestService = {
return data;
},
- async assign(requestData: HelpRequestAssignmentData) {
+ async getAssignments(id: number) {
+ const { data, error } = await supabase.from('help_request_assignments').select('*').eq('help_request_id', id);
+
+ if (error) throw error;
+ return data;
+ },
+
+ async assign(requestData: HelpRequestAssignmentInsert) {
const { data, error } = await supabase.from('help_request_assignments').insert([requestData]).select();
if (error) throw error;
return data[0];
},
+ async unassign(id: number) {
+ const { error } = await supabase.from('help_request_assignments').delete().eq('id', id);
+
+ if (error) throw error;
+ },
async getByType(type: any) {
const { data, error } = await supabase
@@ -155,6 +168,15 @@ 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 {
@@ -177,7 +199,7 @@ export const authService = {
async getSessionUser() {
return supabase.auth.getUser();
},
- async signUp(email: any, password: any, nombre: any, telefono: any) {
+ async signUp(email: string, password: string, nombre: string, telefono: string) {
return supabase.auth.signUp({
email,
password,
@@ -192,10 +214,20 @@ export const authService = {
async signOut() {
return supabase.auth.signOut();
},
- async signIn(email: any, password: any) {
+ async signIn(email: string, password: string) {
return supabase.auth.signInWithPassword({ email, password });
},
async updateUser(metadata: any) {
return supabase.auth.updateUser({ ...metadata });
},
};
+
+const getSupabaseClient = async () => {
+ if (typeof window === 'undefined') {
+ // Si estamos en el servidor, usa el cliente del servidor
+ return await createClient();
+ } else {
+ // Si estamos en el cliente, usa el cliente del navegador
+ return supabase;
+ }
+};
diff --git a/src/lib/supabase/server.ts b/src/lib/supabase/server.ts
index 75ab4181..5bb64f40 100644
--- a/src/lib/supabase/server.ts
+++ b/src/lib/supabase/server.ts
@@ -1,23 +1,30 @@
-import { createServerClient, type CookieOptions } from '@supabase/ssr';
+'use server';
+
+import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
+import { Database } from '@/types/database';
export async function createClient() {
const cookieStore = await cookies();
- return createServerClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, {
- cookies: {
- getAll() {
- return cookieStore.getAll();
- },
- setAll(cookiesToSet) {
- try {
- cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options));
- } catch {
- // The `setAll` method was called from a Server Component.
- // This can be ignored if you have middleware refreshing
- // user sessions.
- }
+ return createServerClient(
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
+ {
+ cookies: {
+ getAll() {
+ return cookieStore.getAll();
+ },
+ setAll(cookiesToSet) {
+ try {
+ cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options));
+ } catch {
+ // The `setAll` method was called from a Server Component.
+ // This can be ignored if you have middleware refreshing
+ // user sessions.
+ }
+ },
},
},
- });
+ );
}
diff --git a/src/types/Requests.ts b/src/types/Requests.ts
index 8c52aaff..c875a3af 100644
--- a/src/types/Requests.ts
+++ b/src/types/Requests.ts
@@ -4,7 +4,14 @@ export type HelpRequestType = 'necesita' | 'ofrece';
export type HelpRequestUrgencyType = 'alta' | 'media' | 'baja';
export type HelpRequestStatusType = 'pending' | 'in_progress' | 'active';
export type HelpRequestData = Database['public']['Tables']['help_requests']['Row'];
+export type HelpRequestUpdate = Database['public']['Tables']['help_requests']['Update'];
export type HelpRequestAssignmentData = Database['public']['Tables']['help_request_assignments']['Row'];
+export type HelpRequestAssignmentInsert = Database['public']['Tables']['help_request_assignments']['Insert'];
+
+export type HelpRequestAdditionalInfo = {
+ special_situations?: string;
+ email?: string;
+};
export type CollectionPointType = 'permanente' | 'temporal';
export type CollectionPointStatus = 'active' | 'inactive';
diff --git a/src/types/Town.ts b/src/types/Town.ts
new file mode 100644
index 00000000..160382a6
--- /dev/null
+++ b/src/types/Town.ts
@@ -0,0 +1,3 @@
+import { Database } from '@/types/database';
+
+export type Town = Database['public']['Tables']['towns']['Row'];
diff --git a/supabase/migrations/20241106110421_add-missing-policy-help-request-assignments.sql b/supabase/migrations/20241106110421_add-missing-policy-help-request-assignments.sql
new file mode 100644
index 00000000..532177af
--- /dev/null
+++ b/supabase/migrations/20241106110421_add-missing-policy-help-request-assignments.sql
@@ -0,0 +1,9 @@
+CREATE POLICY "authenticated_can_insert_own_records"
+ON public.help_request_assignments
+FOR INSERT
+WITH CHECK ((select auth.uid()) = user_id);
+
+CREATE POLICY "Enable read access for all users"
+ON public.help_request_assignments
+FOR SELECT
+USING (true);
\ No newline at end of file
diff --git a/supabase/seed.sql b/supabase/seed.sql
new file mode 100644
index 00000000..9f1ace76
--- /dev/null
+++ b/supabase/seed.sql
@@ -0,0 +1,33 @@
+INSERT INTO "public"."towns" ("id", "created_at", "name", "people_helping", "help_needed")
+ VALUES ('1', '2024-11-02 17:52:17.645308+00', 'Aldaia', '0', '0'),
+ ('2', '2024-11-02 17:52:17.645308+00', 'Alfafar', '0', '0'),
+ ('3', '2024-11-02 17:52:17.645308+00', 'Albal', '0', '0'),
+ ('4', '2024-11-02 17:52:17.645308+00', 'Alcudia', '0', '0'),
+ ('5', '2024-11-02 17:52:17.645308+00', 'Algemesí', '0', '0'),
+ ('6', '2024-11-02 17:52:17.645308+00', 'Bugarra', '0', '0'),
+ ('7', '2024-11-02 17:52:17.645308+00', 'Catarroja', '0', '0'),
+ ('8', '2024-11-02 17:52:17.645308+00', 'Castelló', '0', '0'),
+ ('9', '2024-11-02 17:52:17.645308+00', 'Cheste', '0', '0'),
+ ('10', '2024-11-02 17:52:17.645308+00', 'Chiva', '0', '0'),
+ ('11', '2024-11-02 17:52:17.645308+00', 'Gestalgar', '0', '0'),
+ ('12', '2024-11-02 17:52:17.645308+00', 'Guadassuar', '0', '0'),
+ ('14', '2024-11-02 17:52:17.645308+00', 'Manuel', '0', '0'),
+ ('15', '2024-11-02 17:52:17.645308+00', 'Massanassa', '0', '0'),
+ ('16', '2024-11-02 17:52:17.645308+00', 'Montserrat', '0', '0'),
+ ('17', '2024-11-02 17:52:17.645308+00', 'Paiporta', '0', '0'),
+ ('18', '2024-11-02 17:52:17.645308+00', 'Pedralba', '0', '0'),
+ ('19', '2024-11-02 17:52:17.645308+00', 'Riba-roja de Túria', '0', '0'),
+ ('20', '2024-11-02 17:52:17.645308+00', 'Sedaví', '0', '0'),
+ ('21', '2024-11-02 17:52:17.645308+00', 'Sot de Chera', '0', '0'),
+ ('22', '2024-11-02 17:52:17.645308+00', 'Torrent', '0', '0'),
+ ('23', '2024-11-02 17:52:17.645308+00', 'Utiel', '0', '0'),
+ ('24', '2024-11-02 17:52:17.645308+00', 'Villar del Arzobispo', '0', '0'),
+ ('25', '2024-11-03 09:34:00.825499+00', 'Alzira', '0', '0'),
+ ('26', '2024-11-03 08:44:02.724841+00', 'Benetusser', '0', '0'),
+ ('27', '2024-11-03 08:44:34.023343+00', 'Turís', '0', '0'),
+ ('28', '2024-11-03 08:47:46.2913+00', 'Picanya', '0', '0'),
+ ('29', '2024-11-03 08:57:38.119705+00', 'La Torre, Valencia', '0', '0'),
+ ('30', '2024-11-03 09:05:24.008619+00', 'Benimaclet', '0', '0'),
+ ('31', '2024-11-03 09:21:27.852067+00', 'Godelleta', '0', '0'),
+ ('32', '2024-11-05 10:38:38.669406+00', 'Llocnou de la Corona', '0', '0'),
+ ('33', '2024-11-05 10:38:52.085488+00', 'Beniparrell', '0', '0');
\ No newline at end of file