From 8806ed2f04279f820d0ba5d84f6ede6e73aa44f0 Mon Sep 17 00:00:00 2001 From: belviskhoremk Date: Thu, 13 Aug 2026 09:18:16 +0200 Subject: [PATCH] feat: wire Rules page to live fetchRules data - Replace static rules import with async fetchRules() function - Update RuleIcon prop from ruleId to iconKey - Add error state handling for data loading failures - Add .error CSS class for error message styling Closes Task 5's deferred compilation breakage: Rules.tsx now imports fetchRules (async) instead of the deleted static rules export, and uses the renamed iconKey prop on RuleIcon. Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH --- src/pages/Rules.module.css | 4 ++++ src/pages/Rules.test.tsx | 32 ++++++++++++++++++++++++++------ src/pages/Rules.tsx | 20 ++++++++++++++++++-- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/pages/Rules.module.css b/src/pages/Rules.module.css index ff20a19..e78bdc0 100644 --- a/src/pages/Rules.module.css +++ b/src/pages/Rules.module.css @@ -29,3 +29,7 @@ text-align: center; margin-top: var(--space-xl); } + +.error { + color: #a33; +} diff --git a/src/pages/Rules.test.tsx b/src/pages/Rules.test.tsx index 066339d..7f695b2 100644 --- a/src/pages/Rules.test.tsx +++ b/src/pages/Rules.test.tsx @@ -1,20 +1,40 @@ import { render, screen } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom' -import { describe, it, expect } from 'vitest' +import { describe, it, expect, vi, beforeEach } from 'vitest' + +const orderMock = vi.fn() +const selectMock = vi.fn(() => ({ order: orderMock })) +const fromMock = vi.fn<(table: string) => { select: typeof selectMock }>(() => ({ select: selectMock })) + +vi.mock('../lib/supabase', () => ({ + supabase: { from: (table: string) => fromMock(table) }, +})) + +const RULE_ROWS = [ + { id: 'r1', title: 'Acompte', body: 'Un acompte est requis.', icon_key: 'deposit', sort_order: 0 }, + { id: 'r2', title: 'Retard', body: 'Les retards ont des frais.', icon_key: 'lateness', sort_order: 1 }, +] + import Rules from './Rules' -import { rules } from '../data/rules' describe('Rules page', () => { - it('renders every rule section title and body', () => { + beforeEach(() => { + orderMock.mockReset().mockResolvedValue({ data: RULE_ROWS, error: null }) + selectMock.mockClear() + fromMock.mockClear() + }) + + it('renders every rule section title and body', async () => { render() - for (const rule of rules) { - expect(screen.getByText(rule.title)).toBeInTheDocument() + for (const rule of RULE_ROWS) { + expect(await screen.findByText(rule.title)).toBeInTheDocument() expect(screen.getByText(rule.body)).toBeInTheDocument() } }) - it('links back to booking', () => { + it('links back to booking', async () => { render() + await screen.findByText('Acompte') expect(screen.getByRole('link', { name: /réserver/i })).toHaveAttribute('href', '/book') }) }) diff --git a/src/pages/Rules.tsx b/src/pages/Rules.tsx index 191d0c8..152aa09 100644 --- a/src/pages/Rules.tsx +++ b/src/pages/Rules.tsx @@ -1,18 +1,34 @@ +import { useEffect, useState } from 'react' import { Link } from 'react-router-dom' import ScrollReveal from '../components/ScrollReveal' import RuleIcon from '../components/RuleIcon' -import { rules } from '../data/rules' +import { fetchRules, type RuleSection } from '../data/rules' import styles from './Rules.module.css' function Rules() { + const [rules, setRules] = useState([]) + const [error, setError] = useState('') + + useEffect(() => { + async function load() { + try { + setRules(await fetchRules()) + } catch (err) { + setError(err && typeof err === 'object' && 'message' in err ? String((err as { message: unknown }).message) : String(err)) + } + } + void load() + }, []) + return (

Règlements et politiques du salon

Merci de les lire avant de réserver votre rendez-vous.

+ {error &&

{error}

} {rules.map((rule, index) => (
- +

{rule.title}

{rule.body}