import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:go_router/go_router.dart'; import 'package:real_estate_mobile/core/constants/app_colors.dart'; import 'package:real_estate_mobile/core/network/api_client.dart'; import 'package:real_estate_mobile/features/auth/presentation/providers/auth_provider.dart'; import 'package:real_estate_mobile/features/home/presentation/widgets/home_header.dart'; // ── Data models ── class FaqItem { final int id; final String icon; final String question; final String answer; final String category; const FaqItem({ required this.id, required this.icon, required this.question, required this.answer, required this.category, }); factory FaqItem.fromJson(Map json) { return FaqItem( id: json['id'] as int? ?? 0, icon: json['icon'] as String? ?? '', question: json['question'] as String? ?? '', answer: json['answer'] as String? ?? '', category: json['category'] as String? ?? '', ); } } // ── Default data (same as web) ── const _defaultFaqs = [ FaqItem( id: 1, icon: 'assets/icons/home_faq_icon.svg', question: 'How do I update my listing status?', answer: 'To update your listing status, log in to your Agent Dashboard. Locate the property in your "Active Listings" tab, click the three-dot menu on the right, and select "Update Status." You can change it to Pending, Sold, or Temporarily Off Market. Changes are reflected immediately.', category: 'agent', ), FaqItem( id: 2, icon: 'assets/icons/home_faq_icon.svg', question: 'What is the pre-approval process?', answer: 'The pre-approval process involves submitting your financial documents to a lender who will review your credit history, income, assets, and debts. Once approved, you\'ll receive a pre-approval letter stating how much you can borrow, which strengthens your position when making offers on properties.', category: 'buying', ), FaqItem( id: 3, icon: 'assets/icons/home_faq_icon.svg', question: 'How do I schedule an open house?', answer: 'To schedule an open house, navigate to your Agent Dashboard and select the property you want to showcase. Click on "Schedule Open House" and choose your preferred date and time.', category: 'agent', ), FaqItem( id: 4, icon: 'assets/icons/home_faq_icon.svg', question: 'How do I reset my password?', answer: 'To reset your password, click on the "Login" button and then select "Forgot Password." Enter your registered email address and we\'ll send you a password reset link. Follow the link to create a new password.', category: 'platform', ), FaqItem( id: 5, icon: 'assets/icons/home_faq_icon.svg', question: 'How do I contact a listing agent directly?', answer: 'You can contact a listing agent by visiting the property page and clicking the "Contact Agent" button. You\'ll be able to send a message directly to the agent through our secure messaging system.', category: 'buying', ), FaqItem( id: 6, icon: 'assets/icons/home_faq_icon.svg', question: 'What if I find inaccurate data on a listing?', answer: 'If you find inaccurate information on a listing, please use the "Report Issue" button on the property page. Describe the inaccuracy and our team will review and correct it within 24-48 hours.', category: 'platform', ), ]; // ── Provider ── final faqProvider = StateNotifierProvider.autoDispose((ref) { return FaqNotifier(); }); class FaqState { final List faqs; final bool isLoading; final int? expandedId; const FaqState({ this.faqs = const [], this.isLoading = true, this.expandedId, }); FaqState copyWith({ List? faqs, bool? isLoading, int? expandedId, bool clearExpanded = false, }) { return FaqState( faqs: faqs ?? this.faqs, isLoading: isLoading ?? this.isLoading, expandedId: clearExpanded ? null : (expandedId ?? this.expandedId), ); } } class FaqNotifier extends StateNotifier { FaqNotifier() : super(const FaqState()) { _load(); } Future _load() async { try { final response = await ApiClient.instance.dio.get('/cms/page/faq'); final data = response.data['data'] as List?; if (data != null) { for (final record in data) { final map = record as Map; if (map['sectionKey'] == 'faqContent') { final content = map['content'] as Map?; if (content != null) { final faqsList = content['faqs'] as List?; if (faqsList != null && faqsList.isNotEmpty) { final faqs = faqsList .map((e) => FaqItem.fromJson(e as Map)) .toList(); state = state.copyWith( faqs: faqs, isLoading: false, expandedId: faqs.first.id, ); return; } } } } } } catch (_) { // Fall through to defaults } // Use defaults state = state.copyWith( faqs: _defaultFaqs, isLoading: false, expandedId: _defaultFaqs.first.id, ); } void toggleFaq(int id) { if (state.expandedId == id) { state = state.copyWith(clearExpanded: true); } else { state = state.copyWith(expandedId: id); } } } // ── Screen ── class FaqScreen extends ConsumerWidget { const FaqScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final state = ref.watch(faqProvider); return Scaffold( backgroundColor: Colors.white, body: Column( children: [ SafeArea( bottom: false, child: const HomeHeader(), ), Expanded( child: state.isLoading ? const Center( child: CircularProgressIndicator( color: AppColors.accentOrange), ) : ListView( padding: const EdgeInsets.fromLTRB(0, 20, 0, 30), children: [ // Title const Padding( padding: EdgeInsets.symmetric(horizontal: 24), child: Text( 'Frequently Asked Questions ?', style: TextStyle( fontFamily: 'Fractul', fontSize: 24, fontWeight: FontWeight.w700, color: AppColors.primaryDark, ), textAlign: TextAlign.center, ), ), const SizedBox(height: 24), // FAQ items ...state.faqs.map((faq) => _FaqAccordion( faq: faq, isExpanded: state.expandedId == faq.id, onTap: () => ref.read(faqProvider.notifier).toggleFaq(faq.id), )), const SizedBox(height: 30), // Still Need Help section const _StillNeedHelpSection(), ], ), ), ], ), bottomNavigationBar: _buildBottomNavBar(context, ref), ); } Widget _buildBottomNavBar(BuildContext context, WidgetRef ref) { return Container( decoration: const BoxDecoration( color: Colors.white, border: Border( top: BorderSide(color: Color(0xFFE8E8E8), width: 1), ), ), child: SafeArea( top: false, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildNavItem( context: context, svgPath: 'assets/icons/nav_home_icon.svg', fallbackIcon: Icons.home, isSelected: false, onTap: () => context.go('/home'), ), _buildNavItem( context: context, svgPath: 'assets/icons/nav_list_icon.svg', fallbackIcon: Icons.list, isSelected: false, onTap: () => context.push('/agents/search'), ), _buildNavItem( context: context, svgPath: 'assets/icons/nav_messages_icon.svg', fallbackIcon: Icons.chat_bubble, isSelected: false, onTap: () { final authState = ref.read(authProvider); if (authState.status != AuthStatus.authenticated) { context.push('/login'); return; } }, ), _buildNavItem( context: context, svgPath: 'assets/icons/nav_profile_icon.svg', fallbackIcon: Icons.person_outline, isSelected: false, onTap: () { final authState = ref.read(authProvider); if (authState.status != AuthStatus.authenticated) { context.push('/login'); return; } }, ), ], ), ), ), ); } Widget _buildNavItem({ required BuildContext context, required String svgPath, required IconData fallbackIcon, required bool isSelected, required VoidCallback onTap, }) { return GestureDetector( onTap: onTap, behavior: HitTestBehavior.opaque, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: SvgPicture.asset( svgPath, width: 24, height: 24, colorFilter: isSelected ? const ColorFilter.mode(AppColors.primaryDark, BlendMode.srcIn) : const ColorFilter.mode( AppColors.accentOrange, BlendMode.srcIn), placeholderBuilder: (_) => Icon( fallbackIcon, size: 24, color: isSelected ? AppColors.primaryDark : AppColors.accentOrange, ), ), ), ); } } // ── Accordion item ── class _FaqAccordion extends StatelessWidget { final FaqItem faq; final bool isExpanded; final VoidCallback onTap; const _FaqAccordion({ required this.faq, required this.isExpanded, required this.onTap, }); @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(horizontal: 0, vertical: 0), decoration: BoxDecoration( border: Border.all( color: AppColors.primaryDark.withValues(alpha: 0.15), width: 1, ), borderRadius: BorderRadius.circular(7), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Question row GestureDetector( onTap: onTap, behavior: HitTestBehavior.opaque, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 18), child: Row( children: [ // Icon SvgPicture.asset( 'assets/icons/home_faq_icon.svg', width: 22, height: 22, placeholderBuilder: (_) => const Icon( Icons.home_outlined, color: AppColors.accentOrange, size: 22, ), ), const SizedBox(width: 14), // Question text Expanded( child: Text( faq.question, style: TextStyle( fontFamily: isExpanded ? 'Fractul' : 'SourceSerif4', fontSize: 16, fontWeight: isExpanded ? FontWeight.w500 : FontWeight.w600, color: AppColors.primaryDark, ), ), ), const SizedBox(width: 12), // Chevron Icon( isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right, color: AppColors.primaryDark, size: 20, ), ], ), ), ), // Answer (expanded) if (isExpanded) ...[ // Divider Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Divider( height: 1, color: AppColors.primaryDark.withValues(alpha: 0.15), ), ), Padding( padding: const EdgeInsets.fromLTRB(56, 14, 20, 18), child: Text( faq.answer, style: const TextStyle( fontFamily: 'SourceSerif4', fontSize: 14, fontWeight: FontWeight.w400, color: AppColors.primaryDark, height: 1.5, ), ), ), ], ], ), ); } } // ── Still Need Help section ── class _StillNeedHelpSection extends StatelessWidget { const _StillNeedHelpSection(); @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(horizontal: 0), decoration: BoxDecoration( border: Border.all( color: AppColors.primaryDark.withValues(alpha: 0.15), width: 1, ), borderRadius: BorderRadius.circular(7), ), padding: const EdgeInsets.fromLTRB(24, 24, 20, 24), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Left side: text Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Still Need Help ?', style: TextStyle( fontFamily: 'Fractul', fontSize: 14, fontWeight: FontWeight.w700, color: AppColors.primaryDark, ), ), const SizedBox(height: 10), const Text( 'Our Support Team Is Available\nMon-Fri, 9am-6pm IST', style: TextStyle( fontFamily: 'SourceSerif4', fontSize: 14, fontWeight: FontWeight.w400, color: AppColors.primaryDark, height: 1.4, ), ), ], ), ), // Right side: buttons Column( children: [ // Start Live Chat _buildSupportButton( icon: Icons.chat_bubble_outline, label: 'Start Live Chat', onTap: () {}, ), const SizedBox(height: 12), // Email Support _buildSupportButton( icon: Icons.email_outlined, label: 'Email Support', onTap: () {}, ), ], ), ], ), ); } Widget _buildSupportButton({ required IconData icon, required String label, required VoidCallback onTap, }) { return GestureDetector( onTap: onTap, child: Container( width: 162, height: 38, decoration: BoxDecoration( borderRadius: BorderRadius.circular(7), border: Border.all( color: AppColors.primaryDark.withValues(alpha: 0.15), width: 1, ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, size: 18, color: AppColors.primaryDark), const SizedBox(width: 6), Text( label, style: const TextStyle( fontFamily: 'SourceSerif4', fontSize: 14, fontWeight: FontWeight.w400, color: AppColors.primaryDark, ), ), ], ), ), ); } }