reservation livres

This commit is contained in:
AISSI-JUDE-CHRIST
2026-06-11 23:08:21 +02:00
parent de47c293b8
commit 010ec9c11a
6 changed files with 93 additions and 18 deletions
+2
View File
@@ -9,6 +9,7 @@ import AddBook from './pages/AddBook';
import BookDetail from './pages/BookDetail';
import Customers from './pages/Customers';
import Login from './pages/Login';
import Reservations from './pages/Reservations';
import { useAuth } from './context/AuthContext';
function RequireAuth({ children }) {
@@ -33,6 +34,7 @@ export default function App() {
<Route path="books/:bookId" element={<RequireAuth><BookDetail /></RequireAuth>} />
<Route path="books/new" element={<RequireAdmin><AddBook /></RequireAdmin>} />
<Route path="orders" element={<RequireAuth><Orders /></RequireAuth>} />
<Route path="reservations" element={<RequireAuth><Reservations /></RequireAuth>} />
<Route path="profile" element={<RequireAuth><Profile /></RequireAuth>} />
<Route path="customers" element={<RequireAdmin><Customers /></RequireAdmin>} />
<Route path="*" element={<NotFound />} />
+1
View File
@@ -19,6 +19,7 @@ export default function Navbar() {
<li><Link to="/">Accueil</Link></li>
<li><Link to="/books">Catalogue</Link></li>
{user && <li><Link to="/orders">Commandes</Link></li>}
{user?.role === 'user' && <li><Link to="/reservations">Mes réservations</Link></li>}
{user && <li><Link to="/profile">Mon compte</Link></li>}
{user?.role === 'admin' && <li><Link to="/customers">Clients</Link></li>}
</ul>
@@ -0,0 +1,42 @@
import { createContext, useContext, useState } from 'react';
const ReservationContext = createContext(null);
export function ReservationProvider({ children }) {
const [reservations, setReservations] = useState(() => {
const saved = localStorage.getItem('reservations');
return saved ? JSON.parse(saved) : [];
});
function addReservation(book, phoneNumber) {
const reservation = {
reservationId: crypto.randomUUID(),
bookId: book.isbn,
bookTitle: book.title,
bookAuthor: book.author,
phoneNumber,
status: 'CONFIRMED',
reservedAt: new Date().toISOString(),
};
const updated = [...reservations, reservation];
setReservations(updated);
localStorage.setItem('reservations', JSON.stringify(updated));
return reservation;
}
function cancelReservation(reservationId) {
const updated = reservations.filter(r => r.reservationId !== reservationId);
setReservations(updated);
localStorage.setItem('reservations', JSON.stringify(updated));
}
return (
<ReservationContext.Provider value={{ reservations, addReservation, cancelReservation }}>
{children}
</ReservationContext.Provider>
);
}
export function useReservations() {
return useContext(ReservationContext);
}
+4 -1
View File
@@ -2,6 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { AuthProvider } from './context/AuthContext';
import { ReservationProvider } from './context/ReservationContext';
import App from './App';
import './styles/global.css';
@@ -10,7 +11,9 @@ root.render(
<React.StrictMode>
<BrowserRouter>
<AuthProvider>
<App />
<ReservationProvider>
<App />
</ReservationProvider>
</AuthProvider>
</BrowserRouter>
</React.StrictMode>
+7 -17
View File
@@ -1,34 +1,26 @@
import { useState, useEffect } from 'react';
import { useParams, Link } from 'react-router-dom';
import { getBookById, reserveBook } from '../api/books';
import { getBookById } from '../api/books';
import { useAuth } from '../context/AuthContext';
import { useReservations } from '../context/ReservationContext';
export default function BookDetail() {
const { user } = useAuth();
const { addReservation } = useReservations();
const { bookId } = useParams();
const [book, setBook] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [phoneNumber, setPhoneNumber] = useState('');
const [reservationStatus, setReservationStatus] = useState(null);
const [reserving, setReserving] = useState(false);
useEffect(() => { getBookById(bookId).then((response) => setBook(response.data)).catch((err) => { console.error(err); setError('Livre introuvable.'); }).finally(() => setLoading(false)); }, [bookId]);
function handleReservation(e) {
e.preventDefault();
setReserving(true);
setReservationStatus(null);
reserveBook(bookId, { phoneNumber })
.then(() => {
setReservationStatus({ success: true, message: 'Réservation effectuée avec succès !' });
setPhoneNumber('');
})
.catch((err) => {
const msg = err.response?.data || 'Erreur lors de la réservation.';
setReservationStatus({ success: false, message: msg });
})
.finally(() => setReserving(false));
addReservation(book, phoneNumber);
setReservationStatus({ success: true, message: 'Réservation effectuée avec succès !' });
setPhoneNumber('');
}
if (loading) return <main><p>Chargement</p></main>;
@@ -61,9 +53,7 @@ export default function BookDetail() {
required
/>
</label>
<button type="submit" disabled={reserving}>
{reserving ? 'Réservation…' : 'Réserver'}
</button>
<button type="submit">Réserver</button>
</form>
{reservationStatus && (
<p style={{ color: reservationStatus.success ? 'green' : 'red' }}>
+37
View File
@@ -0,0 +1,37 @@
import { useReservations } from '../context/ReservationContext';
import { Link } from 'react-router-dom';
export default function Reservations() {
const { reservations, cancelReservation } = useReservations();
if (reservations.length === 0) {
return (
<main>
<h1>Mes réservations</h1>
<p>Aucune réservation pour le moment.</p>
<Link to="/books"> Retour au catalogue</Link>
</main>
);
}
return (
<main>
<h1>Mes réservations</h1>
<ul>
{reservations.map(r => (
<li key={r.reservationId}>
<strong>{r.bookTitle}</strong> {r.bookAuthor}
<br />
Téléphone : {r.phoneNumber}
<br />
Réservé le : {new Date(r.reservedAt).toLocaleDateString('fr-FR')}
<br />
Statut : {r.status}
<br />
<button onClick={() => cancelReservation(r.reservationId)}>Annuler</button>
</li>
))}
</ul>
</main>
);
}