Neda/admin_panel/lib/screens/dashboard_screen.dart

281 lines
9.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import '../providers/user_provider.dart';
import '../providers/group_provider.dart';
import '../theme/app_theme.dart';
import '../widgets/app_sidebar.dart';
import '../widgets/responsive_layout.dart';
import '../widgets/stat_card.dart';
import '../config/app_config.dart';
class DashboardScreen extends StatefulWidget {
const DashboardScreen({super.key});
@override
State<DashboardScreen> createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<UserProvider>().loadUsers();
context.read<GroupProvider>().loadGroups();
});
}
@override
Widget build(BuildContext context) {
return ResponsiveLayout(
title: 'داشبورد',
sidebar: const AppSidebar(),
body: _DashboardBody(),
);
}
}
class _DashboardBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// ── Header ─────────────────────────────────────────────────
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'داشبورد',
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.w800,
color: AppTheme.textPrimary,
),
),
const SizedBox(height: 4),
Text(
'خلاصه وضعیت سیستم NEDA',
style: const TextStyle(
fontSize: 14,
color: AppTheme.textSecondary,
),
),
],
),
),
if (AppConfig.debugMode)
Container(
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: AppTheme.warning.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: AppTheme.warning.withValues(alpha: 0.4)),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.bug_report_rounded,
size: 14, color: AppTheme.warning),
const SizedBox(width: 6),
Text(
'Debug Mode',
style: TextStyle(
color: AppTheme.warning,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
const SizedBox(height: 28),
// ── Stat cards ─────────────────────────────────────────────
_StatsGrid(),
const SizedBox(height: 28),
// ── Quick actions ──────────────────────────────────────────
const Text(
'دسترسی سریع',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
color: AppTheme.textPrimary,
),
),
const SizedBox(height: 16),
_QuickActions(),
],
),
);
}
}
class _StatsGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer2<UserProvider, GroupProvider>(
builder: (_, users, groups, __) {
return LayoutBuilder(
builder: (context, constraints) {
final crossAxisCount = constraints.maxWidth >= 700 ? 4 : 2;
return GridView.count(
crossAxisCount: crossAxisCount,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
mainAxisSpacing: 16,
crossAxisSpacing: 16,
childAspectRatio: constraints.maxWidth >= 700 ? 1.6 : 1.4,
children: [
StatCard(
title: 'کل کاربران',
value: users.isLoading ? '...' : '${users.totalCount}',
icon: Icons.people_rounded,
color: AppTheme.primary,
subtitle: '${users.activeCount} فعال',
),
StatCard(
title: 'کل گروه‌ها',
value: groups.isLoading ? '...' : '${groups.totalCount}',
icon: Icons.groups_rounded,
color: const Color(0xFF7C3AED),
subtitle: '${groups.activeCount} فعال',
),
StatCard(
title: 'کاربران غیرفعال',
value: users.isLoading
? '...'
: '${users.totalCount - users.activeCount}',
icon: Icons.person_off_rounded,
color: AppTheme.warning,
),
StatCard(
title: 'گروه‌های غیرفعال',
value: groups.isLoading
? '...'
: '${groups.totalCount - groups.activeCount}',
icon: Icons.group_off_rounded,
color: AppTheme.danger,
),
],
);
},
);
},
);
}
}
class _QuickActions extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
final isWide = constraints.maxWidth >= 500;
return Wrap(
spacing: 12,
runSpacing: 12,
children: [
_ActionCard(
label: 'ایجاد کاربر جدید',
icon: Icons.person_add_rounded,
color: AppTheme.primary,
onTap: () => context.go('/users'),
),
_ActionCard(
label: 'ایجاد گروه جدید',
icon: Icons.group_add_rounded,
color: const Color(0xFF7C3AED),
onTap: () => context.go('/groups'),
),
_ActionCard(
label: 'مدیریت کاربران',
icon: Icons.manage_accounts_rounded,
color: const Color(0xFF0891B2),
onTap: () => context.go('/users'),
),
_ActionCard(
label: 'مدیریت گروه‌ها',
icon: Icons.settings_rounded,
color: AppTheme.success,
onTap: () => context.go('/groups'),
),
_ActionCard(
label: 'ارسال اعلان عمومی',
icon: Icons.campaign_rounded,
color: const Color(0xFFEA580C),
onTap: () => context.go('/notifications'),
),
]
.map((w) => SizedBox(
width: isWide
? (constraints.maxWidth - 48) / 5
: (constraints.maxWidth - 12) / 2,
child: w,
))
.toList(),
);
});
}
}
class _ActionCard extends StatelessWidget {
final String label;
final IconData icon;
final Color color;
final VoidCallback onTap;
const _ActionCard({
required this.label,
required this.icon,
required this.color,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return Card(
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 44,
height: 44,
decoration: BoxDecoration(
color: color.withValues(alpha: 0.12),
borderRadius: BorderRadius.circular(10),
),
child: Icon(icon, color: color, size: 22),
),
const SizedBox(height: 12),
Text(
label,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppTheme.textPrimary,
),
),
],
),
),
),
);
}
}