import { useEffect, useState, useCallback } from "react"; import { useTranslation } from "react-i18next"; import { Info, RefreshCw, Download, CheckCircle, AlertCircle, RotateCcw, Loader2, ShieldCheck, BookOpen, ChevronRight, FileText, } from "lucide-react"; import { getVersion } from "@tauri-apps/api/app"; import { useUpdater } from "../hooks/useUpdater"; import { Link } from "react-router-dom"; import { APP_NAME } from "../shared/constants"; import { PageHelp } from "../components/shared/PageHelp"; import DataManagementCard from "../components/settings/DataManagementCard"; import LicenseCard from "../components/settings/LicenseCard"; import LogViewerCard from "../components/settings/LogViewerCard"; export default function SettingsPage() { const { t, i18n } = useTranslation(); const { state, checkForUpdate, downloadAndInstall, installAndRestart } = useUpdater(); const [version, setVersion] = useState(""); const [releaseNotes, setReleaseNotes] = useState(null); const fetchReleaseNotes = useCallback( (targetVersion: string) => { const file = i18n.language === "fr" ? "/CHANGELOG.fr.md" : "/CHANGELOG.md"; fetch(file) .then((r) => r.text()) .then((text) => { const escaped = targetVersion.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const re = new RegExp( `^## \\[?${escaped}\\]?.*$\\n([\\s\\S]*?)(?=^## |$(?!\\n))`, "m", ); const match = text.match(re); setReleaseNotes( match ? match[1].trim() : null, ); }) .catch(() => setReleaseNotes(null)); }, [i18n.language], ); useEffect(() => { getVersion().then(setVersion); }, []); useEffect(() => { if (state.status === "available" && state.version) { fetchReleaseNotes(state.version); } }, [state.status, state.version, fetchReleaseNotes]); const progressPercent = state.contentLength && state.contentLength > 0 ? Math.round((state.progress / state.contentLength) * 100) : null; return (

{t("settings.title")}

{/* License card */} {/* About card */}
S

{APP_NAME}

{t("settings.version", { version })}

{/* User guide card */}

{t("settings.userGuide.title")}

{t("settings.userGuide.description")}

{/* Changelog card */}

{t("changelog.title")}

{t("changelog.description")}

{/* Update card */}

{t("settings.updates.title")}

{/* idle */} {state.status === "idle" && ( )} {/* checking */} {state.status === "checking" && (
{t("settings.updates.checking")}
)} {/* up to date */} {state.status === "upToDate" && (
{t("settings.updates.upToDate")}
)} {/* available */} {state.status === "available" && (

{t("settings.updates.available", { version: state.version })}

{(() => { const notes = releaseNotes || state.body; if (!notes) return null; return (

{t("settings.updates.releaseNotes")}

{notes.split("\n").map((line, i) => { const trimmed = line.trim(); if (!trimmed) return
; if (trimmed.startsWith("### ")) return

{trimmed.slice(4)}

; if (trimmed.startsWith("## ")) return

{trimmed.slice(3)}

; if (trimmed.startsWith("- ")) return

{"\u2022 "}{trimmed.slice(2).replace(/\*\*(.+?)\*\*/g, "$1")}

; return

{trimmed}

; })}
); })()}
)} {/* downloading */} {state.status === "downloading" && (
{t("settings.updates.downloading")} {progressPercent !== null && {progressPercent}%}
)} {/* ready to install */} {state.status === "readyToInstall" && (

{t("settings.updates.readyToInstall")}

)} {/* installing */} {state.status === "installing" && (
{t("settings.updates.installing")}
)} {/* error */} {state.status === "error" && (
{t("settings.updates.error")}

{state.error}

)}
{/* Logs */} {/* Data management */} {/* Data safety notice */}

{t("settings.dataSafeNotice")}

); }