Masquer la saisie des PIN sysadmin
This commit is contained in:
parent
ddb391c673
commit
ff1700ec5e
2 changed files with 107 additions and 22 deletions
|
|
@ -18,6 +18,8 @@ export default function GestionGroupes() {
|
|||
const [busy, setBusy] = useState(false);
|
||||
const [msg, setMsg] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const [pinFormOuvert, setPinFormOuvert] = useState(false);
|
||||
const [pinForm, setPinForm] = useState({ actuel: '', nouveau: '', confirmation: '' });
|
||||
|
||||
const charger = async () => {
|
||||
setLoading(true);
|
||||
|
|
@ -167,17 +169,17 @@ export default function GestionGroupes() {
|
|||
}
|
||||
};
|
||||
|
||||
const changerPinSysadmin = async () => {
|
||||
const pinActuel = window.prompt('PIN actuel');
|
||||
if (!pinActuel) return;
|
||||
const nouveauPin = window.prompt('Nouveau PIN sysadmin (4 chiffres)');
|
||||
if (!nouveauPin) return;
|
||||
if (!/^[0-9]{4}$/.test(nouveauPin)) {
|
||||
const changerPinSysadmin = async (e) => {
|
||||
e.preventDefault();
|
||||
if (!/^[0-9]{4}$/.test(pinForm.actuel)) {
|
||||
setError('Le PIN actuel doit contenir 4 chiffres');
|
||||
return;
|
||||
}
|
||||
if (!/^[0-9]{4}$/.test(pinForm.nouveau)) {
|
||||
setError('Le nouveau PIN doit contenir 4 chiffres');
|
||||
return;
|
||||
}
|
||||
const confirmation = window.prompt('Confirmer le nouveau PIN');
|
||||
if (confirmation !== nouveauPin) {
|
||||
if (pinForm.confirmation !== pinForm.nouveau) {
|
||||
setError('La confirmation ne correspond pas');
|
||||
return;
|
||||
}
|
||||
|
|
@ -186,10 +188,12 @@ export default function GestionGroupes() {
|
|||
setMsg('');
|
||||
try {
|
||||
const res = await api.post('/admin/sysadmin-pin', {
|
||||
pin_actuel: pinActuel,
|
||||
nouveau_pin: nouveauPin,
|
||||
pin_actuel: pinForm.actuel,
|
||||
nouveau_pin: pinForm.nouveau,
|
||||
});
|
||||
setMsg(res.message || 'PIN sysadmin mis à jour');
|
||||
setPinForm({ actuel: '', nouveau: '', confirmation: '' });
|
||||
setPinFormOuvert(false);
|
||||
} catch (e) {
|
||||
setError(e.message);
|
||||
} finally {
|
||||
|
|
@ -214,7 +218,11 @@ export default function GestionGroupes() {
|
|||
Créer un groupe
|
||||
</button>
|
||||
<button
|
||||
onClick={changerPinSysadmin}
|
||||
onClick={() => {
|
||||
setPinFormOuvert((ouvert) => !ouvert);
|
||||
setPinForm({ actuel: '', nouveau: '', confirmation: '' });
|
||||
setError('');
|
||||
}}
|
||||
disabled={busy}
|
||||
className="w-full min-h-[48px] p-3 bg-gray-800 text-white rounded-xl text-sm font-bold disabled:opacity-40"
|
||||
>
|
||||
|
|
@ -222,6 +230,53 @@ export default function GestionGroupes() {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
{pinFormOuvert && (
|
||||
<form onSubmit={changerPinSysadmin} className="bg-white rounded-2xl p-4 shadow-sm space-y-3">
|
||||
<h2 className="font-bold text-gray-800">Changer le PIN sysadmin</h2>
|
||||
<input
|
||||
type="password"
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
maxLength={4}
|
||||
placeholder="PIN actuel"
|
||||
value={pinForm.actuel}
|
||||
onChange={(e) => setPinForm({ ...pinForm, actuel: e.target.value.replace(/\D/g, '').slice(0, 4) })}
|
||||
className="w-full p-3 bg-gray-50 rounded-xl border-0 text-center tracking-[0.8em]"
|
||||
autoComplete="current-password"
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
maxLength={4}
|
||||
placeholder="Nouveau PIN"
|
||||
value={pinForm.nouveau}
|
||||
onChange={(e) => setPinForm({ ...pinForm, nouveau: e.target.value.replace(/\D/g, '').slice(0, 4) })}
|
||||
className="w-full p-3 bg-gray-50 rounded-xl border-0 text-center tracking-[0.8em]"
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
maxLength={4}
|
||||
placeholder="Confirmer le nouveau PIN"
|
||||
value={pinForm.confirmation}
|
||||
onChange={(e) => setPinForm({ ...pinForm, confirmation: e.target.value.replace(/\D/g, '').slice(0, 4) })}
|
||||
className="w-full p-3 bg-gray-50 rounded-xl border-0 text-center tracking-[0.8em]"
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<button type="submit" disabled={busy} className="p-3 bg-green-600 text-white rounded-xl text-sm font-bold disabled:opacity-40">
|
||||
Enregistrer
|
||||
</button>
|
||||
<button type="button" onClick={() => { setPinFormOuvert(false); setPinForm({ actuel: '', nouveau: '', confirmation: '' }); }} className="p-3 bg-gray-100 text-gray-600 rounded-xl text-sm font-bold">
|
||||
Annuler
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
|
||||
{form && (
|
||||
<div className="bg-white rounded-2xl p-4 shadow-sm space-y-3">
|
||||
<h2 className="font-bold text-gray-800">{editionId === 'nouveau' ? 'Nouveau groupe' : 'Modifier le groupe'}</h2>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ export default function Login() {
|
|||
const [groupeId, setGroupeId] = useState(localStorage.getItem('gm_groupe_id') || '');
|
||||
const [groupeOuvert, setGroupeOuvert] = useState('');
|
||||
const [seSouvenir, setSeSouvenir] = useState(!!localStorage.getItem('gm_courriel'));
|
||||
const [sysadminOuvert, setSysadminOuvert] = useState(false);
|
||||
const [sysadminPin, setSysadminPin] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (groupes.length === 0) loadGroupes();
|
||||
|
|
@ -47,11 +49,11 @@ export default function Login() {
|
|||
} catch {}
|
||||
};
|
||||
|
||||
const ouvrirSysadmin = async () => {
|
||||
const pin = window.prompt('PIN Sysadmin');
|
||||
if (!pin) return;
|
||||
const ouvrirSysadmin = async (e) => {
|
||||
e.preventDefault();
|
||||
if (sysadminPin.length !== 4) return;
|
||||
try {
|
||||
const data = await api.post('/admin/sysadmin-login', { pin });
|
||||
const data = await api.post('/admin/sysadmin-login', { pin: sysadminPin });
|
||||
api.setToken(data.access_token, false);
|
||||
localStorage.setItem('gm_sysadmin_instance', '1');
|
||||
localStorage.removeItem('gm_groupe_id');
|
||||
|
|
@ -72,6 +74,8 @@ export default function Login() {
|
|||
setPage('G14');
|
||||
} catch (e) {
|
||||
useStore.setState({ error: e.message });
|
||||
} finally {
|
||||
setSysadminPin('');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -186,13 +190,39 @@ export default function Login() {
|
|||
Découvrir l'application
|
||||
</a>
|
||||
|
||||
{sysadminOuvert && (
|
||||
<form onSubmit={ouvrirSysadmin} className="mb-3 rounded-2xl bg-white/95 p-3 shadow-lg">
|
||||
<input
|
||||
type="password"
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
maxLength={4}
|
||||
placeholder="PIN sysadmin"
|
||||
value={sysadminPin}
|
||||
onChange={(e) => setSysadminPin(e.target.value.replace(/\D/g, '').slice(0, 4))}
|
||||
className="mb-2 w-full rounded-xl border-0 bg-gray-50 p-3 text-center text-lg tracking-[0.8em] focus:ring-2 focus:ring-aa-blue"
|
||||
autoFocus
|
||||
/>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<button type="submit" disabled={sysadminPin.length !== 4} className="rounded-xl bg-aa-blue p-3 text-sm font-bold text-white disabled:opacity-40">
|
||||
Ouvrir
|
||||
</button>
|
||||
<button type="button" onClick={() => { setSysadminOuvert(false); setSysadminPin(''); }} className="rounded-xl bg-gray-100 p-3 text-sm font-bold text-gray-600">
|
||||
Annuler
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
|
||||
{!sysadminOuvert && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={ouvrirSysadmin}
|
||||
onClick={() => setSysadminOuvert(true)}
|
||||
className="mx-auto mb-3 block px-3 py-2 text-xs font-semibold text-blue-200/80"
|
||||
>
|
||||
Sysadmin
|
||||
</button>
|
||||
)}
|
||||
<p className="text-center text-xs text-blue-300">100% logiciel libre · Hébergé au Québec</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue