Checkpoint: Ajout d’un filtre par action dans la liste des automatismes, avec catégories Type d’achat, Service, Ventilation, Abonnement, Abonnement Oui et Abonnement Non. Tests, TypeScript, build et rendu visuel validés en sandbox.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import DashboardLayout from "@/components/DashboardLayout";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
@@ -33,6 +33,11 @@ import {
|
||||
} from "@/components/ui/table";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { trpc } from "@/lib/trpc";
|
||||
import {
|
||||
AUTOMATION_ACTION_FILTERS,
|
||||
type AutomationActionFilter,
|
||||
matchesAutomationActionFilter,
|
||||
} from "@shared/automationActions";
|
||||
import { toast } from "sonner";
|
||||
import { Plus, Edit, Trash2, Power, PowerOff, Copy } from "lucide-react";
|
||||
|
||||
@@ -63,6 +68,7 @@ export default function AutomationRules() {
|
||||
const [wizardStep, setWizardStep] = useState(1);
|
||||
const [testResultsOpen, setTestResultsOpen] = useState(false);
|
||||
const [testResults, setTestResults] = useState<any>(null);
|
||||
const [actionFilter, setActionFilter] = useState<AutomationActionFilter>("all");
|
||||
|
||||
// Form state
|
||||
const [ruleName, setRuleName] = useState("");
|
||||
@@ -320,6 +326,11 @@ export default function AutomationRules() {
|
||||
{ value: "<=", label: "inférieur ou égal à" },
|
||||
];
|
||||
|
||||
const filteredRules = useMemo(
|
||||
() => rules.filter((rule) => matchesAutomationActionFilter(rule.actions, actionFilter)),
|
||||
[rules, actionFilter],
|
||||
);
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<div className="space-y-6">
|
||||
@@ -348,12 +359,36 @@ export default function AutomationRules() {
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="mb-4 flex flex-wrap items-center gap-3 rounded-lg border border-slate-200 bg-slate-50 p-3">
|
||||
<Label htmlFor="automation-action-filter" className="font-medium text-slate-700">
|
||||
Filtrer par action
|
||||
</Label>
|
||||
<Select value={actionFilter} onValueChange={(value) => setActionFilter(value as AutomationActionFilter)}>
|
||||
<SelectTrigger id="automation-action-filter" className="w-[260px] bg-white">
|
||||
<SelectValue placeholder="Toutes les actions" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{AUTOMATION_ACTION_FILTERS.map((filter) => (
|
||||
<SelectItem key={filter.value} value={filter.value}>
|
||||
{filter.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span className="text-sm text-slate-500">
|
||||
{filteredRules.length} règle{filteredRules.length > 1 ? "s" : ""} affichée{filteredRules.length > 1 ? "s" : ""}
|
||||
</span>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<div className="text-center py-8 text-gray-500">Chargement...</div>
|
||||
) : rules.length === 0 ? (
|
||||
<div className="text-center py-8 text-gray-500">
|
||||
Aucune règle d'automatisme configurée
|
||||
</div>
|
||||
) : filteredRules.length === 0 ? (
|
||||
<div className="text-center py-8 text-gray-500">
|
||||
Aucune règle ne correspond à cette action
|
||||
</div>
|
||||
) : (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
@@ -366,7 +401,7 @@ export default function AutomationRules() {
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{rules.map((rule) => {
|
||||
{filteredRules.map((rule) => {
|
||||
let conditionsDisplay = "";
|
||||
let actionsDisplay = "";
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user