Files
2026-DEV-BUT3/src/context/OrdersContext.jsx
T
2026-04-25 16:04:54 +02:00

114 lines
2.9 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react'
const STORAGE_KEY = 'librairie-orders'
function loadOrders() {
try {
const raw = localStorage.getItem(STORAGE_KEY)
if (raw === null) return []
const parsed = JSON.parse(raw)
return Array.isArray(parsed) ? parsed : []
} catch {
return []
}
}
function saveOrders(orders) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(orders))
}
function round2(n) {
return Math.round((Number(n) + Number.EPSILON) * 100) / 100
}
function calcSubtotal(items) {
return round2(
items.reduce((sum, it) => sum + Number(it.unitPrice) * Number(it.qty), 0),
)
}
function calcDiscount({ subtotal, promotion }) {
if (!promotion) return 0
if (promotion.type === 'percent') {
const pct = Number(promotion.value)
if (!Number.isFinite(pct) || pct <= 0) return 0
return round2((subtotal * pct) / 100)
}
return 0
}
const OrdersContext = createContext(null)
export function OrdersProvider({ children }) {
const [orders, setOrders] = useState(loadOrders)
useEffect(() => {
saveOrders(orders)
}, [orders])
/**
* Équivalent local dun POST /api/orders.
* orderDraft: { items: [{ bookId, title, unitPrice, qty }], promotion?: { code, type, value } }
*/
const createOrder = useCallback((orderDraft) => {
const items = Array.isArray(orderDraft?.items) ? orderDraft.items : []
const cleaned = items
.map((it) => ({
bookId: String(it.bookId),
title: String(it.title || ''),
unitPrice: Number(it.unitPrice),
qty: Math.max(0, Math.trunc(Number(it.qty) || 0)),
}))
.filter((it) => it.bookId && it.qty > 0 && Number.isFinite(it.unitPrice))
if (cleaned.length === 0) {
throw new Error('Aucun article dans la commande')
}
const subtotal = calcSubtotal(cleaned)
const promotion = orderDraft?.promotion
? {
code: String(orderDraft.promotion.code || ''),
type: String(orderDraft.promotion.type || 'percent'),
value: Number(orderDraft.promotion.value),
}
: null
const discount = calcDiscount({ subtotal, promotion })
const total = round2(Math.max(0, subtotal - discount))
const order = {
id: crypto.randomUUID(),
createdAt: new Date().toISOString(),
items: cleaned,
promotion: promotion && promotion.code ? promotion : null,
subtotal,
discount,
total,
}
setOrders((prev) => [order, ...prev])
return order
}, [])
const value = useMemo(() => ({ orders, createOrder }), [orders, createOrder])
return <OrdersContext.Provider value={value}>{children}</OrdersContext.Provider>
}
// eslint-disable-next-line react-refresh/only-export-components
export function useOrders() {
const ctx = useContext(OrdersContext)
if (!ctx) {
throw new Error('useOrders doit être utilisé dans un OrdersProvider')
}
return ctx
}