Checkpoint: Ajout des modes de fréquence quotidien, hebdomadaire (avec sélecteur de jour Lun-Dim), mensuel (avec choix du jour 1-28) et intervalle (1h à 24h). Le cron est rechargé immédiatement après sauvegarde pour tous les paramètres de planification.

This commit is contained in:
Manus
2026-06-29 17:07:28 -04:00
parent 1f1a479029
commit cffb3d4201
5 changed files with 120 additions and 41 deletions

View File

@@ -1,4 +1,4 @@
{
"version": "3967f6c2",
"timestamp": 1782655834971
"version": "6c88c7af",
"timestamp": 1782767248272
}

View File

@@ -220,8 +220,10 @@ export default function SettingsPage() {
sharepoint_token: "",
auth_mode: "local",
import_time: "06:00",
fetch_mode: "scheduled",
fetch_mode: "daily",
fetch_interval_minutes: "1440",
fetch_week_day: "1",
fetch_month_day: "1",
});
useEffect(() => {
@@ -465,57 +467,106 @@ export default function SettingsPage() {
<CardDescription>Configurez la fréquence et l'heure de déclenchement des mises à jour automatiques (import Excel + lecture RSS).</CardDescription>
</CardHeader>
<CardContent className="space-y-5">
{/* Mode */}
{/* Fréquence */}
<div className="space-y-2">
<Label className="text-sm font-medium">Mode de planification</Label>
<div className="grid grid-cols-2 gap-3 max-w-md">
{(["scheduled", "interval"] as const).map((mode) => (
<Label className="text-sm font-medium">Fréquence de mise à jour</Label>
<div className="grid grid-cols-2 gap-3 max-w-lg">
{([
{ value: "daily", label: "Quotidienne", desc: "Chaque jour à l'heure choisie" },
{ value: "weekly", label: "Hebdomadaire", desc: "Un jour précis chaque semaine" },
{ value: "monthly", label: "Mensuelle", desc: "Un jour précis chaque mois" },
{ value: "interval", label: "Intervalle", desc: "Toutes les N heures" },
] as const).map((opt) => (
<button
key={mode}
key={opt.value}
type="button"
onClick={() => set("fetch_mode", mode)}
onClick={() => set("fetch_mode", opt.value)}
className={cn(
"flex items-center gap-2 p-3 rounded-lg border-2 text-left transition-all text-sm",
(form.fetch_mode || "scheduled") === mode
(form.fetch_mode || "daily") === opt.value
? "border-primary bg-primary/5"
: "border-border hover:border-primary/40"
)}
>
<Clock className={cn("h-4 w-4", (form.fetch_mode || "scheduled") === mode ? "text-primary" : "text-muted-foreground")} />
<Clock className={cn("h-4 w-4 shrink-0", (form.fetch_mode || "daily") === opt.value ? "text-primary" : "text-muted-foreground")} />
<div>
<p className="font-medium">{mode === "scheduled" ? "Heure fixe" : "Intervalle"}</p>
<p className="text-xs text-muted-foreground">{mode === "scheduled" ? "Chaque jour à une heure précise" : "Toutes les N heures"}</p>
<p className="font-medium">{opt.label}</p>
<p className="text-xs text-muted-foreground">{opt.desc}</p>
</div>
</button>
))}
</div>
</div>
{/* Heure fixe */}
{(form.fetch_mode || "scheduled") === "scheduled" && (
{/* Heure (tous les modes sauf intervalle) */}
{(form.fetch_mode || "daily") !== "interval" && (
<div className="space-y-2 max-w-xs">
<Label>Heure d'import quotidien</Label>
<Label>Heure de déclenchement</Label>
<Input
type="time"
value={form.import_time || "06:00"}
onChange={(e) => set("import_time", e.target.value)}
/>
<p className="text-xs text-muted-foreground">
Prochain import : demain à {form.import_time || "06:00"}
</p>
</div>
)}
{/* Jour de la semaine (hebdomadaire) */}
{(form.fetch_mode || "daily") === "weekly" && (
<div className="space-y-2">
<Label className="text-sm font-medium">Jour de la semaine</Label>
<div className="flex flex-wrap gap-2">
{[
{ label: "Lun", value: "1" },
{ label: "Mar", value: "2" },
{ label: "Mer", value: "3" },
{ label: "Jeu", value: "4" },
{ label: "Ven", value: "5" },
{ label: "Sam", value: "6" },
{ label: "Dim", value: "0" },
].map((d) => (
<button
key={d.value}
type="button"
onClick={() => set("fetch_week_day", d.value)}
className={cn(
"w-12 py-2 rounded-lg border-2 text-sm font-medium transition-all",
(form.fetch_week_day || "1") === d.value
? "border-primary bg-primary/5 text-primary"
: "border-border hover:border-primary/40 text-foreground"
)}
>
{d.label}
</button>
))}
</div>
</div>
)}
{/* Jour du mois (mensuel) */}
{(form.fetch_mode || "daily") === "monthly" && (
<div className="space-y-2 max-w-xs">
<Label>Jour du mois (128)</Label>
<Input
type="number"
min={1}
max={28}
value={form.fetch_month_day || "1"}
onChange={(e) => set("fetch_month_day", e.target.value)}
/>
<p className="text-xs text-muted-foreground">Maximum 28 pour garantir l'exécution tous les mois</p>
</div>
)}
{/* Intervalle */}
{(form.fetch_mode || "scheduled") === "interval" && (
<div className="space-y-2 max-w-xs">
<Label>Fréquence de mise à jour</Label>
<div className="grid grid-cols-3 gap-2">
{(form.fetch_mode || "daily") === "interval" && (
<div className="space-y-2">
<Label className="text-sm font-medium">Intervalle de répétition</Label>
<div className="flex flex-wrap gap-2">
{[
{ label: "1h", value: "60" },
{ label: "2h", value: "120" },
{ label: "4h", value: "240" },
{ label: "6h", value: "360" },
{ label: "1h", value: "60" },
{ label: "2h", value: "120" },
{ label: "4h", value: "240" },
{ label: "6h", value: "360" },
{ label: "12h", value: "720" },
{ label: "24h", value: "1440" },
].map((opt) => (
@@ -524,7 +575,7 @@ export default function SettingsPage() {
type="button"
onClick={() => set("fetch_interval_minutes", opt.value)}
className={cn(
"py-2 px-3 rounded-lg border-2 text-sm font-medium transition-all",
"w-14 py-2 rounded-lg border-2 text-sm font-medium transition-all",
(form.fetch_interval_minutes || "1440") === opt.value
? "border-primary bg-primary/5 text-primary"
: "border-border hover:border-primary/40 text-foreground"
@@ -535,7 +586,9 @@ export default function SettingsPage() {
))}
</div>
<p className="text-xs text-muted-foreground">
Import toutes les {(form.fetch_interval_minutes || "1440") === "60" ? "heure" : `${parseInt(form.fetch_interval_minutes || "1440") / 60} heures`}
Import toutes les {parseInt(form.fetch_interval_minutes || "1440") >= 60
? `${parseInt(form.fetch_interval_minutes || "1440") / 60}h`
: `${form.fetch_interval_minutes || "1440"} min`}
</p>
</div>
)}