Inital commit

This commit is contained in:
2026-04-20 00:24:00 +02:00
commit 1f21d857e4
23 changed files with 2591 additions and 0 deletions
+197
View File
@@ -0,0 +1,197 @@
import { useState } from 'react'
import type { Cart, CartTemplate, Section, Product, Drone } from '../types'
const CARTS_KEY = 'carts'
const ACTIVE_KEY = 'active-cart-id'
function loadCarts(): Cart[] {
try {
const raw = localStorage.getItem(CARTS_KEY)
if (raw) return JSON.parse(raw) as Cart[]
} catch {}
return []
}
function loadActiveId(carts: Cart[]): string | null {
const stored = localStorage.getItem(ACTIVE_KEY)
if (stored && carts.find(c => c.id === stored)) return stored
return carts[0]?.id ?? null
}
function saveCarts(carts: Cart[]) {
localStorage.setItem(CARTS_KEY, JSON.stringify(carts))
}
export function useCarts() {
const [carts, setCarts] = useState<Cart[]>(() => loadCarts())
const [activeId, setActiveId] = useState<string | null>(() => {
const c = loadCarts()
return loadActiveId(c)
})
const activeCart = carts.find(c => c.id === activeId) ?? null
function mutateCarts(fn: (carts: Cart[]) => Cart[]) {
setCarts(prev => {
const next = fn(prev)
saveCarts(next)
return next
})
}
function mutateActiveCart(fn: (cart: Cart) => Cart) {
mutateCarts(carts => carts.map(c => c.id === activeId ? fn(c) : c))
}
// ── Cart management ────────────────────────────────────────────────────────
function createCart(name: string, template?: CartTemplate): string {
const id = crypto.randomUUID()
const cart: Cart = {
id,
name,
createdAt: new Date().toISOString().slice(0, 10),
templateId: template?.id,
sections: template ? structuredClone(template.sections) : [],
}
mutateCarts(prev => [...prev, cart])
setActiveCart(id)
return id
}
function deleteCart(id: string) {
mutateCarts(prev => {
const next = prev.filter(c => c.id !== id)
if (activeId === id) {
const newActive = next[0]?.id ?? null
setActiveId(newActive)
if (newActive) localStorage.setItem(ACTIVE_KEY, newActive)
else localStorage.removeItem(ACTIVE_KEY)
}
return next
})
}
function renameCart(id: string, name: string) {
mutateCarts(carts => carts.map(c => c.id === id ? { ...c, name } : c))
}
function setActiveCart(id: string) {
setActiveId(id)
localStorage.setItem(ACTIVE_KEY, id)
}
function importCart(json: string): boolean {
try {
const cart = JSON.parse(json) as Cart
if (!cart.id || !cart.name || !Array.isArray(cart.sections)) return false
const imported = { ...cart, id: crypto.randomUUID() }
mutateCarts(prev => [...prev, imported])
setActiveCart(imported.id)
return true
} catch {
return false
}
}
function exportCart() {
if (!activeCart) return
const blob = new Blob([JSON.stringify(activeCart, null, 2)], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${activeCart.name.toLowerCase().replace(/\s+/g, '-')}.json`
a.click()
URL.revokeObjectURL(url)
}
// ── Section management ────────────────────────────────────────────────────
function addSection(section: Omit<Section, 'items'>) {
mutateActiveCart(cart => ({
...cart,
sections: [...cart.sections, { ...section, items: [] }],
}))
}
function removeSection(sectionId: string) {
mutateActiveCart(cart => ({
...cart,
sections: cart.sections.filter(s => s.id !== sectionId),
}))
}
function renameSection(sectionId: string, label: string) {
mutateActiveCart(cart => ({
...cart,
sections: cart.sections.map(s => s.id === sectionId ? { ...s, label } : s),
}))
}
// ── Item management ───────────────────────────────────────────────────────
function addItem(sectionId: string, item: Product | Drone) {
mutateActiveCart(cart => ({
...cart,
sections: cart.sections.map(s =>
s.id === sectionId ? { ...s, items: [...s.items, item] } : s
),
}))
}
function updateItem(sectionId: string, item: Product | Drone) {
mutateActiveCart(cart => ({
...cart,
sections: cart.sections.map(s =>
s.id === sectionId
? { ...s, items: s.items.map(i => i.id === item.id ? item : i) }
: s
),
}))
}
function removeItem(sectionId: string, itemId: string) {
mutateActiveCart(cart => ({
...cart,
sections: cart.sections.map(s =>
s.id === sectionId
? { ...s, items: s.items.filter(i => i.id !== itemId) }
: s
),
}))
}
function copyItemToCart(item: Product | Drone, targetCartId: string, targetSectionId: string) {
const copy = { ...structuredClone(item), id: crypto.randomUUID() }
mutateCarts(carts => carts.map(c => {
if (c.id !== targetCartId) return c
const hasSection = c.sections.some(s => s.id === targetSectionId)
if (!hasSection) return c
return {
...c,
sections: c.sections.map(s =>
s.id === targetSectionId ? { ...s, items: [...s.items, copy] } : s
),
}
}))
}
return {
carts,
activeCart,
activeId,
setActiveCart,
createCart,
deleteCart,
renameCart,
importCart,
exportCart,
addSection,
removeSection,
renameSection,
addItem,
updateItem,
removeItem,
copyItemToCart,
}
}