diff --git a/lib/core/app_router.dart b/lib/core/app_router.dart index 4b778cbd..e2322e22 100644 --- a/lib/core/app_router.dart +++ b/lib/core/app_router.dart @@ -15,7 +15,7 @@ class AppRouter { static GlobalKey navigatorKey = GlobalKey(); // Домены для deep links (в т.ч. ссылки из пушей dev2.eatvio.com) - static const List _deepLinkHosts = ['eatvio.ru', 'www.eatvio.ru']; + static const List deepLinkHosts = ['eatvio.ru', 'eatvio.com']; static GoRouter appRouter = GoRouter( initialLocation: RouteConstants.updateScreen, @@ -34,7 +34,8 @@ class AppRouter { final host = uri.host.toLowerCase(); final segments = uri.pathSegments; - final isDeepLink = _deepLinkHosts.contains(host); + // Проверяем, что хост заканчивается на один из разрешенных доменов + final isDeepLink = deepLinkHosts.any((allowedHost) => host == allowedHost || host.endsWith('.$allowedHost')); if (!isDeepLink) { return null; @@ -190,7 +191,7 @@ class AppRouter { if (uri.host.isEmpty && uri.pathSegments.isNotEmpty) { uri = Uri( scheme: 'https', - host: _deepLinkHosts.first, + host: deepLinkHosts.first, pathSegments: uri.pathSegments, queryParameters: uri.queryParameters.isEmpty ? null : uri.queryParameters, ); diff --git a/lib/core/notifications/push_navigation_handler.dart b/lib/core/notifications/push_navigation_handler.dart index b26db5e3..085c5b23 100644 --- a/lib/core/notifications/push_navigation_handler.dart +++ b/lib/core/notifications/push_navigation_handler.dart @@ -1,6 +1,7 @@ import 'dart:developer' as developer; import 'package:eatvio_app/core/app_router.dart'; +import 'package:eatvio_app/core/routing/route_constants.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -70,22 +71,88 @@ class PushNavigationHandler { static void _handleMessageInternal(RemoteMessage message, {required String source}) { final data = message.data; - final actionUrl = data['action_url'] as String?; + + // Пытаемся взять URL из action_url или action (бэкенд шлёт и то и другое) + String? rawUrl = data['action_url'] as String?; + if (rawUrl == null || rawUrl.isEmpty) { + rawUrl = data['action'] as String?; + } - if (actionUrl == null || actionUrl.isEmpty) { + if (rawUrl != null && rawUrl.isNotEmpty) { developer.log( - 'PushNavigationHandler: no action_url in message data, source=$source, data=$data', + 'PushNavigationHandler: navigating by url=$rawUrl, source=$source', name: 'PushNavigationHandler', ); + + // Если это URL, но без схемы, добавляем https + String finalUrl = rawUrl; + if (!finalUrl.startsWith('http') && finalUrl.contains('/')) { + finalUrl = 'https://${AppRouter.deepLinkHosts.first}/$finalUrl'.replaceAll('//', '/').replaceFirst('https:/', 'https://'); + } + + AppRouter.navigateByDeepLinkUrl(finalUrl); + return; + } + + // Fallback: навигация по типу уведомления, если URL отсутствует. + final target = _resolveTargetByType(data); + if (target != null) { + developer.log( + 'PushNavigationHandler: fallback navigation by type, target=$target, source=$source, data=$data', + name: 'PushNavigationHandler', + ); + AppRouter.appRouter.go(target); return; } developer.log( - 'PushNavigationHandler: navigating by action_url=$actionUrl, source=$source', + 'PushNavigationHandler: no action_url/action and no known type, source=$source, data=$data', name: 'PushNavigationHandler', ); + } - AppRouter.navigateByDeepLinkUrl(actionUrl); + /// Определяет маршрут по полям `type` / `action` из data, если URL отсутствует. + static String? _resolveTargetByType(Map data) { + final type = data['type'] as String? ?? ''; + final action = data['action'] as String? ?? ''; + final databaseType = data['database_type'] as String? ?? ''; + + // Чат + if (type == 'chat_message' || databaseType == 'chat-message') { + return RouteConstants.chatSelectScreen; + } + + // Дневник + if (type == 'diary_reminder' || action == 'open_diary' || databaseType == 'diary-reminder') { + return RouteConstants.diaryScreen; + } + + // Комментарий консультанта к дневнику + if (type == 'consultant_diary_comment' || databaseType == 'consultant-left-diary-comment') { + return RouteConstants.diaryScreen; + } + + // Консультации (plan-related) + if (type.startsWith('plan_') || type.startsWith('chosen_plan_') || databaseType.contains('plan')) { + return RouteConstants.consultationsScreen; + } + + // Диета + if (type == 'diet_started' || type == 'diet_cancelled' || databaseType.startsWith('diet-')) { + return RouteConstants.feedScreen; + } + + // Бейдж + if (type == 'badge_awarded' || databaseType == 'badge-awarded') { + return RouteConstants.myProfileScreen; + } + + // Мотивация + if (type == 'motivation') { + return RouteConstants.feedScreen; + } + + return null; } }