diff --git a/src/components/BankCard.astro b/src/components/BankCard.astro index ad6c9d1..431cd65 100644 --- a/src/components/BankCard.astro +++ b/src/components/BankCard.astro @@ -5,9 +5,9 @@ const { name, monthly_allowance, type = "FLUX" } = frontmatter; // --- LOGIQUE DE COULEUR SUBTILE --- const bankConfigs = { - UpDĂ©jeuner: { color: "#f97316", icon: "🍮" }, // Orange Up - "La Banque Postale": { color: "#137bb1", icon: "🏩" }, // Bleu BP - Sumeria: { color: "#116853", icon: "⚡" }, // Vert d'eau + UpDĂ©jeuner: { color: "#f97316", icon: "🍮" }, + "La Banque Postale": { color: "#137bb1", icon: "🏩" }, + Sumeria: { color: "#116853", icon: "⚡" }, }; const config = bankConfigs[name as keyof typeof bankConfigs] || { @@ -16,25 +16,36 @@ const config = bankConfigs[name as keyof typeof bankConfigs] || { }; const color = config.color; -const now = new Date(); -// Importe le type si nĂ©cessaire (Astro le gĂ©nĂšre pour toi) -// import type { CollectionEntry } from 'astro:content'; +// --- LOGIQUE DE RÉCUPÉRATION TEMPORELLE DYNAMIQUE --- -const currentMonthEntries = allHumans.filter((h: any) => { - // Remplace 'any' par 'CollectionEntry<"humans">' si tu veux ĂȘtre strict - const d = new Date(h.data.date); - return ( - d.getMonth() === now.getMonth() && d.getFullYear() === now.getFullYear() - ); -}); +// 1. On cherche toutes les entrĂ©es qui contiennent rĂ©ellement des flux +const entriesWithFlux = allHumans.filter((h: any) => + h.data.manifestations?.some((m: any) => m.cercle === "FLX"), +); + +// 2. On trouve la date de la toute derniĂšre transaction enregistrĂ©e (pour ne pas ĂȘtre bloquĂ© par un changement de mois vide) +const lastFluxEntry = entriesWithFlux.sort( + (a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime(), +)[0]; + +// 3. On dĂ©finit la pĂ©riode de rĂ©fĂ©rence (Mois/AnnĂ©e) +const refDate = lastFluxEntry ? new Date(lastFluxEntry.data.date) : new Date(); +const refMonth = refDate.getMonth(); +const refYear = refDate.getFullYear(); + +// 4. Somme des flux pour cette pĂ©riode et pour cette banque spĂ©cifique +const totalFlux = allHumans.reduce((acc: number, entry: any) => { + const d = new Date(entry.data.date); + const isSamePeriod = + d.getMonth() === refMonth && d.getFullYear() === refYear; + + if (!isSamePeriod) return acc; -// Somme des flux -// BankCard.astro (Partie Logique) -const totalFlux = currentMonthEntries.reduce((acc: number, entry: any) => { const flxManifests = entry.data.manifestations?.filter((m: any) => { - // ON FILTRE : cercle FLX ET la source doit correspondre au nom de la carte - return m.cercle === "FLX" && m.source === name; + const sourceName = m.source?.trim().toLowerCase(); + const cardName = name?.trim().toLowerCase(); + return m.cercle === "FLX" && sourceName === cardName; }) || []; return ( @@ -46,6 +57,11 @@ const totalFlux = currentMonthEntries.reduce((acc: number, entry: any) => { ); }, 0); +// Log de contrĂŽle dans ton terminal Lenovo +console.log( + `[${name}] Bilan basĂ© sur : ${refMonth + 1}/${refYear} | Total : ${totalFlux}`, +); + const percentage = Math.max( 0, Math.min(100, Math.round((totalFlux / monthly_allowance) * 100)), @@ -128,9 +144,8 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" }; .bank-card { background: linear-gradient(135deg, #fff 0%, #f8fafc 100%); color: #1a202c; - border-color: var( - --accent - ) !important; /* Bordure subtile de la couleur de la banque */ + border-color: var(--accent) !important; + border-width: 2px; } .card-inner { @@ -145,7 +160,7 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" }; display: flex; justify-content: space-between; align-items: center; - border-bottom: 1px solid #e2e8f0; /* SoulignĂ© subtil */ + border-bottom: 1px solid #e2e8f0; padding-bottom: 5px; margin-bottom: 10px; } @@ -154,7 +169,7 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" }; font-weight: bold; font-family: "Philosopher", serif; font-size: 1.1rem; - color: var(--accent); /* Nom colorĂ© subtilement */ + color: var(--accent); } .visual-container { @@ -169,10 +184,11 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" }; overflow: hidden; gap: 10px; border: 1px solid rgba(0, 0, 0, 0.05); + padding: 10px 0; } .circular-chart { - max-width: 100px; + max-width: 80px; width: 100%; } .circle-bg { @@ -182,7 +198,7 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" }; } .circle { fill: none; - stroke: var(--accent); /* La jauge prend la couleur de la banque */ + stroke: var(--accent); stroke-width: 2.8; stroke-linecap: round; transition: stroke-dasharray 1s ease; @@ -196,15 +212,13 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" }; } .status-badge { - background: var( - --state-color - ); /* Garde la couleur d'Ă©tat (vert/orange/rouge) pour la sĂ©curitĂ© */ + background: var(--state-color); color: white; font-size: 0.5rem; - padding: 1px 6px; + padding: 2px 8px; border-radius: 4px; text-transform: uppercase; - letter-spacing: 0.5px; + font-weight: bold; } .card-type-line { @@ -223,6 +237,7 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" }; color: #94a3b8; margin-bottom: 10px; min-height: 1.5rem; + line-height: 1.2; } .stat-row { @@ -238,12 +253,12 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" }; } .segment { width: 14px; - height: 4px; + height: 6px; background: #e2e8f0; border-radius: 1px; } .segment.active { - background: var(--accent); /* Segments de la couleur de la banque */ + background: var(--accent); } .card-footer { @@ -253,5 +268,6 @@ else if (percentage < 85) status = { label: "ÉQUILIBRE", color: "#3b82f6" }; align-items: center; font-size: 0.6rem; color: #94a3b8; + padding-top: 10px; } diff --git a/src/components/ShoppingCard.astro b/src/components/ShoppingCard.astro new file mode 100644 index 0000000..4546365 --- /dev/null +++ b/src/components/ShoppingCard.astro @@ -0,0 +1,139 @@ +--- +// components/ShoppingCard.astro +const { item, remaining, total, unit, category } = Astro.props; + +// Calcul du pourcentage pour la jauge +const percentage = Math.max(0, Math.min(100, (remaining / total) * 100)); +const isLow = remaining > 0 && percentage < 25; +const isEmpty = remaining <= 0; +--- + +
+
+
+ {item} + {isEmpty ? "❌" : "📩"} +
+ +
+
+ {remaining} + {unit} +
+ +
+
+
+
+
+ +
+
{category || "Logistique"}
+

Capacité max: {total} {unit}

+
+
+
+ + diff --git a/src/pages/collection.astro b/src/pages/collection.astro index 3a9a95d..cfb08cf 100644 --- a/src/pages/collection.astro +++ b/src/pages/collection.astro @@ -4,31 +4,62 @@ import Layout from "../layouts/Layout.astro"; import Card from "../components/Card.astro"; import EventCard from "../components/EventCard.astro"; import BankCard from "../components/BankCard.astro"; +import ShoppingCard from "../components/ShoppingCard.astro"; const allHumans = await getCollection("humans"); +const allEvents = await getCollection("events"); +const allBanks = await getCollection("banks"); +const allStocks = await getCollection("stocks"); + const myHumans = allHumans.filter((entry: any) => entry.id.startsWith("latchimynicolas/"), ); -const allEvents = await getCollection("events"); -const allBanks = await getCollection("banks"); +const inventoryWithStatus = allStocks.map((stock) => { + const itemName = stock.data.item || ""; + const consumed = allHumans.reduce((acc, human) => { + const manifestations = human.data.manifestations || []; + const consosForItem = manifestations.filter( + (m: any) => + m.type === "conso" && + m.item?.trim().toLowerCase() === itemName.trim().toLowerCase(), + ); + const totalConsumedByHuman = consosForItem.reduce( + (sum: number, m: any) => sum + (Number(m.amount) || 1), + 0, + ); + return acc + totalConsumedByHuman; + }, 0); + + return { + ...stock, + remaining: (stock.data.quantity || 0) - consumed, + }; +}); + +const groupedStocks = inventoryWithStatus.reduce((acc: any, item: any) => { + const pathParts = item.id.split("/"); + const datePath = + pathParts.length >= 3 ? pathParts.slice(0, 3).join("/") : "Divers"; + if (!acc[datePath]) acc[datePath] = []; + acc[datePath].push(item); + return acc; +}, {}); + +const sortedStockDates = Object.keys(groupedStocks).sort((a, b) => + b.localeCompare(a), +); -// 1. Tri const sortedEntries = allHumans.sort( - (a: any, b: any) => - new Date(b.data.date).getTime() - new Date(a.data.date).getTime(), + (a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime(), ); - const sortedEvents = allEvents.sort( - (a: any, b: any) => - new Date(a.data.date).getTime() - new Date(b.data.date).getTime(), + (a, b) => new Date(a.data.date).getTime() - new Date(b.data.date).getTime(), ); - -const sortedBanks = allBanks.sort((a: any, b: any) => +const sortedBanks = allBanks.sort((a, b) => a.data.name.localeCompare(b.data.name), ); -// 2. Groupement const groupedHumans = sortedEntries.reduce((acc: any, entry: any) => { const userName = entry.data.name; if (!acc[userName]) acc[userName] = []; @@ -41,30 +72,26 @@ const groupedHumans = sortedEntries.reduce((acc: any, entry: any) => {
← Retour au flux

Collection

-
- {/* SECTION HUMAINS */} + {/* HUMAINS */} { Object.entries(groupedHumans).map(([userName, cards]) => ( -
+
- {userName} - ({(cards as any[]).length} souffles) + {userName} ({(cards as any[]).length}) - -
)) } - {/* SECTION ÉVÉNEMENTS */} - { - sortedEvents.length > 0 && ( -
- - ÉvĂ©nements ({sortedEvents.length} cartes) - -
- {sortedEvents.map((event) => ( + {/* ÉVÉNEMENTS */} +
+ ÉvĂ©nements +
- ) - } +
+ )) + } + +
- {/* SECTION TRÉSORERIES */} -
- - Trésoreries (Sources de Flux) - -
+ {/* LOGISTIQUE */} +
+ Logistique du Souffle + { + sortedStockDates.map((date) => ( +
+

+ {date.split("/").reverse().join(" / ")} +

+
+ {groupedStocks[date].map((stock: any) => ( +
+
+ +
+
+ ))} +
+
+ )) + } +
+ + {/* TRÉSORERIES */} +
+ Trésoreries +
{ sortedBanks.map((bank) => ( -
diff --git a/src/pages/index.astro b/src/pages/index.astro index 677ddf3..928ecb8 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -15,7 +15,6 @@ const allEvents = await getCollection("events", ({ data }) => { // Récupération de la banque const allBanks = await getCollection("banks"); -const upCard = allBanks.find((b) => b.id === "up" || b.id === "up.md"); // 2. Tris temporels const sortedAll = allHumans.sort( @@ -144,17 +143,17 @@ const latestPerUser = Array.from( } { - upCard && ( + allBanks.map((bank) => (
- ) + )) } @@ -192,8 +191,6 @@ const latestPerUser = Array.from( padding: 60px 20px; width: 100%; scrollbar-width: none; - -ms-overflow-style: none; - -webkit-overflow-scrolling: touch; } .hero-flex::-webkit-scrollbar { @@ -255,7 +252,11 @@ const latestPerUser = Array.from( /* 6. Centrage Desktop (Lenovo) */ @media (min-width: 1025px) { .hero-flex { - justify-content: center; + justify-content: flex-start; + padding-left: calc( + 50vw - 160px + ); /* Optionnel : pour centrer la PREMIÈRE carte au milieu de l'écran */ + padding-right: 50vw; gap: 40px; } }