import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import '../../core/theme/app_theme.dart'; import '../../core/widgets/status_badge.dart'; import '../../core/widgets/error_view.dart'; import 'contracts_provider.dart'; class ContractDetailScreen extends ConsumerWidget { final int id; const ContractDetailScreen({super.key, required this.id}); @override Widget build(BuildContext context, WidgetRef ref) { final async = ref.watch(contractDetailProvider(id)); return async.when( loading: () => const Scaffold(body: Center(child: CircularProgressIndicator())), error: (e, _) => Scaffold(appBar: AppBar(), body: ErrorView(message: e.toString(), onRetry: () => ref.invalidate(contractDetailProvider(id)))), data: (contract) => Scaffold( appBar: AppBar( title: const Text('Contract Detail'), flexibleSpace: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [AppColors.primary, AppColors.primaryDark], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), ), foregroundColor: Colors.white, actions: [ IconButton( icon: const Icon(Icons.edit_outlined), onPressed: () async { await context.push('/contracts/$id/edit'); ref.invalidate(contractDetailProvider(id)); }, ), ], ), body: ListView( padding: const EdgeInsets.all(16), children: [ // Header card _card(Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(children: [ Expanded(child: Text(contract.title, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w700, color: AppColors.text))), const SizedBox(width: 8), StatusBadge(contract.status), ]), const SizedBox(height: 12), if (contract.companyName != null) _info('Company', contract.companyName!), if (contract.vendorName != null) _info('Vendor', contract.vendorName!), if (contract.predecessors.isNotEmpty) _info('Menggantikan', contract.predecessors.map((p) => p.title).join(', '), color: AppColors.textSub), if (contract.successors.isNotEmpty) _info('Digantikan oleh', contract.successors.map((s) => s.title).join(', '), color: AppColors.primary), if (contract.periodStart != null) _info('Start', DateFormat('d MMMM yyyy').format(contract.periodStart!)), if (contract.periodEnd != null) _info('End', DateFormat('d MMMM yyyy').format(contract.periodEnd!), color: contract.isExpiringSoon ? AppColors.warning : null), if (contract.isExpiringSoon && contract.status == 'Active') Container( margin: const EdgeInsets.only(top: 8), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: AppColors.warningLight, borderRadius: BorderRadius.circular(8), ), child: Row(children: [ const Icon(Icons.warning_amber_rounded, size: 14, color: AppColors.warning), const SizedBox(width: 6), Text('Expires in ${contract.daysUntilExpiry} days', style: const TextStyle(fontSize: 12, color: Color(0xFFB45309), fontWeight: FontWeight.w600)), ]), ), ], )), const SizedBox(height: 12), // AI Analysis (body HTML parsed to sections) if (contract.body != null && contract.body!.isNotEmpty) ...[ const Text('AI Analysis', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w700, color: AppColors.text)), const SizedBox(height: 8), ..._parseAccordionSections(contract.body!).map((s) => _AccordionCard(title: s.$1, body: s.$2)), ], const SizedBox(height: 24), ], ), ), ); } List<(String, String)> _parseAccordionSections(String html) { // Extract h2/h3 sections from HTML final sections = <(String, String)>[]; final sectionTitles = [ 'Ringkasan', 'Harga', 'Jangka Waktu', 'Sanksi', 'Pasal Kritis', ]; // Simple: split by

or

tags final regex = RegExp(r']*>(.*?)(.*?)(?=]*>'), '').trim())]; } for (final m in matches) { final title = m.group(1)?.replaceAll(RegExp(r'<[^>]*>'), '').trim() ?? ''; final body = m.group(2)?.replaceAll(RegExp(r'<[^>]*>'), '').trim() ?? ''; if (title.isNotEmpty) sections.add((title, body)); } if (sections.isEmpty) { for (int i = 0; i < sectionTitles.length; i++) { sections.add((sectionTitles[i], '')); } } return sections; } Widget _card(Widget child) => Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColors.border), ), child: child, ); Widget _info(String label, String value, {Color? color}) => Padding( padding: const EdgeInsets.only(bottom: 8), child: Row(children: [ SizedBox(width: 90, child: Text(label, style: const TextStyle(fontSize: 13, color: AppColors.textSub))), Expanded(child: Text(value, style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: color ?? AppColors.text))), ]), ); } class _AccordionCard extends StatefulWidget { final String title; final String body; const _AccordionCard({required this.title, required this.body}); @override State<_AccordionCard> createState() => _AccordionCardState(); } class _AccordionCardState extends State<_AccordionCard> { bool _expanded = false; @override Widget build(BuildContext context) => Container( margin: const EdgeInsets.only(bottom: 8), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColors.border), ), child: Column( children: [ InkWell( onTap: () => setState(() => _expanded = !_expanded), borderRadius: BorderRadius.circular(12), child: Padding( padding: const EdgeInsets.all(14), child: Row(children: [ Expanded(child: Text(widget.title, style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 14))), Icon(_expanded ? Icons.expand_less : Icons.expand_more, color: AppColors.textSub), ]), ), ), if (_expanded && widget.body.isNotEmpty) Padding( padding: const EdgeInsets.fromLTRB(14, 0, 14, 14), child: Text(widget.body, style: const TextStyle(fontSize: 13, color: AppColors.text, height: 1.5)), ), ], ), ); }