sokko-g/website/src/components/ToolboxModals.jsx
Shinuwa 68005ef918
All checks were successful
Deploy Sokko G / deploy (push) Successful in 6s
new tool timer & alert revamp
2026-07-26 11:41:42 +02:00

76 lines
3.6 KiB
JavaScript

// Rôle : fournit les modales globales liées aux toolboxes et confirmations.
import { useEffect, useState } from "react";
import { Icon } from "./Icon.jsx";
import { lockBodyScroll } from "../utils/bodyScrollLock.js";
function useModalScrollLock() {
useEffect(() => lockBodyScroll(), []);
}
export function ConfirmModal({ title, message, confirmLabel = "Confirmer", cancelLabel = "Annuler", danger = false, onClose }) {
useModalScrollLock();
return (
<div className="confirm-modal-root">
<div className="confirm-backdrop" onClick={() => onClose(false)} />
<section className="confirm-modal" role="dialog" aria-modal="true" aria-labelledby="confirm-title" aria-describedby="confirm-message">
<header><h2 id="confirm-title">{title}</h2></header>
<p id="confirm-message">{message}</p>
<footer>
<button onClick={() => onClose(false)}>{cancelLabel}</button>
<button className={danger ? "danger confirm-danger" : "primary"} onClick={() => onClose(true)}>{confirmLabel}</button>
</footer>
</section>
</div>
);
}
export function NotificationToast({ message, position = "right", onClose }) {
return (
<div className={`notification-toast is-${position === "left" ? "left" : "right"}`} role="status" aria-live="polite">
<span>{message}</span>
<button type="button" onClick={onClose} aria-label="Fermer l'alerte" title="Fermer">
<Icon name="close" />
</button>
</div>
);
}
export function CreateToolboxModal({ gameId, initialName = "", onClose }) {
useModalScrollLock();
const [name, setName] = useState(initialName);
return (
<div className="confirm-modal-root">
<div className="confirm-backdrop" onClick={() => onClose("")} />
<section className="confirm-modal toolbox-create-modal" role="dialog" aria-modal="true" aria-labelledby="toolbox-create-title">
<header><h2 id="toolbox-create-title">{gameId ? "Créer et associer une toolbox" : "Nouvelle toolbox"}</h2></header>
<form onSubmit={(event) => {
event.preventDefault();
if (name.trim()) onClose(name.trim());
}}>
<label className="field"><span>Nom</span><input name="name" autoComplete="off" placeholder="Nom de la toolbox" required value={name} onChange={(event) => setName(event.target.value)} autoFocus /></label>
<footer><button type="button" onClick={() => onClose("")}>Annuler</button><button className="primary" type="submit">Créer</button></footer>
</form>
</section>
</div>
);
}
export function LinkToolboxModal({ toolboxes, selectedId, onClose }) {
useModalScrollLock();
const [toolboxId, setToolboxId] = useState(selectedId);
return (
<div className="confirm-modal-root">
<div className="confirm-backdrop" onClick={() => onClose(null)} />
<section className="confirm-modal toolbox-link-modal" role="dialog" aria-modal="true" aria-labelledby="toolbox-link-title">
<header><h2 id="toolbox-link-title">Lier une toolbox</h2></header>
<form onSubmit={(event) => {
event.preventDefault();
onClose(toolboxId);
}}>
<label className="field"><span>Toolbox associée</span><select value={toolboxId} onChange={(event) => setToolboxId(event.target.value)} autoFocus><option value="">Aucune</option>{toolboxes.map((toolbox) => <option key={toolbox.id} value={toolbox.id}>{toolbox.name}</option>)}</select></label>
<footer><button type="button" onClick={() => onClose(null)}>Annuler</button><button className="primary" type="submit">Valider</button></footer>
</form>
</section>
</div>
);
}