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:url_launcher/url_launcher.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'; // ── 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()) { Future.microtask(_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); if (state.isLoading) { return const Center( child: CircularProgressIndicator(color: AppColors.accentOrange), ); } return ListView( padding: const EdgeInsets.fromLTRB(0, 8, 0, 30), children: [ // Back button Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 0), child: Align( alignment: Alignment.centerLeft, child: GestureDetector( onTap: () { if (Navigator.of(context).canPop()) { Navigator.of(context).pop(); } else { context.go('/home'); } }, child: Container( width: 36, height: 36, decoration: BoxDecoration( color: AppColors.primaryDark.withValues(alpha: 0.08), shape: BoxShape.circle, ), child: const Icon( Icons.arrow_back_ios_new_rounded, color: AppColors.primaryDark, size: 18, ), ), ), ), ), const SizedBox(height: 12), // 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(), ], ); } } // ── 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 ConsumerWidget { const _StillNeedHelpSection(); @override Widget build(BuildContext context, WidgetRef ref) { 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: () { final authState = ref.read(authProvider); if (authState.status != AuthStatus.authenticated) { context.push('/login'); return; } context.push('/support/chat'); }, ), const SizedBox(height: 12), // Email Support _buildSupportButton( icon: Icons.email_outlined, label: 'Email Support', onTap: () { final uri = Uri( scheme: 'mailto', path: 'support@re-quest.co', queryParameters: { 'subject': 'Support Request', }, ); launchUrl(uri, mode: LaunchMode.externalApplication); }, ), ], ), ], ), ); } 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, ), ), ], ), ), ); } }