Unify category autocomplete fields
All checks were successful
Deploy Sokko G / deploy (push) Successful in 17s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 17s
This commit is contained in:
parent
e3d823d0b1
commit
055fb78d60
21 changed files with 739 additions and 168 deletions
|
|
@ -104,12 +104,24 @@ export function RngSimulatorModule({ toolboxId, moduleId, context, textExchangeO
|
|||
const [occurrenceDrafts, setOccurrenceDrafts] = useState({ perHour: null, perDay: null, perMonth: null });
|
||||
const rateDraft = useDraftForm({ label: "", rate: RNG_SIMULATOR_DEFAULT_RATE });
|
||||
const activeRate = data.rates.find((rate) => rate.id === data.activeRateId) || data.rates[0] || null;
|
||||
const summary = useMemo(() => activeRate ? calculateRngSummary({ rate: activeRate.rate, ...data.settings }) : null, [activeRate, data.settings]);
|
||||
const summary = useMemo(() => activeRate ? calculateRngSummary({
|
||||
rate: activeRate.rate,
|
||||
multiplier: activeRate.multiplier,
|
||||
simulationDraws: data.settings.simulationDraws,
|
||||
perHour: activeRate.perHour,
|
||||
perDay: activeRate.perDay,
|
||||
perMonth: activeRate.perMonth
|
||||
}) : null, [activeRate, data.settings.simulationDraws]);
|
||||
|
||||
useEffect(() => {
|
||||
setHistory(readSimulationHistory(historyStorageKey));
|
||||
}, [historyStorageKey]);
|
||||
|
||||
useEffect(() => {
|
||||
setMultiplierDraft(null);
|
||||
setOccurrenceDrafts({ perHour: null, perDay: null, perMonth: null });
|
||||
}, [activeRate?.id]);
|
||||
|
||||
function save(nextData) {
|
||||
context.setModuleData(toolboxId, moduleId, nextData, "rngSimulator");
|
||||
}
|
||||
|
|
@ -118,21 +130,28 @@ export function RngSimulatorModule({ toolboxId, moduleId, context, textExchangeO
|
|||
const settings = { ...data.settings };
|
||||
if (field === "simulationDraws") {
|
||||
settings[field] = clampInteger(value, RNG_SIMULATOR_LIMITS.simulationDrawsMin, RNG_SIMULATOR_LIMITS.simulationDrawsMax, data.settings.simulationDraws);
|
||||
} else if (field === "multiplier") {
|
||||
settings[field] = clampDecimal(value, RNG_SIMULATOR_LIMITS.multiplierMin, RNG_SIMULATOR_LIMITS.multiplierMax, 0);
|
||||
} else {
|
||||
settings[field] = clampDecimal(value, RNG_SIMULATOR_LIMITS.occurrenceRateMin, RNG_SIMULATOR_LIMITS.occurrenceRateMax, data.settings[field]);
|
||||
}
|
||||
save({ ...data, settings });
|
||||
}
|
||||
|
||||
function updateActiveRateSettings(field, value) {
|
||||
if (!activeRate) return;
|
||||
const nextValue = field === "multiplier"
|
||||
? clampDecimal(value, RNG_SIMULATOR_LIMITS.multiplierMin, RNG_SIMULATOR_LIMITS.multiplierMax, 0)
|
||||
: clampDecimal(value, RNG_SIMULATOR_LIMITS.occurrenceRateMin, RNG_SIMULATOR_LIMITS.occurrenceRateMax, activeRate[field]);
|
||||
save({
|
||||
...data,
|
||||
rates: data.rates.map((rate) => rate.id === activeRate.id ? { ...rate, [field]: nextValue } : rate)
|
||||
});
|
||||
}
|
||||
|
||||
function updateMultiplier(value) {
|
||||
setMultiplierDraft(value);
|
||||
if (String(value).trim() === "") {
|
||||
updateSettings("multiplier", 0);
|
||||
updateActiveRateSettings("multiplier", 0);
|
||||
return;
|
||||
}
|
||||
updateSettings("multiplier", value);
|
||||
updateActiveRateSettings("multiplier", value);
|
||||
}
|
||||
|
||||
function blurMultiplier() {
|
||||
|
|
@ -141,7 +160,7 @@ export function RngSimulatorModule({ toolboxId, moduleId, context, textExchangeO
|
|||
const parsed = Number(raw.replace(",", "."));
|
||||
if (!raw || !Number.isFinite(parsed)) {
|
||||
setMultiplierDraft(null);
|
||||
updateSettings("multiplier", 0);
|
||||
updateActiveRateSettings("multiplier", 0);
|
||||
return;
|
||||
}
|
||||
setMultiplierDraft(null);
|
||||
|
|
@ -149,16 +168,16 @@ export function RngSimulatorModule({ toolboxId, moduleId, context, textExchangeO
|
|||
|
||||
function clearMultiplier() {
|
||||
setMultiplierDraft(null);
|
||||
updateSettings("multiplier", 0);
|
||||
updateActiveRateSettings("multiplier", 0);
|
||||
}
|
||||
|
||||
function updateOccurrence(field, value) {
|
||||
setOccurrenceDrafts((drafts) => ({ ...drafts, [field]: value }));
|
||||
if (String(value).trim() === "") {
|
||||
updateSettings(field, 0);
|
||||
updateActiveRateSettings(field, 0);
|
||||
return;
|
||||
}
|
||||
updateSettings(field, value);
|
||||
updateActiveRateSettings(field, value);
|
||||
}
|
||||
|
||||
function blurOccurrence(field) {
|
||||
|
|
@ -166,7 +185,7 @@ export function RngSimulatorModule({ toolboxId, moduleId, context, textExchangeO
|
|||
if (value === null) return;
|
||||
const raw = value.trim();
|
||||
const parsed = Number(raw.replace(",", "."));
|
||||
if (!raw || !Number.isFinite(parsed)) updateSettings(field, 0);
|
||||
if (!raw || !Number.isFinite(parsed)) updateActiveRateSettings(field, 0);
|
||||
setOccurrenceDrafts((drafts) => ({ ...drafts, [field]: null }));
|
||||
}
|
||||
|
||||
|
|
@ -207,12 +226,12 @@ export function RngSimulatorModule({ toolboxId, moduleId, context, textExchangeO
|
|||
|
||||
function runSimulation() {
|
||||
if (!activeRate) return;
|
||||
const result = simulateRngDraws(activeRate.rate, data.settings.simulationDraws, Math.random, data.settings.multiplier);
|
||||
const result = simulateRngDraws(activeRate.rate, data.settings.simulationDraws, Math.random, activeRate.multiplier);
|
||||
const entry = {
|
||||
id: context.uid("rng"),
|
||||
label: activeRate.label,
|
||||
rate: activeRate.rate,
|
||||
multiplier: data.settings.multiplier,
|
||||
multiplier: activeRate.multiplier,
|
||||
...result
|
||||
};
|
||||
const nextHistory = addRngSimulationHistory(history, entry);
|
||||
|
|
@ -302,7 +321,7 @@ export function RngSimulatorModule({ toolboxId, moduleId, context, textExchangeO
|
|||
<div className="rng-simulator-field rng-simulator-multiplier-field">
|
||||
<span>{textContent.multiplierLabel || "Multiplicateur"}</span>
|
||||
<div className="rng-simulator-percent-input">
|
||||
<input className="nds-input" data-size="sm" type="text" inputMode="decimal" value={multiplierDraft ?? String(data.settings.multiplier ?? 0)} onChange={(event) => updateMultiplier(event.target.value)} onBlur={blurMultiplier} aria-label={textContent.multiplierLabel || "Multiplicateur"} />
|
||||
<input className="nds-input" data-size="sm" type="text" inputMode="decimal" value={multiplierDraft ?? String(activeRate.multiplier ?? 0)} onChange={(event) => updateMultiplier(event.target.value)} onBlur={blurMultiplier} aria-label={textContent.multiplierLabel || "Multiplicateur"} />
|
||||
<span>%</span>
|
||||
<button className="nds-icon-button" data-size="xs" type="button" onClick={clearMultiplier} aria-label={textContent.clearMultiplierButton || "Réinitialiser le multiplicateur"} title={textContent.clearMultiplierButton || "Réinitialiser le multiplicateur"}>
|
||||
<Icon name="rubber" />
|
||||
|
|
@ -320,15 +339,15 @@ export function RngSimulatorModule({ toolboxId, moduleId, context, textExchangeO
|
|||
<div className="rng-simulator-settings rng-simulator-three-columns">
|
||||
<label className="rng-simulator-field">
|
||||
<span>{textContent.perHourLabel || "Par heure"}</span>
|
||||
<input className="nds-input" data-size="sm" type="text" inputMode="decimal" value={occurrenceDrafts.perHour ?? String(data.settings.perHour ?? 0)} onChange={(event) => updateOccurrence("perHour", event.target.value)} onBlur={() => blurOccurrence("perHour")} />
|
||||
<input className="nds-input" data-size="sm" type="text" inputMode="decimal" value={occurrenceDrafts.perHour ?? String(activeRate.perHour ?? 0)} onChange={(event) => updateOccurrence("perHour", event.target.value)} onBlur={() => blurOccurrence("perHour")} />
|
||||
</label>
|
||||
<label className="rng-simulator-field">
|
||||
<span>{textContent.perDayLabel || "Par jour"}</span>
|
||||
<input className="nds-input" data-size="sm" type="text" inputMode="decimal" value={occurrenceDrafts.perDay ?? String(data.settings.perDay ?? 0)} onChange={(event) => updateOccurrence("perDay", event.target.value)} onBlur={() => blurOccurrence("perDay")} />
|
||||
<input className="nds-input" data-size="sm" type="text" inputMode="decimal" value={occurrenceDrafts.perDay ?? String(activeRate.perDay ?? 0)} onChange={(event) => updateOccurrence("perDay", event.target.value)} onBlur={() => blurOccurrence("perDay")} />
|
||||
</label>
|
||||
<label className="rng-simulator-field">
|
||||
<span>{textContent.perMonthLabel || "Par mois"}</span>
|
||||
<input className="nds-input" data-size="sm" type="text" inputMode="decimal" value={occurrenceDrafts.perMonth ?? String(data.settings.perMonth ?? 0)} onChange={(event) => updateOccurrence("perMonth", event.target.value)} onBlur={() => blurOccurrence("perMonth")} />
|
||||
<input className="nds-input" data-size="sm" type="text" inputMode="decimal" value={occurrenceDrafts.perMonth ?? String(activeRate.perMonth ?? 0)} onChange={(event) => updateOccurrence("perMonth", event.target.value)} onBlur={() => blurOccurrence("perMonth")} />
|
||||
</label>
|
||||
</div>
|
||||
<div className="rng-simulator-time-grid">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue