import 'package:decimal/decimal.dart'; import 'package:fintracker_api/fintracker_api.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/utils/ru_date.dart'; import '../portfolio/providers.dart' show scopesProvider; import 'data/goals_api.dart'; /// Create/edit form for a goal. Returns the goal to save, or null when cancelled. class GoalEditDialog extends ConsumerStatefulWidget { const GoalEditDialog({super.key, this.initial}); final Goal? initial; @override ConsumerState createState() => _GoalEditDialogState(); } class _GoalEditDialogState extends ConsumerState { final _formKey = GlobalKey(); late final _name = TextEditingController(text: widget.initial?.name ?? ''); late final _amount = TextEditingController( text: widget.initial?.targetAmount ?? '', ); late final _contribution = TextEditingController( text: widget.initial?.monthlyContribution ?? '', ); late final _note = TextEditingController(text: widget.initial?.note ?? ''); late String _scope = widget.initial?.scope ?? 'all'; late DateTime? _targetDate = widget.initial?.targetDate; late bool _archived = widget.initial?.archived ?? false; @override void dispose() { _name.dispose(); _amount.dispose(); _contribution.dispose(); _note.dispose(); super.dispose(); } String? _decimalValidator(String? v, {bool required = true}) { final text = (v ?? '').trim().replaceAll(',', '.'); if (text.isEmpty) return required ? 'Обязательное поле' : null; return Decimal.tryParse(text) == null ? 'Нужно число' : null; } static String? _decimal(String text) { final normalized = text.trim().replaceAll(',', '.').replaceAll(' ', ''); if (normalized.isEmpty) return null; return Decimal.tryParse(normalized)?.toString(); } @override Widget build(BuildContext context) { final scopes = ref.watch(scopesProvider).valueOrNull ?? const []; return AlertDialog( title: Text(widget.initial == null ? 'Новая цель' : 'Цель'), content: SizedBox( width: 420, child: Form( key: _formKey, child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ TextFormField( controller: _name, decoration: const InputDecoration(labelText: 'Название'), validator: (v) => (v ?? '').trim().isEmpty ? 'Обязательное поле' : null, ), const SizedBox(height: 12), DropdownButtonFormField( initialValue: scopes.any((s) => s.scope == _scope) || _scope == 'all' ? _scope : 'all', decoration: const InputDecoration(labelText: 'Что считаем'), items: [ if (!scopes.any((s) => s.scope == 'all')) const DropdownMenuItem(value: 'all', child: Text('Всё')), for (final s in scopes) DropdownMenuItem(value: s.scope, child: Text(s.name)), ], onChanged: (v) => setState(() => _scope = v ?? 'all'), ), const SizedBox(height: 12), TextFormField( controller: _amount, keyboardType: const TextInputType.numberWithOptions( decimal: true, ), decoration: const InputDecoration( labelText: 'Целевая сумма, ₽', ), validator: _decimalValidator, ), const SizedBox(height: 12), TextFormField( controller: _contribution, keyboardType: const TextInputType.numberWithOptions( decimal: true, ), decoration: const InputDecoration( labelText: 'Ежемесячный взнос, ₽', helperText: 'необязательно', ), validator: (v) => _decimalValidator(v, required: false), ), const SizedBox(height: 12), Row( children: [ Expanded( child: Text( _targetDate == null ? 'Целевая дата не задана' : 'Целевая дата: ${ruDate(_targetDate!)}', ), ), TextButton( onPressed: () async { final now = DateTime.now(); final picked = await showDatePicker( context: context, initialDate: _targetDate ?? DateTime(now.year + 3, now.month, now.day), firstDate: DateTime(now.year - 1), lastDate: DateTime(now.year + 50), ); if (picked != null) setState(() => _targetDate = picked); }, child: const Text('Выбрать'), ), if (_targetDate != null) IconButton( tooltip: 'Убрать дату', icon: const Icon(Icons.clear), onPressed: () => setState(() => _targetDate = null), ), ], ), const SizedBox(height: 12), TextFormField( controller: _note, decoration: const InputDecoration(labelText: 'Заметка'), ), if (widget.initial != null) SwitchListTile( contentPadding: EdgeInsets.zero, title: const Text('В архиве'), value: _archived, onChanged: (v) => setState(() => _archived = v), ), ], ), ), ), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Отмена'), ), FilledButton( onPressed: () { if (!(_formKey.currentState?.validate() ?? false)) return; Navigator.of(context).pop( Goal( id: widget.initial?.id ?? 0, name: _name.text.trim(), scope: _scope, targetAmount: _decimal(_amount.text) ?? '0', currency: widget.initial?.currency ?? 'RUB', targetDate: _targetDate, monthlyContribution: _decimal(_contribution.text), note: _note.text.trim().isEmpty ? null : _note.text.trim(), archived: _archived, ), ); }, child: const Text('Сохранить'), ), ], ); } }