diff --git a/creche_app/lib/features/children/child_detail_screen.dart b/creche_app/lib/features/children/child_detail_screen.dart deleted file mode 100644 index 6af518a..0000000 --- a/creche_app/lib/features/children/child_detail_screen.dart +++ /dev/null @@ -1,592 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:intl/intl.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; -import 'package:uuid/uuid.dart'; -import 'package:go_router/go_router.dart'; -import '/core/supabase_client.dart'; -import '/models/child.dart'; -import '/models/profile.dart'; -import '/shared/widgets/custom_button.dart'; -import '/core/auth_provider.dart'; - -const _bg = Color(0xFF0D1117); -const _card = Color(0xFF161B22); -const _blue = Color(0xFF4FC3F7); -const _green = Color(0xFF2ECC71); -const _red = Color(0xFFE74C3C); -const _amber = Color(0xFFFFB300); - -class ChildDetailScreen extends ConsumerStatefulWidget { - final String id; - const ChildDetailScreen({super.key, required this.id}); - @override - ConsumerState createState() => _State(); -} - -class _State extends ConsumerState with SingleTickerProviderStateMixin { - late TabController _tabs; - Child? _child; - bool _loading = true; - bool _isNew = false; - bool _saving = false; - final _formKey = GlobalKey(); - - // Profile tab - final _firstCtrl = TextEditingController(); - final _lastCtrl = TextEditingController(); - DateTime _birth = DateTime.now().subtract(const Duration(days: 730)); - String? _photoUrl; - String? _classId; - String? _teacherId; - String? _roomId; - - // Health tab - final _allergyCtrl = TextEditingController(); - final _foodRestCtrl = TextEditingController(); - final _medicalNotesCtrl = TextEditingController(); - final List _allergyList = []; - final List _foodRestList = []; - - // Dropdown data from DB - List> _rooms = []; - List _teachers = []; - - @override - void initState() { - super.initState(); - _tabs = TabController(length: 4, vsync: this); - _isNew = widget.id == 'new'; - _loadDropdowns(); - if (!_isNew) _loadChild(); else setState(() => _loading = false); - } - - @override - void dispose() { - _tabs.dispose(); - _firstCtrl.dispose(); _lastCtrl.dispose(); - _allergyCtrl.dispose(); _foodRestCtrl.dispose(); _medicalNotesCtrl.dispose(); - super.dispose(); - } - - Future _loadDropdowns() async { - final sb = ref.read(supabaseProvider); - try { - final rooms = await sb.from('rooms').select().order('name'); - final teachers = await sb.from('profiles').select().inFilter('role', ['teacher','staff']).order('full_name'); - if (mounted) setState(() { - _rooms = List>.from(rooms); - _teachers = teachers.map((t) => Profile.fromMap(t)).toList(); - }); - } catch (_) {} - } - - Future _loadChild() async { - final sb = ref.read(supabaseProvider); - try { - final data = await sb.from('children').select().eq('id', widget.id).single(); - final child = Child.fromMap(data); - setState(() { - _child = child; - _firstCtrl.text = child.firstName; - _lastCtrl.text = child.lastName; - _birth = child.birthDate; - _photoUrl = child.photoUrl; - _classId = child.classId.isEmpty ? null : child.classId; - _teacherId = child.teacherId.isEmpty ? null : child.teacherId; - _roomId = child.roomId; - // Parse allergies - if (child.allergies != null && child.allergies!.isNotEmpty) { - _allergyList.addAll(child.allergies!.split(',').map((s) => s.trim()).where((s) => s.isNotEmpty)); - } - if (child.foodRestrictions != null && child.foodRestrictions!.isNotEmpty) { - _foodRestList.addAll(child.foodRestrictions!.split(',').map((s) => s.trim()).where((s) => s.isNotEmpty)); - } - _loading = false; - }); - } catch (e) { - if (mounted) { _snack('Erro ao carregar: $e'); setState(() => _loading = false); } - } - } - - Future _save() async { - if (!_formKey.currentState!.validate()) return; - setState(() => _saving = true); - final sb = ref.read(supabaseProvider); - try { - final data = { - 'first_name': _firstCtrl.text.trim(), - 'last_name': _lastCtrl.text.trim(), - 'birth_date': _birth.toIso8601String().split('T')[0], - 'photo_url': _photoUrl, - 'class_id': _classId ?? '', - 'teacher_id': _teacherId ?? '', - 'room_id': _roomId, - 'status': 'active', - 'allergies': _allergyList.join(', '), - 'food_restrictions': _foodRestList.join(', '), - }; - if (_isNew) { - await sb.from('children').insert(data); - } else { - await sb.from('children').update(data).eq('id', widget.id); - } - if (mounted) { _snack('Guardado! ✓', ok: true); await Future.delayed(const Duration(milliseconds: 500)); if (mounted) context.go('/children'); } - } catch (e) { if (mounted) _snack('Erro: $e'); } - finally { if (mounted) setState(() => _saving = false); } - } - - Future _pickPhoto() async { - final img = await ImagePicker().pickImage(source: ImageSource.gallery, imageQuality: 70); - if (img == null) return; - final sb = ref.read(supabaseProvider); - final bytes = await img.readAsBytes(); - final path = 'children/${const Uuid().v4()}.jpg'; - await sb.storage.from('photos').uploadBinary(path, bytes); - final url = sb.storage.from('photos').getPublicUrl(path); - setState(() => _photoUrl = url); - } - - 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) { - if (_loading) return const Scaffold(backgroundColor: _bg, body: Center(child: CircularProgressIndicator(color: _blue))); - - return Scaffold( - backgroundColor: _bg, - appBar: AppBar( - backgroundColor: _card, elevation: 0, - title: Text(_isNew ? 'Nova Criança' : (_child?.fullName ?? 'Criança'), - style: const TextStyle(color: _blue, fontWeight: FontWeight.bold)), - bottom: _isNew ? null : TabBar( - controller: _tabs, indicatorColor: _blue, labelColor: _blue, - unselectedLabelColor: Colors.white38, - isScrollable: true, tabAlignment: TabAlignment.start, - tabs: const [Tab(text: 'Perfil'), Tab(text: 'Saúde'), Tab(text: 'Diário'), Tab(text: 'Presença')], - ), - ), - body: _isNew - ? Form(key: _formKey, child: _buildProfileForm()) - : TabBarView(controller: _tabs, children: [ - Form(key: _formKey, child: _buildProfileForm()), - _buildHealthTab(), - _buildDiaryTab(), - _buildAttendanceTab(), - ]), - ); - } - - // ── ABA PERFIL ───────────────────────────────────────────────── - Widget _buildProfileForm() => SingleChildScrollView( - padding: const EdgeInsets.all(18), - child: Column(children: [ - // Foto - Center(child: Stack(children: [ - Container(width: 100, height: 100, - decoration: BoxDecoration(shape: BoxShape.circle, - border: Border.all(color: _blue.withOpacity(0.3), width: 2), - color: _blue.withOpacity(0.08)), - child: _photoUrl != null - ? ClipOval(child: Image.network(_photoUrl!, fit: BoxFit.cover)) - : const Icon(Icons.child_care, size: 50, color: _blue), - ), - Positioned(bottom: 0, right: 0, child: GestureDetector( - onTap: _pickPhoto, - child: Container( - padding: const EdgeInsets.all(7), - decoration: BoxDecoration(color: _blue, shape: BoxShape.circle, - border: Border.all(color: _bg, width: 2)), - child: const Icon(Icons.camera_alt, color: Colors.white, size: 15), - ), - )), - ])), - const SizedBox(height: 22), - _field(_firstCtrl, 'Nome', Icons.person_outline, req: true), - const SizedBox(height: 12), - _field(_lastCtrl, 'Sobrenome', Icons.person, req: true), - const SizedBox(height: 12), - // Data de nascimento - GestureDetector( - onTap: () async { - final d = await showDatePicker(context: context, - initialDate: _birth, firstDate: DateTime(2015), lastDate: DateTime.now(), - builder: (ctx, child) => Theme( - data: ThemeData.dark().copyWith(colorScheme: const ColorScheme.dark(primary: _blue)), - child: child!)); - if (d != null) setState(() => _birth = d); - }, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14), - decoration: BoxDecoration(color: Colors.white.withOpacity(0.04), borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.white.withOpacity(0.09))), - child: Row(children: [ - Icon(Icons.cake, color: _blue.withOpacity(0.7), size: 19), - const SizedBox(width: 12), - Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Data de Nascimento', style: TextStyle(color: Colors.white.withOpacity(0.4), fontSize: 11)), - Text(DateFormat('dd/MM/yyyy').format(_birth), - style: const TextStyle(color: Colors.white, fontSize: 14)), - ]), - const Spacer(), - Icon(Icons.edit_calendar, color: Colors.white.withOpacity(0.2), size: 16), - ]), - ), - ), - const SizedBox(height: 12), - // Sala (do DB) - _dropdown( - value: _roomId, - hint: 'Seleccionar Sala', - icon: Icons.meeting_room_outlined, - items: _rooms.map((r) => DropdownMenuItem( - value: r['id'] as String, - child: Text(r['name'] ?? '', style: const TextStyle(color: Colors.white)))).toList(), - onChanged: (v) => setState(() => _roomId = v), - ), - const SizedBox(height: 12), - // Educadora (do DB) - _dropdown( - value: _teacherId, - hint: 'Seleccionar Educadora', - icon: Icons.supervisor_account_outlined, - items: _teachers.map((t) => DropdownMenuItem( - value: t.id, - child: Text(t.fullName, style: const TextStyle(color: Colors.white)))).toList(), - onChanged: (v) => setState(() => _teacherId = v), - ), - const SizedBox(height: 28), - CustomButton(text: _isNew ? 'Criar Criança' : 'Guardar', isLoading: _saving, - onPressed: _save, icon: Icons.save_outlined), - const SizedBox(height: 20), - ]), - ); - - // ── ABA SAÚDE ────────────────────────────────────────────────── - Widget _buildHealthTab() => SingleChildScrollView( - padding: const EdgeInsets.all(18), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - - _healthCard( - title: '⚠️ Alergias', - color: _red, - chips: _allergyList, - ctrl: _allergyCtrl, - hint: 'Ex: Amendoim, Leite, Glúten...', - onAdd: () { if (_allergyCtrl.text.trim().isNotEmpty) { - setState(() { _allergyList.add(_allergyCtrl.text.trim()); _allergyCtrl.clear(); }); - _saveHealthData(); - }}, - onRemove: (i) { setState(() => _allergyList.removeAt(i)); _saveHealthData(); }, - ), - const SizedBox(height: 14), - - _healthCard( - title: '🚫 Alimentos Não Permitidos', - color: _amber, - chips: _foodRestList, - ctrl: _foodRestCtrl, - hint: 'Ex: Carne de porco, frutos do mar...', - onAdd: () { if (_foodRestCtrl.text.trim().isNotEmpty) { - setState(() { _foodRestList.add(_foodRestCtrl.text.trim()); _foodRestCtrl.clear(); }); - _saveHealthData(); - }}, - onRemove: (i) { setState(() => _foodRestList.removeAt(i)); _saveHealthData(); }, - ), - const SizedBox(height: 14), - - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration(color: _card, borderRadius: BorderRadius.circular(14), - border: Border.all(color: Colors.white.withOpacity(0.07))), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('📋 Observações Médicas', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 13)), - const SizedBox(height: 10), - TextField(controller: _medicalNotesCtrl, maxLines: 4, - style: const TextStyle(color: Colors.white, fontSize: 13), - decoration: InputDecoration( - hintText: 'Condições médicas, medicação habitual, contacto de emergência...', - hintStyle: const TextStyle(color: Color(0xFF555555), fontSize: 12), - filled: true, fillColor: Colors.white.withOpacity(0.04), - border: OutlineInputBorder(borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Colors.white.withOpacity(0.09))), - contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - )), - const SizedBox(height: 10), - CustomButton(text: 'Guardar Observações', onPressed: _saveHealthData, icon: Icons.save_outlined), - ]), - ), - - const SizedBox(height: 14), - // Link para medicação - GestureDetector( - onTap: () => Navigator.push(context, MaterialPageRoute( - builder: (_) => _MedQuickView(childId: widget.id, childName: _child?.fullName ?? ''))), - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: _amber.withOpacity(0.07), - borderRadius: BorderRadius.circular(14), - border: Border.all(color: _amber.withOpacity(0.3)), - ), - child: const Row(children: [ - Icon(Icons.medication, color: _amber), - SizedBox(width: 12), - Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Medicação', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)), - Text('Ver / gerir medicação activa desta criança', style: TextStyle(color: Color(0xFF888888), fontSize: 11)), - ])), - Icon(Icons.chevron_right, color: _amber), - ]), - ), - ), - ]), - ); - - Future _saveHealthData() async { - if (_isNew || widget.id.isEmpty) return; - final sb = ref.read(supabaseProvider); - try { - await sb.from('children').update({ - 'allergies': _allergyList.join(', '), - 'food_restrictions': _foodRestList.join(', '), - }).eq('id', widget.id); - } catch (_) {} - } - - Widget _healthCard({ - required String title, required Color color, - required List chips, required TextEditingController ctrl, - required String hint, required VoidCallback onAdd, required Function(int) onRemove, - }) => Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration(color: _card, borderRadius: BorderRadius.circular(14), - border: Border.all(color: color.withOpacity(0.2))), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, style: TextStyle(color: color, fontWeight: FontWeight.bold, fontSize: 13)), - const SizedBox(height: 10), - if (chips.isEmpty) - Text('Nenhum registo', style: TextStyle(color: Colors.white.withOpacity(0.25), fontSize: 12)) - else - Wrap(spacing: 6, runSpacing: 4, children: chips.asMap().entries.map((e) => - Chip( - label: Text(e.value, style: const TextStyle(color: Colors.white, fontSize: 12)), - backgroundColor: color.withOpacity(0.12), - deleteIconColor: color.withOpacity(0.6), - side: BorderSide(color: color.withOpacity(0.3)), - onDeleted: () => onRemove(e.key), - )).toList()), - const SizedBox(height: 10), - Row(children: [ - Expanded(child: TextField( - controller: ctrl, - style: const TextStyle(color: Colors.white, fontSize: 13), - onSubmitted: (_) => onAdd(), - decoration: InputDecoration( - hintText: hint, hintStyle: const TextStyle(color: Color(0xFF555555), fontSize: 12), - filled: true, fillColor: Colors.white.withOpacity(0.04), - contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - border: OutlineInputBorder(borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Colors.white.withOpacity(0.09))), - ), - )), - const SizedBox(width: 8), - GestureDetector( - onTap: onAdd, - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration(color: color.withOpacity(0.15), shape: BoxShape.circle, - border: Border.all(color: color.withOpacity(0.3))), - child: Icon(Icons.add, color: color, size: 18), - ), - ), - ]), - ]), - ); - - // ── ABA DIÁRIO ───────────────────────────────────────────────── - Widget _buildDiaryTab() { - final sb = ref.read(supabaseProvider); - return FutureBuilder>>( - future: sb.from('daily_diaries').select() - .eq('child_id', widget.id).order('date', ascending: false).limit(20), - builder: (ctx, snap) { - if (!snap.hasData) return const Center(child: CircularProgressIndicator(color: _blue)); - if (snap.data!.isEmpty) return _empty('Sem entradas no diário'); - return ListView.builder( - padding: const EdgeInsets.all(14), - itemCount: snap.data!.length, - itemBuilder: (_, i) { - final d = snap.data![i]; - final date = DateTime.tryParse(d['date'] ?? '') ?? DateTime.now(); - return Container( - margin: const EdgeInsets.only(bottom: 10), - padding: const EdgeInsets.all(14), - decoration: BoxDecoration(color: _card, borderRadius: BorderRadius.circular(14), - border: Border.all(color: Colors.white.withOpacity(0.07))), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row(children: [ - Icon(Icons.book_outlined, color: _blue, size: 16), - const SizedBox(width: 6), - Text(DateFormat('EEEE, d MMM yyyy', 'pt_PT').format(date), - style: const TextStyle(color: _blue, fontWeight: FontWeight.bold, fontSize: 13)), - ]), - if ((d['activities'] ?? '').isNotEmpty) ...[ - const SizedBox(height: 6), - Text(d['activities'], style: const TextStyle(color: Colors.white70, fontSize: 13)), - ], - if ((d['institution_notes'] ?? '').isNotEmpty) ...[ - const SizedBox(height: 6), - Row(children: [ - const Icon(Icons.business_outlined, size: 12, color: _amber), - const SizedBox(width: 4), - Expanded(child: Text(d['institution_notes'], - style: const TextStyle(color: _amber, fontSize: 12))), - ]), - ], - ]), - ); - }, - ); - }, - ); - } - - // ── ABA PRESENÇA ─────────────────────────────────────────────── - Widget _buildAttendanceTab() { - final sb = ref.read(supabaseProvider); - return FutureBuilder>>( - future: sb.from('attendance').select() - .eq('child_id', widget.id).order('date', ascending: false).limit(30), - builder: (ctx, snap) { - if (!snap.hasData) return const Center(child: CircularProgressIndicator(color: _blue)); - if (snap.data!.isEmpty) return _empty('Sem registos de presença'); - return ListView.builder( - padding: const EdgeInsets.all(14), - itemCount: snap.data!.length, - itemBuilder: (_, i) { - final a = snap.data![i]; - final present = a['present'] as bool? ?? false; - final date = DateTime.tryParse(a['date'] ?? '') ?? DateTime.now(); - return Container( - margin: const EdgeInsets.only(bottom: 8), - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - decoration: BoxDecoration(color: _card, borderRadius: BorderRadius.circular(12), - border: Border.all(color: present ? _green.withOpacity(0.2) : _red.withOpacity(0.2))), - child: Row(children: [ - Icon(present ? Icons.check_circle : Icons.cancel, - color: present ? _green : _red, size: 20), - const SizedBox(width: 10), - Text(DateFormat('EEEE, d/MM/yyyy', 'pt_PT').format(date), - style: const TextStyle(color: Colors.white, fontSize: 13)), - const Spacer(), - Text(present ? 'Presente' : 'Ausente', - style: TextStyle(color: present ? _green : _red, fontSize: 12)), - ]), - ); - }, - ); - }, - ); - } - - // ── HELPERS ──────────────────────────────────────────────────── - Widget _field(TextEditingController c, String label, IconData icon, {bool req = false}) => TextFormField( - controller: c, - style: const TextStyle(color: Colors.white, fontSize: 14), - validator: req ? (v) => (v?.trim().isEmpty ?? true) ? 'Obrigatório' : null : null, - decoration: InputDecoration( - labelText: label, labelStyle: TextStyle(color: Colors.white.withOpacity(0.4), fontSize: 13), - prefixIcon: Icon(icon, color: _blue.withOpacity(0.7), size: 19), - 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)), - errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: _red)), - contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14), - ), - ); - - Widget _dropdown({T? value, required String hint, required IconData icon, - required List> items, required ValueChanged onChanged}) => - DropdownButtonFormField( - value: value, dropdownColor: _card, - style: const TextStyle(color: Colors.white, fontSize: 14), - decoration: InputDecoration( - hintText: hint, hintStyle: TextStyle(color: Colors.white.withOpacity(0.3), fontSize: 13), - prefixIcon: Icon(icon, color: _blue.withOpacity(0.7), size: 19), - filled: true, fillColor: Colors.white.withOpacity(0.04), - enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), - borderSide: BorderSide(color: Colors.white.withOpacity(0.09))), - contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14), - ), - items: items, - onChanged: onChanged, - ); - - Widget _empty(String msg) => Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.info_outline, size: 48, color: Colors.white.withOpacity(0.1)), - const SizedBox(height: 10), - Text(msg, style: const TextStyle(color: Color(0xFF888888), fontSize: 13)), - ])); -} - -// ── Quick view medicação ligada à criança ────────────────────────── -class _MedQuickView extends StatelessWidget { - final String childId, childName; - const _MedQuickView({required this.childId, required this.childName}); - - @override - Widget build(BuildContext context) { - final sb = Supabase.instance.client; - return Scaffold( - backgroundColor: _bg, - appBar: AppBar(backgroundColor: _card, elevation: 0, - title: Text('Medicação — $childName', style: const TextStyle(color: _amber, fontSize: 15))), - body: StreamBuilder>>( - stream: sb.from('medications').stream(primaryKey: ['id']).eq('child_id', childId), - builder: (ctx, snap) { - if (!snap.hasData) return const Center(child: CircularProgressIndicator(color: _blue)); - if (snap.data!.isEmpty) return Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Icons.medication_outlined, size: 50, color: Color(0xFF333333)), - const SizedBox(height: 10), - const Text('Sem medicação registada', style: TextStyle(color: Color(0xFF888888))), - ])); - return ListView.builder( - padding: const EdgeInsets.all(14), - itemCount: snap.data!.length, - itemBuilder: (_, i) { - final m = snap.data![i]; - final active = m['active'] as bool? ?? false; - return Container( - margin: const EdgeInsets.only(bottom: 10), - padding: const EdgeInsets.all(14), - decoration: BoxDecoration( - color: _card, borderRadius: BorderRadius.circular(14), - border: Border.all(color: active ? _amber.withOpacity(0.3) : Colors.white.withOpacity(0.06))), - child: Row(children: [ - Icon(Icons.medication, color: active ? _amber : Colors.white38), - const SizedBox(width: 12), - Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(m['medication_name'] ?? '', style: TextStyle( - color: active ? Colors.white : Colors.white38, fontWeight: FontWeight.bold)), - if ((m['dosage'] ?? '').isNotEmpty) - Text(m['dosage'], style: const TextStyle(color: Color(0xFF888888), fontSize: 12)), - ])), - Switch(value: active, activeColor: _amber, - onChanged: (v) => sb.from('medications').update({'active': v}).eq('id', m['id'])), - ]), - ); - }, - ); - }, - ), - ); - } -}