diff --git a/my-library/src/App.jsx b/my-library/src/App.jsx
index ff39111..a10b954 100644
--- a/my-library/src/App.jsx
+++ b/my-library/src/App.jsx
@@ -1,4 +1,4 @@
-import { Routes, Route } from 'react-router-dom';
+import { Routes, Route, Navigate } from 'react-router-dom';
import Layout from './components/Layout';
import Home from './pages/Home';
import Books from './pages/Books';
@@ -8,19 +8,34 @@ import NotFound from './pages/NotFound';
import AddBook from './pages/AddBook';
import BookDetail from './pages/BookDetail';
import Customers from './pages/Customers';
+import Login from './pages/Login';
+import { useAuth } from './context/AuthContext';
+
+function RequireAuth({ children }) {
+ const { user } = useAuth();
+ return user ? children : ;
+}
+
+function RequireAdmin({ children }) {
+ const { user } = useAuth();
+ if (!user) return ;
+ if (user.role !== 'admin') return ;
+ return children;
+}
export default function App() {
return (
+ } />
}>
} />
} />
- } />
- } />
+ } />
+ } />
+ } />
+ } />
+ } />
} />
- } />
- } />
- } />
);
diff --git a/my-library/src/components/Navbar.jsx b/my-library/src/components/Navbar.jsx
index c60e798..84dce88 100644
--- a/my-library/src/components/Navbar.jsx
+++ b/my-library/src/components/Navbar.jsx
@@ -1,7 +1,16 @@
-import { Link } from 'react-router-dom';
+import { Link, useNavigate } from 'react-router-dom';
+import { useAuth } from '../context/AuthContext';
import '../styles/navbar.css';
export default function Navbar() {
+ const { user, logout } = useAuth();
+ const navigate = useNavigate();
+
+ function handleLogout() {
+ logout();
+ navigate('/login');
+ }
+
return (
);
diff --git a/my-library/src/context/AuthContext.js b/my-library/src/context/AuthContext.js
new file mode 100644
index 0000000..c9e5c41
--- /dev/null
+++ b/my-library/src/context/AuthContext.js
@@ -0,0 +1,39 @@
+import { createContext, useContext, useState } from 'react';
+
+const USERS = [
+ { username: 'admin', password: 'admin', role: 'admin' },
+ { username: 'alice', password: 'bob', role: 'user' },
+];
+
+const AuthContext = createContext(null);
+
+export function AuthProvider({ children }) {
+ const [user, setUser] = useState(() => {
+ const saved = localStorage.getItem('auth');
+ return saved ? JSON.parse(saved) : null;
+ });
+
+ function login(username, password) {
+ const found = USERS.find(u => u.username === username && u.password === password);
+ if (!found) return false;
+ const { password: _, ...safe } = found;
+ setUser(safe);
+ localStorage.setItem('auth', JSON.stringify(safe));
+ return true;
+ }
+
+ function logout() {
+ setUser(null);
+ localStorage.removeItem('auth');
+ }
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useAuth() {
+ return useContext(AuthContext);
+}
diff --git a/my-library/src/index.js b/my-library/src/index.js
index 7b56730..71c19cb 100644
--- a/my-library/src/index.js
+++ b/my-library/src/index.js
@@ -1,6 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
+import { AuthProvider } from './context/AuthContext';
import App from './App';
import './styles/global.css';
@@ -8,7 +9,9 @@ const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
-
+
+
+
);
\ No newline at end of file
diff --git a/my-library/src/pages/BookDetail.jsx b/my-library/src/pages/BookDetail.jsx
index 68194d6..77cf45c 100644
--- a/my-library/src/pages/BookDetail.jsx
+++ b/my-library/src/pages/BookDetail.jsx
@@ -1,14 +1,35 @@
import { useState, useEffect } from 'react';
import { useParams, Link } from 'react-router-dom';
-import { getBookById } from '../api/books';
+import { getBookById, reserveBook } from '../api/books';
+import { useAuth } from '../context/AuthContext';
export default function BookDetail() {
- const { bookId } = useParams();
+ const { user } = useAuth();
+ 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]);
+ 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));
+ }
if (loading) return Chargement…
;
if (error) return {error}
← Retour au catalogue;
@@ -26,6 +47,30 @@ export default function BookDetail() {
Langue : {book.language}
Catégories : {book.categories?.join(', ')}
{book.description && {book.description}
}
+
+ {user?.role === 'user' &&
+ Réserver ce livre
+
+ {reservationStatus && (
+
+ {reservationStatus.message}
+
+ )}
+ }
);
}
\ No newline at end of file
diff --git a/my-library/src/pages/Books.jsx b/my-library/src/pages/Books.jsx
index 0c283e5..e4d4115 100644
--- a/my-library/src/pages/Books.jsx
+++ b/my-library/src/pages/Books.jsx
@@ -1,8 +1,10 @@
import { useState, useEffect } from 'react';
import { getBooks } from '../api/books';
import { Link } from 'react-router-dom';
+import { useAuth } from '../context/AuthContext';
export default function Books() {
+ const { user } = useAuth();
const [books, setBooks] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
@@ -28,7 +30,7 @@ export default function Books() {
return (
Catalogue
- + Ajouter un livre
+ {user?.role === 'admin' && + Ajouter un livre}
{books.map((book) => (
-
diff --git a/my-library/src/pages/Login.jsx b/my-library/src/pages/Login.jsx
new file mode 100644
index 0000000..1e0689d
--- /dev/null
+++ b/my-library/src/pages/Login.jsx
@@ -0,0 +1,57 @@
+import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { useAuth } from '../context/AuthContext';
+
+export default function Login() {
+ const { login } = useAuth();
+ const navigate = useNavigate();
+ const [form, setForm] = useState({ username: '', password: '' });
+ const [error, setError] = useState(null);
+
+ function handleSubmit(e) {
+ e.preventDefault();
+ const ok = login(form.username, form.password);
+ if (ok) {
+ navigate('/');
+ } else {
+ setError('Identifiants incorrects.');
+ }
+ }
+
+ return (
+
+
Connexion
+
+ Comptes disponibles :
+
+ - admin / admin (administrateur)
+ - user / user (utilisateur)
+
+
+ );
+}