feat: Enhance reservation functionality

This commit is contained in:
2026-04-22 10:23:22 -04:00
parent 7f1e82acc2
commit 534d66c774
25 changed files with 1236 additions and 91 deletions

View File

@@ -0,0 +1,22 @@
-- Allow members to cancel their own reservations and edit reason/comment.
-- 1. Expand status check constraint to include 'cancelled'
alter table public.reservations
drop constraint reservations_status_check;
alter table public.reservations
add constraint reservations_status_check
check (status in ('pending', 'tentative', 'confirmed', 'cancelled'));
-- 2. Exclude cancelled reservations from the public slots view so cancelled
-- slots appear as available again on the schedule.
drop view if exists public.reservation_slots;
create view public.reservation_slots
with (security_invoker = false)
as
select id, boat_id, start_time, end_time, status
from public.reservations
where status <> 'cancelled';
grant select on public.reservation_slots to authenticated;

View File

@@ -0,0 +1,12 @@
-- The overlap exclusion constraint must not apply to cancelled reservations,
-- so that a cancelled slot can be re-booked by another member.
alter table public.reservations
drop constraint no_overlapping_reservations;
alter table public.reservations
add constraint no_overlapping_reservations
exclude using gist (
boat_id with =,
tstzrange(start_time, end_time, '[)') with &&
) where (status <> 'cancelled');

View File

@@ -0,0 +1,20 @@
-- Prevent members from modifying (cancelling or editing) reservations whose
-- session has already started. Admins bypass this via service-role updates;
-- the trigger only fires on connections where auth.uid() is a non-admin member.
-- For simplicity we enforce it for all non-service-role connections.
create or replace function public.prevent_past_reservation_updates()
returns trigger
language plpgsql
as $$
begin
if old.start_time < now() then
raise exception 'past_reservation: Reservations that have already started cannot be modified.';
end if;
return new;
end;
$$;
create trigger check_past_reservation_update
before update on public.reservations
for each row execute function public.prevent_past_reservation_updates();

View File

@@ -0,0 +1,25 @@
-- Expose user_id and member_name in reservation_slots.
-- JOIN with members is safe here because security_invoker=false runs as view owner,
-- bypassing RLS — so any authenticated user can see names without a separate members query.
-- Must drop+recreate because CREATE OR REPLACE VIEW cannot insert a column mid-list.
drop view if exists public.reservation_slots;
create view public.reservation_slots
with (security_invoker = false)
as
select
r.id,
r.boat_id,
r.user_id,
r.start_time,
r.end_time,
r.status,
coalesce(
nullif(trim(m.first_name || ' ' || m.last_name), ''),
m.email
) as member_name
from public.reservations r
left join public.members m on m.user_id = r.user_id
where r.status <> 'cancelled';
grant select on public.reservation_slots to authenticated;