reservation livres
This commit is contained in:
@@ -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 />} />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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>
|
||||
<ReservationProvider>
|
||||
<App />
|
||||
</ReservationProvider>
|
||||
</AuthProvider>
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>
|
||||
|
||||
@@ -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(() => {
|
||||
addReservation(book, phoneNumber);
|
||||
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));
|
||||
}
|
||||
|
||||
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' }}>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user