bharat_erp/lib/modules/users/presentation/screens/user_detail_screen.dart
2026-07-14 18:15:26 +05:30

145 lines
4.8 KiB
Dart

import '../../../../shared/widgets/app_card.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../../core/utils/formatters.dart';
import '../../../../core/errors/failure.dart';
import '../../../../shared/widgets/app_button.dart';
import '../../../../shared/widgets/app_confirmation_dialog.dart';
import '../../../../shared/widgets/app_loading_view.dart';
import '../../../../shared/widgets/app_status_chip.dart';
import '../../../../shared/widgets/error_view.dart';
import '../../../../shared/widgets/page_header.dart';
import '../../../../shared/models/user_management_models.dart';
import '../providers/users_provider.dart';
import '../../../../shared/widgets/app_toast.dart';
class UserDetailScreen extends ConsumerWidget {
const UserDetailScreen({super.key, required this.userId});
final String userId;
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsync = ref.watch(userDetailProvider(userId));
return Padding(
padding: const EdgeInsets.all(24),
child: userAsync.when(
loading: () => const AppLoadingView(message: 'Loading user details...'),
error: (error, _) => ErrorView.fromFailure(
error is Failure ? error : Failure.unknown(message: error.toString()),
onRetry: () => ref.invalidate(userDetailProvider(userId)),
),
data: (user) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PageHeader(
title: user.fullName,
subtitle: user.employeeCode,
actions: [
OutlinedButton.icon(
onPressed: () => context.push('/users/$userId/edit'),
icon: const Icon(Icons.edit_outlined),
label: const Text('Edit'),
),
const SizedBox(width: 8),
AppButton(
label: 'Deactivate',
expand: false,
onPressed: () => _deactivate(context, ref),
),
],
),
const SizedBox(height: 24),
AppCard(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_DetailRow(label: 'Email', value: user.email),
_DetailRow(label: 'Mobile', value: user.mobile),
_DetailRow(label: 'Role', value: user.roleLabel),
_DetailRow(label: 'Department', value: user.departmentLabel),
_DetailRow(
label: 'Status',
valueWidget: AppStatusChip(status: user.status),
),
if (user.createdAt != null)
_DetailRow(
label: 'Created',
value: DateFormatter.displayDateTime(user.createdAt),
),
if (user.updatedAt != null)
_DetailRow(
label: 'Updated',
value: DateFormatter.displayDateTime(user.updatedAt),
),
],
),
),
),
],
),
),
);
}
Future<void> _deactivate(BuildContext context, WidgetRef ref) async {
final confirmed = await showAppConfirmationDialog(
context: context,
title: 'Deactivate user',
message: 'Are you sure you want to deactivate this user?',
confirmLabel: 'Deactivate',
isDestructive: true,
);
if (confirmed != true || !context.mounted) return;
final success = await ref.read(userDetailProvider(userId).notifier).deactivate();
if (!context.mounted) return;
showAppToastFromSnackBar(context,
SnackBar(content: Text(success ? 'User deactivated' : 'Failed to deactivate')),
);
if (success) context.pop();
}
}
class _DetailRow extends StatelessWidget {
const _DetailRow({
required this.label,
this.value,
this.valueWidget,
});
final String label;
final String? value;
final Widget? valueWidget;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 140,
child: Text(
label,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
Expanded(
child: valueWidget ?? Text(value ?? '—'),
),
],
),
);
}
}