Initial commit: monorepo Naturcalabacera reservas (apps/api + apps/web + packages/shared)

This commit is contained in:
2026-04-30 10:09:44 +01:00
commit a0ccb8ca64
188 changed files with 16418 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
import { useEffect, useState } from 'react';
import { supabase } from '../lib/supabase';
import type { Reservation, NewReservation, Property } from '../types';
export function useReservations(property: Property) {
const [reservations, setReservations] = useState<Reservation[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchReservations = async () => {
try {
setLoading(true);
const { data, error } = await supabase
.from('reservations')
.select('*')
.eq('property', property)
.order('start_date', { ascending: true });
if (error) throw error;
setReservations(data || []);
} catch (err: unknown) {
setError(err instanceof Error ? err.message : 'Error desconocido');
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchReservations();
// Suscripción realtime filtrada por propiedad
const channel = supabase
.channel(`reservations_${property}`)
.on(
'postgres_changes',
{
event: '*',
schema: 'natur_reservas',
table: 'reservations',
filter: `property=eq.${property}`,
},
() => {
fetchReservations();
}
)
.subscribe();
return () => {
supabase.removeChannel(channel);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [property]);
const createReservation = async (reservation: NewReservation): Promise<Reservation> => {
const { data: authData } = await supabase.auth.getUser();
const payload = {
...reservation,
property,
created_by: authData.user?.id,
};
const { data, error } = await supabase
.from('reservations')
.insert([payload])
.select('id')
.single();
if (error) throw error;
const { data: created, error: fetchError } = await supabase
.from('reservations')
.select('*')
.eq('id', data.id)
.single();
if (fetchError) throw fetchError;
return created as Reservation;
};
const updateReservation = async (id: string, updates: Partial<Reservation>) => {
const { data: authData } = await supabase.auth.getUser();
const payload = {
...updates,
updated_by: authData.user?.id,
};
const { error } = await supabase
.from('reservations')
.update(payload)
.eq('id', id);
if (error) throw error;
};
const deleteReservation = async (id: string) => {
const { error } = await supabase.from('reservations').delete().eq('id', id);
if (error) throw error;
};
return {
reservations,
loading,
error,
createReservation,
updateReservation,
deleteReservation,
refreshResolver: fetchReservations,
};
}