import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { characterApi } from '../api/endpoints'; import { api } from '../api/client'; import { Coins, ShoppingBag, Sword, Shield, Heart } from 'lucide-react'; const RARITY_COLORS: Record = { common: '#9ca3af', rare: '#5ba4f5', epic: '#a78bfa', legendary: '#f4c94e', }; const TYPE_EMOJI: Record = { weapon: '⚔️', armor: '🛡️', consumable: '🧪', }; const ZONE_LABELS: Record = { marais: '🌿 Marais', egouts: '🕳️ Égouts', desert: '🏜️ Désert', }; interface ShopItem { id: string; name: string; description: string | null; type: string; rarity: string; attackBonus: number; defenseBonus: number; buyPrice: number; minLevel: number; zone: string | null; affordable: boolean; levelOk: boolean; sellPrice: number; } function ShopItemCard({ item, onBuy, buying }: { item: ShopItem; onBuy: () => void; buying: boolean }) { const canBuy = item.affordable && item.levelOk; const rarityColor = RARITY_COLORS[item.rarity] ?? '#9ca3af'; return (
{TYPE_EMOJI[item.type] ?? '📦'}
{item.name} {item.rarity}
{item.description &&

{item.description}

}
{item.attackBonus > 0 && +{item.attackBonus} ATK} {item.defenseBonus > 0 && +{item.defenseBonus} DEF} {item.type === 'consumable' && +50% PV} {item.minLevel > 1 && Niv. {item.minLevel}+}
{item.buyPrice}
{!item.levelOk &&
Niv. {item.minLevel} requis
}
); } export function ShopPage() { const qc = useQueryClient(); const { data: char } = useQuery({ queryKey: ['character'], queryFn: characterApi.me }); const { data: catalogue, isLoading } = useQuery({ queryKey: ['shop'], queryFn: () => api.get('/shop'), }); const buyMut = useMutation({ mutationFn: (itemId: string) => api.post(`/shop/buy/${itemId}`), onSuccess: () => { qc.invalidateQueries({ queryKey: ['character'] }); qc.invalidateQueries({ queryKey: ['shop'] }); qc.invalidateQueries({ queryKey: ['inventory'] }); }, }); if (isLoading) return
Chargement…
; // Group by zone const zones = new Map(); for (const item of (catalogue ?? [])) { const zone = item.zone ?? 'general'; const list = zones.get(zone) ?? []; list.push(item); zones.set(zone, list); } // Order: general first, then by zone const zoneOrder = ['general', 'marais', 'egouts', 'desert']; const sortedZones = Array.from(zones.entries()).sort((a, b) => zoneOrder.indexOf(a[0]) - zoneOrder.indexOf(b[0]) ); return (

Boutique

{char && ( {char.gold} or )}
{buyMut.isSuccess && (
{(buyMut.data as any)?.type === 'consumable' ? `🧪 ${(buyMut.data as any)?.item} utilisé ! +${(buyMut.data as any)?.effect?.healed} PV` : `✅ ${(buyMut.data as any)?.item} acheté ! (-${(buyMut.data as any)?.goldSpent} or)` }
)} {buyMut.isError && (
{(buyMut.error as Error).message}
)} {sortedZones.map(([zone, items]) => (

{zone === 'general' ? '🧪 Consommables' : ZONE_LABELS[zone] ?? zone}

{items.map(item => ( buyMut.mutate(item.id)} buying={buyMut.isPending} /> ))}
))}
); }