import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:marco/controller/project_controller.dart'; import 'package:marco/controller/service_project/service_project_details_screen_controller.dart'; import 'package:marco/helpers/utils/launcher_utils.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; class ServiceProjectDetailsScreen extends StatefulWidget { final String projectId; const ServiceProjectDetailsScreen({super.key, required this.projectId}); @override State createState() => _ServiceProjectDetailsScreenState(); } class _ServiceProjectDetailsScreenState extends State with SingleTickerProviderStateMixin { late TabController _tabController; final ServiceProjectDetailsController controller = Get.put(ServiceProjectDetailsController()); @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); controller.setProjectId(widget.projectId); } @override void dispose() { _tabController.dispose(); super.dispose(); } // ---------------- Helper Widgets ---------------- Widget _buildDetailRow({ required IconData icon, required String label, required String value, VoidCallback? onTap, VoidCallback? onLongPress, bool isActionable = false, }) { return Padding( padding: const EdgeInsets.symmetric(vertical: 12), child: InkWell( onTap: isActionable && value != 'NA' ? onTap : null, onLongPress: isActionable && value != 'NA' ? onLongPress : null, borderRadius: BorderRadius.circular(5), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.redAccent.withOpacity(0.1), borderRadius: BorderRadius.circular(5), ), child: Icon(icon, size: 20, color: Colors.redAccent), ), MySpacing.width(16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: TextStyle( fontSize: 12, color: Colors.grey[600], fontWeight: FontWeight.w500, ), ), MySpacing.height(4), Text( value, style: TextStyle( fontSize: 15, color: isActionable && value != 'NA' ? Colors.redAccent : Colors.black87, fontWeight: FontWeight.w500, decoration: isActionable && value != 'NA' ? TextDecoration.underline : TextDecoration.none, ), ), ], ), ), if (isActionable && value != 'NA') Icon(Icons.chevron_right, color: Colors.grey[400], size: 20), ], ), ), ); } Widget _buildSectionCard({ required String title, required IconData titleIcon, required List children, }) { return Card( elevation: 2, shadowColor: Colors.black12, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(titleIcon, size: 20, color: Colors.redAccent), MySpacing.width(8), Text( title, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87), ), ], ), MySpacing.height(8), const Divider(), ...children, ], ), ), ); } String _formatDate(DateTime? date) { if (date == null) return 'NA'; try { return DateFormat('d/M/yyyy').format(date); } catch (_) { return 'NA'; } } Widget _buildProfileTab() { final project = controller.projectDetail.value; if (project == null) return const Center(child: Text("No project data")); return Padding( padding: MySpacing.all(12), child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ // Header Card( elevation: 2, shadowColor: Colors.black12, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5)), child: Padding( padding: const EdgeInsets.all(16), child: Row( children: [ const Icon(Icons.work_outline, size: 45, color: Colors.redAccent), MySpacing.width(16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MyText.titleMedium(project.name, fontWeight: 700), MySpacing.height(6), MyText.bodySmall( project.client?.name ?? 'N/A', fontWeight: 500), ], ), ), ], ), ), ), MySpacing.height(16), // Project Information _buildSectionCard( title: 'Project Information', titleIcon: Icons.info_outline, children: [ _buildDetailRow( icon: Icons.calendar_today_outlined, label: 'Assigned Date', value: _formatDate(project.assignedDate), ), _buildDetailRow( icon: Icons.location_on_outlined, label: 'Address', value: project.address, ), _buildDetailRow( icon: Icons.people_outline, label: 'Contact Name', value: project.contactName, ), _buildDetailRow( icon: Icons.phone_outlined, label: 'Contact Phone', value: project.contactPhone, isActionable: true, onTap: () => LauncherUtils.launchPhone(project.contactPhone), onLongPress: () => LauncherUtils.copyToClipboard( project.contactPhone, typeLabel: 'Phone'), ), _buildDetailRow( icon: Icons.email_outlined, label: 'Contact Email', value: project.contactEmail, isActionable: true, onTap: () => LauncherUtils.launchEmail(project.contactEmail), onLongPress: () => LauncherUtils.copyToClipboard( project.contactEmail, typeLabel: 'Email'), ), ], ), MySpacing.height(12), // Status if (project.status != null) _buildSectionCard( title: 'Status', titleIcon: Icons.flag_outlined, children: [ _buildDetailRow( icon: Icons.info_outline, label: 'Status', value: project.status!.status, ), ], ), // Services if (project.services != null && project.services!.isNotEmpty) _buildSectionCard( title: 'Services', titleIcon: Icons.miscellaneous_services_outlined, children: project.services!.map((service) { return _buildDetailRow( icon: Icons.build_outlined, label: service.name, value: service.description ?? '-', ); }).toList(), ), MySpacing.height(12), // Client Section if (project.client != null) _buildSectionCard( title: 'Client Information', titleIcon: Icons.business_outlined, children: [ _buildDetailRow( icon: Icons.person_outline, label: 'Client Name', value: project.client!.name, ), _buildDetailRow( icon: Icons.phone_outlined, label: 'Client Phone', value: project.client!.contactNumber ?? 'NA', isActionable: true, onTap: () => LauncherUtils.launchPhone( project.client!.contactNumber ?? ''), onLongPress: () => LauncherUtils.copyToClipboard( project.client!.contactNumber ?? '', typeLabel: 'Phone'), ), ], ), MySpacing.height(40), ], ), ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5F5F5), appBar: PreferredSize( preferredSize: const Size.fromHeight(72), child: AppBar( backgroundColor: const Color(0xFFF5F5F5), elevation: 0.5, automaticallyImplyLeading: false, titleSpacing: 0, title: Padding( padding: MySpacing.xy(16, 0), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ IconButton( icon: const Icon(Icons.arrow_back_ios_new, color: Colors.black, size: 20), onPressed: () => Get.toNamed('/dashboard/service-projects'), ), MySpacing.width(8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ MyText.titleLarge( 'Service Projects', fontWeight: 700, color: Colors.black, ), MySpacing.height(2), GetBuilder( builder: (projectController) { final projectName = projectController.selectedProject?.name ?? 'Select Project'; return Row( children: [ const Icon(Icons.work_outline, size: 14, color: Colors.grey), MySpacing.width(4), Expanded( child: MyText.bodySmall( projectName, fontWeight: 600, overflow: TextOverflow.ellipsis, color: Colors.grey[700], ), ), ], ); }, ), ], ), ), ], ), ), ), ), body: Column( children: [ // ---------------- TabBar ---------------- Container( color: Colors.white, child: TabBar( controller: _tabController, labelColor: Colors.black, unselectedLabelColor: Colors.grey, indicatorColor: Colors.red, indicatorWeight: 3, isScrollable: false, tabs: const [ Tab(text: "Profile"), Tab(text: "Jobs"), ], ), ), // ---------------- TabBarView ---------------- Expanded( child: Obx(() { if (controller.isLoading.value) { return const Center(child: CircularProgressIndicator()); } if (controller.errorMessage.value.isNotEmpty) { return Center(child: Text(controller.errorMessage.value)); } return TabBarView( controller: _tabController, children: [ // Profile Tab _buildProfileTab(), // Jobs Tab - empty Container(color: Colors.white), ], ); }), ), ], ), ); } }