Eliminar creche_app/lib/features/diary/new_diary_screen.dart

This commit is contained in:
Alberto 2026-03-11 19:24:54 +00:00
parent 0ec2797511
commit f2f795cf38
1 changed files with 0 additions and 392 deletions

View File

@ -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<NewDiaryScreen> createState() => _State();
}
class _State extends ConsumerState<NewDiaryScreen> {
final _actCtrl = TextEditingController();
final _notesCtrl = TextEditingController();
final _instNotesCtrl = TextEditingController(); // notas da instituição
String? _childId;
List<Child> _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<void> _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<void> _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<String>(
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<Widget> 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<bool> 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<String> 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()),
]);
}