From a2fdad46d41cfed6cda42e7ce28749916c77e77c Mon Sep 17 00:00:00 2001 From: syoul Date: Mon, 23 Mar 2026 23:17:10 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20bouton=20Personnaliser=20pour=20p=C3=A9?= =?UTF-8?q?riode=20personnalis=C3=A9e=20(1=E2=80=93365=20jours)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clic sur "Personnaliser" → champ inline focusé, pré-rempli si déjà custom. Valider avec Entrée ou blur, annuler avec Échap. Plage 1–365 jours. Le bouton affiche la valeur courante (ex. "14 jours") quand une période custom est active, et reprend la surbrillance dorée comme les autres boutons. Co-Authored-By: Claude Sonnet 4.6 --- src/components/PeriodSelector.tsx | 71 +++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/src/components/PeriodSelector.tsx b/src/components/PeriodSelector.tsx index f043cc0..91169cb 100644 --- a/src/components/PeriodSelector.tsx +++ b/src/components/PeriodSelector.tsx @@ -1,3 +1,5 @@ +import { useState, useRef, useEffect } from 'react'; + interface PeriodSelectorProps { value: number; onChange: (days: number) => void; @@ -11,16 +13,40 @@ const PERIODS = [ { label: '30 jours', days: 30 }, ]; +const PRESET_DAYS = new Set([1, 7, 30]); + export function PeriodSelector({ value, onChange, animationActive, onAnimate }: PeriodSelectorProps) { + const [customOpen, setCustomOpen] = useState(false); + const [inputVal, setInputVal] = useState(''); + const inputRef = useRef(null); + + // Ouvre le champ custom avec la valeur courante pré-remplie + const openCustom = () => { + setInputVal(PRESET_DAYS.has(value) ? '' : String(value)); + setCustomOpen(true); + }; + + useEffect(() => { + if (customOpen) inputRef.current?.focus(); + }, [customOpen]); + + const commit = () => { + const n = parseInt(inputVal, 10); + if (n >= 1 && n <= 365) onChange(n); + setCustomOpen(false); + }; + + const isCustomActive = !PRESET_DAYS.has(value); + return ( -
+
{PERIODS.map(({ label, days }) => ( ))} +
+ + {/* Bouton Personnaliser + champ inline */} + {customOpen ? ( +
+ setInputVal(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') commit(); + if (e.key === 'Escape') setCustomOpen(false); + }} + onBlur={commit} + placeholder="jours" + className="w-16 px-2 py-1 text-sm bg-[#1a1b23] border border-[#d4a843] rounded-md text-[#d4a843] text-center focus:outline-none tabular-nums [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none" + /> + j +
+ ) : ( + + )} + +
+