feat(#96): différencier la consultation admin et le mode édition
Affiche une identité visuelle dédiée pour les super admins et adapte l’action par ligne (oeil en lecture seule, crayon en édition) avec modale strictement read-only quand l’utilisateur n’a pas les droits. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,12 +9,14 @@ class AdminUserFormDialog extends StatefulWidget {
|
||||
final AppUser? initialUser;
|
||||
final bool withRelais;
|
||||
final bool adminMode;
|
||||
final bool readOnly;
|
||||
|
||||
const AdminUserFormDialog({
|
||||
super.key,
|
||||
this.initialUser,
|
||||
this.withRelais = true,
|
||||
this.adminMode = false,
|
||||
this.readOnly = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -194,6 +196,7 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
}
|
||||
|
||||
Future<void> _submit() async {
|
||||
if (widget.readOnly) return;
|
||||
if (_isSubmitting) return;
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
|
||||
@@ -304,6 +307,7 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
}
|
||||
|
||||
Future<void> _delete() async {
|
||||
if (widget.readOnly) return;
|
||||
if (!_isEditMode || _isSubmitting) return;
|
||||
|
||||
final confirmed = await showDialog<bool>(
|
||||
@@ -363,15 +367,19 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
_isEditMode
|
||||
? (widget.adminMode
|
||||
? 'Modifier un administrateur'
|
||||
: 'Modifier un gestionnaire')
|
||||
? (widget.readOnly
|
||||
? (widget.adminMode
|
||||
? 'Consulter un administrateur'
|
||||
: 'Consulter un gestionnaire')
|
||||
: (widget.adminMode
|
||||
? 'Modifier un administrateur'
|
||||
: 'Modifier un gestionnaire'))
|
||||
: (widget.adminMode
|
||||
? 'Créer un administrateur'
|
||||
: 'Créer un gestionnaire'),
|
||||
),
|
||||
),
|
||||
if (_isEditMode)
|
||||
if (_isEditMode && !widget.readOnly)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
tooltip: 'Fermer',
|
||||
@@ -416,7 +424,12 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
if (_isEditMode) ...[
|
||||
if (widget.readOnly) ...[
|
||||
FilledButton(
|
||||
onPressed: _isSubmitting ? null : () => Navigator.of(context).pop(false),
|
||||
child: const Text('Fermer'),
|
||||
),
|
||||
] else if (_isEditMode) ...[
|
||||
OutlinedButton(
|
||||
onPressed: _isSubmitting ? null : _delete,
|
||||
style: OutlinedButton.styleFrom(foregroundColor: Colors.red.shade700),
|
||||
@@ -458,42 +471,46 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
Widget _buildNomField() {
|
||||
return TextFormField(
|
||||
controller: _nomController,
|
||||
readOnly: widget.readOnly,
|
||||
textCapitalization: TextCapitalization.words,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Nom',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
validator: (v) => _required(v, 'Nom'),
|
||||
validator: widget.readOnly ? null : (v) => _required(v, 'Nom'),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPrenomField() {
|
||||
return TextFormField(
|
||||
controller: _prenomController,
|
||||
readOnly: widget.readOnly,
|
||||
textCapitalization: TextCapitalization.words,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Prénom',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
validator: (v) => _required(v, 'Prénom'),
|
||||
validator: widget.readOnly ? null : (v) => _required(v, 'Prénom'),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEmailField() {
|
||||
return TextFormField(
|
||||
controller: _emailController,
|
||||
readOnly: widget.readOnly,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Email',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
validator: _validateEmail,
|
||||
validator: widget.readOnly ? null : _validateEmail,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPasswordField() {
|
||||
return TextFormField(
|
||||
controller: _passwordController,
|
||||
readOnly: widget.readOnly,
|
||||
obscureText: _obscurePassword,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
@@ -505,38 +522,43 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
? 'Nouveau mot de passe'
|
||||
: 'Mot de passe',
|
||||
border: const OutlineInputBorder(),
|
||||
suffixIcon: ExcludeFocus(
|
||||
child: IconButton(
|
||||
focusNode: _passwordToggleFocusNode,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_obscurePassword = !_obscurePassword;
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
_obscurePassword ? Icons.visibility_off : Icons.visibility,
|
||||
),
|
||||
),
|
||||
),
|
||||
suffixIcon: widget.readOnly
|
||||
? null
|
||||
: ExcludeFocus(
|
||||
child: IconButton(
|
||||
focusNode: _passwordToggleFocusNode,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_obscurePassword = !_obscurePassword;
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
_obscurePassword ? Icons.visibility_off : Icons.visibility,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
validator: _validatePassword,
|
||||
validator: widget.readOnly ? null : _validatePassword,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTelephoneField() {
|
||||
return TextFormField(
|
||||
controller: _telephoneController,
|
||||
readOnly: widget.readOnly,
|
||||
keyboardType: TextInputType.phone,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly,
|
||||
LengthLimitingTextInputFormatter(10),
|
||||
_FrenchPhoneNumberFormatter(),
|
||||
],
|
||||
inputFormatters: widget.readOnly
|
||||
? null
|
||||
: [
|
||||
FilteringTextInputFormatter.digitsOnly,
|
||||
LengthLimitingTextInputFormatter(10),
|
||||
_FrenchPhoneNumberFormatter(),
|
||||
],
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Téléphone (ex: 06 12 34 56 78)',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
validator: _validatePhone,
|
||||
validator: widget.readOnly ? null : _validatePhone,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -568,7 +590,7 @@ class _AdminUserFormDialogState extends State<AdminUserFormDialog> {
|
||||
),
|
||||
),
|
||||
],
|
||||
onChanged: _isLoadingRelais
|
||||
onChanged: (_isLoadingRelais || widget.readOnly)
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
|
||||
Reference in New Issue
Block a user