import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:injector/injector.dart'; import 'package:intl/intl.dart'; import 'package:professional_repository/professional_repository.dart'; import 'package:prosappco/blocs/service_bloc/service_bloc.dart'; import 'package:prosappco/screens/service/user_service_screen.dart'; import 'package:service_repository/service_repository.dart'; import 'package:shimmer/shimmer.dart'; import 'package:user_repository/user_repository.dart'; const _kPrimary = Color(0xFF1565C0); extension _Th on BuildContext { ThemeData get _t => Theme.of(this); Color get bg => _t.scaffoldBackgroundColor; Color get card => _t.cardColor; Color get onSurface => _t.colorScheme.onSurface; Color get muted => _t.colorScheme.onSurface.withOpacity(0.55); Color get subtle => _t.colorScheme.onSurface.withOpacity(0.35); bool get isDark => _t.brightness == Brightness.dark; Color get shadowSm => isDark ? Colors.transparent : Colors.black.withOpacity(0.04); } class UserServiceListScreen extends StatefulWidget { const UserServiceListScreen({super.key}); @override State createState() => _UserServiceListScreenState(); } class _UserServiceListScreenState extends State { late final ServiceBloc serviceBloc; @override void initState() { super.initState(); serviceBloc = Injector.appInstance.get(); serviceBloc.add(LoadServicesForUser(ApiUserRepository.currentUserId ?? '')); } @override Widget build(BuildContext context) { return BlocProvider( create: (context) => serviceBloc, child: Scaffold( backgroundColor: context.bg, appBar: AppBar( title: const Text('Mis Servicios'), backgroundColor: _kPrimary, foregroundColor: Colors.white, elevation: 0, ), body: BlocBuilder( builder: (context, serviceState) { if (serviceState is ServicesForUserLoaded) { if (serviceState.services.isEmpty) return _emptyState(context); return ListView.builder( padding: const EdgeInsets.symmetric(vertical: 12), itemCount: serviceState.services.length, itemBuilder: (_, index) { final info = serviceState.services[index]; return _ServiceCard( user: info.user, service: info.service, onTap: () => Navigator.push( context, CupertinoPageRoute( builder: (_) => UserServiceScreen(serviceId: info.service.id!)), ), ); }, ); } return _shimmerList(); }, ), ), ); } } Widget _emptyState(BuildContext context) { final subtle = Theme.of(context).colorScheme.onSurface.withOpacity(0.35); final muted = Theme.of(context).colorScheme.onSurface.withOpacity(0.55); return Center( child: Padding( padding: const EdgeInsets.all(32), child: Column(mainAxisSize: MainAxisSize.min, children: [ Container( width: 72, height: 72, decoration: BoxDecoration( color: subtle.withOpacity(0.1), shape: BoxShape.circle), child: Icon(Icons.list_alt_outlined, size: 36, color: subtle), ), const SizedBox(height: 16), Text('Sin servicios', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w700, color: muted)), const SizedBox(height: 6), Text('Tus servicios activos aparecerán aquí.', textAlign: TextAlign.center, style: TextStyle(fontSize: 13, color: subtle, height: 1.5)), ]), ), ); } Widget _shimmerList() { return Shimmer.fromColors( baseColor: Colors.grey[300]!, highlightColor: Colors.grey[100]!, child: ListView.builder( padding: const EdgeInsets.symmetric(vertical: 12), itemCount: 8, itemBuilder: (_, __) => Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), height: 84, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(14)), ), ), ); } class _ServiceCard extends StatelessWidget { final MyUser user; final ServiceEntity service; final VoidCallback onTap; const _ServiceCard( {required this.user, required this.service, required this.onTap}); @override Widget build(BuildContext context) { final si = _statusInfo(service.status); final dateStr = DateFormat('dd MMM yyyy', 'es').format(DateTime.parse(service.day)); final timeStr = ScheduleEntity.getFormatTime(service.range1Hour1) ?? ''; return Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), decoration: BoxDecoration( color: context.card, borderRadius: BorderRadius.circular(14), boxShadow: [ BoxShadow( color: context.shadowSm, blurRadius: 10, offset: const Offset(0, 2)) ], ), child: ClipRRect( borderRadius: BorderRadius.circular(14), child: InkWell( onTap: onTap, child: IntrinsicHeight( child: Row(children: [ Container(width: 4, color: si.color), Padding( padding: const EdgeInsets.all(12), child: Container( width: 50, height: 50, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: si.color.withOpacity(0.35), width: 2)), child: ClipOval( child: (user.picture == null || user.picture!.isEmpty) ? Container( color: _kPrimary.withOpacity(0.1), child: Center( child: Text( user.name?.isNotEmpty == true ? user.name![0].toUpperCase() : '?', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: _kPrimary), ), ), ) : Image.network(user.picture!, fit: BoxFit.cover), ), ), ), Expanded( child: Padding( padding: const EdgeInsets.symmetric(vertical: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text(user.name ?? '', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w700, color: context.onSurface)), if (service.description.isNotEmpty) ...[ const SizedBox(height: 2), Text('"${service.description}"', style: TextStyle( fontSize: 12, color: context.muted, fontStyle: FontStyle.italic), maxLines: 1, overflow: TextOverflow.ellipsis), ], const SizedBox(height: 5), Row(children: [ Icon(Icons.calendar_today_outlined, size: 11, color: context.subtle), const SizedBox(width: 4), Text('$dateStr · $timeStr', style: TextStyle( fontSize: 11, color: context.muted, fontWeight: FontWeight.w500)), ]), ], ), ), ), Padding( padding: const EdgeInsets.fromLTRB(8, 12, 12, 12), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ _StatusBadge(si: si), const SizedBox(height: 6), Icon(Icons.chevron_right, size: 18, color: context.subtle), ], ), ), ]), ), ), ), ); } } class _StatusBadge extends StatelessWidget { final _StatusInfo si; const _StatusBadge({required this.si}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: si.color.withOpacity(0.1), borderRadius: BorderRadius.circular(20), border: Border.all(color: si.color.withOpacity(0.3)), ), child: Row(mainAxisSize: MainAxisSize.min, children: [ Icon(si.icon, size: 10, color: si.color), const SizedBox(width: 4), Text(si.label, style: TextStyle( fontSize: 10, fontWeight: FontWeight.w700, color: si.color)), ]), ); } } class _StatusInfo { final String label; final Color color; final IconData icon; const _StatusInfo(this.label, this.color, this.icon); } _StatusInfo _statusInfo(ServiceStatus status) { switch (status) { case ServiceStatus.acepted: return const _StatusInfo( 'Aceptado', Color(0xFF1565C0), Icons.check_circle_outline); case ServiceStatus.active: return const _StatusInfo( 'En curso', Color(0xFF16A34A), Icons.play_circle_outline); case ServiceStatus.completed: return const _StatusInfo( 'Completado', Color(0xFF64748B), Icons.task_alt_outlined); case ServiceStatus.denied: return const _StatusInfo( 'Rechazado', Color(0xFFDC2626), Icons.cancel_outlined); case ServiceStatus.cancelled: return const _StatusInfo( 'Cancelado', Color(0xFF9CA3AF), Icons.remove_circle_outline); case ServiceStatus.selfBooked: return const _StatusInfo( 'Reservado', Color(0xFF7C3AED), Icons.bookmark_outline); default: return const _StatusInfo( 'Pendiente', Color(0xFFD97706), Icons.hourglass_top_outlined); } }