Initial commit: NANAHUI CRM - Flutter Firebase CRM assistant

This commit is contained in:
2026-03-27 14:38:10 +05:00
commit 78d15daa35
161 changed files with 9924 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
class AlarmsScreen extends StatelessWidget {
const AlarmsScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Будильники'),
),
body: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: 5,
itemBuilder: (context, index) {
return _AlarmCard(index: index);
},
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Новый будильник'),
),
);
}
}
class _AlarmCard extends StatelessWidget {
final int index;
const _AlarmCard({required this.index});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
leading: CircleAvatar(
backgroundColor: index % 2 == 0 ? Colors.blue : Colors.grey,
child: const Icon(Icons.alarm, color: Colors.white),
),
title: Text('Будильник #${index + 1}'),
subtitle: Text('${8 + index}:00'),
trailing: Switch(
value: index % 2 == 0,
onChanged: (value) {},
),
),
);
}
}
+79
View File
@@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../providers/auth_provider.dart';
class AuthScreen extends ConsumerWidget {
const AuthScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final authState = ref.watch(authProvider);
return Scaffold(
body: SafeArea(
child: Center(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.business_center,
size: 120,
color: Colors.blue,
),
const SizedBox(height: 32),
const Text(
'NANAHUI CRM',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'CRM-ассистент для команд',
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
const SizedBox(height: 48),
authState.when(
data: (user) {
if (user != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go('/home');
});
}
return const SizedBox.shrink();
},
loading: () => const CircularProgressIndicator(),
error: (error, stack) => Text(
'Error: $error',
style: const TextStyle(color: Colors.red),
),
),
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: () {
ref.read(authProvider.notifier).signInWithGoogle();
},
icon: const Icon(Icons.login),
label: const Text('Войти через Google'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 32,
vertical: 16,
),
),
),
],
),
),
),
),
);
}
}
+94
View File
@@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
class CalendarScreen extends StatelessWidget {
const CalendarScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Календарь'),
actions: [
IconButton(
icon: const Icon(Icons.sync),
onPressed: () {
// Синхронизация с Google Calendar
},
),
],
),
body: Column(
children: [
_buildCalendarHeader(),
Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: 5,
itemBuilder: (context, index) {
return _CalendarEventCard(index: index);
},
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
);
}
Widget _buildCalendarHeader() {
return Container(
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: const Icon(Icons.chevron_left),
onPressed: () {},
),
const Text(
'Март 2026',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
IconButton(
icon: const Icon(Icons.chevron_right),
onPressed: () {},
),
],
),
);
}
}
class _CalendarEventCard extends StatelessWidget {
final int index;
const _CalendarEventCard({required this.index});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
leading: Container(
width: 4,
height: 40,
decoration: BoxDecoration(
color: _getEventColor(index),
borderRadius: BorderRadius.circular(2),
),
),
title: Text('Событие #${index + 1}'),
subtitle: Text('10:00 - 11:00'),
trailing: const Icon(Icons.more_vert),
),
);
}
Color _getEventColor(int index) {
final colors = [Colors.blue, Colors.green, Colors.orange, Colors.purple];
return colors[index % colors.length];
}
}
+233
View File
@@ -0,0 +1,233 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class DashboardScreen extends StatelessWidget {
const DashboardScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('NANAHUI CRM'),
actions: [
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {},
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildWelcomeCard(),
const SizedBox(height: 24),
_buildQuickStats(),
const SizedBox(height: 24),
_buildQuickActions(context),
],
),
),
);
}
Widget _buildWelcomeCard() {
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Добро пожаловать!',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
'Управляйте задачами команды и планируйте работу с помощью AI',
style: TextStyle(color: Colors.grey),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: OutlinedButton.icon(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Новая задача'),
),
),
const SizedBox(width: 12),
Expanded(
child: OutlinedButton.icon(
onPressed: () {},
icon: const Icon(Icons.auto_awesome),
label: const Text('AI План'),
),
),
],
),
],
),
),
);
}
Widget _buildQuickStats() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Быстрая статистика',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: _StatCard(
icon: Icons.task,
label: 'Задачи',
value: '12',
color: Colors.blue,
),
),
const SizedBox(width: 12),
Expanded(
child: _StatCard(
icon: Icons.pending_actions,
label: 'В работе',
value: '5',
color: Colors.orange,
),
),
const SizedBox(width: 12),
Expanded(
child: _StatCard(
icon: Icons.check_circle,
label: 'Готово',
value: '48',
color: Colors.green,
),
),
],
),
],
);
}
Widget _buildQuickActions(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Быстрые действия',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Wrap(
spacing: 12,
runSpacing: 12,
children: [
_ActionChip(
icon: Icons.calendar_today,
label: 'Планирование',
onTap: () => context.go('/home/calendar'),
),
_ActionChip(
icon: Icons.account_tree,
label: 'Mind-карта',
onTap: () => context.go('/home/mindmap'),
),
_ActionChip(
icon: Icons.insights,
label: 'Аналитика',
onTap: () {},
),
_ActionChip(
icon: Icons.people,
label: 'Команда',
onTap: () {},
),
],
),
],
);
}
}
class _StatCard extends StatelessWidget {
final IconData icon;
final String label;
final String value;
final Color color;
const _StatCard({
required this.icon,
required this.label,
required this.value,
required this.color,
});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Icon(icon, color: color, size: 32),
const SizedBox(height: 8),
Text(
value,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
Text(
label,
style: const TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
),
);
}
}
class _ActionChip extends StatelessWidget {
final IconData icon;
final String label;
final VoidCallback onTap;
const _ActionChip({
required this.icon,
required this.label,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 20),
const SizedBox(width: 8),
Text(label),
],
),
),
);
}
}
+67
View File
@@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'dashboard_screen.dart';
import 'tasks_screen.dart';
import 'mind_map_screen.dart';
import 'calendar_screen.dart';
import 'alarms_screen.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _selectedIndex = 0;
final List<Widget> _screens = [
const DashboardScreen(),
const TasksScreen(),
const MindMapScreen(),
const CalendarScreen(),
const AlarmsScreen(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: _screens[_selectedIndex],
bottomNavigationBar: NavigationBar(
selectedIndex: _selectedIndex,
onDestinationSelected: (index) {
setState(() {
_selectedIndex = index;
});
},
destinations: const [
NavigationDestination(
icon: Icon(Icons.dashboard_outlined),
selectedIcon: Icon(Icons.dashboard),
label: 'Главная',
),
NavigationDestination(
icon: Icon(Icons.task_outlined),
selectedIcon: Icon(Icons.task),
label: 'Задачи',
),
NavigationDestination(
icon: Icon(Icons.account_tree_outlined),
selectedIcon: Icon(Icons.account_tree),
label: 'Mind-карта',
),
NavigationDestination(
icon: Icon(Icons.calendar_today_outlined),
selectedIcon: Icon(Icons.calendar_today),
label: 'Календарь',
),
NavigationDestination(
icon: Icon(Icons.alarm_outlined),
selectedIcon: Icon(Icons.alarm),
label: 'Будильники',
),
],
),
);
}
}
+60
View File
@@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
class MindMapScreen extends StatelessWidget {
const MindMapScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Mind-карта'),
actions: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {
// Edit mode - только для админов
},
),
IconButton(
icon: const Icon(Icons.download),
onPressed: () {},
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.account_tree,
size: 100,
color: Colors.grey,
),
const SizedBox(height: 24),
const Text(
'Mind-карта проекта',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
'Создайте структуру задач в виде дерева',
style: TextStyle(color: Colors.grey),
),
const SizedBox(height: 32),
ElevatedButton.icon(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Создать mind-карту'),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// AI генерация mind-карты
},
child: const Icon(Icons.auto_awesome),
),
);
}
}
+86
View File
@@ -0,0 +1,86 @@
import 'package:flutter/material.dart';
class TasksScreen extends StatelessWidget {
const TasksScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Задачи'),
actions: [
IconButton(
icon: const Icon(Icons.filter_list),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.search),
onPressed: () {},
),
],
),
body: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: 10,
itemBuilder: (context, index) {
return _TaskCard(index: index);
},
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('Новая задача'),
),
);
}
}
class _TaskCard extends StatelessWidget {
final int index;
const _TaskCard({required this.index});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
leading: CircleAvatar(
backgroundColor: _getPriorityColor(index),
child: Text('${index + 1}'),
),
title: Text('Задача #${index + 1}'),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 4),
Text('Описание задачи...'),
const SizedBox(height: 4),
Row(
children: [
Icon(Icons.calendar_today, size: 12, color: Colors.grey),
const SizedBox(width: 4),
Text(
'До: ${DateTime.now().add(Duration(days: index)).toString().split(' ')[0]}',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
],
),
trailing: PopupMenuButton(
itemBuilder: (context) => [
const PopupMenuItem(value: 'edit', child: Text('Редактировать')),
const PopupMenuItem(value: 'delete', child: Text('Удалить')),
],
),
isThreeLine: true,
),
);
}
Color _getPriorityColor(int index) {
final colors = [Colors.red, Colors.orange, Colors.blue, Colors.green];
return colors[index % colors.length];
}
}