Checkpoint: isSubscription appliqué lors des imports. Seuil de confiance persisté en base (champ learningConfidenceThreshold dans userSettings). LearningSettings.tsx charge et sauvegarde le seuil via settings.get/upsert.

This commit is contained in:
Manus
2026-04-12 15:27:19 -04:00
parent 95aee693ea
commit 132f8ccec2
6 changed files with 1752 additions and 9 deletions

View File

@@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, useEffect } from "react";
import DashboardLayout from "@/components/DashboardLayout";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
@@ -34,14 +34,31 @@ const FIELD_COLORS: Record<string, string> = {
isSubscription: "bg-orange-100 text-orange-800",
};
const DEFAULT_CONFIDENCE_THRESHOLD = 2;
const DEFAULT_THRESHOLD = 2;
export default function LearningSettings() {
const utils = trpc.useUtils();
const { data: learnings, isLoading } = trpc.learnings.list.useQuery();
const [confidenceThreshold, setConfidenceThreshold] = useState(DEFAULT_CONFIDENCE_THRESHOLD);
const { data: settings, isLoading: settingsLoading } = trpc.settings.get.useQuery();
const [confidenceThreshold, setConfidenceThreshold] = useState(DEFAULT_THRESHOLD);
const [editingThreshold, setEditingThreshold] = useState(false);
const [thresholdInput, setThresholdInput] = useState(String(DEFAULT_CONFIDENCE_THRESHOLD));
const [thresholdInput, setThresholdInput] = useState(String(DEFAULT_THRESHOLD));
// Sync threshold from DB when settings load
useEffect(() => {
if (settings?.learningConfidenceThreshold != null) {
setConfidenceThreshold(settings.learningConfidenceThreshold);
setThresholdInput(String(settings.learningConfidenceThreshold));
}
}, [settings?.learningConfidenceThreshold]);
const upsertSettingsMutation = trpc.settings.upsert.useMutation({
onSuccess: () => {
utils.settings.get.invalidate();
},
onError: () => toast.error("Erreur lors de la sauvegarde du seuil"),
});
const deleteMutation = trpc.learnings.delete.useMutation({
onSuccess: () => {
@@ -97,6 +114,7 @@ export default function LearningSettings() {
}
setConfidenceThreshold(val);
setEditingThreshold(false);
upsertSettingsMutation.mutate({ learningConfidenceThreshold: val });
toast.success(`Seuil de confiance mis à jour : ${val} application(s)`);
};
@@ -184,10 +202,15 @@ export default function LearningSettings() {
<CardDescription>
Un apprentissage est marqué <strong>Confirmé</strong> quand il a é appliqué au moins{" "}
<strong>{confidenceThreshold} fois</strong>. En dessous, il est <strong>En observation</strong>.
Ce réglage est sauvegardé et partagé entre toutes vos sessions.
</CardDescription>
</CardHeader>
<CardContent>
{editingThreshold ? (
{settingsLoading ? (
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<RefreshCw className="w-4 h-4 animate-spin" /> Chargement...
</div>
) : editingThreshold ? (
<div className="flex items-center gap-3">
<Label htmlFor="threshold" className="text-sm whitespace-nowrap">
Nombre minimum d'applications :
@@ -201,7 +224,9 @@ export default function LearningSettings() {
onChange={(e) => setThresholdInput(e.target.value)}
className="w-24"
/>
<Button size="sm" onClick={handleSaveThreshold}>Appliquer</Button>
<Button size="sm" onClick={handleSaveThreshold} disabled={upsertSettingsMutation.isPending}>
{upsertSettingsMutation.isPending ? <RefreshCw className="w-4 h-4 animate-spin" /> : "Appliquer"}
</Button>
<Button size="sm" variant="ghost" onClick={() => { setEditingThreshold(false); setThresholdInput(String(confidenceThreshold)); }}>
Annuler
</Button>
@@ -229,8 +254,8 @@ export default function LearningSettings() {
</CardHeader>
<CardContent className="text-sm text-muted-foreground space-y-1">
<p>
Quand vous modifiez manuellement le <strong>type d'achat</strong>, le <strong>service concerné</strong> ou
la <strong>ventilation comptable</strong> d'une facture (dans le détail ou dans la liste BAP), le système mémorise cette
Quand vous modifiez manuellement le <strong>type d'achat</strong>, le <strong>service concerné</strong>,
la <strong>ventilation comptable</strong> ou le champ <strong>Abonnement</strong> d'une facture, le système mémorise cette
correction pour ce fournisseur.
</p>
<p>
@@ -256,7 +281,7 @@ export default function LearningSettings() {
<Brain className="w-12 h-12 text-gray-300 mb-4" />
<h3 className="text-lg font-semibold text-gray-500">Aucun apprentissage enregistré</h3>
<p className="text-sm text-muted-foreground mt-2 max-w-sm">
Modifiez manuellement les champs d'une facture (type d'achat, service, ventilation) pour que le système
Modifiez manuellement les champs d'une facture (type d'achat, service, ventilation, abonnement) pour que le système
commence à apprendre.
</p>
</CardContent>