Files
2026-DEV-BUT3/src/context/PromotionsContext.jsx
T

123 lines
2.8 KiB
React
Raw Normal View History

import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react'
const STORAGE_KEY = 'librairie-promotions'
function loadPromotions() {
try {
const raw = localStorage.getItem(STORAGE_KEY)
if (raw === null) return []
const parsed = JSON.parse(raw)
return Array.isArray(parsed) ? parsed : []
} catch {
return []
}
}
function savePromotions(promotions) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(promotions))
}
function normalizeCode(code) {
return String(code || '')
.trim()
.toUpperCase()
.replace(/\s+/g, '')
}
const PromotionsContext = createContext(null)
export function PromotionsProvider({ children }) {
const [promotions, setPromotions] = useState(loadPromotions)
useEffect(() => {
savePromotions(promotions)
}, [promotions])
const createPromotion = useCallback((promo) => {
const code = normalizeCode(promo.code)
const value = Number(promo.value)
if (!code) throw new Error('Code promo invalide')
if (!Number.isFinite(value) || value <= 0) {
throw new Error('Valeur de promo invalide')
}
setPromotions((prev) => {
if (prev.some((p) => p.code === code)) {
throw new Error('Ce code promo existe déjà')
}
return [
...prev,
{
id: crypto.randomUUID(),
code,
type: 'percent',
value,
active: true,
createdAt: new Date().toISOString(),
},
]
})
}, [])
const setPromotionActive = useCallback((code, active) => {
const normalized = normalizeCode(code)
setPromotions((prev) =>
prev.map((p) => (p.code === normalized ? { ...p, active } : p)),
)
}, [])
const removePromotion = useCallback((code) => {
const normalized = normalizeCode(code)
setPromotions((prev) => prev.filter((p) => p.code !== normalized))
}, [])
const getActivePromotionByCode = useCallback(
(code) => {
const normalized = normalizeCode(code)
return promotions.find((p) => p.code === normalized && p.active) || null
},
[promotions],
)
const value = useMemo(
() => ({
promotions,
createPromotion,
removePromotion,
setPromotionActive,
getActivePromotionByCode,
normalizeCode,
}),
[
promotions,
createPromotion,
removePromotion,
setPromotionActive,
getActivePromotionByCode,
],
)
return (
<PromotionsContext.Provider value={value}>
{children}
</PromotionsContext.Provider>
)
}
// eslint-disable-next-line react-refresh/only-export-components
export function usePromotions() {
const ctx = useContext(PromotionsContext)
if (!ctx) {
throw new Error('usePromotions doit être utilisé dans un PromotionsProvider')
}
return ctx
}