diff --git a/my-library/src/App.jsx b/my-library/src/App.jsx index 06cbff5..e0083bb 100644 --- a/my-library/src/App.jsx +++ b/my-library/src/App.jsx @@ -11,6 +11,7 @@ import Customers from './pages/Customers'; import Login from './pages/Login'; import Reservations from './pages/Reservations'; import Returns from './pages/Returns'; +import Subscription from './pages/Subscription'; import { useAuth } from './context/AuthContext'; function RequireAuth({ children }) { @@ -39,6 +40,7 @@ export default function App() { } /> } /> } /> + } /> } /> diff --git a/my-library/src/components/Navbar.jsx b/my-library/src/components/Navbar.jsx index 4cdd047..9872ec9 100644 --- a/my-library/src/components/Navbar.jsx +++ b/my-library/src/components/Navbar.jsx @@ -20,6 +20,7 @@ export default function Navbar() {
  • Catalogue
  • {user &&
  • Commandes
  • } {user?.role === 'user' &&
  • Mes réservations
  • } + {user?.role === 'user' &&
  • Mon abonnement
  • } {user &&
  • Mon compte
  • } {user?.role === 'admin' &&
  • Clients
  • } {user?.role === 'admin' &&
  • Retours
  • } diff --git a/my-library/src/context/SubscriptionContext.js b/my-library/src/context/SubscriptionContext.js new file mode 100644 index 0000000..7a0cc8d --- /dev/null +++ b/my-library/src/context/SubscriptionContext.js @@ -0,0 +1,50 @@ +import { createContext, useContext, useState } from 'react'; + +const SubscriptionContext = createContext(null); + +const PLANS = [ + { id: 'basic', name: 'Basic', price: 9.99, description: '2 livres par mois' }, + { id: 'standard', name: 'Standard', price: 14.99, description: '5 livres par mois' }, + { id: 'premium', name: 'Premium', price: 24.99, description: 'Livres illimités par mois' }, +]; + +export { PLANS }; + +export function SubscriptionProvider({ children }) { + const [subscription, setSubscription] = useState(() => { + const saved = localStorage.getItem('subscription'); + return saved ? JSON.parse(saved) : null; + }); + + function subscribe(planId, phoneNumber) { + const plan = PLANS.find(p => p.id === planId); + const newSubscription = { + subscriptionId: crypto.randomUUID(), + planId, + planName: plan.name, + price: plan.price, + phoneNumber, + status: 'ACTIVE', + startDate: new Date().toISOString(), + }; + setSubscription(newSubscription); + localStorage.setItem('subscription', JSON.stringify(newSubscription)); + return newSubscription; + } + + function cancelSubscription() { + const updated = { ...subscription, status: 'CANCELLED' }; + setSubscription(updated); + localStorage.setItem('subscription', JSON.stringify(updated)); + } + + return ( + + {children} + + ); +} + +export function useSubscription() { + return useContext(SubscriptionContext); +} diff --git a/my-library/src/index.js b/my-library/src/index.js index ae97fdc..50db091 100644 --- a/my-library/src/index.js +++ b/my-library/src/index.js @@ -5,6 +5,7 @@ import { AuthProvider } from './context/AuthContext'; import { ReservationProvider } from './context/ReservationContext'; import { ReviewProvider } from './context/ReviewContext'; import { ReturnProvider } from './context/ReturnContext'; +import { SubscriptionProvider } from './context/SubscriptionContext'; import App from './App'; import './styles/global.css'; @@ -16,7 +17,9 @@ root.render( - + + + diff --git a/my-library/src/pages/BookDetail.jsx b/my-library/src/pages/BookDetail.jsx index e4b3f47..b1cd5c8 100644 --- a/my-library/src/pages/BookDetail.jsx +++ b/my-library/src/pages/BookDetail.jsx @@ -4,10 +4,12 @@ import { getBookById } from '../api/books'; import { useAuth } from '../context/AuthContext'; import { useReservations } from '../context/ReservationContext'; import { useReviews } from '../context/ReviewContext'; +import { useSubscription } from '../context/SubscriptionContext'; export default function BookDetail() { const { user } = useAuth(); - const { addReservation } = useReservations(); + const { subscription } = useSubscription(); + const { addReservation, reservations } = useReservations(); const { addReview, getReviewsByBook } = useReviews(); const [rating, setRating] = useState(5); const [comment, setComment] = useState(''); @@ -97,27 +99,60 @@ export default function BookDetail() { )} - {user?.role === 'user' &&
    -

    Réserver ce livre

    -
    - - -
    - {reservationStatus && ( -

    - {reservationStatus.message} -

    - )} -
    } + {user?.role === 'user' && ( +
    +

    Réserver ce livre

    + {!subscription || subscription.status !== 'ACTIVE' ? ( +

    + Vous devez avoir un abonnement actif pour réserver un livre.{' '} + S'abonner +

    + ) : (() => { + const QUOTAS = { basic: 2, standard: 5, premium: Infinity }; + const quota = QUOTAS[subscription.planId]; + const thisMonthStart = new Date(); + thisMonthStart.setDate(1); + thisMonthStart.setHours(0, 0, 0, 0); + const usedThisMonth = reservations.filter(r => + new Date(r.reservedAt) >= thisMonthStart + ).length; + const remaining = quota - usedThisMonth; + + if (remaining <= 0) { + return ( +

    + Vous avez atteint votre quota de {quota} réservation(s) ce mois-ci. + Passer au plan supérieur +

    + ); + } + + return ( + <> +

    Réservations restantes ce mois : {remaining === Infinity ? 'illimitées' : remaining}

    +
    + + +
    + {reservationStatus && ( +

    + {reservationStatus.message} +

    + )} + + ); + })()} +
    + )} ); } \ No newline at end of file diff --git a/my-library/src/pages/Subscription.jsx b/my-library/src/pages/Subscription.jsx new file mode 100644 index 0000000..a0f36c7 --- /dev/null +++ b/my-library/src/pages/Subscription.jsx @@ -0,0 +1,74 @@ +import { useState } from 'react'; +import { useSubscription } from '../context/SubscriptionContext'; + +export default function Subscription() { + const { subscription, subscribe, cancelSubscription, PLANS } = useSubscription(); + const [selectedPlan, setSelectedPlan] = useState('basic'); + const [phoneNumber, setPhoneNumber] = useState(''); + const [message, setMessage] = useState(null); + + function handleSubscribe(e) { + e.preventDefault(); + subscribe(selectedPlan, phoneNumber); + setMessage({ success: true, text: 'Abonnement créé avec succès !' }); + setPhoneNumber(''); + } + + function handleCancel() { + cancelSubscription(); + setMessage({ success: false, text: 'Abonnement annulé.' }); + } + + return ( +
    +

    Mon abonnement

    + + {subscription && subscription.status === 'ACTIVE' ? ( +
    +

    Abonnement actif

    +

    Plan : {subscription.planName}

    +

    Prix : {subscription.price} € / mois

    +

    Téléphone : {subscription.phoneNumber}

    +

    Depuis le : {new Date(subscription.startDate).toLocaleDateString('fr-FR')}

    +

    Statut : {subscription.status}

    + +
    + ) : ( +
    +

    Choisir un abonnement

    +
    +
    + {PLANS.map(plan => ( + + ))} +
    + + +
    +
    + )} + + {message && ( +

    {message.text}

    + )} +
    + ); +}