/// Page: Model Houses Page /// /// Displays model house library and design requests following html/nha-mau.html. library; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:worker/core/constants/ui_constants.dart'; import 'package:worker/core/router/app_router.dart'; import 'package:worker/core/theme/colors.dart'; /// Model Houses Page /// /// Two tabs: /// 1. Thư viện mẫu - Model house library with 360° views /// 2. Yêu cầu thiết kế - Design requests with status tracking class ModelHousesPage extends ConsumerStatefulWidget { const ModelHousesPage({super.key}); @override ConsumerState createState() => _ModelHousesPageState(); } class _ModelHousesPageState extends ConsumerState with SingleTickerProviderStateMixin { late TabController _tabController; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); } @override void dispose() { _tabController.dispose(); super.dispose(); } void _showInfoDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text( 'Hướng dẫn sử dụng', style: TextStyle(fontWeight: FontWeight.bold), ), content: const SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text('Đây là nội dung hướng dẫn sử dụng cho tính năng Nhà mẫu:'), SizedBox(height: 12), Text( '• Tab "Thư viện Mẫu 360": Là nơi công ty cung cấp các mẫu thiết kế 360° có sẵn để bạn tham khảo.', ), SizedBox(height: 8), Text( '• Tab "Yêu cầu Thiết kế": Là nơi bạn gửi yêu cầu (ticket) để đội ngũ thiết kế của chúng tôi hỗ trợ bạn.', ), SizedBox(height: 8), Text( '• Bấm nút "+" trong tab "Yêu cầu Thiết kế" để tạo một Yêu cầu Thiết kế mới.', ), SizedBox(height: 8), Text( '• Khi yêu cầu hoàn thành, bạn có thể xem link thiết kế 3D trong trang chi tiết yêu cầu.', ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Đóng'), ), ], ), ); } void _createNewRequest() { context.push(RouteNames.designRequestCreate); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.grey50, appBar: AppBar( backgroundColor: AppColors.white, elevation: AppBarSpecs.elevation, leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () => Navigator.of(context).pop(), ), centerTitle: false, title: const Text( 'Nhà mẫu', style: TextStyle( color: Colors.black, fontSize: 20, fontWeight: FontWeight.w600, ), ), actions: [ IconButton( icon: const Icon(Icons.info_outline, color: Colors.black), onPressed: _showInfoDialog, ), const SizedBox(width: AppSpacing.sm), ], bottom: TabBar( controller: _tabController, indicatorColor: AppColors.primaryBlue, indicatorWeight: 3, labelColor: AppColors.primaryBlue, labelStyle: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), unselectedLabelColor: AppColors.grey500, unselectedLabelStyle: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), tabs: const [ Tab(text: 'Thư viện mẫu'), Tab(text: 'Yêu cầu thiết kế'), ], ), ), body: TabBarView( controller: _tabController, children: const [_LibraryTab(), _DesignRequestsTab()], ), floatingActionButton: AnimatedBuilder( animation: _tabController, builder: (context, child) { // Show FAB only on Design Requests tab return _tabController.index == 1 ? FloatingActionButton( onPressed: _createNewRequest, backgroundColor: AppColors.primaryBlue, elevation: 4, child: const Icon( Icons.add, color: AppColors.white, size: 28, ), ) : const SizedBox.shrink(); }, ), ); } } /// Library Tab - Model house 360° library class _LibraryTab extends StatelessWidget { const _LibraryTab(); @override Widget build(BuildContext context) { return ListView( padding: const EdgeInsets.all(20), children: const [ _LibraryCard( imageUrl: 'https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?w=800&h=200&fit=crop', title: 'Căn hộ Studio', date: '15/11/2024', description: 'Thiết kế hiện đại cho căn hộ studio 35m², tối ưu không gian sống với gạch men cao cấp và màu sắc hài hòa.', has360View: true, ), _LibraryCard( imageUrl: 'https://images.unsplash.com/photo-1570129477492-45c003edd2be?w=800&h=200&fit=crop', title: 'Biệt thự Hiện đại', date: '12/11/2024', description: 'Biệt thự 3 tầng với phong cách kiến trúc hiện đại, sử dụng gạch granite và ceramic premium tạo điểm nhấn.', has360View: true, ), _LibraryCard( imageUrl: 'https://images.unsplash.com/photo-1562663474-6cbb3eaa4d14?w=800&h=200&fit=crop', title: 'Nhà phố Tối giản', date: '08/11/2024', description: 'Nhà phố 4x15m với thiết kế tối giản, tận dụng ánh sáng tự nhiên và gạch men màu trung tính.', has360View: true, ), _LibraryCard( imageUrl: 'https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?w=800&h=200&fit=crop', title: 'Chung cư Cao cấp', date: '05/11/2024', description: 'Căn hộ 3PN với nội thất sang trọng, sử dụng gạch marble và ceramic cao cấp nhập khẩu Italy.', has360View: true, ), ], ); } } /// Library Card Widget class _LibraryCard extends StatelessWidget { const _LibraryCard({ required this.imageUrl, required this.title, required this.date, required this.description, this.has360View = false, }); final String imageUrl; final String title; final String date; final String description; final bool has360View; @override Widget build(BuildContext context) { return Card( elevation: 2, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), margin: const EdgeInsets.only(bottom: 20), child: InkWell( onTap: () { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Chức năng xem chi tiết sẽ được triển khai trong phiên bản tiếp theo', ), ), ); }, borderRadius: BorderRadius.circular(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Image with 360 badge Stack( children: [ ClipRRect( borderRadius: const BorderRadius.vertical( top: Radius.circular(12), ), child: CachedNetworkImage( imageUrl: imageUrl, width: double.infinity, height: 200, fit: BoxFit.cover, placeholder: (context, url) => Container( height: 200, color: AppColors.grey100, child: const Center(child: CircularProgressIndicator()), ), errorWidget: (context, url, error) => Container( height: 200, color: AppColors.grey100, child: const Icon( Icons.image_not_supported, size: 48, color: AppColors.grey500, ), ), ), ), if (has360View) Positioned( top: 12, right: 12, child: Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: AppColors.primaryBlue.withValues(alpha: 0.9), borderRadius: BorderRadius.circular(16), ), child: const Text( 'Xem 360°', style: TextStyle( color: AppColors.white, fontSize: 12, fontWeight: FontWeight.w600, ), ), ), ), ], ), // Content Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: AppColors.grey900, ), ), const SizedBox(height: 8), // Date Row( children: [ const Icon( Icons.calendar_today, size: 14, color: AppColors.grey500, ), const SizedBox(width: 6), Text( 'Ngày đăng: $date', style: const TextStyle( fontSize: 14, color: AppColors.grey500, ), ), ], ), const SizedBox(height: 12), // Description Text( description, style: const TextStyle( fontSize: 14, color: AppColors.grey500, height: 1.5, ), ), ], ), ), ], ), ), ); } } /// Design Requests Tab class _DesignRequestsTab extends StatelessWidget { const _DesignRequestsTab(); @override Widget build(BuildContext context) { return ListView( padding: const EdgeInsets.all(20), children: const [ _RequestCard( code: '#YC001', status: DesignRequestStatus.completed, date: '20/10/2024', description: 'Thiết kế nhà phố 3 tầng - Anh Minh (Quận 7)', ), _RequestCard( code: '#YC002', status: DesignRequestStatus.designing, date: '25/10/2024', description: 'Cải tạo căn hộ chung cư - Chị Lan (Quận 2)', ), _RequestCard( code: '#YC003', status: DesignRequestStatus.pending, date: '28/10/2024', description: 'Thiết kế biệt thự 2 tầng - Anh Đức (Bình Dương)', ), _RequestCard( code: '#YC004', status: DesignRequestStatus.pending, date: '01/11/2024', description: 'Thiết kế cửa hàng kinh doanh - Chị Mai (Quận 1)', ), ], ); } } /// Design Request Status enum DesignRequestStatus { pending, designing, completed } /// Request Card Widget class _RequestCard extends StatelessWidget { const _RequestCard({ required this.code, required this.status, required this.date, required this.description, }); final String code; final DesignRequestStatus status; final String date; final String description; Color _getStatusColor() { switch (status) { case DesignRequestStatus.pending: return const Color(0xFFffc107); // Warning yellow case DesignRequestStatus.designing: return const Color(0xFF3730a3); // Indigo case DesignRequestStatus.completed: return const Color(0xFF065f46); // Success green } } Color _getStatusBackgroundColor() { switch (status) { case DesignRequestStatus.pending: return const Color(0xFFfef3c7); // Light yellow case DesignRequestStatus.designing: return const Color(0xFFe0e7ff); // Light indigo case DesignRequestStatus.completed: return const Color(0xFFd1fae5); // Light green } } String _getStatusText() { switch (status) { case DesignRequestStatus.pending: return 'CHỜ TIẾP NHẬN'; case DesignRequestStatus.designing: return 'ĐANG THIẾT KẾ'; case DesignRequestStatus.completed: return 'HOÀN THÀNH'; } } @override Widget build(BuildContext context) { return Card( elevation: 2, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), margin: const EdgeInsets.only(bottom: 16), child: InkWell( onTap: () { context.push( '/model-houses/design-request/${code.replaceAll('#', '')}', ); }, borderRadius: BorderRadius.circular(12), child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header: Code and Status Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Mã yêu cầu: $code', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w700, color: AppColors.grey900, ), ), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: _getStatusBackgroundColor(), borderRadius: BorderRadius.circular(20), ), child: Text( _getStatusText(), style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: _getStatusColor(), ), ), ), ], ), const SizedBox(height: 8), // Date Text( 'Ngày gửi: $date', style: const TextStyle(fontSize: 14, color: AppColors.grey500), ), const SizedBox(height: 8), // Description Text( description, style: const TextStyle(fontSize: 14, color: AppColors.grey900), ), ], ), ), ), ); } }