diff --git a/assets/icons/home_faq_icon.svg b/assets/icons/home_faq_icon.svg
new file mode 100644
index 0000000..b06f6ae
--- /dev/null
+++ b/assets/icons/home_faq_icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/lib/features/agents/presentation/screens/agent_search_screen.dart b/lib/features/agents/presentation/screens/agent_search_screen.dart
index 1615c26..0c64d46 100644
--- a/lib/features/agents/presentation/screens/agent_search_screen.dart
+++ b/lib/features/agents/presentation/screens/agent_search_screen.dart
@@ -8,6 +8,7 @@ import 'package:real_estate_mobile/features/agents/data/models/agent_profile.dar
import 'package:real_estate_mobile/features/agents/data/models/agent_type.dart';
import 'package:real_estate_mobile/features/agents/presentation/providers/search_agents_provider.dart';
import 'package:real_estate_mobile/features/agents/presentation/widgets/agent_filter_sheet.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';
class AgentSearchScreen extends ConsumerStatefulWidget {
@@ -390,14 +391,26 @@ class _AgentSearchScreenState extends ConsumerState {
svgPath: 'assets/icons/nav_messages_icon.svg',
fallbackIcon: Icons.chat_bubble,
isSelected: false,
- onTap: () {},
+ onTap: () {
+ final authState = ref.read(authProvider);
+ if (authState.status != AuthStatus.authenticated) {
+ context.push('/login');
+ return;
+ }
+ },
),
_buildNavItem(
index: 3,
svgPath: 'assets/icons/nav_profile_icon.svg',
fallbackIcon: Icons.person_outline,
isSelected: false,
- onTap: () {},
+ onTap: () {
+ final authState = ref.read(authProvider);
+ if (authState.status != AuthStatus.authenticated) {
+ context.push('/login');
+ return;
+ }
+ },
),
],
),
diff --git a/lib/features/faq/presentation/screens/faq_screen.dart b/lib/features/faq/presentation/screens/faq_screen.dart
new file mode 100644
index 0000000..5e07567
--- /dev/null
+++ b/lib/features/faq/presentation/screens/faq_screen.dart
@@ -0,0 +1,545 @@
+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,
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/features/home/presentation/screens/home_screen.dart b/lib/features/home/presentation/screens/home_screen.dart
index 475f419..87381b8 100644
--- a/lib/features/home/presentation/screens/home_screen.dart
+++ b/lib/features/home/presentation/screens/home_screen.dart
@@ -1,7 +1,9 @@
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/features/auth/presentation/providers/auth_provider.dart';
import 'package:real_estate_mobile/features/home/presentation/widgets/featured_professionals_section.dart';
import 'package:real_estate_mobile/features/home/presentation/widgets/features_section.dart';
import 'package:real_estate_mobile/features/home/presentation/widgets/hero_section.dart';
@@ -10,14 +12,14 @@ import 'package:real_estate_mobile/features/home/presentation/widgets/testimonia
import 'package:real_estate_mobile/features/home/presentation/widgets/top_professionals_section.dart';
import 'package:real_estate_mobile/features/home/presentation/widgets/trust_stats_section.dart';
-class HomeScreen extends StatefulWidget {
+class HomeScreen extends ConsumerStatefulWidget {
const HomeScreen({super.key});
@override
- State createState() => _HomeScreenState();
+ ConsumerState createState() => _HomeScreenState();
}
-class _HomeScreenState extends State {
+class _HomeScreenState extends ConsumerState {
int _selectedIndex = 0;
@override
@@ -148,6 +150,13 @@ class _HomeScreenState extends State {
context.push('/agents/search');
return;
}
+ if (index == 2 || index == 3) {
+ final authState = ref.read(authProvider);
+ if (authState.status != AuthStatus.authenticated) {
+ context.push('/login');
+ return;
+ }
+ }
setState(() => _selectedIndex = index);
},
behavior: HitTestBehavior.opaque,
diff --git a/lib/features/home/presentation/widgets/home_header.dart b/lib/features/home/presentation/widgets/home_header.dart
index cbf0164..7cfabb4 100644
--- a/lib/features/home/presentation/widgets/home_header.dart
+++ b/lib/features/home/presentation/widgets/home_header.dart
@@ -154,7 +154,10 @@ class _MenuDrawer extends ConsumerWidget {
context,
icon: Icons.help_outline,
label: "FAQ's",
- onTap: () => Navigator.pop(context),
+ onTap: () {
+ Navigator.pop(context);
+ context.push('/faq');
+ },
),
_buildMenuItem(
context,
@@ -165,55 +168,128 @@ class _MenuDrawer extends ConsumerWidget {
const SizedBox(height: 16),
const Divider(color: AppColors.divider, height: 1),
const SizedBox(height: 16),
- _buildMenuItem(
- context,
- icon: Icons.person_outline,
- label: 'Account Settings',
- onTap: () => Navigator.pop(context),
- ),
- _buildMenuItem(
- context,
- icon: Icons.notifications_outlined,
- label: 'Notification Settings',
- onTap: () => Navigator.pop(context),
- ),
- const SizedBox(height: 16),
- const Divider(color: AppColors.divider, height: 1),
- const SizedBox(height: 24),
- // Log Out button
- SizedBox(
- width: double.infinity,
- child: OutlinedButton.icon(
- onPressed: () {
- Navigator.pop(context);
- ref.read(authProvider.notifier).logout();
- },
- icon: const Icon(
- Icons.logout,
- color: AppColors.accentOrange,
- size: 20,
- ),
- label: const Text(
- 'Log Out',
- style: TextStyle(
- fontFamily: 'Fractul',
- fontSize: 16,
- fontWeight: FontWeight.w700,
+ if (ref.watch(authProvider).status ==
+ AuthStatus.authenticated) ...[
+ _buildMenuItem(
+ context,
+ icon: Icons.person_outline,
+ label: 'Account Settings',
+ onTap: () => Navigator.pop(context),
+ ),
+ _buildMenuItem(
+ context,
+ icon: Icons.notifications_outlined,
+ label: 'Notification Settings',
+ onTap: () => Navigator.pop(context),
+ ),
+ const SizedBox(height: 16),
+ const Divider(color: AppColors.divider, height: 1),
+ const SizedBox(height: 24),
+ // Log Out button
+ SizedBox(
+ width: double.infinity,
+ child: OutlinedButton.icon(
+ onPressed: () {
+ Navigator.pop(context);
+ ref.read(authProvider.notifier).logout();
+ },
+ icon: const Icon(
+ Icons.logout,
color: AppColors.accentOrange,
+ size: 20,
),
- ),
- style: OutlinedButton.styleFrom(
- padding: const EdgeInsets.symmetric(vertical: 16),
- side: const BorderSide(
- color: AppColors.accentOrange,
- width: 1.5,
+ label: const Text(
+ 'Log Out',
+ style: TextStyle(
+ fontFamily: 'Fractul',
+ fontSize: 16,
+ fontWeight: FontWeight.w700,
+ color: AppColors.accentOrange,
+ ),
),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(15),
+ style: OutlinedButton.styleFrom(
+ padding:
+ const EdgeInsets.symmetric(vertical: 16),
+ side: const BorderSide(
+ color: AppColors.accentOrange,
+ width: 1.5,
+ ),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15),
+ ),
),
),
),
- ),
+ ] else ...[
+ // Login button
+ SizedBox(
+ width: double.infinity,
+ child: ElevatedButton.icon(
+ onPressed: () {
+ Navigator.pop(context);
+ context.push('/login');
+ },
+ icon: const Icon(
+ Icons.login,
+ color: Colors.white,
+ size: 20,
+ ),
+ label: const Text(
+ 'Log In',
+ style: TextStyle(
+ fontFamily: 'Fractul',
+ fontSize: 16,
+ fontWeight: FontWeight.w700,
+ color: Colors.white,
+ ),
+ ),
+ style: ElevatedButton.styleFrom(
+ backgroundColor: AppColors.accentOrange,
+ padding:
+ const EdgeInsets.symmetric(vertical: 16),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15),
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(height: 12),
+ // Sign Up button
+ SizedBox(
+ width: double.infinity,
+ child: OutlinedButton.icon(
+ onPressed: () {
+ Navigator.pop(context);
+ context.push('/signup');
+ },
+ icon: const Icon(
+ Icons.person_add_outlined,
+ color: AppColors.accentOrange,
+ size: 20,
+ ),
+ label: const Text(
+ 'Sign Up',
+ style: TextStyle(
+ fontFamily: 'Fractul',
+ fontSize: 16,
+ fontWeight: FontWeight.w700,
+ color: AppColors.accentOrange,
+ ),
+ ),
+ style: OutlinedButton.styleFrom(
+ padding:
+ const EdgeInsets.symmetric(vertical: 16),
+ side: const BorderSide(
+ color: AppColors.accentOrange,
+ width: 1.5,
+ ),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15),
+ ),
+ ),
+ ),
+ ),
+ ],
],
),
),
diff --git a/lib/routing/app_router.dart b/lib/routing/app_router.dart
index 2b12978..2d28ea2 100644
--- a/lib/routing/app_router.dart
+++ b/lib/routing/app_router.dart
@@ -5,6 +5,7 @@ import 'package:real_estate_mobile/features/auth/presentation/providers/auth_pro
import 'package:real_estate_mobile/features/auth/presentation/screens/login_screen.dart';
import 'package:real_estate_mobile/features/auth/presentation/screens/signup_screen.dart';
import 'package:real_estate_mobile/features/agents/presentation/screens/agent_search_screen.dart';
+import 'package:real_estate_mobile/features/faq/presentation/screens/faq_screen.dart';
import 'package:real_estate_mobile/features/home/presentation/screens/home_screen.dart';
final routerProvider = Provider((ref) {
@@ -18,25 +19,35 @@ final routerProvider = Provider((ref) {
authRefreshNotifier.dispose();
});
+ // Public routes accessible without authentication (matching web middleware)
+ const publicRoutes = ['/home', '/agents/search', '/faq'];
+ const authRoutes = ['/login', '/signup'];
+
return GoRouter(
- initialLocation: '/login',
+ initialLocation: '/home',
refreshListenable: authRefreshNotifier,
redirect: (context, state) {
final authState = ref.read(authProvider);
final isAuthenticated = authState.status == AuthStatus.authenticated;
final isLoading = authState.status == AuthStatus.loading;
- final isAuthRoute = state.matchedLocation == '/login' ||
- state.matchedLocation == '/signup';
+ final location = state.matchedLocation;
+ final isAuthRoute = authRoutes.contains(location);
+ final isPublicRoute = publicRoutes.any(
+ (route) => location == route || location.startsWith('$route/'),
+ );
// While checking auth status, don't redirect
if (isLoading) return null;
- // If authenticated and on auth page, go to home
+ // If authenticated and on auth page (login/signup), go to home
if (isAuthenticated && isAuthRoute) return '/home';
- // If not authenticated and on protected page, go to login
- if (!isAuthenticated && !isAuthRoute) return '/login';
+ // Public routes are always accessible
+ if (isPublicRoute || isAuthRoute) return null;
+
+ // Protected routes require authentication — redirect to login
+ if (!isAuthenticated) return '/login';
return null;
},
@@ -60,6 +71,10 @@ final routerProvider = Provider((ref) {
return AgentSearchScreen(initialQuery: query);
},
),
+ GoRoute(
+ path: '/faq',
+ builder: (context, state) => const FaqScreen(),
+ ),
],
);
});