diff --git a/creche_app/lib/features/diary/new_diary_screen.dart b/creche_app/lib/features/diary/new_diary_screen.dart deleted file mode 100644 index b58eb39..0000000 --- a/creche_app/lib/features/diary/new_diary_screen.dart +++ /dev/null @@ -1,392 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; -import 'package:intl/intl.dart'; -import '../../core/auth_provider.dart'; -import '../../models/child.dart'; - -const _bg = Color(0xFF0D1117); -const _card = Color(0xFF161B22); -const _blue = Color(0xFF4FC3F7); -const _green = Color(0xFF2ECC71); -const _amber = Color(0xFFFFB300); -const _red = Color(0xFFE74C3C); - -// OpΓ§Γ΅es de refeiΓ§Γ£o -const _mealOpts = ['bem', 'pouco', 'nao_aceita']; -const _mealLabels = {'bem': '😊 Bem', 'pouco': '😐 Pouco', 'nao_aceita': '😞 NΓ£o aceita'}; -const _hygieneOpts = ['normal', 'diarreia', 'rastoso']; -const _hygieneLabels = {'normal': 'βœ… Normal', 'diarreia': '⚠️ Diarreia', 'rastoso': '😷 Rastoso'}; - -class NewDiaryScreen extends ConsumerStatefulWidget { - final String? childId; - const NewDiaryScreen({super.key, this.childId}); - @override - ConsumerState createState() => _State(); -} - -class _State extends ConsumerState { - final _actCtrl = TextEditingController(); - final _notesCtrl = TextEditingController(); - final _instNotesCtrl = TextEditingController(); // notas da instituiΓ§Γ£o - String? _childId; - List _children = []; - bool _loading = false; - bool _loadingChildren = true; - - // Sono - bool _sleepMorning = false; - bool _sleepAfternoon = false; - - // AlimentaΓ§Γ£o - String _breakfast = ''; - String _lunch = ''; - String _snackMeal = ''; - - // Higiene - int _hygieneFreq = 0; - String _hygieneState = ''; - - @override - void initState() { - super.initState(); - _childId = widget.childId; - _loadChildren(); - } - - @override - void dispose() { - _actCtrl.dispose(); _notesCtrl.dispose(); _instNotesCtrl.dispose(); - super.dispose(); - } - - Future _loadChildren() async { - try { - final sb = Supabase.instance.client; - final data = await sb.from('children').select().order('full_name'); - setState(() { - _children = data.map((d) => Child.fromMap(d)).toList(); - _loadingChildren = false; - }); - } catch (_) { setState(() => _loadingChildren = false); } - } - - Future _save() async { - if (_childId == null) { _snack('Selecciona uma crianΓ§a.'); return; } - if (_actCtrl.text.trim().isEmpty) { _snack('Descreve as actividades do dia.'); return; } - setState(() => _loading = true); - - try { - final sb = Supabase.instance.client; - final profile = await ref.read(currentProfileProvider.future); - if (profile == null) throw Exception('Perfil nΓ£o encontrado'); - final today = DateTime.now().toIso8601String().split('T')[0]; - - // 1. Criar/actualizar diΓ‘rio - final existing = await sb.from('daily_diaries').select('id') - .eq('child_id', _childId!).eq('date', today).maybeSingle(); - - String diaryId; - if (existing != null) { - diaryId = existing['id'] as String; - await sb.from('daily_diaries').update({ - 'activities': _actCtrl.text.trim(), - 'notes': _notesCtrl.text.trim(), - 'institution_notes': _instNotesCtrl.text.trim(), - 'teacher_id': profile.id, - }).eq('id', diaryId); - } else { - final res = await sb.from('daily_diaries').insert({ - 'child_id': _childId, - 'teacher_id': profile.id, - 'date': today, - 'activities': _actCtrl.text.trim(), - 'notes': _notesCtrl.text.trim(), - 'institution_notes': _instNotesCtrl.text.trim(), - }).select('id').single(); - diaryId = res['id'] as String; - } - - // 2. Sono - await sb.from('sleep_records').upsert({ - 'child_id': _childId, - 'diary_id': diaryId, - 'date': today, - 'morning': _sleepMorning, - 'afternoon': _sleepAfternoon, - }, onConflict: 'child_id,date'); - - // 3. AlimentaΓ§Γ£o - if (_breakfast.isNotEmpty || _lunch.isNotEmpty || _snackMeal.isNotEmpty) { - await sb.from('meal_records').upsert({ - 'child_id': _childId, - 'diary_id': diaryId, - 'date': today, - 'breakfast': _breakfast, - 'lunch': _lunch, - 'snack': _snackMeal, - }, onConflict: 'child_id,date'); - } - - // 4. Higiene - if (_hygieneFreq > 0 || _hygieneState.isNotEmpty) { - await sb.from('hygiene_records').upsert({ - 'child_id': _childId, - 'diary_id': diaryId, - 'date': today, - 'frequency': _hygieneFreq, - 'state': _hygieneState, - }, onConflict: 'child_id,date'); - } - - if (mounted) { - _snack('DiΓ‘rio guardado! βœ“', ok: true); - await Future.delayed(const Duration(milliseconds: 600)); - if (mounted) context.pop(); - } - } catch (e) { - _snack('Erro: $e'); - } finally { - if (mounted) setState(() => _loading = false); - } - } - - void _snack(String msg, {bool ok = false}) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(msg, style: const TextStyle(color: Colors.white)), - backgroundColor: ok ? _green : _red, behavior: SnackBarBehavior.floating, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)))); - } - - @override - Widget build(BuildContext context) { - final today = DateFormat('d MMMM yyyy', 'pt_PT').format(DateTime.now()); - - return Scaffold( - backgroundColor: _bg, - appBar: AppBar( - backgroundColor: _card, elevation: 0, - title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('DiΓ‘rio do Dia', style: TextStyle(color: _blue, fontSize: 16, fontWeight: FontWeight.bold)), - Text(today, style: TextStyle(color: Colors.white.withOpacity(0.4), fontSize: 11)), - ]), - actions: [ - TextButton.icon( - icon: _loading ? const SizedBox(width: 16, height: 16, - child: CircularProgressIndicator(color: _blue, strokeWidth: 2)) - : const Icon(Icons.save_outlined, color: _blue, size: 18), - label: const Text('Guardar', style: TextStyle(color: _blue, fontWeight: FontWeight.bold)), - onPressed: _loading ? null : _save, - ), - ], - ), - body: _loadingChildren - ? const Center(child: CircularProgressIndicator(color: _blue)) - : SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column(children: [ - - // ── Seleccionar crianΓ§a ───────────────────────── - _Card(title: 'πŸ‘Ά CrianΓ§a', children: [ - DropdownButtonFormField( - value: _childId, - dropdownColor: _card, - style: const TextStyle(color: Colors.white), - decoration: _dec('Selecciona a crianΓ§a', Icons.child_care), - items: _children.map((c) => DropdownMenuItem( - value: c.id, - child: Text(c.fullName, style: const TextStyle(color: Colors.white)), - )).toList(), - onChanged: (v) => setState(() => _childId = v), - ), - ]), - const SizedBox(height: 12), - - // ── Actividades ───────────────────────────────── - _Card(title: '🎨 Actividades do Dia', children: [ - TextField( - controller: _actCtrl, maxLines: 4, - style: const TextStyle(color: Colors.white, fontSize: 14), - decoration: _dec('Descreve as actividades, brincadeiras, aprendizagens...', Icons.edit_note), - ), - ]), - const SizedBox(height: 12), - - // ── Controlo de Sono ──────────────────────────── - _Card(title: '😴 Controlo de Sono', children: [ - Row(children: [ - Expanded(child: _CheckTile( - label: 'ManhΓ£', value: _sleepMorning, - onChanged: (v) => setState(() => _sleepMorning = v), - )), - const SizedBox(width: 12), - Expanded(child: _CheckTile( - label: 'Tarde', value: _sleepAfternoon, - onChanged: (v) => setState(() => _sleepAfternoon = v), - )), - ]), - ]), - const SizedBox(height: 12), - - // ── AlimentaΓ§Γ£o ───────────────────────────────── - _Card(title: '🍽️ AlimentaΓ§Γ£o', children: [ - _MealRow(label: 'Pequeno AlmoΓ§o', value: _breakfast, - onChanged: (v) => setState(() => _breakfast = v)), - const SizedBox(height: 10), - _MealRow(label: 'AlmoΓ§o', value: _lunch, - onChanged: (v) => setState(() => _lunch = v)), - const SizedBox(height: 10), - _MealRow(label: 'Lanche', value: _snackMeal, - onChanged: (v) => setState(() => _snackMeal = v)), - ]), - const SizedBox(height: 12), - - // ── Higiene/EvacuaΓ§Γ£o ─────────────────────────── - _Card(title: '🚿 Higiene & EvacuaΓ§Γ£o', children: [ - Row(children: [ - const Text('FrequΓͺncia:', style: TextStyle(color: Color(0xFF888888), fontSize: 13)), - const SizedBox(width: 12), - IconButton( - onPressed: () => setState(() => _hygieneFreq = (_hygieneFreq - 1).clamp(0, 20)), - icon: const Icon(Icons.remove_circle_outline, color: _red), - ), - Text('$_hygieneFreq x', - style: const TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)), - IconButton( - onPressed: () => setState(() => _hygieneFreq++), - icon: const Icon(Icons.add_circle_outline, color: _green), - ), - ]), - const SizedBox(height: 10), - const Text('Estado:', style: TextStyle(color: Color(0xFF888888), fontSize: 13)), - const SizedBox(height: 8), - Wrap(spacing: 8, children: _hygieneOpts.map((opt) { - final sel = _hygieneState == opt; - return GestureDetector( - onTap: () => setState(() => _hygieneState = sel ? '' : opt), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7), - decoration: BoxDecoration( - color: sel ? _blue.withOpacity(0.2) : Colors.white.withOpacity(0.05), - borderRadius: BorderRadius.circular(20), - border: Border.all(color: sel ? _blue : Colors.white.withOpacity(0.1)), - ), - child: Text(_hygieneLabels[opt]!, - style: TextStyle(color: sel ? _blue : Colors.white70, fontSize: 13)), - ), - ); - }).toList()), - ]), - const SizedBox(height: 12), - - // ── Notas da Educadora ────────────────────────── - _Card(title: 'πŸ“ Notas da Educadora', children: [ - TextField( - controller: _notesCtrl, maxLines: 3, - style: const TextStyle(color: Colors.white, fontSize: 14), - decoration: _dec('ObservaΓ§Γ΅es, comportamento, necessidades especiais...', Icons.notes), - ), - ]), - const SizedBox(height: 12), - - // ── Notas da InstituiΓ§Γ£o ──────────────────────── - _Card(title: '🏫 Notas da InstituiΓ§Γ£o', children: [ - TextField( - controller: _instNotesCtrl, maxLines: 3, - style: const TextStyle(color: Colors.white, fontSize: 14), - decoration: _dec('Comunicado para o encarregado de educaΓ§Γ£o...', Icons.business_outlined), - ), - ]), - const SizedBox(height: 80), - ]), - ), - floatingActionButton: FloatingActionButton.extended( - backgroundColor: _blue, - onPressed: _loading ? null : _save, - icon: _loading ? const SizedBox(width: 18, height: 18, - child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2)) - : const Icon(Icons.save, color: Colors.white), - label: const Text('Guardar DiΓ‘rio', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)), - ), - ); - } - - InputDecoration _dec(String hint, IconData icon) => InputDecoration( - hintText: hint, hintStyle: const TextStyle(color: Color(0xFF555555), fontSize: 13), - prefixIcon: Icon(icon, color: _blue.withOpacity(0.6), size: 18), - filled: true, fillColor: Colors.white.withOpacity(0.04), - enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), - borderSide: BorderSide(color: Colors.white.withOpacity(0.09))), - focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: _blue, width: 1.5)), - contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), - ); -} - -class _Card extends StatelessWidget { - final String title; final List children; - const _Card({required this.title, required this.children}); - @override - Widget build(BuildContext context) => Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration(color: _card, borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.white.withOpacity(0.07))), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, style: const TextStyle(color: Colors.white, fontSize: 13, fontWeight: FontWeight.bold)), - const SizedBox(height: 12), - ...children, - ]), - ); -} - -class _CheckTile extends StatelessWidget { - final String label; final bool value; final ValueChanged onChanged; - const _CheckTile({required this.label, required this.value, required this.onChanged}); - @override - Widget build(BuildContext context) => GestureDetector( - onTap: () => onChanged(!value), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), - decoration: BoxDecoration( - color: value ? _blue.withOpacity(0.12) : Colors.white.withOpacity(0.04), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: value ? _blue.withOpacity(0.4) : Colors.white.withOpacity(0.09)), - ), - child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(value ? Icons.check_circle : Icons.circle_outlined, - color: value ? _blue : Colors.white38, size: 18), - const SizedBox(width: 8), - Text(label, style: TextStyle(color: value ? _blue : Colors.white60, fontWeight: FontWeight.w500)), - ]), - ), - ); -} - -class _MealRow extends StatelessWidget { - final String label, value; final ValueChanged onChanged; - const _MealRow({required this.label, required this.value, required this.onChanged}); - @override - Widget build(BuildContext context) => Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(label, style: const TextStyle(color: Color(0xFF888888), fontSize: 12)), - const SizedBox(height: 6), - Row(children: _mealOpts.map((opt) { - final sel = value == opt; - Color c = opt == 'bem' ? const Color(0xFF2ECC71) : opt == 'pouco' ? const Color(0xFFFFB300) : const Color(0xFFE74C3C); - return Expanded(child: GestureDetector( - onTap: () => onChanged(sel ? '' : opt), - child: Container( - margin: const EdgeInsets.only(right: 6), - padding: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: sel ? c.withOpacity(0.15) : Colors.white.withOpacity(0.04), - borderRadius: BorderRadius.circular(10), - border: Border.all(color: sel ? c.withOpacity(0.5) : Colors.white.withOpacity(0.08)), - ), - child: Text(_mealLabels[opt]!, textAlign: TextAlign.center, - style: TextStyle(color: sel ? c : Colors.white54, fontSize: 11, fontWeight: FontWeight.w500)), - ), - )); - }).toList()), - ]); -}