import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import '../../core/theme/app_theme.dart'; import '../../core/widgets/loading_button.dart'; import '../../core/api/api_client.dart'; import '../../shared/providers/lookup_providers.dart'; import 'tasks_provider.dart'; class TaskFormScreen extends ConsumerStatefulWidget { final int? editId; const TaskFormScreen({super.key, this.editId}); @override ConsumerState createState() => _TaskFormScreenState(); } class _TaskFormScreenState extends ConsumerState { final _formKey = GlobalKey(); final _titleCtrl = TextEditingController(); DateTime? _dueDate; int? _assignedTo; String _status = 'todo'; bool _loading = false; bool _initDone = false; bool get isEdit => widget.editId != null; @override void dispose() { _titleCtrl.dispose(); super.dispose(); } Future _initEdit() async { if (!isEdit || _initDone) return; _initDone = true; try { final resp = await apiDio.get('/tasks/${widget.editId}'); final data = resp.data as Map; setState(() { _titleCtrl.text = data['title'] ?? ''; _status = data['status'] ?? 'todo'; _assignedTo = data['assigned_to']; if (data['due_date'] != null) _dueDate = DateTime.tryParse(data['due_date']); }); } catch (_) {} } Future _submit() async { if (!_formKey.currentState!.validate()) return; setState(() => _loading = true); try { final data = { 'title': _titleCtrl.text.trim(), 'status': _status, if (_assignedTo != null) 'assigned_to': _assignedTo, if (_dueDate != null) 'due_date': DateFormat('yyyy-MM-dd').format(_dueDate!), }; if (isEdit) { await updateTask(widget.editId!, data); } else { await createTask(data); } if (mounted) context.pop(); } on ApiException catch (e) { if (mounted) ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(e.message), backgroundColor: AppColors.danger)); } finally { if (mounted) setState(() => _loading = false); } } Future _pickDate() async { final picked = await showDatePicker( context: context, initialDate: _dueDate ?? DateTime.now(), firstDate: DateTime.now().subtract(const Duration(days: 1)), lastDate: DateTime.now().add(const Duration(days: 365 * 3)), ); if (picked != null) setState(() => _dueDate = picked); } @override Widget build(BuildContext context) { if (isEdit) _initEdit(); final usersAsync = ref.watch(usersProvider); return Scaffold( appBar: AppBar(title: Text(isEdit ? 'Edit Task' : 'Create Task')), body: Form( key: _formKey, child: ListView( padding: const EdgeInsets.all(16), children: [ _label('Task Title'), TextFormField( controller: _titleCtrl, decoration: const InputDecoration(hintText: 'Enter task title'), validator: (v) => (v == null || v.isEmpty) ? 'Title is required' : null, ), const SizedBox(height: 16), _label('Status'), Row( children: [ for (final s in ['todo', 'in_progress', 'done']) Expanded(child: Padding( padding: const EdgeInsets.only(right: 6), child: ChoiceChip( label: Text(s == 'in_progress' ? 'Progress' : s.capitalize(), style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: _status == s ? Colors.white : AppColors.textSub)), selected: _status == s, selectedColor: AppColors.primary, onSelected: (_) => setState(() => _status = s), ), )), ], ), const SizedBox(height: 16), _label('Assignee (optional)'), usersAsync.when( loading: () => const LinearProgressIndicator(), error: (_, __) => const Text('Failed to load users'), data: (users) => DropdownButtonFormField( value: _assignedTo, decoration: const InputDecoration(hintText: 'Select user'), items: [ const DropdownMenuItem(value: null, child: Text('Unassigned')), ...users.map((u) => DropdownMenuItem(value: u.id, child: Text(u.username))), ], onChanged: (v) => setState(() => _assignedTo = v), ), ), const SizedBox(height: 16), _label('Deadline (optional)'), GestureDetector( onTap: _pickDate, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration( color: AppColors.surface, border: Border.all(color: AppColors.border), borderRadius: BorderRadius.circular(10), ), child: Row(children: [ const Icon(Icons.calendar_today_outlined, size: 16, color: AppColors.textSub), const SizedBox(width: 10), Text( _dueDate != null ? DateFormat('d MMMM yyyy').format(_dueDate!) : 'Select date', style: TextStyle(color: _dueDate != null ? AppColors.text : AppColors.textSub, fontSize: 14), ), const Spacer(), if (_dueDate != null) GestureDetector( onTap: () => setState(() => _dueDate = null), child: const Icon(Icons.clear, size: 16, color: AppColors.textSub), ), ]), ), ), const SizedBox(height: 32), LoadingButton(loading: _loading, label: isEdit ? 'Save Changes' : 'Create Task', onPressed: _submit), ], ), ), ); } Widget _label(String text) => Padding( padding: const EdgeInsets.only(bottom: 6), child: Text(text, style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.text)), ); } extension on String { String capitalize() => isEmpty ? this : this[0].toUpperCase() + substring(1); }