123 lines
2.8 KiB
React
123 lines
2.8 KiB
React
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
|
|
}
|
|
|