import 'package:flutter/material.dart'; import 'package:flux/features/tracking/models/tracking_model.dart'; class TicketTimelineSection extends StatefulWidget { final List logs; final void Function(String message, bool isInternal) onAddNote; const TicketTimelineSection({ super.key, required this.logs, required this.onAddNote, }); @override State createState() => _TicketTimelineSectionState(); } class _TicketTimelineSectionState extends State { final TextEditingController _textController = TextEditingController(); bool _isInternal = true; // Di default blindiamo tutto a uso interno! @override void dispose() { _textController.dispose(); super.dispose(); } void _submitNote() { final text = _textController.text.trim(); if (text.isNotEmpty) { widget.onAddNote(text, _isInternal); _textController.clear(); // Chiudiamo la tastiera se siamo su mobile FocusScope.of(context).unfocus(); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // --- ZONA INPUT --- Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: theme.colorScheme.surfaceContainerHighest.withValues( alpha: 0.3, ), borderRadius: BorderRadius.circular(12), border: Border.all(color: theme.dividerColor), ), child: Column( children: [ Row( children: [ Expanded( child: TextField( controller: _textController, decoration: const InputDecoration( hintText: 'Scrivi un aggiornamento...', border: InputBorder.none, isDense: true, ), textInputAction: TextInputAction.send, onSubmitted: (_) => _submitNote(), ), ), IconButton.filled( onPressed: _submitNote, icon: const Icon(Icons.send, size: 20), tooltip: 'Invia', ), ], ), const Divider(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon( _isInternal ? Icons.lock : Icons.public, size: 16, color: _isInternal ? Colors.amber.shade700 : Colors.green, ), const SizedBox(width: 8), Text( _isInternal ? 'Nota Interna (Privata)' : 'Visibile al Cliente', style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: _isInternal ? Colors.amber.shade700 : Colors.green, ), ), ], ), Switch( value: _isInternal, activeThumbColor: Colors.amber.shade700, activeTrackColor: Colors.amber, inactiveThumbColor: Colors.green, inactiveTrackColor: Colors.green.withValues(alpha: 0.2), onChanged: (val) { setState(() { _isInternal = val; }); }, ), ], ), ], ), ), const SizedBox(height: 24), // --- TIMELINE SCROLLABILE --- if (widget.logs.isEmpty) const Padding( padding: EdgeInsets.all(32.0), child: Center( child: Text( 'Nessun evento registrato.', style: TextStyle(color: Colors.grey), ), ), ) else ConstrainedBox( constraints: const BoxConstraints( maxHeight: 400, ), // Limite di altezza child: ListView.builder( shrinkWrap: true, itemCount: widget.logs.length, itemBuilder: (context, index) { final log = widget.logs[index]; final isLast = index == widget.logs.length - 1; return IntrinsicHeight( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // --- LINEA E PALLINO --- SizedBox( width: 30, child: Column( children: [ Container( margin: const EdgeInsets.only(top: 4), width: 14, height: 14, decoration: BoxDecoration( color: _getEventColor(log.eventType), shape: BoxShape.circle, border: Border.all( color: theme.scaffoldBackgroundColor, width: 2, ), ), ), if (!isLast) Expanded( child: Container( width: 2, color: theme.dividerColor, ), ), ], ), ), // --- CONTENUTO EVENTO --- Expanded( child: Padding( padding: const EdgeInsets.only(bottom: 24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( log.staffName ?? 'Sistema', style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 13, ), ), const SizedBox(width: 8), Text( _formatDate(log.createdAt), style: theme.textTheme.bodySmall?.copyWith( color: Colors.grey, ), ), if (!log.isInternal) ...[ const Spacer(), Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: Colors.green.withValues( alpha: 0.1, ), borderRadius: BorderRadius.circular(4), border: Border.all( color: Colors.green.withValues( alpha: 0.3, ), ), ), child: const Text( "PUBBLICO", style: TextStyle( color: Colors.green, fontSize: 9, fontWeight: FontWeight.bold, ), ), ), ], ], ), const SizedBox(height: 6), Text( log.message, style: const TextStyle(fontSize: 14), ), ], ), ), ), ], ), ); }, ), ), ], ); } Color _getEventColor(TrackingType type) { switch (type) { case TrackingType.statusChange: return Colors.blue; case TrackingType.assignment: return Colors.purple; case TrackingType.systemAlert: return Colors.redAccent; case TrackingType.customerContact: return Colors.teal; case TrackingType.manualNote: // ignore: unreachable_switch_default default: return Colors.amber.shade600; } } String _formatDate(DateTime date) { final day = date.day.toString().padLeft(2, '0'); final month = date.month.toString().padLeft(2, '0'); final hour = date.hour.toString().padLeft(2, '0'); final minute = date.minute.toString().padLeft(2, '0'); return "$day/$month - $hour:$minute"; } }