Boutons de points compacts unifiés + page Le Calendrier des Dieux
Boutons de validation des points : - Les icônes ✓/✕ étaient trop grandes (40px) et dupliquées entre le podium et le reste du classement. Factorisées dans un composant partagé PointsConfirmControls (32px, icône 16px, olive/oxblood, aria-label + tooltip), utilisé à l'identique par JudgePointControls sur le podium ET dans la liste. Nouvelle page /calendrier — "Le Calendrier des Dieux" : - Modèle de données : days (date, dieu, domaine), events (titre, type, heure, lieu, created_by forcé par trigger), settings (ligne unique, date du Tribunal). RLS : lecture ouverte à tout authentifié, écriture (insert/update/delete) réservée au rôle judge par policies dédiées — jamais un simple masquage des boutons côté client. - 8 préréglages de divinités (Dionysos, Arès, Athéna, Aphrodite, Hermès, Poséidon, Hadès, Zeus) avec domaine, couleur d'accent et emblème SVG ; un Archonte peut aussi saisir une divinité libre. - Bannière avec compte à rebours avant la date du Tribunal, éditable par les Archontes. Journées en cartes (jour courant mis en évidence, jours passés estompés, jour du Tribunal en accent oxblood), liste d'événements avec icône par type (activité/défi/épreuve/tribunal). Mode édition (ajout/modification/suppression avec confirmation) réservé aux Archontes. Realtime sur les trois tables. - Ajouté au menu déroulant du header, route protégée par le proxy. Rendu des icônes dynamiques (GodEmblem, EventTypeIcon) via branchement JSX explicite plutôt que variable de composant résolue à l'exécution, pour respecter react-hooks/static-components. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+123
-1
@@ -355,7 +355,129 @@ exception
|
||||
when duplicate_object then null;
|
||||
end $$;
|
||||
|
||||
-- 9. Désigner les premiers juges ---------------------------------------------
|
||||
-- 9. Le Calendrier des Dieux --------------------------------------------------
|
||||
-- Agenda de la semaine : chaque journée est placée sous le patronage d'une
|
||||
-- divinité (nom/domaine en texte libre, l'Archonte choisit un préréglage
|
||||
-- côté client ou saisit le sien). Lecture ouverte à tous, écriture réservée
|
||||
-- aux juges (Archontes), vérifiée côté serveur par RLS — jamais par le
|
||||
-- masquage des boutons en front.
|
||||
|
||||
create table if not exists public.days (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
date date not null unique,
|
||||
god_name text not null,
|
||||
god_domain text not null,
|
||||
description text,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create table if not exists public.events (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
day_id uuid not null references public.days (id) on delete cascade,
|
||||
title text not null,
|
||||
description text,
|
||||
type text not null default 'activite' check (type in ('activite', 'defi', 'epreuve', 'tribunal')),
|
||||
start_time time,
|
||||
location text,
|
||||
created_by uuid references public.profiles (id) on delete set null,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
-- Ligne de configuration unique (id toujours = true) : date du Tribunal.
|
||||
create table if not exists public.settings (
|
||||
id boolean primary key default true,
|
||||
tribunal_date timestamptz,
|
||||
constraint settings_singleton check (id)
|
||||
);
|
||||
insert into public.settings (id) values (true) on conflict (id) do nothing;
|
||||
|
||||
alter table public.days enable row level security;
|
||||
alter table public.events enable row level security;
|
||||
alter table public.settings enable row level security;
|
||||
|
||||
grant select, insert, update, delete on public.days, public.events to authenticated;
|
||||
grant select, update on public.settings to authenticated;
|
||||
|
||||
-- Lecture : tout utilisateur authentifié.
|
||||
drop policy if exists "days viewable by authenticated" on public.days;
|
||||
create policy "days viewable by authenticated" on public.days for select to authenticated using (true);
|
||||
|
||||
drop policy if exists "events viewable by authenticated" on public.events;
|
||||
create policy "events viewable by authenticated" on public.events for select to authenticated using (true);
|
||||
|
||||
drop policy if exists "settings viewable by authenticated" on public.settings;
|
||||
create policy "settings viewable by authenticated" on public.settings for select to authenticated using (true);
|
||||
|
||||
-- Écriture : réservée aux juges.
|
||||
drop policy if exists "days insert by judges" on public.days;
|
||||
create policy "days insert by judges" on public.days for insert to authenticated
|
||||
with check (exists (select 1 from public.profiles p where p.id = auth.uid() and p.role = 'judge'));
|
||||
|
||||
drop policy if exists "days update by judges" on public.days;
|
||||
create policy "days update by judges" on public.days for update to authenticated
|
||||
using (exists (select 1 from public.profiles p where p.id = auth.uid() and p.role = 'judge'))
|
||||
with check (exists (select 1 from public.profiles p where p.id = auth.uid() and p.role = 'judge'));
|
||||
|
||||
drop policy if exists "days delete by judges" on public.days;
|
||||
create policy "days delete by judges" on public.days for delete to authenticated
|
||||
using (exists (select 1 from public.profiles p where p.id = auth.uid() and p.role = 'judge'));
|
||||
|
||||
drop policy if exists "events insert by judges" on public.events;
|
||||
create policy "events insert by judges" on public.events for insert to authenticated
|
||||
with check (exists (select 1 from public.profiles p where p.id = auth.uid() and p.role = 'judge'));
|
||||
|
||||
drop policy if exists "events update by judges" on public.events;
|
||||
create policy "events update by judges" on public.events for update to authenticated
|
||||
using (exists (select 1 from public.profiles p where p.id = auth.uid() and p.role = 'judge'))
|
||||
with check (exists (select 1 from public.profiles p where p.id = auth.uid() and p.role = 'judge'));
|
||||
|
||||
drop policy if exists "events delete by judges" on public.events;
|
||||
create policy "events delete by judges" on public.events for delete to authenticated
|
||||
using (exists (select 1 from public.profiles p where p.id = auth.uid() and p.role = 'judge'));
|
||||
|
||||
drop policy if exists "settings update by judges" on public.settings;
|
||||
create policy "settings update by judges" on public.settings for update to authenticated
|
||||
using (exists (select 1 from public.profiles p where p.id = auth.uid() and p.role = 'judge'))
|
||||
with check (exists (select 1 from public.profiles p where p.id = auth.uid() and p.role = 'judge'));
|
||||
|
||||
-- created_by ne fait jamais confiance au client : toujours l'auteur réel.
|
||||
create or replace function public.enforce_event_insert()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
as $$
|
||||
begin
|
||||
new.created_by := auth.uid();
|
||||
return new;
|
||||
end;
|
||||
$$;
|
||||
|
||||
drop trigger if exists events_before_insert on public.events;
|
||||
create trigger events_before_insert
|
||||
before insert on public.events
|
||||
for each row execute function public.enforce_event_insert();
|
||||
|
||||
do $$
|
||||
begin
|
||||
alter publication supabase_realtime add table public.days;
|
||||
exception
|
||||
when duplicate_object then null;
|
||||
end $$;
|
||||
|
||||
do $$
|
||||
begin
|
||||
alter publication supabase_realtime add table public.events;
|
||||
exception
|
||||
when duplicate_object then null;
|
||||
end $$;
|
||||
|
||||
do $$
|
||||
begin
|
||||
alter publication supabase_realtime add table public.settings;
|
||||
exception
|
||||
when duplicate_object then null;
|
||||
end $$;
|
||||
|
||||
-- 10. Désigner les premiers juges ---------------------------------------------
|
||||
-- À faire une fois les comptes créés (SQL Editor) :
|
||||
--
|
||||
-- update public.profiles set role = 'judge' where id = '<uuid-du-membre>';
|
||||
|
||||
Reference in New Issue
Block a user