feat: add per-page contextual help via CircleHelp icon
Each page now shows a ? icon next to its title that toggles a collapsible help card with page-specific tips. Supports EN/FR via i18n, closes on outside click or X button. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0adfa5fe5e
commit
3351601ff5
11 changed files with 250 additions and 23 deletions
59
src/components/shared/PageHelp.tsx
Normal file
59
src/components/shared/PageHelp.tsx
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { useState, useRef, useEffect } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { CircleHelp, X } from "lucide-react";
|
||||||
|
|
||||||
|
export function PageHelp({ helpKey }: { helpKey: string }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// Close on outside click (same pattern as CategoryCombobox)
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isOpen) return;
|
||||||
|
const handler = (e: MouseEvent) => {
|
||||||
|
if (ref.current && !ref.current.contains(e.target as Node)) {
|
||||||
|
setIsOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener("mousedown", handler);
|
||||||
|
return () => document.removeEventListener("mousedown", handler);
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
|
const tips = t(`${helpKey}.help.tips`, { returnObjects: true }) as string[];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={ref} className="relative">
|
||||||
|
<button
|
||||||
|
onClick={() => setIsOpen(!isOpen)}
|
||||||
|
className="text-[var(--muted-foreground)] hover:text-[var(--foreground)] transition-colors"
|
||||||
|
aria-label={t(`${helpKey}.help.title`)}
|
||||||
|
>
|
||||||
|
<CircleHelp size={20} />
|
||||||
|
</button>
|
||||||
|
{isOpen && (
|
||||||
|
<div className="absolute left-0 top-full mt-2 z-40 w-[calc(100vw-var(--sidebar-width,16rem)-6rem)] max-w-3xl bg-[var(--card)] border border-[var(--border)] rounded-xl p-5 shadow-lg">
|
||||||
|
<div className="flex items-start justify-between gap-4 mb-3">
|
||||||
|
<h3 className="font-semibold text-[var(--foreground)]">
|
||||||
|
{t(`${helpKey}.help.title`)}
|
||||||
|
</h3>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
|
className="text-[var(--muted-foreground)] hover:text-[var(--foreground)] transition-colors shrink-0"
|
||||||
|
>
|
||||||
|
<X size={18} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<ul className="space-y-1.5 text-sm text-[var(--muted-foreground)]">
|
||||||
|
{Array.isArray(tips) &&
|
||||||
|
tips.map((tip, i) => (
|
||||||
|
<li key={i} className="flex gap-2">
|
||||||
|
<span className="shrink-0">•</span>
|
||||||
|
<span>{tip}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,15 @@
|
||||||
"6months": "6 months",
|
"6months": "6 months",
|
||||||
"12months": "12 months",
|
"12months": "12 months",
|
||||||
"all": "All"
|
"all": "All"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"title": "How to use the Dashboard",
|
||||||
|
"tips": [
|
||||||
|
"Use the period selector (top right) to view different time ranges",
|
||||||
|
"Summary cards show your balance, income, and expenses for the selected period",
|
||||||
|
"The pie chart breaks down your expenses by category",
|
||||||
|
"Recent transactions are listed at the bottom"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"import": {
|
"import": {
|
||||||
|
|
@ -145,6 +154,15 @@
|
||||||
"checkDuplicates": "Check duplicates",
|
"checkDuplicates": "Check duplicates",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"import": "Import"
|
"import": "Import"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"title": "How to import bank statements",
|
||||||
|
"tips": [
|
||||||
|
"Set your import folder, then create one subfolder per bank/source with CSV files inside",
|
||||||
|
"Click a source to configure column mapping, delimiter, and date format",
|
||||||
|
"Preview your data before importing to catch formatting issues",
|
||||||
|
"Duplicate detection prevents the same transactions from being imported twice"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"transactions": {
|
"transactions": {
|
||||||
|
|
@ -184,7 +202,16 @@
|
||||||
},
|
},
|
||||||
"autoCategorize": "Auto-categorize",
|
"autoCategorize": "Auto-categorize",
|
||||||
"autoCategorizeResult": "{{count}} transaction(s) categorized",
|
"autoCategorizeResult": "{{count}} transaction(s) categorized",
|
||||||
"autoCategorizeNone": "No new matches found"
|
"autoCategorizeNone": "No new matches found",
|
||||||
|
"help": {
|
||||||
|
"title": "How to use Transactions",
|
||||||
|
"tips": [
|
||||||
|
"Use the filters to search by description, category, source, or date range",
|
||||||
|
"Click a column header to sort transactions",
|
||||||
|
"Assign categories by clicking the category dropdown on each row",
|
||||||
|
"Auto-categorize uses your keyword rules to categorize transactions in bulk"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"categories": {
|
"categories": {
|
||||||
"title": "Categories",
|
"title": "Categories",
|
||||||
|
|
@ -207,7 +234,16 @@
|
||||||
"keywordCount": "Keywords",
|
"keywordCount": "Keywords",
|
||||||
"keywordText": "Keyword...",
|
"keywordText": "Keyword...",
|
||||||
"priority": "Priority",
|
"priority": "Priority",
|
||||||
"customColor": "Custom color"
|
"customColor": "Custom color",
|
||||||
|
"help": {
|
||||||
|
"title": "How to manage Categories",
|
||||||
|
"tips": [
|
||||||
|
"Create top-level categories and subcategories to organize your expenses and income",
|
||||||
|
"Add keywords to a category so transactions matching those words are auto-categorized",
|
||||||
|
"Set a priority on keywords to resolve conflicts when multiple categories match",
|
||||||
|
"Click a category in the tree to view its details, edit it, or manage keywords"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"adjustments": {
|
"adjustments": {
|
||||||
"title": "Adjustments",
|
"title": "Adjustments",
|
||||||
|
|
@ -215,7 +251,15 @@
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
"amount": "Amount",
|
"amount": "Amount",
|
||||||
"recurring": "Recurring"
|
"recurring": "Recurring",
|
||||||
|
"help": {
|
||||||
|
"title": "How to use Adjustments",
|
||||||
|
"tips": [
|
||||||
|
"Adjustments let you add manual entries that don't come from bank imports",
|
||||||
|
"Use them for expected expenses or income not yet reflected in your statements",
|
||||||
|
"Recurring adjustments repeat automatically each period"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"budget": {
|
"budget": {
|
||||||
"title": "Budget",
|
"title": "Budget",
|
||||||
|
|
@ -224,7 +268,15 @@
|
||||||
"planned": "Planned",
|
"planned": "Planned",
|
||||||
"actual": "Actual",
|
"actual": "Actual",
|
||||||
"difference": "Difference",
|
"difference": "Difference",
|
||||||
"template": "Template"
|
"template": "Template",
|
||||||
|
"help": {
|
||||||
|
"title": "How to use Budget",
|
||||||
|
"tips": [
|
||||||
|
"Set planned amounts for each category to track your spending goals",
|
||||||
|
"Compare planned vs. actual spending to see where you're over or under budget",
|
||||||
|
"Use templates to quickly apply the same budget across multiple months"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"reports": {
|
"reports": {
|
||||||
"title": "Reports",
|
"title": "Reports",
|
||||||
|
|
@ -232,7 +284,16 @@
|
||||||
"byCategory": "Expenses by Category",
|
"byCategory": "Expenses by Category",
|
||||||
"overTime": "Category Over Time",
|
"overTime": "Category Over Time",
|
||||||
"trends": "Monthly Trends",
|
"trends": "Monthly Trends",
|
||||||
"export": "Export"
|
"export": "Export",
|
||||||
|
"help": {
|
||||||
|
"title": "How to use Reports",
|
||||||
|
"tips": [
|
||||||
|
"Switch between Trends, By Category, and Over Time views using the tabs",
|
||||||
|
"Use the period selector to adjust the time range for all charts",
|
||||||
|
"Monthly Trends shows your income and expenses over time",
|
||||||
|
"Category Over Time tracks how spending in each category evolves"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
|
|
@ -251,7 +312,15 @@
|
||||||
"error": "Update failed",
|
"error": "Update failed",
|
||||||
"retryButton": "Retry"
|
"retryButton": "Retry"
|
||||||
},
|
},
|
||||||
"dataSafeNotice": "Your data is safe — only the app binary is replaced, your database is not modified."
|
"dataSafeNotice": "Your data is safe — only the app binary is replaced, your database is not modified.",
|
||||||
|
"help": {
|
||||||
|
"title": "About Settings",
|
||||||
|
"tips": [
|
||||||
|
"Check for app updates and install them directly from this page",
|
||||||
|
"Your data is stored locally and is never affected by updates",
|
||||||
|
"Change the app language using the language selector in the sidebar"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,15 @@
|
||||||
"6months": "6 mois",
|
"6months": "6 mois",
|
||||||
"12months": "12 mois",
|
"12months": "12 mois",
|
||||||
"all": "Tout"
|
"all": "Tout"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"title": "Comment utiliser le tableau de bord",
|
||||||
|
"tips": [
|
||||||
|
"Utilisez le sélecteur de période (en haut à droite) pour changer la plage de dates",
|
||||||
|
"Les cartes résumées affichent votre solde, revenus et dépenses pour la période sélectionnée",
|
||||||
|
"Le graphique circulaire détaille vos dépenses par catégorie",
|
||||||
|
"Les transactions récentes sont listées en bas de page"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"import": {
|
"import": {
|
||||||
|
|
@ -145,6 +154,15 @@
|
||||||
"checkDuplicates": "Vérifier les doublons",
|
"checkDuplicates": "Vérifier les doublons",
|
||||||
"confirm": "Confirmer",
|
"confirm": "Confirmer",
|
||||||
"import": "Importer"
|
"import": "Importer"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"title": "Comment importer des relevés bancaires",
|
||||||
|
"tips": [
|
||||||
|
"Configurez votre dossier d'import, puis créez un sous-dossier par banque/source avec des fichiers CSV",
|
||||||
|
"Cliquez sur une source pour configurer le mapping des colonnes, le délimiteur et le format de date",
|
||||||
|
"Prévisualisez vos données avant l'import pour détecter les problèmes de formatage",
|
||||||
|
"La détection des doublons empêche d'importer les mêmes transactions deux fois"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"transactions": {
|
"transactions": {
|
||||||
|
|
@ -184,7 +202,16 @@
|
||||||
},
|
},
|
||||||
"autoCategorize": "Auto-catégoriser",
|
"autoCategorize": "Auto-catégoriser",
|
||||||
"autoCategorizeResult": "{{count}} transaction(s) catégorisée(s)",
|
"autoCategorizeResult": "{{count}} transaction(s) catégorisée(s)",
|
||||||
"autoCategorizeNone": "Aucune correspondance trouvée"
|
"autoCategorizeNone": "Aucune correspondance trouvée",
|
||||||
|
"help": {
|
||||||
|
"title": "Comment utiliser les Transactions",
|
||||||
|
"tips": [
|
||||||
|
"Utilisez les filtres pour rechercher par description, catégorie, source ou plage de dates",
|
||||||
|
"Cliquez sur un en-tête de colonne pour trier les transactions",
|
||||||
|
"Assignez une catégorie via le menu déroulant sur chaque ligne",
|
||||||
|
"L'auto-catégorisation utilise vos règles de mots-clés pour catégoriser en masse"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"categories": {
|
"categories": {
|
||||||
"title": "Catégories",
|
"title": "Catégories",
|
||||||
|
|
@ -207,7 +234,16 @@
|
||||||
"keywordCount": "Mots-clés",
|
"keywordCount": "Mots-clés",
|
||||||
"keywordText": "Mot-clé...",
|
"keywordText": "Mot-clé...",
|
||||||
"priority": "Priorité",
|
"priority": "Priorité",
|
||||||
"customColor": "Couleur personnalisée"
|
"customColor": "Couleur personnalisée",
|
||||||
|
"help": {
|
||||||
|
"title": "Comment gérer les Catégories",
|
||||||
|
"tips": [
|
||||||
|
"Créez des catégories et sous-catégories pour organiser vos dépenses et revenus",
|
||||||
|
"Ajoutez des mots-clés à une catégorie pour que les transactions correspondantes soient auto-catégorisées",
|
||||||
|
"Définissez une priorité sur les mots-clés pour résoudre les conflits entre catégories",
|
||||||
|
"Cliquez sur une catégorie dans l'arbre pour voir ses détails, la modifier ou gérer ses mots-clés"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"adjustments": {
|
"adjustments": {
|
||||||
"title": "Ajustements",
|
"title": "Ajustements",
|
||||||
|
|
@ -215,7 +251,15 @@
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
"amount": "Montant",
|
"amount": "Montant",
|
||||||
"recurring": "Récurrent"
|
"recurring": "Récurrent",
|
||||||
|
"help": {
|
||||||
|
"title": "Comment utiliser les Ajustements",
|
||||||
|
"tips": [
|
||||||
|
"Les ajustements permettent d'ajouter des entrées manuelles non issues de vos relevés bancaires",
|
||||||
|
"Utilisez-les pour des dépenses ou revenus prévus non encore reflétés dans vos relevés",
|
||||||
|
"Les ajustements récurrents se répètent automatiquement à chaque période"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"budget": {
|
"budget": {
|
||||||
"title": "Budget",
|
"title": "Budget",
|
||||||
|
|
@ -224,7 +268,15 @@
|
||||||
"planned": "Prévu",
|
"planned": "Prévu",
|
||||||
"actual": "Réel",
|
"actual": "Réel",
|
||||||
"difference": "Écart",
|
"difference": "Écart",
|
||||||
"template": "Modèle"
|
"template": "Modèle",
|
||||||
|
"help": {
|
||||||
|
"title": "Comment utiliser le Budget",
|
||||||
|
"tips": [
|
||||||
|
"Définissez des montants prévus par catégorie pour suivre vos objectifs de dépenses",
|
||||||
|
"Comparez le prévu et le réel pour voir où vous dépassez ou êtes en dessous du budget",
|
||||||
|
"Utilisez les modèles pour appliquer rapidement le même budget sur plusieurs mois"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"reports": {
|
"reports": {
|
||||||
"title": "Rapports",
|
"title": "Rapports",
|
||||||
|
|
@ -232,7 +284,16 @@
|
||||||
"byCategory": "Dépenses par catégorie",
|
"byCategory": "Dépenses par catégorie",
|
||||||
"overTime": "Catégories dans le temps",
|
"overTime": "Catégories dans le temps",
|
||||||
"trends": "Tendances mensuelles",
|
"trends": "Tendances mensuelles",
|
||||||
"export": "Exporter"
|
"export": "Exporter",
|
||||||
|
"help": {
|
||||||
|
"title": "Comment utiliser les Rapports",
|
||||||
|
"tips": [
|
||||||
|
"Basculez entre les vues Tendances, Par catégorie et Dans le temps via les onglets",
|
||||||
|
"Utilisez le sélecteur de période pour ajuster la plage de dates de tous les graphiques",
|
||||||
|
"Les tendances mensuelles montrent vos revenus et dépenses au fil du temps",
|
||||||
|
"Catégories dans le temps suit l'évolution des dépenses par catégorie"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Paramètres",
|
"title": "Paramètres",
|
||||||
|
|
@ -251,7 +312,15 @@
|
||||||
"error": "Erreur lors de la mise à jour",
|
"error": "Erreur lors de la mise à jour",
|
||||||
"retryButton": "Réessayer"
|
"retryButton": "Réessayer"
|
||||||
},
|
},
|
||||||
"dataSafeNotice": "Vos données sont en sécurité — seul le programme est remplacé, votre base de données n'est pas modifiée."
|
"dataSafeNotice": "Vos données sont en sécurité — seul le programme est remplacé, votre base de données n'est pas modifiée.",
|
||||||
|
"help": {
|
||||||
|
"title": "À propos des Paramètres",
|
||||||
|
"tips": [
|
||||||
|
"Vérifiez les mises à jour de l'application et installez-les directement depuis cette page",
|
||||||
|
"Vos données sont stockées localement et ne sont jamais affectées par les mises à jour",
|
||||||
|
"Changez la langue de l'application via le sélecteur de langue dans la barre latérale"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"save": "Enregistrer",
|
"save": "Enregistrer",
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { PageHelp } from "../components/shared/PageHelp";
|
||||||
|
|
||||||
export default function AdjustmentsPage() {
|
export default function AdjustmentsPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold mb-6">{t("adjustments.title")}</h1>
|
<div className="relative flex items-center gap-3 mb-6">
|
||||||
|
<h1 className="text-2xl font-bold">{t("adjustments.title")}</h1>
|
||||||
|
<PageHelp helpKey="adjustments" />
|
||||||
|
</div>
|
||||||
<div className="bg-[var(--card)] rounded-xl p-8 border border-[var(--border)] text-center text-[var(--muted-foreground)]">
|
<div className="bg-[var(--card)] rounded-xl p-8 border border-[var(--border)] text-center text-[var(--muted-foreground)]">
|
||||||
<p>{t("common.noResults")}</p>
|
<p>{t("common.noResults")}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { PageHelp } from "../components/shared/PageHelp";
|
||||||
|
|
||||||
export default function BudgetPage() {
|
export default function BudgetPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold mb-6">{t("budget.title")}</h1>
|
<div className="relative flex items-center gap-3 mb-6">
|
||||||
|
<h1 className="text-2xl font-bold">{t("budget.title")}</h1>
|
||||||
|
<PageHelp helpKey="budget" />
|
||||||
|
</div>
|
||||||
<div className="bg-[var(--card)] rounded-xl p-8 border border-[var(--border)] text-center text-[var(--muted-foreground)]">
|
<div className="bg-[var(--card)] rounded-xl p-8 border border-[var(--border)] text-center text-[var(--muted-foreground)]">
|
||||||
<p>{t("common.noResults")}</p>
|
<p>{t("common.noResults")}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Plus } from "lucide-react";
|
import { Plus } from "lucide-react";
|
||||||
|
import { PageHelp } from "../components/shared/PageHelp";
|
||||||
import { useCategories } from "../hooks/useCategories";
|
import { useCategories } from "../hooks/useCategories";
|
||||||
import CategoryTree from "../components/categories/CategoryTree";
|
import CategoryTree from "../components/categories/CategoryTree";
|
||||||
import CategoryDetailPanel from "../components/categories/CategoryDetailPanel";
|
import CategoryDetailPanel from "../components/categories/CategoryDetailPanel";
|
||||||
|
|
@ -26,8 +27,11 @@ export default function CategoriesPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center justify-between mb-6">
|
<div className="relative flex items-center justify-between mb-6">
|
||||||
<h1 className="text-2xl font-bold">{t("categories.title")}</h1>
|
<div className="flex items-center gap-3">
|
||||||
|
<h1 className="text-2xl font-bold">{t("categories.title")}</h1>
|
||||||
|
<PageHelp helpKey="categories" />
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={startCreating}
|
onClick={startCreating}
|
||||||
className="flex items-center gap-2 px-4 py-2 rounded-lg bg-[var(--primary)] text-white text-sm font-medium hover:opacity-90"
|
className="flex items-center gap-2 px-4 py-2 rounded-lg bg-[var(--primary)] text-white text-sm font-medium hover:opacity-90"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Wallet, TrendingUp, TrendingDown } from "lucide-react";
|
import { Wallet, TrendingUp, TrendingDown } from "lucide-react";
|
||||||
import { useDashboard } from "../hooks/useDashboard";
|
import { useDashboard } from "../hooks/useDashboard";
|
||||||
|
import { PageHelp } from "../components/shared/PageHelp";
|
||||||
import PeriodSelector from "../components/dashboard/PeriodSelector";
|
import PeriodSelector from "../components/dashboard/PeriodSelector";
|
||||||
import CategoryPieChart from "../components/dashboard/CategoryPieChart";
|
import CategoryPieChart from "../components/dashboard/CategoryPieChart";
|
||||||
import RecentTransactionsList from "../components/dashboard/RecentTransactionsList";
|
import RecentTransactionsList from "../components/dashboard/RecentTransactionsList";
|
||||||
|
|
@ -43,8 +44,11 @@ export default function DashboardPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={isLoading ? "opacity-50 pointer-events-none" : ""}>
|
<div className={isLoading ? "opacity-50 pointer-events-none" : ""}>
|
||||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
|
<div className="relative flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
|
||||||
<h1 className="text-2xl font-bold">{t("dashboard.title")}</h1>
|
<div className="flex items-center gap-3">
|
||||||
|
<h1 className="text-2xl font-bold">{t("dashboard.title")}</h1>
|
||||||
|
<PageHelp helpKey="dashboard" />
|
||||||
|
</div>
|
||||||
<PeriodSelector value={period} onChange={setPeriod} />
|
<PeriodSelector value={period} onChange={setPeriod} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import ImportReportPanel from "../components/import/ImportReportPanel";
|
||||||
import WizardNavigation from "../components/import/WizardNavigation";
|
import WizardNavigation from "../components/import/WizardNavigation";
|
||||||
import ImportHistoryPanel from "../components/import/ImportHistoryPanel";
|
import ImportHistoryPanel from "../components/import/ImportHistoryPanel";
|
||||||
import { AlertCircle } from "lucide-react";
|
import { AlertCircle } from "lucide-react";
|
||||||
|
import { PageHelp } from "../components/shared/PageHelp";
|
||||||
|
|
||||||
export default function ImportPage() {
|
export default function ImportPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
@ -33,7 +34,10 @@ export default function ImportPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold mb-6">{t("import.title")}</h1>
|
<div className="relative flex items-center gap-3 mb-6">
|
||||||
|
<h1 className="text-2xl font-bold">{t("import.title")}</h1>
|
||||||
|
<PageHelp helpKey="import" />
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Error banner */}
|
{/* Error banner */}
|
||||||
{state.error && (
|
{state.error && (
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useReports } from "../hooks/useReports";
|
import { useReports } from "../hooks/useReports";
|
||||||
|
import { PageHelp } from "../components/shared/PageHelp";
|
||||||
import type { ReportTab } from "../shared/types";
|
import type { ReportTab } from "../shared/types";
|
||||||
import PeriodSelector from "../components/dashboard/PeriodSelector";
|
import PeriodSelector from "../components/dashboard/PeriodSelector";
|
||||||
import MonthlyTrendsChart from "../components/reports/MonthlyTrendsChart";
|
import MonthlyTrendsChart from "../components/reports/MonthlyTrendsChart";
|
||||||
|
|
@ -14,8 +15,11 @@ export default function ReportsPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={state.isLoading ? "opacity-50 pointer-events-none" : ""}>
|
<div className={state.isLoading ? "opacity-50 pointer-events-none" : ""}>
|
||||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
|
<div className="relative flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
|
||||||
<h1 className="text-2xl font-bold">{t("reports.title")}</h1>
|
<div className="flex items-center gap-3">
|
||||||
|
<h1 className="text-2xl font-bold">{t("reports.title")}</h1>
|
||||||
|
<PageHelp helpKey="reports" />
|
||||||
|
</div>
|
||||||
<PeriodSelector value={state.period} onChange={setPeriod} />
|
<PeriodSelector value={state.period} onChange={setPeriod} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import {
|
||||||
import { getVersion } from "@tauri-apps/api/app";
|
import { getVersion } from "@tauri-apps/api/app";
|
||||||
import { useUpdater } from "../hooks/useUpdater";
|
import { useUpdater } from "../hooks/useUpdater";
|
||||||
import { APP_NAME } from "../shared/constants";
|
import { APP_NAME } from "../shared/constants";
|
||||||
|
import { PageHelp } from "../components/shared/PageHelp";
|
||||||
|
|
||||||
export default function SettingsPage() {
|
export default function SettingsPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
@ -31,7 +32,10 @@ export default function SettingsPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 max-w-2xl mx-auto space-y-6">
|
<div className="p-6 max-w-2xl mx-auto space-y-6">
|
||||||
<h1 className="text-2xl font-bold">{t("settings.title")}</h1>
|
<div className="relative flex items-center gap-3">
|
||||||
|
<h1 className="text-2xl font-bold">{t("settings.title")}</h1>
|
||||||
|
<PageHelp helpKey="settings" />
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* About card */}
|
{/* About card */}
|
||||||
<div className="bg-[var(--card)] border border-[var(--border)] rounded-xl p-6">
|
<div className="bg-[var(--card)] border border-[var(--border)] rounded-xl p-6">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Wand2 } from "lucide-react";
|
import { Wand2 } from "lucide-react";
|
||||||
|
import { PageHelp } from "../components/shared/PageHelp";
|
||||||
import { useTransactions } from "../hooks/useTransactions";
|
import { useTransactions } from "../hooks/useTransactions";
|
||||||
import TransactionFilterBar from "../components/transactions/TransactionFilterBar";
|
import TransactionFilterBar from "../components/transactions/TransactionFilterBar";
|
||||||
import TransactionSummaryBar from "../components/transactions/TransactionSummaryBar";
|
import TransactionSummaryBar from "../components/transactions/TransactionSummaryBar";
|
||||||
|
|
@ -26,8 +27,9 @@ export default function TransactionsPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-3 mb-6">
|
<div className="relative flex items-center gap-3 mb-6">
|
||||||
<h1 className="text-2xl font-bold">{t("transactions.title")}</h1>
|
<h1 className="text-2xl font-bold">{t("transactions.title")}</h1>
|
||||||
|
<PageHelp helpKey="transactions" />
|
||||||
<button
|
<button
|
||||||
onClick={handleAutoCategorize}
|
onClick={handleAutoCategorize}
|
||||||
disabled={state.isAutoCategorizing}
|
disabled={state.isAutoCategorizing}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue