import { useEffect, useState } from "react"; import { useStore } from "../store"; import { SectionItem, QuestItem, CombatType } from "../types"; import QuestDetailPanel from "./QuestDetailPanel"; import { TextWithCoords } from "./TextWithCoords"; function useWindowWidth() { const [width, setWidth] = useState(window.innerWidth); useEffect(() => { const handler = () => setWidth(window.innerWidth); window.addEventListener("resize", handler); return () => window.removeEventListener("resize", handler); }, []); return width; } function combatIcon(name: string): string { const l = name.toLowerCase(); if (l === "solo") return "🗡️"; if (l === "groupe") return "⚔️"; if (l === "donjon") return "💀"; if ( l === "combat_vagues" || l === "combat_tactique" || l === "combat_aleatoire" || l === "combat_zone" || l === "combat" ) return "🗡️"; if (l === "deplacement") return "🗺️"; if (l === "item") return "📦"; // Fallback — conserve l'ancienne logique pour les données CSV existantes if (l.includes("solo") || l.includes("seul")) return "🗡️"; if (l.includes("group") || l.includes("groupe")) return "⚔️"; if (l.includes("donjon") || l.includes("boss")) return "💀"; return "🗡️"; } export default function GuideView() { const { activeGuideData, completedQuests, toggleQuest, activeProfileId, resourcesPanelCollapsed, setResourcesPanelCollapsed, resourceInventory, setResourceQuantity } = useStore(); const resourcesCollapsed = resourcesPanelCollapsed; const setResourcesCollapsed = setResourcesPanelCollapsed; const [selectedQuest, setSelectedQuest] = useState<{ name: string; url: string | null } | null>(null); const windowWidth = useWindowWidth(); const resourcesIsOverlay = resourcesCollapsed || windowWidth < 500; if (!activeGuideData) return null; if (selectedQuest && activeProfileId) { return (
setSelectedQuest(null)} />
); } const { name, effect, recommended_level, resources, sections, combat_legend } = activeGuideData; const allQuests = collectAllQuests(sections); const completedCount = allQuests.filter(q => completedQuests.has(q)).length; const pct = allQuests.length > 0 ? Math.round((completedCount / allQuests.length) * 100) : 0; const isDone = pct === 100; return (
{/* Header */}

{name}

{recommended_level && (
Niv. recommandé : {recommended_level}
)}
{completedCount} / {allQuests.length}
{pct}%
{effect && (
✨ Effet {effect}
)}
{/* Légende */} {combat_legend.length > 0 && ( )} {/* Sections */} {sections.map((section, si) => (

{section.name}

{section.items.map((item, ii) => ( ))}
))}
{/* Resources panel */} {resources.length > 0 && (
{/* Toggle */} {/* List */} {!resourcesCollapsed && (
{resources.map((r, i) => { const owned = resourceInventory[r.name] ?? 0; const done = owned >= r.quantity; return (
{r.name}
{ const v = parseInt(e.target.value); setResourceQuantity(r.name, isNaN(v) ? 0 : Math.max(0, v)); }} style={{ width: "42px", background: "#0d1117", border: `1px solid ${done ? "rgba(74,222,128,0.4)" : "#2d3748"}`, borderRadius: "4px", padding: "2px 4px", color: done ? "#4ade80" : "#e2e8f0", fontSize: "11px", outline: "none", textAlign: "right", }} /> / Ă—{r.quantity}
); })}
)}
)}
); } function Legend({ legend }: { legend: CombatType[] }) { return (
Légende
{legend.map((ct, i) => (
{combatIcon(ct.name)} {ct.name}
))}
); } function SectionItemView({ item, completedQuests, onToggle, onSelect }: { item: SectionItem; completedQuests: Set; onToggle: (name: string) => void; onSelect: (quest: { name: string; url: string | null }) => void; }) { if (item.type === "Instruction") { if (item.text.startsWith("__ZONE__:")) { const zone = item.text.replace("__ZONE__:", ""); return (
{zone}
); } return (
Rappel
); } if (item.type === "Group") { return (
{item.note && (
đź”— {item.note}
)} {item.quests.map((q, i) => ( ))}
); } if (item.type === "Quest") { return ; } return null; } function QuestRow({ quest, completed, onToggle, onSelect, indent }: { quest: QuestItem; completed: boolean; onToggle: (name: string) => void; onSelect: (quest: { name: string; url: string | null }) => void; indent?: boolean; }) { const questPreviews = useStore(s => s.questPreviews); const previewsLoading = useStore(s => s.previewsLoading); const [previewsOpen, setPreviewsOpen] = useState(false); const previews = quest.url ? questPreviews[quest.url] : undefined; const showLoadingPlaceholder = previewsLoading && quest.url !== null && previews === undefined; const hasPreviewSection = showLoadingPlaceholder || (previews && previews.length > 0); return (
{ (e.currentTarget as HTMLElement).style.background = "rgba(255,255,255,0.04)"; }} onMouseLeave={e => { (e.currentTarget as HTMLElement).style.background = "transparent"; }} > onToggle(quest.name)} style={{ marginTop: "2px", flexShrink: 0, cursor: "pointer" }} />
onSelect({ name: quest.name, url: quest.url })} style={{ fontSize: "12px", lineHeight: 1.4, color: completed ? "#4a5568" : "#93c5fd", textDecoration: completed ? "line-through" : "underline", textDecorationColor: "rgba(147,197,253,0.3)", cursor: "pointer", wordBreak: "break-word", }} > {quest.name} {quest.combat_indicators.map((ci, i) => ( {combatIcon(ci.combat_type)} x{ci.count} ))}
{hasPreviewSection && ( setPreviewsOpen(o => !o)} style={{ display: "inline-block", marginTop: "2px", fontSize: "10px", color: "#4a5568", cursor: "pointer", userSelect: "none", }} onMouseEnter={e => { (e.currentTarget as HTMLElement).style.color = "#94a3b8"; }} onMouseLeave={e => { (e.currentTarget as HTMLElement).style.color = "#4a5568"; }} > {previewsOpen ? `▾ À prévoir` : `▸ À prévoir${previews && previews.length > 0 ? ` (${previews.length})` : ""}` } )} {previewsOpen && ( <> {showLoadingPlaceholder && (
)} {!showLoadingPlaceholder && previews && previews.length > 0 && (
{previews.map((ci, i) => ( {combatIcon(ci.combat_type)} ×{ci.count}{ci.combat_type !== "item" ? ` ${ci.combat_type}` : ""} {ci.evitable && ( (évit.) )} {ci.label && ( {ci.label} )} ))}
)} )} {quest.note && (
→
)}
); } function collectAllQuests(sections: import("../types").Section[]): string[] { const names: string[] = []; for (const section of sections) { for (const item of section.items) { if (item.type === "Quest") names.push(item.name); else if (item.type === "Group") item.quests.forEach((q: QuestItem) => names.push(q.name)); } } return names; }