"use client"; // Utilitaires partagés du centre d'apprentissage : fetch typé, niveaux de maîtrise, // formats de dates, bannière d'erreur, anneau de progression. import type { ReactNode } from "react"; import { cn } from "@/components/ui"; // ---------- Fetch JSON avec erreurs françaises ---------- export async function fetchJson(url: string, init?: RequestInit): Promise { const res = await fetch(url, init); const data = await res.json().catch(() => ({})); if (!res.ok) { throw new Error((data as { error?: string }).error ?? `Erreur ${res.status}`); } return data as T; } export function postJson(url: string, body: unknown): Promise { return fetchJson(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); } // ---------- Niveaux de maîtrise ---------- export type MasteryLevel = "a-decouvrir" | "en-construction" | "solide" | "maitrise"; export const LEVELS: Record< MasteryLevel, { label: string; tone: "neutral" | "amber" | "brand" | "green"; hex: string; text: string; bg: string } > = { maitrise: { label: "Maîtrisé", tone: "green", hex: "#10b981", text: "text-emerald-600 dark:text-emerald-400", bg: "bg-emerald-500" }, solide: { label: "Solide", tone: "brand", hex: "#1d64b0", text: "text-brand-600 dark:text-brand-300", bg: "bg-brand-500" }, "en-construction": { label: "En construction", tone: "amber", hex: "#f59e0b", text: "text-amber-600 dark:text-amber-400", bg: "bg-amber-500" }, "a-decouvrir": { label: "À découvrir", tone: "neutral", hex: "#94a3b8", text: "text-muted", bg: "bg-slate-400" }, }; export function levelInfo(level: string) { return LEVELS[(level as MasteryLevel) in LEVELS ? (level as MasteryLevel) : "a-decouvrir"]; } // ---------- Dates (SQLite UTC → local fr-CA) ---------- export function parseDbDate(s: string): Date { return new Date(s.includes("T") || s.endsWith("Z") ? s : s.replace(" ", "T") + "Z"); } export function fmtDate(s: string): string { return parseDbDate(s).toLocaleDateString("fr-CA", { day: "numeric", month: "long", year: "numeric" }); } export function fmtDateTime(s: string): string { return parseDbDate(s).toLocaleString("fr-CA", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }); } // ---------- Bannière d'erreur ---------- export function ErrorBanner({ message, className }: { message: string; className?: string }) { return (
{message}
); } // ---------- Anneau de progression ---------- export function ProgressRing({ value, size = 120, stroke = 10, label, className, }: { value: number; // 0..1 size?: number; stroke?: number; label?: ReactNode; className?: string; }) { const v = Math.min(1, Math.max(0, value)); const r = (size - stroke) / 2; const c = 2 * Math.PI * r; return (
{label ?? ( <> {Math.round(v * 100)}% maîtrise )}
); } // ---------- Points de difficulté (1-5) ---------- export function DifficultyDots({ value }: { value: number }) { return ( {[1, 2, 3, 4, 5].map((i) => ( ))} ); } // ---------- Téléchargement d'un fichier texte ---------- export function downloadText(filename: string, content: string, mime = "text/markdown") { const blob = new Blob([content], { type: mime }); const a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = filename; a.click(); URL.revokeObjectURL(a.href); }