import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../../../app/theme.dart';
import '../../reports/data/demo_report_store.dart';
import '../../jobs/data/job_store.dart';
import '../../../core/auth/auth_store.dart';
import '../../../core/dashboard/web_dashboard_store.dart';
import '../../employees/data/employee_store.dart';
import '../../profile/data/company_store.dart';
class DashboardScreen extends StatelessWidget {
const DashboardScreen({super.key, required this.onCreateReport});
final VoidCallback onCreateReport;
@override
Widget build(BuildContext context) => ListenableBuilder(
listenable: Listenable.merge([
AuthStore.instance,
EmployeeStore.instance,
CompanyStore.instance,
WebDashboardStore.instance,
]),
builder: (context, _) => SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 1040),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 12),
Text(
'${_greeting()},',
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 8),
Text(
'${_displayName()} · bereit für den nächsten Einsatz?',
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 28),
Card(
color: AppColors.forest,
child: Padding(
padding: const EdgeInsets.all(28),
child: LayoutBuilder(
builder: (context, constraints) {
final compact = constraints.maxWidth < 560;
final copy = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(
Icons.mic_rounded,
color: AppColors.lime,
size: 36,
),
const SizedBox(height: 20),
Text(
'Neuen Nachweis erstellen',
style: Theme.of(context).textTheme.headlineMedium
?.copyWith(color: Colors.white),
),
const SizedBox(height: 10),
Text(
'Arbeitszeit, Leistung und Material direkt vor Ort festhalten.',
style: Theme.of(context).textTheme.bodyLarge
?.copyWith(color: Colors.white70),
),
],
);
final action = FilledButton.icon(
style: FilledButton.styleFrom(
backgroundColor: AppColors.lime,
foregroundColor: AppColors.ink,
),
onPressed: onCreateReport,
icon: const Icon(Icons.add_rounded),
label: const Text('Nachweis starten'),
);
return compact
? Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
copy,
const SizedBox(height: 28),
action,
],
)
: Row(
children: [
Expanded(child: copy),
const SizedBox(width: 32),
action,
],
);
},
),
),
),
const SizedBox(height: 28),
Text(
'Heute im Blick',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 14),
Wrap(
spacing: 16,
runSpacing: 16,
children: [
if (kIsWeb) ...[
ListenableBuilder(
listenable: WebDashboardStore.instance,
builder: (context, _) {
final snapshot = WebDashboardStore.instance.snapshot;
return _StatusCard(
icon: Icons.people_outline_rounded,
value: snapshot == null
? '—'
: '${snapshot.customers}',
label: 'Kunden',
);
},
),
ListenableBuilder(
listenable: WebDashboardStore.instance,
builder: (context, _) {
final snapshot = WebDashboardStore.instance.snapshot;
return _StatusCard(
icon: Icons.assignment_outlined,
value: snapshot == null ? '—' : '${snapshot.jobs}',
label: 'Aufträge',
);
},
),
ListenableBuilder(
listenable: WebDashboardStore.instance,
builder: (context, _) {
final snapshot = WebDashboardStore.instance.snapshot;
return _StatusCard(
icon: Icons.badge_outlined,
value: snapshot == null
? '—'
: '${snapshot.employees}',
label: 'Mitarbeiter',
);
},
),
] else ...[
ListenableBuilder(
listenable: JobStore.instance,
builder: (context, _) => _StatusCard(
icon: Icons.assignment_outlined,
value: '${JobStore.instance.jobs.length}',
label: 'Offene Aufträge',
),
),
ListenableBuilder(
listenable: DemoReportStore.instance,
builder: (context, _) => _StatusCard(
icon: Icons.edit_note_rounded,
value:
'${DemoReportStore.instance.reports.where((report) => !report.isFinalized).length}',
label: 'Entwürfe',
),
),
const _StatusCard(
icon: Icons.cloud_done_outlined,
value: 'Lokal',
label: 'Datenstatus',
),
],
],
),
const SizedBox(height: 28),
const Card(
child: ListTile(
contentPadding: EdgeInsets.all(20),
leading: CircleAvatar(
backgroundColor: AppColors.canvas,
child: Icon(
Icons.info_outline_rounded,
color: AppColors.green,
),
),
title: Text(
'Noch keine Einsätze geplant',
style: TextStyle(fontWeight: FontWeight.w700),
),
subtitle: Text(
'Zugewiesene Aufträge erscheinen hier auf einen Blick.',
),
),
),
],
),
),
),
),
);
String _greeting() {
final hour = DateTime.now().hour;
if (hour < 5) return 'Gute Nacht';
if (hour < 12) return 'Guten Morgen';
if (hour < 18) return 'Guten Tag';
if (hour < 22) return 'Guten Abend';
return 'Gute Nacht';
}
String _displayName() {
final email = AuthStore.instance.session?.email;
Employee? match;
if (email != null) {
for (final employee in EmployeeStore.instance.employees) {
if (employee.email.toLowerCase() == email.toLowerCase()) {
match = employee;
break;
}
}
}
final name = match?.name.trim();
if (name != null && name.isNotEmpty) return name;
final owner = CompanyStore.instance.profile.owner.trim();
if (owner.isNotEmpty) return owner;
if (email != null && email.contains('@')) {
return email.split('@').first.replaceAll(RegExp(r'[._-]+'), ' ');
}
return 'dein Team';
}
}
class _StatusCard extends StatelessWidget {
const _StatusCard({
required this.icon,
required this.value,
required this.label,
});
final IconData icon;
final String value;
final String label;
@override
Widget build(BuildContext context) => SizedBox(
width: 210,
child: Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(icon, color: AppColors.green),
const SizedBox(height: 16),
Text(value, style: Theme.of(context).textTheme.headlineMedium),
const SizedBox(height: 4),
Text(label),
],
),
),
),
);
}
