Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/hesabixUI/hesabix_ui/lib/main.dart

5898 lines
266 KiB
Dart
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:go_router/go_router.dart';
import 'core/hesabix_router_pages.dart';
import 'core/business_route_paths.dart';
import 'core/business_nav.dart';
import 'pages/profile/notifications_settings_page.dart';
import 'pages/profile/user_notifications_page.dart';
import 'pages/profile/notification_history_page.dart';
import 'pages/profile/notification_templates_admin_page.dart';
import 'pages/profile/notification_event_types_admin_page.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
import 'l10n/app_localizations.dart';
import 'config/brand_config.dart';
import 'pages/login_page.dart';
import 'pages/profile/profile_shell.dart';
import 'pages/profile/profile_dashboard_page.dart';
import 'pages/profile/new_business_page.dart';
import 'pages/profile/businesses_page.dart';
import 'pages/profile/user_signature_page.dart';
import 'pages/profile/support_page.dart';
import 'pages/profile/support_ticket_detail_page.dart';
import 'pages/profile/create_ticket_page.dart';
import 'pages/profile/change_password_page.dart';
import 'pages/profile/api_keys_page.dart';
import 'pages/profile/sessions_page.dart';
import 'pages/profile/marketing_page.dart';
import 'pages/profile/account_settings_page.dart';
import 'pages/profile/biometric_lock_settings_page.dart';
import 'pages/profile/android_update_settings_page.dart';
import 'pages/profile/windows_update_settings_page.dart';
import 'pages/profile/appearance_settings_page.dart';
import 'pages/profile/verification_page.dart';
import 'pages/profile/operator/operator_tickets_page.dart';
import 'widgets/support/operator_inbox_list.dart';
import 'pages/profile/operator/operator_dashboard_page.dart';
import 'pages/profile/announcements_page.dart';
import 'pages/system_settings_page.dart';
import 'pages/admin/storage_management_page.dart';
import 'pages/admin/system_configuration_page.dart';
import 'pages/admin/user_management_page.dart';
import 'pages/admin/system_reports/system_reports_hub_page.dart';
import 'pages/admin/system_reports/active_users_stats_report_page.dart';
import 'pages/admin/system_reports/signups_timeline_report_page.dart';
import 'pages/admin/email_settings_page.dart';
import 'pages/admin/redis_settings_page.dart';
import 'pages/admin/firewall_admin_page.dart';
import 'pages/admin/system_monitoring_page.dart';
import 'pages/admin/service_logs_page.dart';
import 'pages/admin/business_activity_logs_admin_page.dart';
import 'pages/admin/database_backup_page.dart';
import 'pages/admin/legacy_database_import_page.dart';
import 'pages/admin/system_scripts_page.dart';
import 'pages/admin/announcements_admin_page.dart';
import 'pages/admin/businesses_list_page.dart';
import 'pages/admin/support_operators_page.dart';
import 'pages/admin/notification_moderation_queue_page.dart';
import 'pages/admin/notification_sms_pricing_page.dart';
import 'pages/business/business_shell.dart';
import 'pages/business/dashboard/business_dashboard_page.dart';
import 'pages/business/users_permissions_page.dart';
import 'pages/business/accounts_page.dart';
import 'pages/business/bank_accounts_page.dart';
import 'pages/business/wallet_page.dart';
import 'pages/business/wallet_payment_result_page.dart';
import 'pages/admin/wallet_settings_page.dart';
import 'pages/admin/currencies_admin_page.dart';
import 'pages/admin/fx_providers_admin_page.dart';
import 'pages/admin/payment_gateways_page.dart';
import 'pages/admin/storage_plans_admin_page.dart';
import 'pages/admin/support_plans_admin_page.dart';
import 'pages/admin/support_billing_stats_admin_page.dart';
import 'pages/profile/support_billing_page.dart';
import 'pages/admin/document_monetization_page.dart';
import 'pages/admin/share_link_settings_page.dart';
import 'pages/admin/marketplace_plugins_admin_page.dart';
import 'pages/admin/wallet_payouts_admin_page.dart';
import 'pages/business/invoices_list_page.dart';
import 'pages/business/tax_workspace_page.dart';
import 'pages/business/new_invoice_page.dart';
import 'pages/business/edit_invoice_page.dart';
import 'pages/business/settings_page.dart';
import 'pages/business/business_info_settings_page.dart';
import 'pages/business/business_currencies_settings_page.dart';
import 'pages/business/fx_revaluation_settings_page.dart';
import 'pages/business/fx_auto_sync_settings_page.dart';
import 'pages/business/period_end_fx_revaluation_page.dart';
import 'pages/business/reports_page.dart';
import 'pages/business/kardex_page.dart';
import 'pages/business/debtors_report_page.dart';
import 'pages/business/creditors_report_page.dart';
import 'pages/business/ar_aging_report_page.dart';
import 'pages/business/ap_aging_report_page.dart';
import 'pages/business/person_balances_by_currency_report_page.dart';
import 'pages/business/cash_flow_report_page.dart';
import 'pages/business/fx_revaluation_report_page.dart';
import 'pages/business/people_transactions_report_page.dart';
import 'pages/business/item_movements_report_page.dart';
import 'pages/business/sales_by_product_report_page.dart';
import 'pages/business/inventory_kardex_report_page.dart';
import 'pages/business/inventory_stock_report_page.dart';
import 'pages/business/stock_count_report_page.dart';
import 'pages/business/warehouse_documents_summary_report_page.dart';
import 'pages/business/slow_moving_items_report_page.dart';
import 'pages/business/critical_stock_report_page.dart';
import 'pages/business/inter_warehouse_transfers_report_page.dart';
import 'pages/business/adjustment_documents_report_page.dart';
import 'pages/business/warehouse_performance_report_page.dart';
import 'pages/business/product_movement_history_report_page.dart';
import 'pages/business/inventory_valuation_report_page.dart';
import 'pages/business/pending_documents_report_page.dart';
import 'pages/business/inventory_turnover_report_page.dart';
import 'pages/business/bank_accounts_turnover_report_page.dart';
import 'pages/business/cash_petty_turnover_report_page.dart';
import 'pages/business/activity_logs_page.dart';
import 'pages/business/basalam_reports_pages.dart';
import 'pages/business/woocommerce_reports_pages.dart';
import 'pages/business/daily_sales_report_page.dart';
import 'pages/business/distribution_reports_dashboard_page.dart';
import 'pages/business/monthly_sales_report_page.dart';
import 'pages/business/top_customers_report_page.dart';
import 'pages/business/daily_purchases_report_page.dart';
import 'pages/business/top_suppliers_report_page.dart';
import 'pages/business/materials_consumption_report_page.dart';
import 'pages/business/production_report_page.dart';
import 'pages/business/trial_balance_report_page.dart';
import 'pages/business/balance_sheet_report_page.dart';
import 'pages/business/financial_reports_package_page.dart';
import 'pages/business/general_ledger_report_page.dart';
import 'utils/financial_report_navigation.dart';
import 'pages/business/journal_ledger_report_page.dart';
import 'pages/business/pnl_period_report_page.dart';
import 'pages/business/pnl_cumulative_report_page.dart';
import 'pages/business/account_review_report_page.dart';
import 'pages/business/persons_page.dart';
import 'pages/business/product_attributes_page.dart';
import 'pages/business/product_bundles_page.dart';
import 'pages/business/catalog_spec_fields_page.dart';
import 'pages/business/products_page.dart';
import 'pages/business/product_bulk_prices_sheet_page.dart';
import 'pages/business/projects_page.dart';
import 'pages/business/warranty_management_page.dart';
import 'pages/business/warranty_settings_page.dart';
import 'pages/business/repair_shop/repair_orders_list_page.dart';
import 'pages/business/repair_shop/repair_order_form_page.dart';
import 'pages/business/repair_shop/repair_order_detail_page.dart';
import 'pages/business/repair_shop/repair_technicians_page.dart';
import 'pages/business/repair_shop/repair_settings_page.dart';
import 'pages/business/customer_club/customer_club_main_page.dart';
import 'pages/business/customer_club/customer_club_settings_page.dart';
import 'pages/business/payroll/payroll_main_page.dart';
import 'pages/business/payroll/payroll_reports_page.dart';
import 'pages/business/payroll/payroll_run_edit_page.dart';
import 'pages/business/payroll/payroll_settings_page.dart';
import 'pages/business/telephony/telephony_hub_page.dart';
import 'pages/business/telephony/telephony_live_dashboard_page.dart';
import 'pages/business/telephony/telephony_reports_page.dart';
import 'pages/business/telephony/telephony_softphone_page.dart';
import 'pages/business/distribution/distribution_main_page.dart';
import 'widgets/marketplace/distribution_plugin_gate.dart';
import 'widgets/marketplace/payroll_plugin_gate.dart';
import 'widgets/marketplace/telephony_plugin_gate.dart';
import 'widgets/marketplace/barcode_label_plugin_gate.dart';
import 'pages/business/barcode_labels/label_templates_page.dart';
import 'pages/business/barcode_labels/label_studio_page.dart';
import 'pages/business/barcode_labels/label_printers_page.dart';
import 'pages/business/basalam/basalam_integration_page.dart';
import 'pages/business/basalam/basalam_settings_page.dart';
import 'pages/business/woocommerce/woocommerce_integration_page.dart';
import 'pages/business/woocommerce/woocommerce_opening_inventory_bridge_page.dart';
import 'pages/business/woocommerce/woocommerce_settings_page.dart';
import 'pages/business/notification_templates_page.dart';
import 'pages/business/notification_template_form_page.dart';
import 'pages/public/public_warranty_activation_page.dart';
import 'pages/public/public_warranty_tracking_page.dart';
import 'pages/business/price_lists_page.dart';
import 'pages/business/price_list_items_page.dart';
import 'pages/business/cash_registers_page.dart';
import 'pages/business/petty_cash_page.dart';
import 'pages/business/loan_facilities_page.dart';
import 'pages/business/checks_page.dart';
import 'pages/business/plugin_marketplace_page.dart';
import 'pages/business/marketplace_invoices_page.dart';
import 'pages/business/check_form_page.dart';
import 'pages/business/check_reconciliation_page.dart';
import 'pages/business/receipts_payments_list_page.dart';
import 'pages/business/expense_income_list_page.dart';
import 'pages/business/transfers_page.dart';
import 'pages/business/documents_page.dart';
import 'pages/business/warehouses_page.dart';
import 'pages/business/warehouse_locations_page.dart';
import 'pages/warehouse/warehouse_docs_page.dart';
import 'pages/warehouse/warehouse_document_details_page.dart';
import 'pages/warehouse/stock_count_page.dart';
import 'pages/warehouse/quick_sales_stock_discrepancies_page.dart';
import 'pages/warehouse/goods_expense_income_list_page.dart';
import 'pages/business/installments_report_page.dart';
import 'pages/business/credit_settings_page.dart';
import 'pages/business/business_ai_provider_settings_page.dart';
import 'pages/business/quick_sales_settings_page.dart';
import 'pages/business/quick_sales_page.dart';
import 'pages/business/document_numbering_settings_page.dart';
import 'pages/business/print_settings_page.dart';
import 'pages/business/invoice_share_payment_settings_page.dart';
import 'pages/business/tax_settings_page.dart';
import 'pages/business/fiscal_year_settings_page.dart';
import 'pages/business/installment_plans_page.dart';
import 'pages/error_404_page.dart';
import 'core/app_init_progress.dart';
import 'core/locale_controller.dart';
import 'core/calendar_controller.dart';
import 'core/api_client.dart';
import 'theme/theme_controller.dart';
import 'theme/app_theme.dart';
import 'core/auth_store.dart';
import 'core/mobile_launcher_prefs.dart';
import 'core/mobile_launcher_nav.dart';
import 'core/hesabix_back.dart';
import 'core/biometric_lock_controller.dart';
import 'core/biometric_platform.dart';
import 'core/android_update_platform.dart';
import 'core/windows_update_platform.dart';
import 'widgets/biometric/biometric_lock_gate.dart';
import 'widgets/android_update/android_update_gate.dart';
import 'widgets/windows_update/windows_update_gate.dart';
import 'widgets/notification/in_app_notifications_bootstrap.dart';
import 'widgets/sms_bank/sms_bank_bootstrap.dart';
import 'services/sms_bank/sms_bank_launch_navigation.dart';
import 'pages/business/sms_bank_assistant_settings_page.dart';
import 'core/permission_guard.dart';
import 'core/keyboard_shortcut_listener.dart';
import 'core/route_registry.dart';
import 'widgets/progress_splash_screen.dart';
import 'widgets/url_tracker.dart';
import 'widgets/user_activity_heartbeat.dart';
import 'utils/responsive_helper.dart';
import 'utils/route_prefetcher.dart';
import 'utils/web/web_utils.dart';
import 'pages/business/opening_balance_page.dart';
import 'pages/business/year_end_closing_page.dart';
import 'pages/business/currency_revaluation_page.dart';
import 'pages/business/report_templates_page.dart';
import 'pages/business/report_template_studio_page.dart';
import 'pages/business/report_template_html_editor_page.dart';
import 'pages/business/hscript/hscript_reports_page.dart';
import 'pages/business/hscript/hscript_run_page.dart';
import 'pages/business/hscript/hscript_studio_page.dart';
import 'pages/business/storage_files_page.dart';
import 'pages/business/storage_file_manager_page.dart';
import 'pages/business/document_monetization_page.dart';
import 'pages/business/backup/backup_page.dart';
import 'pages/business/backup/business_ftp_backup_settings_page.dart';
import 'pages/business/backup/restore_page.dart';
import 'pages/mobile_launcher/mobile_launcher_page.dart';
import 'pages/mobile_launcher/mobile_launcher_shell.dart';
import 'pages/mobile_launcher/mobile_launcher_appearance_page.dart';
import 'pages/profile/delete_business_page.dart';
import 'pages/business/fiscal_year_rollback_page.dart';
import 'pages/public/public_person_share_link_page.dart';
import 'pages/public/public_invoice_share_link_page.dart';
import 'pages/public/public_storage_file_share_page.dart';
import 'pages/admin/ai_settings_page.dart';
import 'pages/admin/ai_plans_admin_page.dart';
import 'pages/admin/ai_models_admin_page.dart';
import 'pages/admin/ai_voice_models_admin_page.dart';
import 'pages/admin/ai_provider_credentials_admin_page.dart';
import 'pages/admin/ai_prompts_admin_page.dart';
import 'pages/admin/ai_skills_admin_page.dart';
import 'pages/admin/ai_marketplace_settings_page.dart';
import 'pages/admin/ai_eval_admin_page.dart';
import 'pages/admin/tax_product_codes_page.dart';
import 'pages/admin/zohal_settings_page.dart';
import 'pages/admin/zohal_services_admin_page.dart';
import 'pages/admin/zohal_statistics_page.dart';
import 'pages/business/ai_chat_page.dart';
import 'pages/business/ai_subscription_page.dart';
import 'pages/business/ai_usage_page.dart';
import 'pages/business/zohal_inquiries_page.dart';
import 'pages/business/workflows_page.dart';
import 'pages/business/workflow_marketplace_page.dart';
import 'pages/business/ai_skills_marketplace_page.dart';
import 'pages/business/ai_skills_publisher_revenue_page.dart';
import 'pages/business/workflow_visual_editor_page.dart';
import 'pages/business/crm/crm_dashboard_page.dart';
import 'pages/business/crm/crm_process_definitions_page.dart';
import 'pages/business/crm/crm_leads_page.dart';
import 'pages/business/crm/crm_deals_page.dart';
import 'pages/business/crm/crm_activities_page.dart';
import 'pages/business/crm/crm_reports_page.dart';
import 'pages/business/crm/crm_tasks_page.dart';
import 'pages/business/crm/crm_customer_360_page.dart';
import 'pages/business/crm/crm_sequences_page.dart';
import 'pages/business/crm/crm_notes_calendar_page.dart';
import 'pages/business/crm/crm_web_chat_page.dart';
import 'pages/business/crm/business_crm_settings_page.dart';
import 'pages/business/crm/crm_lead_record_page.dart';
import 'pages/business/crm/crm_deal_record_page.dart';
import 'widgets/windows_close/windows_close_confirm_gate.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
WindowsCloseConfirmGate.installPlatformHandler();
// Use path-based routing instead of hash routing
usePathUrlStrategy();
// با push/replace؛ آدرس مرورگر باید آخرین صفحهٔ پشته را نشان دهد؛ وگرنه URL روی مسیر قبلی می‌ماند و دکمهٔ بازگشت درست عمل نمی‌کند.
GoRouter.optionURLReflectsImperativeAPIs = true;
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
// Global navigator key for accessing Navigator from anywhere
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
/// Route observer for pages that need to react when they become visible again (e.g. list refresh on return).
final RouteObserver<ModalRoute<void>> routeObserver =
RouteObserver<ModalRoute<void>>();
class _MyAppState extends State<MyApp> {
LocaleController? _controller;
CalendarController? _calendarController;
ThemeController? _themeController;
AuthStore? _authStore;
GoRouter? _router;
final BiometricLockController _biometricLockController =
BiometricLockController();
bool _isLoading = true;
DateTime? _loadStartTime;
AppInitProgress _initProgress = const AppInitProgress.initial();
void _reportInitProgress(AppInitPhase phase, {double? progress}) {
final value = progress ?? phase.endProgress;
final snapshot = AppInitProgress(phase: phase, progress: value);
if (!mounted) return;
setState(() => _initProgress = snapshot);
if (kIsWeb) {
notifyWebInitProgress(
initProgress: value,
currentStep: snapshot.webCurrentStep,
totalSteps: snapshot.webTotalSteps,
statusKey: phase.statusKey,
);
}
}
String _initStatusMessage(AppLocalizations t, AppInitPhase phase) {
switch (phase.statusKey) {
case 'loadingLanguageSettings':
return t.loadingLanguageSettings;
case 'loadingCalendarSettings':
return t.loadingCalendarSettings;
case 'loadingThemeSettings':
return t.loadingThemeSettings;
case 'loadingAuthentication':
return t.loadingAuthentication;
case 'initializing':
return t.initializing;
default:
return t.loading;
}
}
@override
void dispose() {
_router?.dispose();
_biometricLockController.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
_loadStartTime = DateTime.now();
_loadControllers();
}
Future<void> _loadControllers() async {
_reportInitProgress(AppInitPhase.language, progress: 0);
final localeController = await LocaleController.load();
if (!mounted) return;
setState(() => _controller = localeController);
_reportInitProgress(AppInitPhase.language);
final calendarController = await CalendarController.load();
if (!mounted) return;
setState(() => _calendarController = calendarController);
_reportInitProgress(AppInitPhase.calendar);
final themeController = ThemeController();
await themeController.load();
if (!mounted) return;
setState(() => _themeController = themeController);
_reportInitProgress(AppInitPhase.theme);
final authStore = AuthStore();
ApiClient.bindAuthStore(authStore);
await authStore.load();
if (!mounted) return;
// پس از در دسترس بودن کلید API، تم ذخیره‌شده کاربر را هم‌گام کن
if (authStore.apiKey != null && authStore.apiKey!.isNotEmpty) {
await themeController.syncFromServerAfterLogin();
}
if (!mounted) return;
setState(() => _authStore = authStore);
_reportInitProgress(AppInitPhase.auth);
_reportInitProgress(
AppInitPhase.finalizing,
progress: AppInitPhase.auth.endProgress,
);
// اضافه کردن listeners
_controller!.addListener(() {
ApiClient.setCurrentLocale(_controller!.locale);
setState(() {});
});
_calendarController!.addListener(() {
setState(() {});
});
_themeController!.addListener(() {
setState(() {});
});
String? lastThemeSyncApiKey = _authStore!.apiKey;
_authStore!.addListener(() {
final key = _authStore!.apiKey;
if (key != null && key.isNotEmpty && key != lastThemeSyncApiKey) {
lastThemeSyncApiKey = key;
unawaited(_themeController!.syncFromServerAfterLogin());
} else if (key == null || key.isEmpty) {
lastThemeSyncApiKey = null;
}
});
// AuthStore changes must NOT call setState here: that rebuilt MyApp and
// recreated GoRouter (resetting Android navigation to / → user dashboard).
// GoRouter.refreshListenable handles login/logout redirects instead.
// تنظیم API Client
ApiClient.setCurrentLocale(_controller!.locale);
ApiClient.bindCalendarController(_calendarController!);
ApiClient.bindAuthStore(_authStore!);
// Preload تمام صفحات برای جلوگیری از تاخیر در navigation
// این کار باعث می‌شود کد تمام صفحات در bundle اصلی قرار گیرد
// استفاده از Route Registry برای preload خودکار صفحات
_preloadPages(
authStore,
localeController,
calendarController,
themeController,
);
// همچنین صفحات از Route Registry را preload کن
RouteRegistry().preloadAll();
// اطمینان از حداقل نمایش splash — روی وب HTML loader کافی است
if (!kIsWeb) {
final elapsed = DateTime.now().difference(_loadStartTime!);
const minimumDuration = Duration(seconds: 1);
if (elapsed < minimumDuration) {
await Future.delayed(minimumDuration - elapsed);
}
}
_reportInitProgress(AppInitPhase.finalizing, progress: 0.95);
// ذخیره URL فعلی قبل از اتمام loading
if (_authStore != null) {
try {
final currentUrl = Uri.base.path;
if (currentUrl.isNotEmpty &&
currentUrl != '/' &&
currentUrl != '/login' &&
(currentUrl.startsWith('/user/profile/') ||
currentUrl.startsWith('/business/') ||
currentUrl.startsWith('/mobile-launcher/'))) {
await _authStore!.saveLastUrl(currentUrl);
}
} catch (e) {
// صرفاً لاگ برای خطای غیر بحرانی ذخیره آدرس - ignore error
debugPrint('Error saving URL: $e');
}
}
// اتمام loading
if (mounted) {
_reportInitProgress(AppInitPhase.finalizing, progress: 1);
setState(() {
_isLoading = false;
});
if (kIsWeb) {
notifyWebAppReady();
}
}
// در Flutter Web، تمام صفحات به صورت eager load می‌شوند
// (همه import شده‌اند) بنابراین کد تمام صفحات در bundle اولیه موجود است
// این باعث می‌شود که تأخیر در جابجایی بین صفحات از بین برود
RoutePrefetcher.initialize();
}
/// Preload تمام صفحات برای جلوگیری از تاخیر در navigation
/// این کار باعث می‌شود کد تمام صفحات در bundle اصلی قرار گیرد
void _preloadPages(
AuthStore authStore,
LocaleController localeController,
CalendarController calendarController,
ThemeController themeController,
) {
try {
// Preload Shell ها
ProfileShell(
authStore: authStore,
localeController: localeController,
calendarController: calendarController,
themeController: themeController,
child: const SizedBox(),
);
BusinessShell(
businessId: 0,
authStore: authStore,
localeController: localeController,
calendarController: calendarController,
themeController: themeController,
child: const SizedBox(),
);
// Preload صفحات Public
PublicPersonShareLinkPage(code: 'preload');
// Preload صفحات Login و Wallet
LoginPage(
localeController: localeController,
calendarController: calendarController,
themeController: themeController,
authStore: authStore,
);
WalletPaymentResultPage(authStore: authStore);
// Preload صفحات Profile
ProfileDashboardPage(
calendarController: calendarController,
authStore: authStore,
);
const AnnouncementsPage();
NewBusinessPage(calendarController: calendarController);
BusinessesPage(authStore: authStore);
MobileLauncherHomePage(businessId: 1, authStore: authStore);
MobileLauncherAppearancePage(businessId: 1, authStore: authStore);
SupportPage(calendarController: calendarController);
MarketingPage(calendarController: calendarController);
const UserSignaturePage();
const ChangePasswordPage();
UserNotificationsPage(calendarController: calendarController);
OperatorTicketsPage(calendarController: calendarController);
const SystemSettingsPage();
const WalletSettingsPage();
const PaymentGatewaysPage();
const AdminStorageManagementPage();
const SystemConfigurationPage();
const ShareLinkSettingsPage();
const UserManagementPage();
const SystemReportsHubPage();
const ActiveUsersStatsReportPage();
const SignupsTimelineReportPage();
const EmailSettingsPage();
const AISettingsPage();
const AIModelsAdminPage();
const AIVoiceModelsAdminPage();
const AIProviderCredentialsAdminPage();
const AIPlansAdminPage();
const AIPromptsAdminPage();
const AISkillsAdminPage();
const AIMarketplaceSettingsPage();
const AnnouncementsAdminPage();
const NotificationsSettingsPage();
const NotificationTemplatesAdminPage();
const StoragePlansAdminPage();
const DocumentMonetizationAdminPage();
const BusinessesListPage();
ZohalSettingsPage();
ZohalServicesAdminPage();
ZohalStatisticsPage();
// Preload صفحات Business (با dummy businessId)
const dummyBusinessId = 0;
BusinessDashboardPage(
businessId: dummyBusinessId,
authStore: authStore,
calendarController: calendarController,
);
UsersPermissionsPage(
businessId: dummyBusinessId.toString(),
authStore: authStore,
calendarController: calendarController,
);
OpeningBalancePage(businessId: dummyBusinessId, authStore: authStore);
AccountsPage(businessId: dummyBusinessId, authStore: authStore);
BankAccountsPage(businessId: dummyBusinessId, authStore: authStore);
PettyCashPage(businessId: dummyBusinessId, authStore: authStore);
CashRegistersPage(businessId: dummyBusinessId, authStore: authStore);
WalletPage(businessId: dummyBusinessId, authStore: authStore);
AISubscriptionPage(businessId: dummyBusinessId, authStore: authStore);
AIUsagePage(businessId: dummyBusinessId, authStore: authStore);
ZohalInquiriesPage(businessId: dummyBusinessId, authStore: authStore);
InvoicesListPage(
businessId: dummyBusinessId,
calendarController: calendarController,
authStore: authStore,
apiClient: ApiClient(),
);
TaxWorkspacePage(
businessId: dummyBusinessId,
calendarController: calendarController,
authStore: authStore,
apiClient: ApiClient(),
);
NewInvoicePage(
businessId: dummyBusinessId,
authStore: authStore,
calendarController: calendarController,
copyFromInvoiceId: null,
);
EditInvoicePage(
businessId: dummyBusinessId,
invoiceId: 0,
authStore: authStore,
calendarController: calendarController,
);
ReportsPage(businessId: dummyBusinessId, authStore: authStore);
KardexPage(
businessId: dummyBusinessId,
calendarController: calendarController,
initialPersonIds: [],
);
DebtorsReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
CreditorsReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
PeopleTransactionsReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
ItemMovementsReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
SalesByProductReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
InventoryKardexReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
BankAccountsTurnoverReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
CashPettyTurnoverReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
DailySalesReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
DistributionReportsDashboardPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
DailyPurchasesReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
MonthlySalesReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
TopCustomersReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
TopSuppliersReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
MaterialsConsumptionReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
ProductionReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
TrialBalanceReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
GeneralLedgerReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
PnlPeriodReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
PnlCumulativeReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
AccountReviewReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
BalanceSheetReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
FinancialReportsPackagePage(
businessId: dummyBusinessId,
calendarController: calendarController,
);
SettingsPage(businessId: dummyBusinessId);
BusinessBackupPage(businessId: dummyBusinessId);
BusinessRestorePage(businessId: dummyBusinessId);
BusinessInfoSettingsPage(businessId: dummyBusinessId);
CreditSettingsPage(businessId: dummyBusinessId);
BusinessPrintSettingsPage(businessId: dummyBusinessId);
InstallmentPlansPage(businessId: dummyBusinessId);
DocumentMonetizationBusinessPage(businessId: dummyBusinessId);
ProductAttributesPage(businessId: dummyBusinessId, authStore: authStore);
ProductsPage(businessId: dummyBusinessId, authStore: authStore);
PriceListsPage(businessId: dummyBusinessId, authStore: authStore);
PriceListItemsPage(
businessId: dummyBusinessId,
priceListId: 0,
authStore: authStore,
);
PersonsPage(businessId: dummyBusinessId, authStore: authStore);
ReceiptsPaymentsListPage(
businessId: dummyBusinessId,
calendarController: calendarController,
authStore: authStore,
apiClient: ApiClient(),
);
InstallmentsReportPage(
businessId: dummyBusinessId,
calendarController: calendarController,
apiClient: ApiClient(),
);
ExpenseIncomeListPage(
businessId: dummyBusinessId,
calendarController: calendarController,
authStore: authStore,
apiClient: ApiClient(),
);
TransfersPage(
businessId: dummyBusinessId,
calendarController: calendarController,
authStore: authStore,
apiClient: ApiClient(),
);
WarehousesPage(businessId: dummyBusinessId);
WarehouseDocsPage(businessId: dummyBusinessId);
DocumentsPage(
businessId: dummyBusinessId,
calendarController: calendarController,
authStore: authStore,
apiClient: ApiClient(),
);
StorageFilesPage(businessId: dummyBusinessId);
StorageFileManagerPage(businessId: dummyBusinessId);
ReportTemplatesPage(businessId: dummyBusinessId, authStore: authStore);
PluginMarketplacePage(businessId: dummyBusinessId, authStore: authStore);
MarketplaceInvoicesPage(
businessId: dummyBusinessId,
authStore: authStore,
);
ChecksPage(
businessId: dummyBusinessId,
authStore: authStore,
calendarController: calendarController,
);
CheckFormPage(
businessId: dummyBusinessId,
authStore: authStore,
calendarController: calendarController,
);
CheckReconciliationPage(
businessId: dummyBusinessId,
authStore: authStore,
calendarController: calendarController,
);
// Preload صفحه Error
const Error404Page();
} catch (e) {
// خطا در preload نباید برنامه را متوقف کند
// فقط log می‌کنیم (در production می‌توانیم debug print کنیم)
debugPrint('Error preloading pages: $e');
}
}
// Root of application with GoRouter
@override
Widget build(BuildContext context) {
// اگر هنوز loading است، splash screen نمایش بده
if (_isLoading ||
_controller == null ||
_calendarController == null ||
_themeController == null ||
_authStore == null) {
final loadingRouter = GoRouter(
// همان نرمال‌سازی ویندوز؛ بدون آن مسیر فایل‌سیستمی در RouteInformationProvider می‌ماند.
initialLocation: SmsBankLaunchNavigation.normalizeInitialLocation(
Uri.base,
),
overridePlatformDefaultLocation:
SmsBankLaunchNavigation.shouldOverridePlatformDefault(Uri.base),
redirect: (context, state) {
if (SmsBankLaunchNavigation.shouldRedirectUnknownPathToRoot(
state.uri.path,
)) {
return '/';
}
return null;
},
routes: <RouteBase>[
// برای تمام مسیرها splash screen نمایش بده
GoRoute(
path: '/:path(.*)',
builder: (context, state) {
return Builder(
builder: (context) {
final t = AppLocalizations.of(context);
final phase = _initProgress.phase;
final localizedMessage = _initStatusMessage(t, phase);
if (kIsWeb) {
return const SizedBox.shrink();
}
return ProgressSplashScreen(
message: localizedMessage,
showLogo: true,
progress: _initProgress.progress,
currentStep: _initProgress.currentStep,
totalSteps: _initProgress.totalSteps,
);
},
);
},
),
],
);
return MaterialApp.router(
title: BrandConfig.materialTitle,
routerConfig: loadingRouter,
theme: _themeController == null
? null
: AppTheme.build(
isDark: false,
locale: _controller?.locale ?? const Locale('fa'),
themeDef: _themeController!.themeDefinition,
),
darkTheme: _themeController == null
? null
: AppTheme.build(
isDark: true,
locale: _controller?.locale ?? const Locale('fa'),
themeDef: _themeController!.themeDefinition,
),
themeMode: _themeController?.mode ?? ThemeMode.system,
locale: _controller?.locale ?? const Locale('fa'),
supportedLocales: const [Locale('en'), Locale('fa')],
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
);
}
final controller = _controller!;
final themeController = _themeController!;
// Create GoRouter once. Recreating it on every AuthStore/theme rebuild
// resets navigation (on Android Uri.base stays "/") and kicks the user
// back to the profile dashboard after entering a business.
_router ??= GoRouter(
navigatorKey: navigatorKey,
observers: [routeObserver],
refreshListenable: _authStore,
// Windows desktop: Uri.base is file://…/exe dir; must not become the route.
initialLocation: SmsBankLaunchNavigation.normalizeInitialLocation(
Uri.base,
),
overridePlatformDefaultLocation:
SmsBankLaunchNavigation.shouldOverridePlatformDefault(Uri.base),
redirect: (context, state) async {
final currentPath = state.uri.path;
final isPublicRoute = currentPath.startsWith('/public');
final isShortPublicSharePath =
currentPath.startsWith('/i/') || currentPath.startsWith('/p/');
// SMS bank notification deep links map to /capture — not a real page.
if (SmsBankLaunchNavigation.shouldRedirectAwayFromCapture(state.uri)) {
return '/';
}
// Desktop filesystem / unknown paths must not stick as routes (Windows 404 on relaunch).
if (SmsBankLaunchNavigation.shouldRedirectUnknownPathToRoot(
currentPath,
)) {
return '/';
}
// اگر authStore هنوز load نشده، منتظر بمان
if (_authStore == null) {
return null;
}
final hasKey =
_authStore!.apiKey != null && _authStore!.apiKey!.isNotEmpty;
// اگر API key ندارد
if (!hasKey) {
if (isPublicRoute || isShortPublicSharePath) {
return null;
}
if (currentPath != '/login') {
return '/login';
}
return null;
}
// اگر API key دارد
// اگر در login است، ترجیح لانچر یا داشبورد پروفایل
// مگر اینکه post-login flow (دیالوگ اثر انگشت) هنوز تمام نشده باشد —
// در غیر این صورت redirect با BiometricPrompt رقابت می‌کند و فعال‌سازی شکست می‌خورد.
if (currentPath == '/login') {
if (_authStore!.deferLoginRedirect) {
return null;
}
final launcherLoc = await MobileLauncherPrefs.resumeHomeLocation(
_authStore!.currentUserId,
);
return launcherLoc ?? '/user/profile/dashboard';
}
// مسیرهای قدیمی پنل بدون segment «tabN» با StatefulShellRoute هم‌خوان نیستند؛ اینجا نرمال می‌شوند.
if (currentPath.startsWith('/business/')) {
final normalized = redirectLegacyBusinessPath(context, state);
if (normalized != null) return normalized;
}
// اگر در root است؛ ابتدا لانچر موبایل در صورت فعال بودن، سپس آخرین URL
if (currentPath == '/') {
final launcherLoc = await MobileLauncherPrefs.resumeHomeLocation(
_authStore!.currentUserId,
);
if (launcherLoc != null) {
return launcherLoc;
}
final lastUrl = await _authStore!.getLastUrl();
if (lastUrl != null &&
lastUrl.isNotEmpty &&
lastUrl != '/' &&
lastUrl != '/login' &&
(lastUrl.startsWith('/user/profile/') ||
lastUrl.startsWith('/business/') ||
lastUrl.startsWith('/mobile-launcher/'))) {
return lastUrl;
}
// وگرنه به dashboard برود (فقط اگر در root باشیم)
return '/user/profile/dashboard';
}
// برای سایر صفحات (شامل صفحات profile و business)، redirect نکن (بماند)
// این مهم است: اگر کاربر در صفحات profile یا business است، بماند
// ذخیره مسیر فعلی به عنوان آخرین URL معتبر
if (!isPublicRoute &&
currentPath.isNotEmpty &&
currentPath != '/' &&
currentPath != '/login' &&
(currentPath.startsWith('/user/profile/') ||
currentPath.startsWith('/business/') ||
currentPath.startsWith('/mobile-launcher/'))) {
try {
await _authStore!.saveLastUrl(currentPath);
} catch (e) {
// صرفاً لاگ برای خطای غیر بحرانی ذخیره آدرس
}
}
return null;
},
routes: <RouteBase>[
GoRoute(
path: '/public/person-link/:code',
name: 'public_person_share_link',
builder: (context, state) => PublicPersonShareLinkPage(
code: state.pathParameters['code'] ?? '',
),
),
GoRoute(
path: '/public/invoice-link/:code',
name: 'public_invoice_share_link',
builder: (context, state) => PublicInvoiceShareLinkPage(
code: state.pathParameters['code'] ?? '',
paymentReturnQuery: state.uri.queryParameters,
),
),
GoRoute(
path: '/i/:code',
name: 'short_invoice_link_redirect',
redirect: (context, state) {
final c = state.pathParameters['code'] ?? '';
if (c.isEmpty) {
return '/';
}
return '/public/invoice-link/${Uri.encodeComponent(c)}';
},
),
GoRoute(
path: '/public/storage-file/:token',
name: 'public_storage_file_share',
builder: (context, state) => PublicStorageFileSharePage(
token: state.pathParameters['token'] ?? '',
),
),
GoRoute(
path: '/public/warranty/activate/:business_id',
name: 'public_warranty_activate',
builder: (context, state) {
final businessId = int.tryParse(
state.pathParameters['business_id'] ?? '',
);
if (businessId == null) {
return const Scaffold(
body: Center(child: Text('شناسه کسب و کار نامعتبر است')),
);
}
return PublicWarrantyActivationPage(businessId: businessId);
},
),
GoRoute(
path: '/public/warranty/track',
name: 'public_warranty_track',
builder: (context, state) {
final codeOrSerial = state.uri.queryParameters['code'];
final linkCode = state.uri.queryParameters['link'];
return PublicWarrantyTrackingPage(
codeOrSerial: codeOrSerial,
linkCode: linkCode,
);
},
),
GoRoute(
path: '/public/warranty/track/:code',
name: 'public_warranty_track_code',
builder: (context, state) {
final code = state.pathParameters['code'] ?? '';
return PublicWarrantyTrackingPage(codeOrSerial: code);
},
),
GoRoute(
path: '/public/warranty/track/link/:linkCode',
name: 'public_warranty_track_link',
builder: (context, state) {
final linkCode = state.pathParameters['linkCode'] ?? '';
return PublicWarrantyTrackingPage(linkCode: linkCode);
},
),
GoRoute(
path: '/login',
name: 'login',
builder: (context, state) {
// ثبت صفحه برای preload خودکار
registerRoutePage(
() => LoginPage(
localeController: controller,
calendarController: _calendarController!,
themeController: themeController,
authStore: _authStore!,
),
);
return LoginPage(
localeController: controller,
calendarController: _calendarController!,
themeController: themeController,
authStore: _authStore!,
);
},
),
GoRoute(
path: '/wallet/payment-result',
name: 'wallet_payment_result',
builder: (context, state) {
// ثبت صفحه برای preload خودکار
registerRoutePage(
() => WalletPaymentResultPage(authStore: _authStore!),
);
return WalletPaymentResultPage(authStore: _authStore!);
},
),
GoRoute(
path: '/mobile-launcher/:businessId',
name: 'mobile_launcher',
redirect: (context, state) {
final businessId = int.tryParse(
state.pathParameters['businessId'] ?? '',
);
if (businessId == null || businessId <= 0) return null;
if (!ResponsiveHelper.isMobile(context)) {
return '/business/$businessId/dashboard';
}
if (state.uri.path == '/mobile-launcher/$businessId') {
return MobileLauncherPrefs.launcherHomePath(businessId);
}
return null;
},
routes: [
ShellRoute(
builder: (context, state, child) {
final businessId = int.tryParse(
state.pathParameters['businessId'] ?? '',
);
if (businessId == null || businessId <= 0) {
return Scaffold(
body: Center(
child: Text(
AppLocalizations.of(
context,
).mobileLauncherInvalidBusiness,
),
),
);
}
return MobileLauncherShell(
businessId: businessId,
authStore: _authStore!,
child: child,
);
},
routes: [
GoRoute(
path: 'home',
name: 'mobile_launcher_home',
builder: (context, state) {
final businessId = int.tryParse(
state.pathParameters['businessId'] ?? '',
);
if (businessId == null || businessId <= 0) {
return Scaffold(
body: Center(
child: Text(
AppLocalizations.of(
context,
).mobileLauncherInvalidBusiness,
),
),
);
}
registerRoutePage(
() => MobileLauncherHomePage(
key: ValueKey('launcher-home-$businessId'),
businessId: businessId,
authStore: _authStore!,
),
);
return MobileLauncherHomePage(
key: ValueKey('launcher-home-$businessId'),
businessId: businessId,
authStore: _authStore!,
);
},
),
GoRoute(
path: 'appearance',
name: 'mobile_launcher_appearance',
builder: (context, state) {
final businessId = int.tryParse(
state.pathParameters['businessId'] ?? '',
);
if (businessId == null || businessId <= 0) {
return Scaffold(
body: Center(
child: Text(
AppLocalizations.of(
context,
).mobileLauncherInvalidBusiness,
),
),
);
}
registerRoutePage(
() => MobileLauncherAppearancePage(
businessId: businessId,
authStore: _authStore!,
),
);
return MobileLauncherAppearancePage(
businessId: businessId,
authStore: _authStore!,
);
},
),
GoRoute(
path: 'quick-sales',
name: 'mobile_launcher_quick_sales',
pageBuilder: (context, state) {
final businessId = int.tryParse(
state.pathParameters['businessId'] ?? '',
);
if (businessId == null || businessId <= 0) {
return hesabixNoTransitionPage(
state,
Scaffold(
body: Center(
child: Text(
AppLocalizations.of(
context,
).mobileLauncherInvalidBusiness,
),
),
),
);
}
if (!_authStore!.hasBusinessPermission('invoices', 'add')) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
final homePath = MobileLauncherPrefs.launcherHomePath(
businessId,
);
registerRoutePage(
() => QuickSalesPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
mobileLauncherHomePath: homePath,
),
);
return hesabixNoTransitionPage(
state,
QuickSalesPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
mobileLauncherHomePath: homePath,
),
);
},
),
],
),
],
),
ShellRoute(
builder: (context, state, child) => ProfileShell(
authStore: _authStore!,
localeController: controller,
calendarController: _calendarController!,
themeController: themeController,
child: child,
),
routes: [
GoRoute(
path: '/user/profile/dashboard',
name: 'profile_dashboard',
builder: (context, state) {
// ثبت صفحه برای preload خودکار
registerRoutePage(
() => ProfileDashboardPage(
calendarController: _calendarController!,
authStore: _authStore!,
),
);
return ProfileDashboardPage(
calendarController: _calendarController!,
authStore: _authStore!,
);
},
),
GoRoute(
path: '/user/profile/announcements',
name: 'profile_announcements',
builder: (context, state) => const AnnouncementsPage(),
),
GoRoute(
path: '/user/profile/new-business',
name: 'profile_new_business',
builder: (context, state) => NewBusinessPage(
calendarController: _calendarController!,
initialFlow: state.uri.queryParameters['flow'],
),
),
GoRoute(
path: '/user/profile/businesses',
name: 'profile_businesses',
builder: (context, state) => BusinessesPage(authStore: _authStore!),
),
GoRoute(
path: '/user/profile/support',
name: 'profile_support',
builder: (context, state) =>
SupportPage(calendarController: _calendarController),
),
GoRoute(
path: '/user/profile/support/billing',
name: 'profile_support_billing',
builder: (context, state) => const SupportBillingPage(),
),
GoRoute(
path: '/user/profile/support/new',
name: 'profile_support_new',
builder: (context, state) =>
const CreateTicketPage(fullPage: true),
),
GoRoute(
path: '/user/profile/support/tickets/:ticketId',
name: 'profile_support_ticket_detail',
builder: (context, state) {
final ticketId = int.parse(state.pathParameters['ticketId']!);
return SupportTicketDetailPage(
ticketId: ticketId,
calendarController: _calendarController,
);
},
),
GoRoute(
path: '/user/profile/account-settings',
name: 'profile_account_settings',
builder: (context, state) => AccountSettingsPage(
calendarController: _calendarController!,
authStore: _authStore!,
),
),
GoRoute(
path: '/user/profile/biometric-lock-settings',
name: 'profile_biometric_lock_settings',
redirect: (context, state) {
if (!supportsBiometricLock) {
return '/user/profile/account-settings';
}
return null;
},
builder: (context, state) =>
BiometricLockSettingsPage(authStore: _authStore!),
),
GoRoute(
path: '/user/profile/android-update-settings',
name: 'profile_android_update_settings',
redirect: (context, state) {
if (!supportsAndroidApkUpdate) {
return '/user/profile/account-settings';
}
return null;
},
builder: (context, state) => const AndroidUpdateSettingsPage(),
),
GoRoute(
path: '/user/profile/windows-update-settings',
name: 'profile_windows_update_settings',
redirect: (context, state) {
if (!supportsWindowsDesktopUpdate) {
return '/user/profile/account-settings';
}
return null;
},
builder: (context, state) => const WindowsUpdateSettingsPage(),
),
GoRoute(
path: '/user/profile/appearance-settings',
name: 'profile_appearance_settings',
builder: (context, state) => AppearanceSettingsPage(
themeController: themeController,
),
),
GoRoute(
path: '/user/profile/marketing',
name: 'profile_marketing',
builder: (context, state) =>
MarketingPage(calendarController: _calendarController!),
),
GoRoute(
path: '/user/profile/signature',
name: 'profile_signature',
builder: (context, state) => const UserSignaturePage(),
),
GoRoute(
path: '/user/profile/change-password',
name: 'profile_change_password',
builder: (context, state) => const ChangePasswordPage(),
),
GoRoute(
path: '/user/profile/verification',
name: 'profile_verification',
builder: (context, state) => const VerificationPage(),
),
GoRoute(
path: '/user/profile/api-keys',
name: 'profile_api_keys',
builder: (context, state) =>
ApiKeysPage(calendarController: _calendarController!),
),
GoRoute(
path: '/user/profile/sessions',
name: 'profile_sessions',
builder: (context, state) => const SessionsPage(),
),
GoRoute(
path: '/user/profile/notifications',
name: 'profile_notifications',
builder: (context, state) => UserNotificationsPage(
calendarController: _calendarController!,
),
),
GoRoute(
path: '/user/profile/notification-history',
name: 'profile_notification_history',
builder: (context, state) => NotificationHistoryPage(
calendarController: _calendarController!,
),
),
GoRoute(
path: '/user/profile/operator',
name: 'profile_operator',
builder: (context, state) {
// بررسی دسترسی اپراتور پشتیبانی
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
if (!_authStore!.canAccessSupportOperator) {
return PermissionGuard.buildAccessDeniedPage();
}
final initialTicketId = int.tryParse(
state.uri.queryParameters['ticket'] ?? '',
);
OperatorInboxView? initialView;
final viewParam = state.uri.queryParameters['view'];
if (viewParam != null) {
for (final v in OperatorInboxView.values) {
if (v.name == viewParam) {
initialView = v;
break;
}
}
}
return OperatorTicketsPage(
calendarController: _calendarController,
initialTicketId: initialTicketId,
authStore: _authStore,
initialInboxView: initialView,
);
},
),
GoRoute(
path: '/user/profile/operator/tickets/:ticketId',
name: 'profile_operator_ticket_detail',
builder: (context, state) {
if (_authStore == null ||
!_authStore!.canAccessSupportOperator) {
return PermissionGuard.buildAccessDeniedPage();
}
final ticketId =
int.tryParse(state.pathParameters['ticketId'] ?? '') ?? 0;
if (ticketId <= 0) {
return PermissionGuard.buildAccessDeniedPage();
}
return SupportTicketDetailPage(
ticketId: ticketId,
calendarController: _calendarController,
isOperator: true,
);
},
),
GoRoute(
path: '/user/profile/operator/dashboard',
name: 'profile_operator_dashboard',
builder: (context, state) {
if (_authStore == null ||
!_authStore!.canAccessSupportOperator) {
return PermissionGuard.buildAccessDeniedPage();
}
return OperatorDashboardPage(
calendarController: _calendarController,
);
},
),
GoRoute(
path: '/user/profile/system-settings',
name: 'profile_system_settings',
builder: (context, state) {
// بررسی دسترسی تنظیمات سیستم (SuperAdmin یا مجوز system_settings)
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const SystemSettingsPage();
},
routes: [
GoRoute(
path: 'wallet',
name: 'system_settings_wallet',
pageBuilder: (context, state) {
if (_authStore == null) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
const WalletSettingsPage(),
);
},
),
GoRoute(
path: 'currencies',
name: 'system_settings_currencies',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const CurrenciesAdminPage();
},
),
GoRoute(
path: 'fx-providers',
name: 'system_settings_fx_providers',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const FxProvidersAdminPage();
},
),
GoRoute(
path: 'wallet-payouts',
name: 'system_settings_wallet_payouts',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const WalletPayoutsAdminPage();
},
),
GoRoute(
path: 'payment-gateways',
name: 'system_settings_payment_gateways',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const PaymentGatewaysPage();
},
),
GoRoute(
path: 'storage',
name: 'system_settings_storage',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AdminStorageManagementPage();
},
),
GoRoute(
path: 'configuration',
name: 'system_settings_configuration',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const SystemConfigurationPage();
},
),
GoRoute(
path: 'share-links',
name: 'system_settings_share_links',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const ShareLinkSettingsPage();
},
),
GoRoute(
path: 'users',
name: 'system_settings_users',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings') ||
_authStore!.hasAppPermission('user_management');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const UserManagementPage();
},
),
GoRoute(
path: 'reports',
name: 'system_settings_reports',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings') ||
_authStore!.hasAppPermission('user_management');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const SystemReportsHubPage();
},
),
GoRoute(
path: 'reports-active-users',
name: 'system_settings_reports_active_users',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings') ||
_authStore!.hasAppPermission('user_management');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const ActiveUsersStatsReportPage();
},
),
GoRoute(
path: 'reports-signups-timeline',
name: 'system_settings_reports_signups_timeline',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings') ||
_authStore!.hasAppPermission('user_management');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const SignupsTimelineReportPage();
},
),
GoRoute(
path: 'support-operators',
name: 'system_settings_support_operators',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed = _authStore!.isSuperAdmin;
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const SupportOperatorsPage();
},
),
// Notification Moderation Queue
GoRoute(
path: 'notification-moderation',
name: 'notification_moderation_queue',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed = _authStore!.isSuperAdmin;
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const NotificationModerationQueuePage();
},
),
// Notification SMS Pricing
GoRoute(
path: 'notification-sms-pricing',
name: 'notification_sms_pricing',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const NotificationSmsPricingPage();
},
),
GoRoute(
path: 'email',
name: 'system_settings_email',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const EmailSettingsPage();
},
),
GoRoute(
path: 'ai-settings',
name: 'system_settings_ai_settings',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AISettingsPage();
},
),
GoRoute(
path: 'ai-provider-credentials',
name: 'system_settings_ai_provider_credentials',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AIProviderCredentialsAdminPage();
},
),
GoRoute(
path: 'ai-models',
name: 'system_settings_ai_models',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AIModelsAdminPage();
},
),
GoRoute(
path: 'ai-voice-models',
name: 'system_settings_ai_voice_models',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AIVoiceModelsAdminPage();
},
),
GoRoute(
path: 'ai-plans',
name: 'system_settings_ai_plans',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AIPlansAdminPage();
},
),
GoRoute(
path: 'ai-prompts',
name: 'system_settings_ai_prompts',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AIPromptsAdminPage();
},
),
GoRoute(
path: 'ai-skills',
name: 'system_settings_ai_skills',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AISkillsAdminPage();
},
),
GoRoute(
path: 'ai-marketplace',
name: 'system_settings_ai_marketplace',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AIMarketplaceSettingsPage();
},
),
GoRoute(
path: 'ai-eval',
name: 'system_settings_ai_eval',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AIEvalAdminPage();
},
),
GoRoute(
path: 'announcements',
name: 'system_settings_announcements',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const AnnouncementsAdminPage();
},
),
GoRoute(
path: 'notifications',
name: 'system_settings_notifications',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const NotificationsSettingsPage();
},
),
GoRoute(
path: 'notification-templates',
name: 'system_settings_notification_templates',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const NotificationTemplatesAdminPage();
},
),
GoRoute(
path: 'notification-event-defaults',
name: 'system_settings_notification_event_defaults',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const NotificationEventTypesAdminPage();
},
),
GoRoute(
path: 'tax-product-codes',
name: 'system_settings_tax_product_codes',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const TaxProductCodesPage();
},
),
GoRoute(
path: 'storage-plans',
name: 'system_settings_storage_plans',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const StoragePlansAdminPage();
},
),
GoRoute(
path: 'support-plans',
name: 'system_settings_support_plans',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const SupportPlansAdminPage();
},
),
GoRoute(
path: 'support-billing-stats',
name: 'system_settings_support_billing_stats',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const SupportBillingStatsAdminPage();
},
),
GoRoute(
path: 'marketplace-plugins',
name: 'system_settings_marketplace_plugins',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const MarketplacePluginsAdminPage();
},
),
GoRoute(
path: 'document-monetization',
name: 'system_settings_document_monetization',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const DocumentMonetizationAdminPage();
},
),
GoRoute(
path: 'zohal-settings',
name: 'system_settings_zohal_settings',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return ZohalSettingsPage();
},
),
GoRoute(
path: 'zohal-services',
name: 'system_settings_zohal_services',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return ZohalServicesAdminPage();
},
),
GoRoute(
path: 'zohal-statistics',
name: 'system_settings_zohal_statistics',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return ZohalStatisticsPage();
},
),
GoRoute(
path: 'businesses',
name: 'system_settings_businesses',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed = _authStore!.isSuperAdmin;
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const BusinessesListPage();
},
),
GoRoute(
path: 'redis',
name: 'system_settings_redis',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const RedisSettingsPage();
},
),
GoRoute(
path: 'firewall',
name: 'system_settings_firewall',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const FirewallAdminPage();
},
),
GoRoute(
path: 'monitoring',
name: 'system_settings_monitoring',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const SystemMonitoringPage();
},
),
GoRoute(
path: 'service-logs',
name: 'system_settings_service_logs',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const ServiceLogsPage();
},
),
GoRoute(
path: 'business-activity-logs',
name: 'system_settings_business_activity_logs',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const BusinessActivityLogsAdminPage();
},
),
GoRoute(
path: 'database-backup',
name: 'system_settings_database_backup',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed =
_authStore!.isSuperAdmin ||
_authStore!.hasAppPermission('system_settings');
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const DatabaseBackupPage();
},
),
GoRoute(
path: 'legacy-import',
name: 'system_settings_legacy_import',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
if (!_authStore!.isSuperAdmin) {
return PermissionGuard.buildAccessDeniedPage();
}
return const LegacyDatabaseImportPage();
},
),
GoRoute(
path: 'scripts',
name: 'system_settings_scripts',
builder: (context, state) {
if (_authStore == null) {
return PermissionGuard.buildAccessDeniedPage();
}
final allowed = _authStore!.isSuperAdmin;
if (!allowed) {
return PermissionGuard.buildAccessDeniedPage();
}
return const SystemScriptsPage();
},
),
],
),
],
),
GoRoute(
path: '/business/:business_id',
redirect: redirectLegacyBusinessPath,
routes: [
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MobileLauncherBackScope(
businessId: businessId,
authStore: _authStore!,
child: HesabixBackScope(
businessId: businessId,
child: BusinessShell(
businessId: businessId,
authStore: _authStore!,
localeController: controller,
calendarController: _calendarController!,
themeController: themeController,
child: navigationShell,
),
),
);
},
branches: [
for (var i = 0; i < BusinessRoutePaths.tabBranchCount; i++)
StatefulShellBranch(
routes: [
GoRoute(
path: 'tab$i',
redirect: (context, state) {
final segs = state.uri.pathSegments;
if (segs.isNotEmpty && segs.last == 'tab$i') {
return '${state.uri.path}/dashboard';
}
return null;
},
routes: [
GoRoute(
path: 'dashboard',
pageBuilder: (context, state) =>
hesabixNoTransitionPage(
state,
BusinessDashboardPage(
businessId: int.parse(
state.pathParameters['business_id']!,
),
authStore: _authStore!,
calendarController: _calendarController!,
),
),
),
GoRoute(
path: 'users-permissions',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
UsersPermissionsPage(
businessId: businessId.toString(),
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'opening-balance',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
OpeningBalancePage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'year-end-closing',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
YearEndClosingPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'currency-revaluation',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (_authStore == null ||
!_authStore!.isMultiCurrency) {
return hesabixNoTransitionPage(
state,
Scaffold(
appBar: AppBar(
title: const Text('تسعیر ارز'),
),
body: const Center(
child: Padding(
padding: EdgeInsets.all(24),
child: Text(
'این بخش فقط برای کسب‌وکارهای چندارزی فعال است.\n'
'از تنظیمات کسب‌وکار، یک ارز فرعی اضافه کنید.',
textAlign: TextAlign.center,
),
),
),
),
);
}
return hesabixNoTransitionPage(
state,
CurrencyRevaluationPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'chart-of-accounts',
pageBuilder: (context, state) =>
hesabixNoTransitionPage(
state,
AccountsPage(
businessId: int.parse(
state.pathParameters['business_id']!,
),
authStore: _authStore!,
),
),
),
GoRoute(
path: 'accounts',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
BankAccountsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'petty-cash',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
PettyCashPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'cash-box',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
CashRegistersPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'wallet',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WalletPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'loan-facilities',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
LoanFacilitiesPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'ai/chat',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
AIChatPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController,
),
);
},
),
GoRoute(
path: 'ai/chat/:sessionId',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final sessionId = int.tryParse(
state.pathParameters['sessionId'] ?? '',
);
return hesabixNoTransitionPage(
state,
AIChatPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController,
initialSessionId: sessionId,
),
);
},
),
GoRoute(
path: 'ai/subscription',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
AISubscriptionPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'ai/usage',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
AIUsagePage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'zohal/inquiries',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ZohalInquiriesPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'workflows/new',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
// workflow از extra می‌آید یا null است برای افزودن جدید
final workflow =
state.extra as Map<String, dynamic>?;
return MaterialPage(
key: state.pageKey,
child: WorkflowVisualEditorPage(
businessId: businessId,
authStore: _authStore!,
workflow: workflow,
),
);
},
),
GoRoute(
path: 'workflows/:workflow_id/edit',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
// workflow از extra می‌آید
final workflow =
state.extra as Map<String, dynamic>?;
return MaterialPage(
key: state.pageKey,
child: WorkflowVisualEditorPage(
businessId: businessId,
authStore: _authStore!,
workflow: workflow,
),
);
},
),
GoRoute(
path: 'warranty',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WarrantyManagementPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'warranty/settings',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WarrantySettingsPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'repair-shop',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
RepairOrdersListPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'repair-shop/new',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
RepairOrderFormPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'repair-shop/:order_id',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final orderId = int.parse(
state.pathParameters['order_id']!,
);
return hesabixNoTransitionPage(
state,
RepairOrderDetailPage(
businessId: businessId,
orderId: orderId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'repair-shop-technicians',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
RepairTechniciansPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'repair-shop-settings',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
RepairSettingsPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'customer-club',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
CustomerClubMainPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'payroll',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
PayrollPluginGate(
businessId: businessId,
child: PayrollMainPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
),
);
},
),
GoRoute(
path: 'telephony',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
TelephonyPluginGate(
businessId: businessId,
child: TelephonyHubPage(
businessId: businessId,
authStore: _authStore!,
),
),
);
},
),
GoRoute(
path: 'telephony/calls',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
TelephonyPluginGate(
businessId: businessId,
child: TelephonyCallsPage(
businessId: businessId,
authStore: _authStore!,
),
),
);
},
),
GoRoute(
path: 'telephony/live',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
TelephonyPluginGate(
businessId: businessId,
child: TelephonyLiveDashboardPage(
businessId: businessId,
authStore: _authStore!,
),
),
);
},
),
GoRoute(
path: 'telephony/reports',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
TelephonyPluginGate(
businessId: businessId,
child: TelephonyReportsPage(
businessId: businessId,
authStore: _authStore!,
),
),
);
},
),
GoRoute(
path: 'telephony/softphone',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
TelephonyPluginGate(
businessId: businessId,
child: TelephonySoftphonePage(
businessId: businessId,
authStore: _authStore!,
),
),
);
},
),
GoRoute(
path: 'settings/telephony',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
TelephonyPluginGate(
businessId: businessId,
child: TelephonySettingsPage(
businessId: businessId,
authStore: _authStore!,
),
),
);
},
),
GoRoute(
path: 'payroll/reports',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
PayrollPluginGate(
businessId: businessId,
child: PayrollReportsPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
),
);
},
),
GoRoute(
path: 'payroll/new',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
PayrollPluginGate(
businessId: businessId,
child: PayrollRunEditPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
),
);
},
),
GoRoute(
path: 'payroll/:run_id',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final runId = int.parse(
state.pathParameters['run_id']!,
);
return hesabixNoTransitionPage(
state,
PayrollPluginGate(
businessId: businessId,
child: PayrollRunEditPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
runId: runId,
),
),
);
},
),
GoRoute(
path: 'distribution',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
DistributionPluginGate(
businessId: businessId,
child: DistributionMainPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
),
);
},
),
GoRoute(
path: 'basalam',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
BasalamIntegrationPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'woocommerce',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WoocommerceIntegrationPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'woocommerce/opening-inventory',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final canWoo =
_authStore!.hasBusinessPermission(
'woocommerce',
'view',
) ||
_authStore!.currentBusiness?.isOwner == true;
if (!canWoo) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
WoocommerceOpeningInventoryBridgePage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'notification-templates',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
NotificationTemplatesPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'notification-templates/new',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
NotificationTemplateFormPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'notification-templates/:template_id/edit',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final templateId = int.parse(
state.pathParameters['template_id']!,
);
return hesabixNoTransitionPage(
state,
NotificationTemplateFormPage(
businessId: businessId,
templateId: templateId,
),
);
},
),
GoRoute(
path: 'workflows',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: WorkflowsPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'workflows/marketplace',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: WorkflowMarketplacePage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'ai/skills/marketplace',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: AISkillsMarketplacePage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'ai/skills/publisher',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: AISkillsPublisherRevenuePage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'crm',
redirect: (context, state) =>
'${BusinessRoutePaths.prefixFromRouterState(state)}/crm/dashboard',
),
GoRoute(
path: 'crm/dashboard',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmDashboardPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'crm/process-definitions',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmProcessDefinitionsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'crm/leads',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmLeadsPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'crm/leads/:leadId',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final leadId = int.parse(
state.pathParameters['leadId']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmLeadRecordPage(
businessId: businessId,
leadId: leadId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'crm/deals',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmDealsPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'crm/deals/:dealId',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final dealId = int.parse(
state.pathParameters['dealId']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmDealRecordPage(
businessId: businessId,
dealId: dealId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'crm/activities',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmActivitiesPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'crm/reports',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmReportsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'crm/tasks',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmTasksPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'crm/customer-360',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final pidRaw =
state.uri.queryParameters['personId'] ??
state.uri.queryParameters['person_id'];
final personId = pidRaw != null
? int.tryParse(pidRaw)
: null;
return MaterialPage(
key: state.pageKey,
child: CrmCustomer360Page(
businessId: businessId,
authStore: _authStore!,
initialPersonId: personId,
),
);
},
),
GoRoute(
path: 'crm/sequences',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmSequencesPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'crm/notes-calendar',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmNotesCalendarPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'crm/web-chat',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return MaterialPage(
key: state.pageKey,
child: CrmWebChatPage(
businessId: businessId,
authStore: _authStore!,
apiClient: ApiClient(),
),
);
},
),
GoRoute(
path: 'invoice',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
InvoicesListPage(
businessId: businessId,
calendarController: _calendarController!,
authStore: _authStore!,
apiClient: ApiClient(),
),
);
},
),
GoRoute(
path: 'tax-workspace',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'moadian',
'view',
) &&
_authStore!.currentBusiness?.isOwner !=
true) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
TaxWorkspacePage(
businessId: businessId,
calendarController: _calendarController!,
authStore: _authStore!,
apiClient: ApiClient(),
),
);
},
),
GoRoute(
path: 'invoice/new',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final copyFromRaw =
state.uri.queryParameters['copy_from'];
final copyFromId =
copyFromRaw != null &&
copyFromRaw.trim().isNotEmpty
? int.tryParse(copyFromRaw.trim())
: null;
final personIdRaw =
state.uri.queryParameters['person_id'];
final initialPersonId =
personIdRaw != null &&
personIdRaw.trim().isNotEmpty
? int.tryParse(personIdRaw.trim())
: null;
return hesabixNoTransitionPage(
state,
NewInvoicePage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
copyFromInvoiceId: copyFromId,
initialPersonId: initialPersonId,
),
);
},
),
GoRoute(
path: 'invoice/:invoice_id/edit',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final invoiceId = int.parse(
state.pathParameters['invoice_id']!,
);
return hesabixNoTransitionPage(
state,
EditInvoicePage(
businessId: businessId,
invoiceId: invoiceId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ReportsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'reports/kardex',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
// Parse person_id(s) from query
final qp = state.uri.queryParameters;
final qpAll = state.uri.queryParametersAll;
final Set<int> initialPersonIds = <int>{};
final single = int.tryParse(
qp['person_id'] ?? '',
);
if (single != null) initialPersonIds.add(single);
final multi =
(qpAll['person_id'] ?? const <String>[])
.map((e) => int.tryParse(e))
.whereType<int>();
initialPersonIds.addAll(multi);
final personIdsCsv = qp['person_ids'];
if (personIdsCsv != null &&
personIdsCsv.trim().isNotEmpty) {
for (final part in personIdsCsv.split(',')) {
final p = int.tryParse(part.trim());
if (p != null) initialPersonIds.add(p);
}
}
// Also parse from extra
try {
if (state.extra is Map) {
final extra = state.extra as Map;
final list = extra['person_ids'];
if (list is List) {
for (final v in list) {
if (v is int) {
initialPersonIds.add(v);
} else {
final p = int.tryParse('$v');
if (p != null) {
initialPersonIds.add(p);
}
}
}
}
}
} catch (_) {}
return hesabixNoTransitionPage(
state,
KardexPage(
businessId: businessId,
calendarController: _calendarController!,
initialPersonIds: initialPersonIds.toList(),
),
);
},
),
GoRoute(
path: 'reports/debtors',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
DebtorsReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/ar-aging',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ArAgingReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/ap-aging',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ApAgingReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/person-balances-by-currency',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
PersonBalancesByCurrencyReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/cash-flow',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
CashFlowReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/fx-revaluation',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
FxRevaluationReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/creditors',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
CreditorsReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/people-transactions',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final personIdsRaw =
state.uri.queryParameters['person_ids'] ??
state.uri.queryParameters['person_id'];
int? initialPersonId;
if (personIdsRaw != null &&
personIdsRaw.trim().isNotEmpty) {
initialPersonId = int.tryParse(
personIdsRaw.split(',').first.trim(),
);
}
return hesabixNoTransitionPage(
state,
PeopleTransactionsReportPage(
businessId: businessId,
calendarController: _calendarController!,
initialPersonId: initialPersonId,
),
);
},
),
GoRoute(
path: 'reports/item-movements',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ItemMovementsReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/sales-by-product',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
SalesByProductReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/inventory-kardex',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
InventoryKardexReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/inventory-stock',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
InventoryStockReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/stock-count',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
StockCountReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/warehouse-documents-summary',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WarehouseDocumentsSummaryReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/slow-moving-items',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
SlowMovingItemsReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/critical-stock',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
CriticalStockReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/inter-warehouse-transfers',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
InterWarehouseTransfersReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/adjustment-documents',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
AdjustmentDocumentsReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/warehouse-performance',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WarehousePerformanceReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/product-movement-history',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ProductMovementHistoryReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/inventory-valuation',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
InventoryValuationReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/pending-documents',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
PendingDocumentsReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/inventory-turnover',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
InventoryTurnoverReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/bank-accounts-turnover',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
BankAccountsTurnoverReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/cash-petty-turnover',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
CashPettyTurnoverReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/distribution-dashboard',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
DistributionPluginGate(
businessId: businessId,
child: DistributionReportsDashboardPage(
businessId: businessId,
calendarController: _calendarController!,
),
),
);
},
),
GoRoute(
path: 'reports/daily-sales',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
DailySalesReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/daily-purchases',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
DailyPurchasesReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/monthly-sales',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
MonthlySalesReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/top-customers',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
TopCustomersReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/top-suppliers',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
TopSuppliersReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/materials-consumption',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
MaterialsConsumptionReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/production',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ProductionReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/trial-balance',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
TrialBalanceReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/general-ledger',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final qp = state.uri.queryParameters;
final initialAccount = accountFromQueryParams(qp);
final filters = reportFiltersFromQueryParams(qp);
return hesabixNoTransitionPage(
state,
GeneralLedgerReportPage(
businessId: businessId,
calendarController: _calendarController!,
initialAccount: initialAccount,
initialFiscalYearId: filters.fiscalYearId,
initialDateFrom: filters.dateFrom,
initialDateTo: filters.dateTo,
initialCurrencyId: filters.currencyId,
initialProjectId: filters.projectId,
),
);
},
),
GoRoute(
path: 'reports/journal-ledger',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
JournalLedgerReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/pnl-period',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
PnlPeriodReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/pnl-cumulative',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
PnlCumulativeReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/financial-package',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
FinancialReportsPackagePage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/balance-sheet',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
BalanceSheetReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/accounts-review',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
AccountReviewReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/activity-logs',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ActivityLogsPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/basalam/overview',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
BasalamReportsOverviewPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/basalam/synced-invoices',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
BasalamSyncedInvoicesReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/basalam/dead-letter',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
BasalamDeadLetterReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/basalam/product-conflicts',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
BasalamProductConflictsReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/woocommerce/overview',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WooCommerceReportsOverviewPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/woocommerce/recent-orders',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WooCommerceRecentOrdersReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/woocommerce/catalog',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WooCommerceCatalogReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'reports/woocommerce/bridge-health',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WooCommerceBridgeHealthReportPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'settings',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
// گارد دسترسی: فقط کاربرانی که دسترسی join دارند
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
SettingsPage(businessId: businessId),
);
},
),
GoRoute(
path: 'settings/backup',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
BusinessBackupPage(businessId: businessId),
);
},
),
GoRoute(
path: 'settings/ftp-backup',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
final isOwner =
_authStore!.currentBusiness?.id ==
businessId &&
_authStore!.currentBusiness?.isOwner == true;
final hasFtp = _authStore!.hasBusinessPermission(
'settings',
'manage_ftp',
);
if (!isOwner && !hasFtp) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
BusinessFtpBackupSettingsPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'settings/ai-provider',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final isOwner =
_authStore!.currentBusiness?.id ==
businessId &&
_authStore!.currentBusiness?.isOwner == true;
final hasPerm = _authStore!.hasBusinessPermission(
'settings',
'manage_ai_provider',
);
if (!isOwner && !hasPerm) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
BusinessAIProviderSettingsPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'settings/restore',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
BusinessRestorePage(businessId: businessId),
);
},
),
GoRoute(
path: 'settings/delete',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
// فقط مالک می‌تواند حذف کند
if (_authStore!.currentBusiness?.isOwner !=
true) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
DeleteBusinessPage(businessId: businessId),
);
},
),
GoRoute(
path: 'settings/fiscal-year-rollback',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final isOwner =
_authStore!.currentBusiness?.id ==
businessId &&
_authStore!.currentBusiness?.isOwner == true;
final canRollback =
isOwner ||
_authStore!.hasBusinessPermission(
'fiscal_years',
'rollback',
);
if (!canRollback) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
FiscalYearRollbackPage(businessId: businessId),
);
},
),
GoRoute(
path: 'settings/business',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
BusinessInfoSettingsPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'settings/currencies',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'business',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
BusinessCurrenciesSettingsPage(
businessId: businessId,
authStore: _authStore,
),
);
},
),
GoRoute(
path: 'settings/fx-revaluation',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'business',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
FxRevaluationSettingsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'settings/fx-auto-sync',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'business',
) &&
!_authStore!.hasBusinessPermission(
'currency_revaluation',
'view',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
FxAutoSyncSettingsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'settings/period-end-fx',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.isMultiCurrency) {
return hesabixNoTransitionPage(
state,
Scaffold(
appBar: AppBar(
title: const Text('تسعیر پایان دوره'),
),
body: const Center(
child: Padding(
padding: EdgeInsets.all(24),
child: Text(
'این بخش فقط برای کسب‌وکارهای چندارزی فعال است.',
textAlign: TextAlign.center,
),
),
),
),
);
}
if (!_authStore!.hasBusinessPermission(
'currency_revaluation',
'view',
) &&
!_authStore!.hasBusinessPermission(
'settings',
'business',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
PeriodEndFxRevaluationPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'settings/quick-sales',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'business',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
QuickSalesSettingsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'quick-sales',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'invoices',
'add',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
QuickSalesPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'settings/credit',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
CreditSettingsPage(businessId: businessId),
);
},
),
GoRoute(
path: 'settings/crm',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.canReadSection('crm')) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
BusinessCrmSettingsPage(
businessId: businessId,
authStore: _authStore!,
apiClient: ApiClient(),
),
);
},
),
GoRoute(
path: 'settings/basalam',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
final canBasalam =
_authStore!.hasBusinessPermission(
'basalam',
'view',
) ||
_authStore!.currentBusiness?.isOwner == true;
if (!canBasalam) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
BasalamSettingsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'settings/woocommerce',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
final canWoo =
_authStore!.hasBusinessPermission(
'woocommerce',
'view',
) ||
_authStore!.currentBusiness?.isOwner == true;
if (!canWoo) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
WoocommerceSettingsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'settings/customer-club',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
final isOwner =
_authStore!.currentBusiness?.id ==
businessId &&
_authStore!.currentBusiness?.isOwner == true;
final canAccess =
isOwner ||
_authStore!.hasBusinessPermission(
'customer_club',
'view',
) ||
_authStore!.hasBusinessPermission(
'customer_club',
'manage',
);
if (!canAccess) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
CustomerClubSettingsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'settings/payroll',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
final isOwner =
_authStore!.currentBusiness?.id ==
businessId &&
_authStore!.currentBusiness?.isOwner == true;
final canAccess =
isOwner ||
_authStore!.hasBusinessPermission(
'payroll',
'view',
) ||
_authStore!.hasBusinessPermission(
'payroll',
'manage',
);
if (!canAccess) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
PayrollPluginGate(
businessId: businessId,
child: PayrollSettingsPage(
businessId: businessId,
authStore: _authStore!,
),
),
);
},
),
GoRoute(
path: 'settings/document-numbering',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
DocumentNumberingSettingsPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'settings/tax',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final isOwner =
_authStore!.currentBusiness?.isOwner == true;
if (!isOwner &&
!_authStore!.hasBusinessPermission(
'moadian',
'manage_settings',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
TaxSettingsPage(businessId: businessId),
);
},
),
GoRoute(
path: 'settings/fiscal-year',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'fiscal_years',
'edit',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
FiscalYearSettingsPage(businessId: businessId),
);
},
),
GoRoute(
path: 'settings/print',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
BusinessPrintSettingsPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'settings/invoice-share-payment',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
InvoiceSharePaymentSettingsPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'settings/installments',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
InstallmentPlansPage(businessId: businessId),
);
},
),
GoRoute(
path: 'settings/sms-bank',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
SmsBankAssistantSettingsPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'document-monetization',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'settings',
'join',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
DocumentMonetizationBusinessPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'product-attributes',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ProductAttributesPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'product-bundles',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ProductBundlesPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'catalog-spec-fields',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'products',
'view',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
CatalogSpecFieldsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'products/bulk-prices-sheet',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
if (!_authStore!.hasBusinessPermission(
'products',
'view',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
ProductBulkPricesSheetPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'products',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ProductsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'barcode-labels',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
BarcodeLabelPluginGate(
businessId: businessId,
child: LabelTemplatesPage(
businessId: businessId,
authStore: _authStore!,
),
),
);
},
routes: [
GoRoute(
path: 'studio/new',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final q = state.uri.queryParameters;
final w = double.tryParse(q['w'] ?? '');
final h = double.tryParse(q['h'] ?? '');
final roll =
q['roll'] == '1' || q['roll'] == 'true';
return hesabixNoTransitionPage(
state,
BarcodeLabelPluginGate(
businessId: businessId,
child: LabelStudioPage(
businessId: businessId,
authStore: _authStore!,
initialWidthMm: w,
initialHeightMm: h,
initialRollMode: roll,
),
),
);
},
),
GoRoute(
path: 'studio/:template_id',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final templateId = int.parse(
state.pathParameters['template_id']!,
);
return hesabixNoTransitionPage(
state,
BarcodeLabelPluginGate(
businessId: businessId,
child: LabelStudioPage(
businessId: businessId,
authStore: _authStore!,
templateId: templateId,
),
),
);
},
),
GoRoute(
path: 'printers',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
BarcodeLabelPluginGate(
businessId: businessId,
child: LabelPrintersPage(
businessId: businessId,
authStore: _authStore!,
),
),
);
},
),
],
),
GoRoute(
path: 'price-lists',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
PriceListsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'price-lists/:price_list_id/items',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final priceListId = int.parse(
state.pathParameters['price_list_id']!,
);
return hesabixNoTransitionPage(
state,
PriceListItemsPage(
businessId: businessId,
priceListId: priceListId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'persons',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
PersonsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'projects',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ProjectsPage(
businessId: businessId,
calendarController: _calendarController!,
authStore: _authStore!,
apiClient: ApiClient(),
),
);
},
),
// Receipts & Payments: list with data table
GoRoute(
path: 'receipts-payments',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ReceiptsPaymentsListPage(
businessId: businessId,
calendarController: _calendarController!,
authStore: _authStore!,
apiClient: ApiClient(),
),
);
},
),
// Installments report
GoRoute(
path: 'installments-report',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
InstallmentsReportPage(
businessId: businessId,
calendarController: _calendarController!,
apiClient: ApiClient(),
),
);
},
),
GoRoute(
path: 'expense-income',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ExpenseIncomeListPage(
businessId: businessId,
calendarController: _calendarController!,
authStore: _authStore!,
apiClient: ApiClient(),
),
);
},
),
GoRoute(
path: 'transfers',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
TransfersPage(
businessId: businessId,
calendarController: _calendarController!,
authStore: _authStore!,
apiClient: ApiClient(),
),
);
},
),
GoRoute(
path: 'warehouses/:warehouse_id/locations',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final warehouseId = int.parse(
state.pathParameters['warehouse_id']!,
);
return hesabixNoTransitionPage(
state,
WarehouseLocationsPage(
businessId: businessId,
warehouseId: warehouseId,
),
);
},
),
GoRoute(
path: 'warehouses',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WarehousesPage(businessId: businessId),
);
},
),
GoRoute(
path: 'warehouse-docs',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
WarehouseDocsPage(businessId: businessId),
);
},
),
GoRoute(
path: 'warehouse-docs/:doc_id',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final docId = int.parse(
state.pathParameters['doc_id']!,
);
return hesabixNoTransitionPage(
state,
WarehouseDocumentDetailsPage(
businessId: businessId,
documentId: docId,
),
);
},
),
GoRoute(
path: 'stock-count',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final calendarController =
ApiClient.getCalendarController();
return hesabixNoTransitionPage(
state,
StockCountPage(
businessId: businessId,
calendarController: calendarController,
),
);
},
),
GoRoute(
path: 'quick-sales-stock-discrepancies',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
QuickSalesStockDiscrepanciesPage(
businessId: businessId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'goods-expense-income',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
GoodsExpenseIncomeListPage(
businessId: businessId,
),
);
},
),
GoRoute(
path: 'documents',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
DocumentsPage(
businessId: businessId,
calendarController: _calendarController!,
authStore: _authStore!,
apiClient: ApiClient(),
),
);
},
),
GoRoute(
path: 'storage-files',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
StorageFilesPage(businessId: businessId),
);
},
),
GoRoute(
path: 'storage-files/file-manager',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
StorageFileManagerPage(businessId: businessId),
);
},
),
GoRoute(
path: 'report-templates',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ReportTemplatesPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'hscript',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
HScriptReportsPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'hscript/studio/new',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
HScriptStudioPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'hscript/studio/:report_id',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final reportId = int.parse(
state.pathParameters['report_id']!,
);
return hesabixNoTransitionPage(
state,
HScriptStudioPage(
businessId: businessId,
authStore: _authStore!,
reportId: reportId,
),
);
},
),
GoRoute(
path: 'hscript/run/:report_id',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final reportId = int.parse(
state.pathParameters['report_id']!,
);
return hesabixNoTransitionPage(
state,
HScriptRunPage(
businessId: businessId,
authStore: _authStore!,
reportId: reportId,
),
);
},
),
GoRoute(
path: 'report-templates/studio/new',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final q = state.uri.queryParameters;
return hesabixNoTransitionPage(
state,
ReportTemplateStudioPage(
businessId: businessId,
authStore: _authStore!,
moduleKey: q['module_key'],
subtype: q['subtype'],
),
);
},
),
GoRoute(
path: 'report-templates/studio/:template_id',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final templateId = int.parse(
state.pathParameters['template_id']!,
);
return hesabixNoTransitionPage(
state,
ReportTemplateStudioPage(
businessId: businessId,
authStore: _authStore!,
templateId: templateId,
),
);
},
),
GoRoute(
path: 'report-templates/html/new',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final q = state.uri.queryParameters;
final seed =
state.extra is ReportTemplateHtmlEditorSeed
? state.extra as ReportTemplateHtmlEditorSeed
: null;
return hesabixNoTransitionPage(
state,
ReportTemplateHtmlEditorPage(
businessId: businessId,
authStore: _authStore!,
moduleKey: q['module_key'] ?? seed?.moduleKey,
subtype: q['subtype'] ?? seed?.subtype,
seed: seed,
),
);
},
),
GoRoute(
path: 'report-templates/html/:template_id/edit',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final templateId = int.parse(
state.pathParameters['template_id']!,
);
final seed =
state.extra is ReportTemplateHtmlEditorSeed
? state.extra as ReportTemplateHtmlEditorSeed
: null;
return hesabixNoTransitionPage(
state,
ReportTemplateHtmlEditorPage(
businessId: businessId,
authStore: _authStore!,
templateId: templateId,
seed: seed,
),
);
},
),
GoRoute(
path: 'plugin-marketplace',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
// گارد دسترسی مشاهده بازار
if (!_authStore!.hasBusinessPermission(
'marketplace',
'view',
)) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
final returnTo =
state.uri.queryParameters['returnTo'];
return hesabixNoTransitionPage(
state,
PluginMarketplacePage(
businessId: businessId,
authStore: _authStore!,
returnToPath: returnTo,
),
);
},
),
GoRoute(
path: 'plugin-marketplace/invoices',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final allowed =
_authStore!.hasBusinessPermission(
'marketplace',
'invoices',
) ||
_authStore!.hasBusinessPermission(
'marketplace',
'view',
);
if (!allowed) {
return hesabixNoTransitionPage(
state,
PermissionGuard.buildAccessDeniedPage(),
);
}
return hesabixNoTransitionPage(
state,
MarketplaceInvoicesPage(
businessId: businessId,
authStore: _authStore!,
),
);
},
),
GoRoute(
path: 'checks',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
ChecksPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'checks/new',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
CheckFormPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'checks/:check_id/edit',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
final checkId = int.tryParse(
state.pathParameters['check_id'] ?? '0',
);
return hesabixNoTransitionPage(
state,
CheckFormPage(
businessId: businessId,
authStore: _authStore!,
checkId: checkId,
calendarController: _calendarController!,
),
);
},
),
GoRoute(
path: 'checks/reconciliation',
pageBuilder: (context, state) {
final businessId = int.parse(
state.pathParameters['business_id']!,
);
return hesabixNoTransitionPage(
state,
CheckReconciliationPage(
businessId: businessId,
authStore: _authStore!,
calendarController: _calendarController!,
),
);
},
),
],
),
],
),
],
),
],
),
// صفحه 404 برای مسیرهای نامعتبر
GoRoute(
path: '/404',
name: 'error_404',
builder: (context, state) => const Error404Page(),
),
],
errorBuilder: (context, state) => const Error404Page(),
);
return AnimatedBuilder(
animation: Listenable.merge([controller, themeController]),
builder: (context, _) {
return UrlTracker(
authStore: _authStore!,
child: UserActivityHeartbeat(
authStore: _authStore!,
child: MaterialApp.router(
title: BrandConfig.materialTitle,
theme: AppTheme.build(
isDark: false,
locale: controller.locale,
themeDef: themeController.themeDefinition,
),
darkTheme: AppTheme.build(
isDark: true,
locale: controller.locale,
themeDef: themeController.themeDefinition,
),
themeMode: themeController.mode,
routerConfig: _router!,
locale: controller.locale,
supportedLocales: AppLocalizations.supportedLocales,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
builder: (context, child) {
final theme = Theme.of(context);
final baseStyle =
theme.textTheme.bodyMedium ?? const TextStyle();
return InAppNotificationsBootstrap(
authStore: _authStore!,
calendarController: _calendarController,
child: SmsBankBootstrap(
authStore: _authStore!,
calendarController: _calendarController,
biometricLockController: _biometricLockController,
child: AndroidUpdateGate(
child: WindowsCloseConfirmGate(
child: WindowsUpdateGate(
child: BiometricLockGate(
authStore: _authStore!,
lockController: _biometricLockController,
child: DefaultTextStyle(
style: baseStyle,
child: KeyboardShortcutListener(
child: child ?? const SizedBox(),
),
),
),
),
),
),
),
);
},
),
),
);
},
);
}
}