fix(admin): require current password for self password change and fix field ordering
- initialize `newPassword` in form state on load - add `needsCurrentPassword` flag triggered by email or password change when editing self - route self password change to profile endpoint with current password verification - move role tag input above password section and update current password field visibility logic
This commit is contained in:
@@ -46,6 +46,7 @@ const UserEditModal = ({ userId, currentUserId, isOpen, onClose, onSaved }) => {
|
|||||||
name: userJson.user.name || '',
|
name: userJson.user.name || '',
|
||||||
email: userJson.user.email || '',
|
email: userJson.user.email || '',
|
||||||
currentPassword: '',
|
currentPassword: '',
|
||||||
|
newPassword: '',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast.error(userJson.message || 'Utilisateur introuvable');
|
toast.error(userJson.message || 'Utilisateur introuvable');
|
||||||
@@ -90,10 +91,12 @@ const UserEditModal = ({ userId, currentUserId, isOpen, onClose, onSaved }) => {
|
|||||||
|
|
||||||
const emailChanged = userData && formData.email !== userData.email;
|
const emailChanged = userData && formData.email !== userData.email;
|
||||||
|
|
||||||
|
const needsCurrentPassword = isSelf && (emailChanged || !!formData.newPassword);
|
||||||
|
|
||||||
const validate = () => {
|
const validate = () => {
|
||||||
const newErrors = {};
|
const newErrors = {};
|
||||||
if (!formData.name?.trim()) newErrors.name = 'Le nom est requis';
|
if (!formData.name?.trim()) newErrors.name = 'Le nom est requis';
|
||||||
if (emailChanged && isSelf && !formData.currentPassword) newErrors.currentPassword = 'Le mot de passe est requis pour changer le courriel';
|
if (needsCurrentPassword && !formData.currentPassword) newErrors.currentPassword = 'Le mot de passe actuel est requis';
|
||||||
setErrors(newErrors);
|
setErrors(newErrors);
|
||||||
return Object.keys(newErrors).length === 0;
|
return Object.keys(newErrors).length === 0;
|
||||||
};
|
};
|
||||||
@@ -175,11 +178,16 @@ const UserEditModal = ({ userId, currentUserId, isOpen, onClose, onSaved }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (formData.newPassword) {
|
if (formData.newPassword) {
|
||||||
const pwdRes = await fetch(`/zen/api/users/${userId}/password`, {
|
const pwdUrl = isSelf ? '/zen/api/users/profile/password' : `/zen/api/users/${userId}/password`;
|
||||||
method: 'PUT',
|
const pwdMethod = isSelf ? 'POST' : 'PUT';
|
||||||
|
const pwdBody = isSelf
|
||||||
|
? { currentPassword: formData.currentPassword, newPassword: formData.newPassword }
|
||||||
|
: { newPassword: formData.newPassword };
|
||||||
|
const pwdRes = await fetch(pwdUrl, {
|
||||||
|
method: pwdMethod,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
body: JSON.stringify({ newPassword: formData.newPassword }),
|
body: JSON.stringify(pwdBody),
|
||||||
});
|
});
|
||||||
const pwdData = await pwdRes.json();
|
const pwdData = await pwdRes.json();
|
||||||
if (!pwdRes.ok) {
|
if (!pwdRes.ok) {
|
||||||
@@ -242,17 +250,17 @@ const UserEditModal = ({ userId, currentUserId, isOpen, onClose, onSaved }) => {
|
|||||||
placeholder="courriel@exemple.com"
|
placeholder="courriel@exemple.com"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{isSelf && emailChanged && (
|
|
||||||
<Input
|
<TagInput
|
||||||
label="Mot de passe actuel *"
|
label="Rôles attribués"
|
||||||
type="password"
|
options={roleOptions}
|
||||||
value={formData.currentPassword}
|
value={selectedRoleIds}
|
||||||
onChange={(value) => handleInputChange('currentPassword', value)}
|
onChange={setSelectedRoleIds}
|
||||||
placeholder="Votre mot de passe"
|
placeholder="Rechercher un rôle..."
|
||||||
error={errors.currentPassword}
|
renderTag={(opt, onRemove) => (
|
||||||
description="Requis pour confirmer le changement de courriel"
|
<RoleBadge key={opt.value} name={opt.label} color={opt.color} onRemove={onRemove} />
|
||||||
/>
|
)}
|
||||||
)}
|
/>
|
||||||
|
|
||||||
<div className="border-t border-neutral-200 dark:border-neutral-700 pt-4 flex flex-col gap-3">
|
<div className="border-t border-neutral-200 dark:border-neutral-700 pt-4 flex flex-col gap-3">
|
||||||
<Input
|
<Input
|
||||||
@@ -275,16 +283,17 @@ const UserEditModal = ({ userId, currentUserId, isOpen, onClose, onSaved }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TagInput
|
{needsCurrentPassword && (
|
||||||
label="Rôles attribués"
|
<Input
|
||||||
options={roleOptions}
|
label="Mot de passe actuel *"
|
||||||
value={selectedRoleIds}
|
type="password"
|
||||||
onChange={setSelectedRoleIds}
|
value={formData.currentPassword}
|
||||||
placeholder="Rechercher un rôle..."
|
onChange={(value) => handleInputChange('currentPassword', value)}
|
||||||
renderTag={(opt, onRemove) => (
|
placeholder="Votre mot de passe"
|
||||||
<RoleBadge key={opt.value} name={opt.label} color={opt.color} onRemove={onRemove} />
|
error={errors.currentPassword}
|
||||||
)}
|
description={emailChanged && formData.newPassword ? 'Requis pour confirmer le changement de courriel et de mot de passe' : emailChanged ? 'Requis pour confirmer le changement de courriel' : 'Requis pour confirmer le changement de mot de passe'}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
Reference in New Issue
Block a user