Files
fintrack/app/settings/page.tsx

233 lines
9.0 KiB
TypeScript

"use client"
import { useState } from "react"
import { Sidebar } from "@/components/dashboard/sidebar"
import { useBankingData } from "@/lib/hooks"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Download, Trash2, Upload, RefreshCw, Database, FileJson, Tags } from "lucide-react"
import type { BankingData } from "@/lib/types"
export default function SettingsPage() {
const { data, isLoading, refresh, update } = useBankingData()
const [importing, setImporting] = useState(false)
if (isLoading || !data) {
return (
<div className="flex h-screen">
<Sidebar />
<main className="flex-1 flex items-center justify-center">
<RefreshCw className="w-8 h-8 animate-spin text-muted-foreground" />
</main>
</div>
)
}
const exportData = () => {
const dataStr = JSON.stringify(data, null, 2)
const blob = new Blob([dataStr], { type: "application/json" })
const url = URL.createObjectURL(blob)
const a = document.createElement("a")
a.href = url
a.download = `fintrack-backup-${new Date().toISOString().split("T")[0]}.json`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
}
const importData = () => {
const input = document.createElement("input")
input.type = "file"
input.accept = ".json"
input.onchange = async (e) => {
const file = (e.target as HTMLInputElement).files?.[0]
if (!file) return
setImporting(true)
try {
const content = await file.text()
const importedData = JSON.parse(content) as BankingData
// Validate structure
if (!importedData.accounts || !importedData.transactions || !importedData.categories || !importedData.folders) {
alert("Format de fichier invalide")
return
}
update(importedData)
alert("Données importées avec succès")
} catch (error) {
alert("Erreur lors de l'import")
} finally {
setImporting(false)
}
}
input.click()
}
const resetData = () => {
localStorage.removeItem("banking-app-data")
window.location.reload()
}
const clearAllCategories = async () => {
try {
const response = await fetch("/api/banking/transactions/clear-categories", {
method: "POST",
})
if (!response.ok) throw new Error("Erreur")
refresh()
alert("Catégories supprimées de toutes les opérations")
} catch (error) {
console.error(error)
alert("Erreur lors de la suppression des catégories")
}
}
const categorizedCount = data.transactions.filter((t) => t.categoryId).length
return (
<div className="flex h-screen bg-background">
<Sidebar />
<main className="flex-1 overflow-auto">
<div className="p-6 space-y-6 max-w-2xl">
<div>
<h1 className="text-2xl font-bold text-foreground">Paramètres</h1>
<p className="text-muted-foreground">Gérez vos données et préférences</p>
</div>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Database className="w-5 h-5" />
Données
</CardTitle>
<CardDescription>Exportez ou importez vos données pour les sauvegarder ou les transférer</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between p-4 bg-muted rounded-lg">
<div>
<p className="font-medium">Statistiques</p>
<p className="text-sm text-muted-foreground">
{data.accounts.length} comptes, {data.transactions.length} transactions, {data.categories.length}{" "}
catégories
</p>
</div>
</div>
<div className="flex gap-2">
<Button onClick={exportData} variant="outline" className="flex-1 bg-transparent">
<Download className="w-4 h-4 mr-2" />
Exporter (JSON)
</Button>
<Button onClick={importData} variant="outline" className="flex-1 bg-transparent" disabled={importing}>
<Upload className="w-4 h-4 mr-2" />
{importing ? "Import..." : "Importer"}
</Button>
</div>
</CardContent>
</Card>
<Card className="border-red-200">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-red-600">
<Trash2 className="w-5 h-5" />
Zone dangereuse
</CardTitle>
<CardDescription>Actions irréversibles - procédez avec prudence</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
{/* Supprimer catégories des opérations */}
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="outline" className="w-full justify-start border-orange-300 text-orange-700 hover:bg-orange-50">
<Tags className="w-4 h-4 mr-2" />
Supprimer les catégories des opérations
<span className="ml-auto text-xs text-muted-foreground">
{categorizedCount} opération{categorizedCount > 1 ? "s" : ""} catégorisée{categorizedCount > 1 ? "s" : ""}
</span>
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Supprimer toutes les catégories ?</AlertDialogTitle>
<AlertDialogDescription>
Cette action va retirer la catégorie de {categorizedCount} opération{categorizedCount > 1 ? "s" : ""}.
Les catégories elles-mêmes ne seront pas supprimées, seulement leur affectation aux opérations.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Annuler</AlertDialogCancel>
<AlertDialogAction onClick={clearAllCategories} className="bg-orange-600 hover:bg-orange-700">
Supprimer les affectations
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
{/* Réinitialiser toutes les données */}
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive" className="w-full justify-start">
<Trash2 className="w-4 h-4 mr-2" />
Réinitialiser toutes les données
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Êtes-vous sûr ?</AlertDialogTitle>
<AlertDialogDescription>
Cette action supprimera définitivement tous vos comptes, transactions, catégories et dossiers.
Cette action est irréversible.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Annuler</AlertDialogCancel>
<AlertDialogAction onClick={resetData} className="bg-red-600 hover:bg-red-700">
Supprimer tout
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<FileJson className="w-5 h-5" />
Format OFX
</CardTitle>
<CardDescription>Informations sur l'import de fichiers</CardDescription>
</CardHeader>
<CardContent>
<div className="prose prose-sm text-muted-foreground">
<p>
L'application accepte les fichiers au format OFX (Open Financial Exchange) ou QFX. Ces fichiers sont
généralement disponibles depuis l'espace client de votre banque.
</p>
<p className="mt-2">
Lors de l'import, les transactions sont automatiquement catégorisées selon les mots-clés définis. Les
doublons sont détectés et ignorés automatiquement.
</p>
</div>
</CardContent>
</Card>
</div>
</main>
</div>
)
}