import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../models/work_order.dart'; import '../providers/work_order_provider.dart'; import '../theme.dart'; import '../l10n/app_localizations.dart'; class WorkOrderDetailPage extends ConsumerStatefulWidget { final String orderId; const WorkOrderDetailPage({super.key, required this.orderId}); @override ConsumerState createState() => _WorkOrderDetailPageState(); } class _WorkOrderDetailPageState extends ConsumerState { @override void initState() { super.initState(); Future.microtask(() { ref.read(workOrderProvider.notifier).getDetail(widget.orderId); }); } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final state = ref.watch(workOrderProvider); final order = state.orders.firstWhere( (o) => o.id == widget.orderId, orElse: () => state.orders.isNotEmpty ? state.orders.first : _mockOrder(context, l10n), ); return Scaffold( backgroundColor: AppColors.background, appBar: AppBar(title: Text(l10n.workOrderDetail)), body: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(context, order, l10n), const SizedBox(height: 20), _buildInfoCard(context, order, l10n), const SizedBox(height: 20), _buildDescriptionCard(context, order, l10n), if (order.images.isNotEmpty) ...[ const SizedBox(height: 20), _buildImagesCard(context, order, l10n), ], const SizedBox(height: 20), _buildTimeline(context, order, l10n), ], ), ), ); } Widget _buildHeader(BuildContext context, WorkOrder order, AppLocalizations l10n) { return Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( gradient: AppGradients.primary, borderRadius: BorderRadius.circular(20), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(20), ), child: Text( order.statusText, style: const TextStyle( color: Colors.white, fontSize: 13, fontWeight: FontWeight.w600, ), ), ), const SizedBox(height: 16), Text( order.title, style: const TextStyle( fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white, ), ), const SizedBox(height: 8), Row( children: [ Icon(Icons.location_on_outlined, size: 16, color: Colors.white.withOpacity(0.8)), const SizedBox(width: 6), Text( order.location ?? l10n.unknownLocation, style: TextStyle( fontSize: 14, color: Colors.white.withOpacity(0.85), ), ), ], ), ], ), ); } Widget _buildInfoCard(BuildContext context, WorkOrder order, AppLocalizations l10n) { return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), ), child: Column( children: [ _buildInfoRow(l10n.workOrderId, order.id, Icons.tag), const Divider(height: 24), _buildInfoRow(l10n.creator, order.creatorName, Icons.person_outline), const Divider(height: 24), _buildInfoRow(l10n.assignee, order.assigneeName ?? l10n.notAssigned, Icons.assignment_ind_outlined), const Divider(height: 24), _buildInfoRow(l10n.category, order.category, Icons.folder_outlined), const Divider(height: 24), _buildInfoRow(l10n.priority, _getPriorityText(context, order.priority), Icons.flag_outlined), const Divider(height: 24), _buildInfoRow( l10n.createTime, '${order.createdAt.month}/${order.createdAt.day} ${order.createdAt.hour.toString().padLeft(2, '0')}:${order.createdAt.minute.toString().padLeft(2, '0')}', Icons.access_time, ), ], ), ); } Widget _buildInfoRow(String label, String value, IconData icon) { return Row( children: [ Icon(icon, size: 18, color: AppColors.primary), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: const TextStyle(fontSize: 12, color: AppColors.textTertiary), ), const SizedBox(height: 2), Text( value, style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w500, color: AppColors.textPrimary, ), ), ], ), ), ], ); } Widget _buildDescriptionCard(BuildContext context, WorkOrder order, AppLocalizations l10n) { return Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.description_outlined, size: 18, color: AppColors.primary), const SizedBox(width: 8), Text( l10n.problemDesc, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), ), ], ), const SizedBox(height: 12), Text( order.description, style: const TextStyle( fontSize: 15, color: AppColors.textSecondary, height: 1.6, ), ), ], ), ); } Widget _buildImagesCard(BuildContext context, WorkOrder order, AppLocalizations l10n) { return Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.image_outlined, size: 18, color: AppColors.primary), const SizedBox(width: 8), Text( l10n.attachments, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), ), ], ), const SizedBox(height: 12), Wrap( spacing: 12, runSpacing: 12, children: order.images.map((img) { return Container( width: 100, height: 100, decoration: BoxDecoration( color: AppColors.background, borderRadius: BorderRadius.circular(12), ), child: const Icon(Icons.image, color: AppColors.textTertiary), ); }).toList(), ), ], ), ); } Widget _buildTimeline(BuildContext context, WorkOrder order, AppLocalizations l10n) { return Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.timeline, size: 18, color: AppColors.primary), const SizedBox(width: 8), Text( l10n.progress, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), ), ], ), const SizedBox(height: 20), _TimelineItem( isFirst: true, isActive: true, title: l10n.workOrderCreated, subtitle: '${order.creatorName} ${l10n.createdWorkOrder}', time: '${order.createdAt.month}/${order.createdAt.day} ${order.createdAt.hour.toString().padLeft(2, '0')}:${order.createdAt.minute.toString().padLeft(2, '0')}', ), if (order.assigneeName != null) _TimelineItem( isActive: true, title: l10n.workOrderAssigned, subtitle: '${l10n.assignee} ${order.assigneeName}', time: '${order.createdAt.month}/${order.createdAt.day} ${(order.createdAt.hour + 1).toString().padLeft(2, '0')}:${order.createdAt.minute.toString().padLeft(2, '0')}', ), if (order.status.index >= 2) _TimelineItem( isActive: true, title: l10n.startProcessing, subtitle: l10n.staffStartedProcessing, time: '${order.createdAt.month}/${order.createdAt.day} ${(order.createdAt.hour + 2).toString().padLeft(2, '0')}:${order.createdAt.minute.toString().padLeft(2, '0')}', ), if (order.completedAt != null) _TimelineItem( isLast: true, isActive: true, title: l10n.workOrderCompleted, subtitle: l10n.workOrderFinished, time: '${order.completedAt!.month}/${order.completedAt!.day} ${order.completedAt!.hour.toString().padLeft(2, '0')}:${order.completedAt!.minute.toString().padLeft(2, '0')}', ), ], ), ); } String _getPriorityText(BuildContext context, String priority) { final l10n = AppLocalizations.of(context)!; switch (priority) { case 'urgent': return l10n.urgent; case 'high': return l10n.high; default: return l10n.normal; } } WorkOrder _mockOrder(BuildContext context, AppLocalizations l10n) { return WorkOrder( id: widget.orderId, title: l10n.unknownWorkOrder, description: l10n.workOrderLoadFailed, status: WorkOrderStatus.pending, creatorName: l10n.system, createdAt: DateTime.now(), priority: 'normal', category: l10n.other, images: [], ); } } class _TimelineItem extends StatelessWidget { final bool isFirst; final bool isLast; final bool isActive; final String title; final String subtitle; final String time; const _TimelineItem({ this.isFirst = false, this.isLast = false, required this.isActive, required this.title, required this.subtitle, required this.time, }); @override Widget build(BuildContext context) { return IntrinsicHeight( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( children: [ if (!isFirst) Container(width: 2, height: 20, color: isActive ? AppColors.primary.withOpacity(0.3) : AppColors.divider), Container( width: 12, height: 12, decoration: BoxDecoration( color: isActive ? AppColors.primary : AppColors.divider, shape: BoxShape.circle, border: Border.all(color: AppColors.surface, width: 2), ), ), if (!isLast) Expanded(child: Container(width: 2, color: isActive ? AppColors.primary.withOpacity(0.3) : AppColors.divider)), ], ), const SizedBox(width: 16), Expanded( child: Padding( padding: EdgeInsets.only(bottom: isLast ? 0 : 24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, color: isActive ? AppColors.textPrimary : AppColors.textTertiary, ), ), const SizedBox(height: 4), Text( subtitle, style: TextStyle( fontSize: 13, color: isActive ? AppColors.textSecondary : AppColors.textTertiary, ), ), const SizedBox(height: 4), Text( time, style: TextStyle( fontSize: 12, color: AppColors.textTertiary, ), ), ], ), ), ), ], ), ); } }