kasy-cli 1.37.0 → 1.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/scaffold/CHANGELOG.json +9 -0
- package/lib/scaffold/backends/api/patch/lib/core/data/api/user_api.dart +18 -0
- package/lib/scaffold/backends/patch-base-hashes.json +4 -4
- package/lib/scaffold/backends/supabase/patch/lib/core/data/api/user_api.dart +8 -0
- package/package.json +1 -1
- package/templates/firebase/.firebase/hosting.YnVpbGQvd2Vi.cache +23 -23
- package/templates/firebase/AGENTS.md +20 -10
- package/templates/firebase/DESIGN_SYSTEM.md +13 -0
- package/templates/firebase/README.en.md +1 -1
- package/templates/firebase/README.es.md +1 -1
- package/templates/firebase/README.md +1 -1
- package/templates/firebase/lib/components/kasy_app_bar.dart +57 -16
- package/templates/firebase/lib/components/kasy_bottom_sheet.dart +283 -66
- package/templates/firebase/lib/components/kasy_date_picker.dart +61 -46
- package/templates/firebase/lib/components/kasy_sidebar.dart +397 -28
- package/templates/firebase/lib/components/kasy_web_header.dart +11 -3
- package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +2 -213
- package/templates/firebase/lib/core/bottom_menu/sidebar_focus.dart +224 -0
- package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +12 -4
- package/templates/firebase/lib/core/chrome/web_header_scope.dart +20 -0
- package/templates/firebase/lib/core/data/api/user_api.dart +4 -0
- package/templates/firebase/lib/core/data/repositories/user_repository.dart +5 -0
- package/templates/firebase/lib/core/dev_inspector/dev_inspector.dart +525 -65
- package/templates/firebase/lib/core/dev_inspector/dev_inspector_info.dart +47 -0
- package/templates/firebase/lib/core/icons/kasy_icons.dart +16 -1
- package/templates/firebase/lib/core/states/user_state_notifier.dart +41 -0
- package/templates/firebase/lib/core/theme/universal_theme.dart +9 -0
- package/templates/firebase/lib/core/web_device_preview/png_clipboard.dart +14 -0
- package/templates/firebase/lib/core/web_device_preview/png_clipboard_io.dart +9 -0
- package/templates/firebase/lib/core/web_device_preview/png_clipboard_web.dart +36 -0
- package/templates/firebase/lib/core/web_device_preview/png_export_result.dart +2 -0
- package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +498 -466
- package/templates/firebase/lib/core/widgets/responsive_layout.dart +8 -0
- package/templates/firebase/lib/features/authentication/ui/signin_page.dart +11 -7
- package/templates/firebase/lib/features/home/home_components_page.dart +16 -6
- package/templates/firebase/lib/features/local_reminders/ui/reminder_page.dart +7 -0
- package/templates/firebase/lib/features/notifications/ui/components/notification_settings_sheet.dart +23 -13
- package/templates/firebase/lib/features/notifications/ui/notifications_page.dart +3 -0
- package/templates/firebase/lib/features/notifications/ui/widgets/web_notifications_bell.dart +262 -0
- package/templates/firebase/lib/features/settings/settings_page.dart +51 -38
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +549 -376
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_routes.dart +14 -4
- package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +266 -141
- package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +23 -30
- package/templates/firebase/lib/features/settings/ui/components/language_switcher.dart +30 -49
- package/templates/firebase/lib/i18n/en.i18n.json +23 -9
- package/templates/firebase/lib/i18n/es.i18n.json +23 -9
- package/templates/firebase/lib/i18n/pt.i18n.json +23 -9
- package/templates/firebase/lib/router.dart +43 -25
- package/templates/firebase/pubspec.yaml +1 -1
- package/templates/firebase/test/admin_shell_chrome_test.dart +104 -0
- package/templates/firebase/test/features/authentication/data/api/user_api_fake.dart +3 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_paywalls.dart +0 -53
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
"overview": "Overview",
|
|
13
13
|
"users": "Users",
|
|
14
14
|
"requests": "Requests",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
15
|
+
"tools": "Tools",
|
|
16
|
+
"debug": "Debug"
|
|
17
17
|
},
|
|
18
|
+
"back_to_app": "Back to app",
|
|
18
19
|
"overview": {
|
|
19
20
|
"section": "Project",
|
|
20
21
|
"backend": "Backend",
|
|
@@ -74,11 +75,12 @@
|
|
|
74
75
|
"cancel": "Cancel"
|
|
75
76
|
},
|
|
76
77
|
"groups": {
|
|
78
|
+
"actions": "Actions",
|
|
77
79
|
"features": "Features",
|
|
78
|
-
"showcase": "Showcase",
|
|
79
80
|
"preview": "Preview",
|
|
80
81
|
"debug_actions": "Debug actions",
|
|
81
|
-
"identity": "Identity"
|
|
82
|
+
"identity": "Identity",
|
|
83
|
+
"notification_test": "Notification test"
|
|
82
84
|
},
|
|
83
85
|
"settings_entry": {
|
|
84
86
|
"title": "Admin",
|
|
@@ -452,8 +454,8 @@
|
|
|
452
454
|
"specificDate": "Specific date",
|
|
453
455
|
"timeLabel": "Time",
|
|
454
456
|
"dayLabel": "Day of week",
|
|
455
|
-
"dateLabel": "Date
|
|
456
|
-
"selectDate": "Select date
|
|
457
|
+
"dateLabel": "Date",
|
|
458
|
+
"selectDate": "Select date"
|
|
457
459
|
},
|
|
458
460
|
"dailyReminder": {
|
|
459
461
|
"title": "Reminder",
|
|
@@ -600,7 +602,13 @@
|
|
|
600
602
|
"send_push_preview_now": "now",
|
|
601
603
|
"send_push_preview_title_placeholder": "Notification title",
|
|
602
604
|
"send_push_preview_body_placeholder": "Your message body shows here",
|
|
603
|
-
"device_preview_title": "Device Preview (web only)"
|
|
605
|
+
"device_preview_title": "Device Preview (web only)",
|
|
606
|
+
"send_push_section_recipients": "Recipients",
|
|
607
|
+
"send_push_section_content": "Content",
|
|
608
|
+
"send_push_section_advanced": "Advanced",
|
|
609
|
+
"send_push_audience_all": "Everyone",
|
|
610
|
+
"send_push_audience_specific": "Specific",
|
|
611
|
+
"send_push_audience_all_hint": "The notification will be sent to every subscribed user."
|
|
604
612
|
}
|
|
605
613
|
},
|
|
606
614
|
"rate_banner": {
|
|
@@ -619,6 +627,7 @@
|
|
|
619
627
|
"push_subtitle_disabled": "Tap to enable in Settings",
|
|
620
628
|
"push_subtitle_waiting": "Enable to stay in the loop",
|
|
621
629
|
"mark_all_read": "Mark as read",
|
|
630
|
+
"see_all": "See all",
|
|
622
631
|
"group_today": "Today",
|
|
623
632
|
"group_yesterday": "Yesterday",
|
|
624
633
|
"group_older": "Older",
|
|
@@ -684,7 +693,10 @@
|
|
|
684
693
|
"copyForAi": "Copy for AI",
|
|
685
694
|
"selectWidgetFirst": "Select a widget on screen first, then tap Copy.",
|
|
686
695
|
"inspectorHint": "Tap the UI to select a widget (purple outline). Then copy for your AI prompt.",
|
|
687
|
-
"statusActive": "Inspecting"
|
|
696
|
+
"statusActive": "Inspecting",
|
|
697
|
+
"fieldSize": "Size",
|
|
698
|
+
"fieldColor": "Color",
|
|
699
|
+
"copyJson": "Copy JSON"
|
|
688
700
|
},
|
|
689
701
|
"webDevicePreview": {
|
|
690
702
|
"frame": "Frame",
|
|
@@ -692,7 +704,9 @@
|
|
|
692
704
|
"darkTheme": "Dark theme",
|
|
693
705
|
"landscape": "Landscape",
|
|
694
706
|
"textScale": "Text scale",
|
|
695
|
-
"screenshot": "Screenshot"
|
|
707
|
+
"screenshot": "Screenshot",
|
|
708
|
+
"imageCopied": "Image copied — paste it in chat",
|
|
709
|
+
"imageDownloaded": "Image downloaded"
|
|
696
710
|
},
|
|
697
711
|
"biometric_prompt": {
|
|
698
712
|
"title_ios_face": "Turn on Face ID for App Lock?",
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
"overview": "Resumen",
|
|
13
13
|
"users": "Usuarios",
|
|
14
14
|
"requests": "Solicitudes",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
15
|
+
"tools": "Herramientas",
|
|
16
|
+
"debug": "Depuración"
|
|
17
17
|
},
|
|
18
|
+
"back_to_app": "Volver a la app",
|
|
18
19
|
"overview": {
|
|
19
20
|
"section": "Proyecto",
|
|
20
21
|
"backend": "Backend",
|
|
@@ -74,11 +75,12 @@
|
|
|
74
75
|
"cancel": "Cancelar"
|
|
75
76
|
},
|
|
76
77
|
"groups": {
|
|
78
|
+
"actions": "Acciones",
|
|
77
79
|
"features": "Funciones",
|
|
78
|
-
"showcase": "Vitrina",
|
|
79
80
|
"preview": "Vista previa",
|
|
80
81
|
"debug_actions": "Acciones de debug",
|
|
81
|
-
"identity": "Identidad"
|
|
82
|
+
"identity": "Identidad",
|
|
83
|
+
"notification_test": "Prueba de notificación"
|
|
82
84
|
},
|
|
83
85
|
"settings_entry": {
|
|
84
86
|
"title": "Admin",
|
|
@@ -452,8 +454,8 @@
|
|
|
452
454
|
"specificDate": "Fecha específica",
|
|
453
455
|
"timeLabel": "Hora",
|
|
454
456
|
"dayLabel": "Día de la semana",
|
|
455
|
-
"dateLabel": "Fecha
|
|
456
|
-
"selectDate": "Seleccionar fecha
|
|
457
|
+
"dateLabel": "Fecha",
|
|
458
|
+
"selectDate": "Seleccionar fecha"
|
|
457
459
|
},
|
|
458
460
|
"dailyReminder": {
|
|
459
461
|
"title": "Recordatorio",
|
|
@@ -600,7 +602,13 @@
|
|
|
600
602
|
"send_push_preview_now": "ahora",
|
|
601
603
|
"send_push_preview_title_placeholder": "Título de la notificación",
|
|
602
604
|
"send_push_preview_body_placeholder": "El cuerpo del mensaje aparece aquí",
|
|
603
|
-
"device_preview_title": "Device Preview (solo web)"
|
|
605
|
+
"device_preview_title": "Device Preview (solo web)",
|
|
606
|
+
"send_push_section_recipients": "Destinatarios",
|
|
607
|
+
"send_push_section_content": "Contenido",
|
|
608
|
+
"send_push_section_advanced": "Avanzado",
|
|
609
|
+
"send_push_audience_all": "Todos",
|
|
610
|
+
"send_push_audience_specific": "Específicos",
|
|
611
|
+
"send_push_audience_all_hint": "La notificación se enviará a todos los usuarios suscritos."
|
|
604
612
|
}
|
|
605
613
|
},
|
|
606
614
|
"rate_banner": {
|
|
@@ -619,6 +627,7 @@
|
|
|
619
627
|
"push_subtitle_disabled": "Toca para activar en Configuración",
|
|
620
628
|
"push_subtitle_waiting": "Activa para no perderte nada",
|
|
621
629
|
"mark_all_read": "Marcar leídas",
|
|
630
|
+
"see_all": "Ver todas",
|
|
622
631
|
"group_today": "Hoy",
|
|
623
632
|
"group_yesterday": "Ayer",
|
|
624
633
|
"group_older": "Más antiguas",
|
|
@@ -684,7 +693,10 @@
|
|
|
684
693
|
"copyForAi": "Copiar para IA",
|
|
685
694
|
"selectWidgetFirst": "Selecciona un widget en pantalla primero y luego toca Copiar.",
|
|
686
695
|
"inspectorHint": "Toca la interfaz para seleccionar (borde morado). Luego copia para tu prompt de IA.",
|
|
687
|
-
"statusActive": "Inspeccionando"
|
|
696
|
+
"statusActive": "Inspeccionando",
|
|
697
|
+
"fieldSize": "Tamaño",
|
|
698
|
+
"fieldColor": "Color",
|
|
699
|
+
"copyJson": "Copiar JSON"
|
|
688
700
|
},
|
|
689
701
|
"webDevicePreview": {
|
|
690
702
|
"frame": "Frame",
|
|
@@ -692,7 +704,9 @@
|
|
|
692
704
|
"darkTheme": "Tema oscuro",
|
|
693
705
|
"landscape": "Horizontal",
|
|
694
706
|
"textScale": "Escala de texto",
|
|
695
|
-
"screenshot": "Captura de pantalla"
|
|
707
|
+
"screenshot": "Captura de pantalla",
|
|
708
|
+
"imageCopied": "Imagen copiada — pégala en el chat",
|
|
709
|
+
"imageDownloaded": "Imagen descargada"
|
|
696
710
|
},
|
|
697
711
|
"biometric_prompt": {
|
|
698
712
|
"title_ios_face": "¿Activar Face ID en el bloqueo?",
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
"overview": "Visão geral",
|
|
13
13
|
"users": "Usuários",
|
|
14
14
|
"requests": "Solicitações",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
15
|
+
"tools": "Ferramentas",
|
|
16
|
+
"debug": "Depuração"
|
|
17
17
|
},
|
|
18
|
+
"back_to_app": "Voltar ao app",
|
|
18
19
|
"overview": {
|
|
19
20
|
"section": "Projeto",
|
|
20
21
|
"backend": "Backend",
|
|
@@ -74,11 +75,12 @@
|
|
|
74
75
|
"cancel": "Cancelar"
|
|
75
76
|
},
|
|
76
77
|
"groups": {
|
|
78
|
+
"actions": "Ações",
|
|
77
79
|
"features": "Recursos",
|
|
78
|
-
"showcase": "Vitrine",
|
|
79
80
|
"preview": "Preview",
|
|
80
81
|
"debug_actions": "Ações de debug",
|
|
81
|
-
"identity": "Identidade"
|
|
82
|
+
"identity": "Identidade",
|
|
83
|
+
"notification_test": "Teste de notificação"
|
|
82
84
|
},
|
|
83
85
|
"settings_entry": {
|
|
84
86
|
"title": "Admin",
|
|
@@ -452,8 +454,8 @@
|
|
|
452
454
|
"specificDate": "Data específica",
|
|
453
455
|
"timeLabel": "Horário",
|
|
454
456
|
"dayLabel": "Dia da semana",
|
|
455
|
-
"dateLabel": "Data
|
|
456
|
-
"selectDate": "Selecionar data
|
|
457
|
+
"dateLabel": "Data",
|
|
458
|
+
"selectDate": "Selecionar data"
|
|
457
459
|
},
|
|
458
460
|
"dailyReminder": {
|
|
459
461
|
"title": "Lembrete",
|
|
@@ -600,7 +602,13 @@
|
|
|
600
602
|
"send_push_preview_now": "agora",
|
|
601
603
|
"send_push_preview_title_placeholder": "Título da notificação",
|
|
602
604
|
"send_push_preview_body_placeholder": "O corpo da mensagem aparece aqui",
|
|
603
|
-
"device_preview_title": "Device Preview (somente web)"
|
|
605
|
+
"device_preview_title": "Device Preview (somente web)",
|
|
606
|
+
"send_push_section_recipients": "Destinatários",
|
|
607
|
+
"send_push_section_content": "Conteúdo",
|
|
608
|
+
"send_push_section_advanced": "Avançado",
|
|
609
|
+
"send_push_audience_all": "Todos",
|
|
610
|
+
"send_push_audience_specific": "Específicos",
|
|
611
|
+
"send_push_audience_all_hint": "A notificação será enviada para todos os usuários inscritos."
|
|
604
612
|
}
|
|
605
613
|
},
|
|
606
614
|
"rate_banner": {
|
|
@@ -619,6 +627,7 @@
|
|
|
619
627
|
"push_subtitle_disabled": "Toque para ativar nas configurações",
|
|
620
628
|
"push_subtitle_waiting": "Ative para não perder novidades",
|
|
621
629
|
"mark_all_read": "Marcar lidas",
|
|
630
|
+
"see_all": "Ver todas",
|
|
622
631
|
"group_today": "Hoje",
|
|
623
632
|
"group_yesterday": "Ontem",
|
|
624
633
|
"group_older": "Mais antigas",
|
|
@@ -684,7 +693,10 @@
|
|
|
684
693
|
"copyForAi": "Copiar para IA",
|
|
685
694
|
"selectWidgetFirst": "Selecione um widget na tela primeiro e depois toque em Copiar.",
|
|
686
695
|
"inspectorHint": "Toque na interface para selecionar (contorno roxo). Depois copie para usar na IA.",
|
|
687
|
-
"statusActive": "Inspecionando"
|
|
696
|
+
"statusActive": "Inspecionando",
|
|
697
|
+
"fieldSize": "Tamanho",
|
|
698
|
+
"fieldColor": "Cor",
|
|
699
|
+
"copyJson": "Copiar JSON"
|
|
688
700
|
},
|
|
689
701
|
"webDevicePreview": {
|
|
690
702
|
"frame": "Frame",
|
|
@@ -692,7 +704,9 @@
|
|
|
692
704
|
"darkTheme": "Tema escuro",
|
|
693
705
|
"landscape": "Paisagem",
|
|
694
706
|
"textScale": "Escala de texto",
|
|
695
|
-
"screenshot": "Screenshot"
|
|
707
|
+
"screenshot": "Screenshot",
|
|
708
|
+
"imageCopied": "Imagem copiada — cole no chat",
|
|
709
|
+
"imageDownloaded": "Imagem baixada"
|
|
696
710
|
},
|
|
697
711
|
"biometric_prompt": {
|
|
698
712
|
"title_ios_face": "Ativar Face ID no bloqueio do app?",
|
|
@@ -26,9 +26,7 @@ import 'package:kasy_kit/features/local_reminders/ui/reminder_page.dart';
|
|
|
26
26
|
import 'package:kasy_kit/features/onboarding/ui/onboarding_page.dart';
|
|
27
27
|
import 'package:kasy_kit/features/settings/ui/components/admin/admin_home_widgets.dart';
|
|
28
28
|
import 'package:kasy_kit/features/settings/ui/components/admin/admin_page.dart';
|
|
29
|
-
import 'package:kasy_kit/features/settings/ui/components/admin/admin_paywalls.dart';
|
|
30
29
|
import 'package:kasy_kit/features/settings/ui/components/admin/admin_routes.dart';
|
|
31
|
-
import 'package:kasy_kit/features/settings/ui/components/admin/send_push_notification_page.dart';
|
|
32
30
|
import 'package:kasy_kit/features/subscriptions/ui/component/premium_page_factory.dart';
|
|
33
31
|
import 'package:kasy_kit/features/subscriptions/ui/premium_page.dart';
|
|
34
32
|
import 'package:logger/logger.dart';
|
|
@@ -71,6 +69,16 @@ String? _authRedirect(Ref ref, GoRouterState state) {
|
|
|
71
69
|
// redirect yet — we re-run once the state resolves (refresh listenable).
|
|
72
70
|
if (user.isLoading) return null;
|
|
73
71
|
|
|
72
|
+
// Admin area is role-gated at the ROUTING layer (URLs included), not just by
|
|
73
|
+
// hiding UI: in production, /admin and every /admin/* section open only for an
|
|
74
|
+
// authenticated admin (role == "admin"). Anyone else — including someone who
|
|
75
|
+
// types the URL directly — is bounced home. Open in debug for development.
|
|
76
|
+
// This sits on top of the server-side data rules that ultimately protect the
|
|
77
|
+
// data; here it guarantees the screens themselves are never even reachable.
|
|
78
|
+
if (state.uri.path.startsWith('/admin') && !kDebugMode && !user.isAdmin) {
|
|
79
|
+
return '/';
|
|
80
|
+
}
|
|
81
|
+
|
|
74
82
|
final String loc = state.matchedLocation;
|
|
75
83
|
final bool onAuthRoute = _authRoutes.contains(loc);
|
|
76
84
|
final bool onboardingDone = ref
|
|
@@ -296,25 +304,42 @@ GoRouter generateRouter({
|
|
|
296
304
|
child: const RecoverPasswordPage(),
|
|
297
305
|
),
|
|
298
306
|
),
|
|
299
|
-
// Admin console:
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
307
|
+
// Admin console: a StatefulShellRoute so every section is a real,
|
|
308
|
+
// URL-addressable screen that keeps its own state while the navigation
|
|
309
|
+
// rail persists across them. The top-level sections (/admin, /admin/users,
|
|
310
|
+
// /admin/requests) and the four "Ferramentas" sub-screens (/admin/tools/*)
|
|
311
|
+
// are ALL branches — each its own URL, reached from the sidebar. Registered
|
|
312
|
+
// always (admins reach it in release too); the redirect above blocks
|
|
313
|
+
// /admin* for non-admins in production. adminSections() is the single
|
|
314
|
+
// source the sidebar reads too, so branches and nav rows stay aligned (the
|
|
315
|
+
// debug-only sections drop out of both together).
|
|
316
|
+
StatefulShellRoute.indexedStack(
|
|
317
|
+
// Enter /admin with the app's standard page transition
|
|
318
|
+
// (KasyNavigationConfig.push), same as every other route — pageBuilder
|
|
319
|
+
// (not builder), otherwise go_router falls back to its default platform
|
|
320
|
+
// transition. Switching sections is instant (IndexedStack), like tabs.
|
|
321
|
+
pageBuilder: (context, state, navigationShell) => kasyTransitionPage(
|
|
305
322
|
key: state.pageKey,
|
|
306
|
-
child:
|
|
323
|
+
child: AdminShell(navigationShell: navigationShell),
|
|
307
324
|
),
|
|
325
|
+
branches: [
|
|
326
|
+
for (final section in adminSections())
|
|
327
|
+
StatefulShellBranch(
|
|
328
|
+
routes: [
|
|
329
|
+
GoRoute(
|
|
330
|
+
path: section.path,
|
|
331
|
+
pageBuilder: (context, state) => kasyTransitionPage(
|
|
332
|
+
key: state.pageKey,
|
|
333
|
+
child: section.build(),
|
|
334
|
+
),
|
|
335
|
+
),
|
|
336
|
+
],
|
|
337
|
+
),
|
|
338
|
+
],
|
|
308
339
|
),
|
|
340
|
+
// Drill-downs pushed full-screen from inside the console (their own back
|
|
341
|
+
// button), debug-only — the redirect above keeps /admin* admin-only.
|
|
309
342
|
if (kDebugMode) ...[
|
|
310
|
-
GoRoute(
|
|
311
|
-
name: 'admin_paywalls',
|
|
312
|
-
path: adminRoutePaywalls,
|
|
313
|
-
pageBuilder: (context, state) => kasyTransitionPage(
|
|
314
|
-
key: state.pageKey,
|
|
315
|
-
child: const AdminPaywalls(),
|
|
316
|
-
),
|
|
317
|
-
),
|
|
318
343
|
GoRoute(
|
|
319
344
|
name: 'admin_home_widgets',
|
|
320
345
|
path: adminRouteHomeWidgets,
|
|
@@ -323,6 +348,7 @@ GoRouter generateRouter({
|
|
|
323
348
|
child: const AdminHomeWidgets(),
|
|
324
349
|
),
|
|
325
350
|
),
|
|
351
|
+
// Paywall variant preview — pushed from the Paywalls section.
|
|
326
352
|
GoRoute(
|
|
327
353
|
name: 'admin_premium_preview',
|
|
328
354
|
path: '/admin/premium/:variant',
|
|
@@ -343,14 +369,6 @@ GoRouter generateRouter({
|
|
|
343
369
|
},
|
|
344
370
|
),
|
|
345
371
|
],
|
|
346
|
-
GoRoute(
|
|
347
|
-
name: 'send_push',
|
|
348
|
-
path: adminRouteSendPush,
|
|
349
|
-
pageBuilder: (context, state) => kasyTransitionPage(
|
|
350
|
-
key: state.pageKey,
|
|
351
|
-
child: const SendPushNotificationPage(),
|
|
352
|
-
),
|
|
353
|
-
),
|
|
354
372
|
GoRoute(
|
|
355
373
|
name: '404',
|
|
356
374
|
path: '/404',
|
|
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|
|
16
16
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
|
17
17
|
# In Windows, build-name is used as the major, minor, and patch parts
|
|
18
18
|
# of the product and file versions while build-number is used as the build suffix.
|
|
19
|
-
version: 1.0.0+
|
|
19
|
+
version: 1.0.0+60
|
|
20
20
|
|
|
21
21
|
environment:
|
|
22
22
|
sdk: ^3.11.0
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import 'package:flutter/material.dart';
|
|
2
|
+
import 'package:flutter_test/flutter_test.dart';
|
|
3
|
+
import 'package:go_router/go_router.dart';
|
|
4
|
+
import 'package:kasy_kit/components/kasy_sidebar.dart';
|
|
5
|
+
import 'package:kasy_kit/components/kasy_web_header.dart';
|
|
6
|
+
import 'package:kasy_kit/core/data/models/user.dart';
|
|
7
|
+
import 'package:kasy_kit/core/states/models/user_state.dart';
|
|
8
|
+
import 'package:kasy_kit/features/settings/ui/components/admin/admin_page.dart';
|
|
9
|
+
import 'package:kasy_kit/features/settings/ui/components/admin/admin_routes.dart';
|
|
10
|
+
import 'package:kasy_kit/i18n/translations.g.dart';
|
|
11
|
+
|
|
12
|
+
import 'test_utils.dart';
|
|
13
|
+
|
|
14
|
+
/// Mirrors the real admin shell: every section (top-level AND the "Ferramentas"
|
|
15
|
+
/// sub-screens) is its own branch, so they all share the same chrome and a
|
|
16
|
+
/// persistent rail. Branch order/paths match [adminSections] so the shell's
|
|
17
|
+
/// currentIndex lines up; the branch bodies are placeholders so the test stays
|
|
18
|
+
/// focused on the chrome (sidebar + header), not on each page's providers.
|
|
19
|
+
GoRouter _adminTestRouter(String initial) => GoRouter(
|
|
20
|
+
initialLocation: initial,
|
|
21
|
+
routes: [
|
|
22
|
+
GoRoute(path: '/', builder: (_, _) => const SizedBox()),
|
|
23
|
+
StatefulShellRoute.indexedStack(
|
|
24
|
+
builder: (c, s, shell) => AdminShell(navigationShell: shell),
|
|
25
|
+
branches: [
|
|
26
|
+
for (final section in adminSections())
|
|
27
|
+
StatefulShellBranch(
|
|
28
|
+
routes: [
|
|
29
|
+
GoRoute(
|
|
30
|
+
path: section.path,
|
|
31
|
+
builder: (_, _) =>
|
|
32
|
+
Center(child: Text('section-${section.id.name}')),
|
|
33
|
+
),
|
|
34
|
+
],
|
|
35
|
+
),
|
|
36
|
+
],
|
|
37
|
+
),
|
|
38
|
+
],
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
UserState _adminUser() => UserState(
|
|
42
|
+
user: User.authenticated(
|
|
43
|
+
id: '1',
|
|
44
|
+
email: 'admin@email.com',
|
|
45
|
+
name: 'Admin',
|
|
46
|
+
onboarded: true,
|
|
47
|
+
role: 'admin',
|
|
48
|
+
creationDate: DateTime.now(),
|
|
49
|
+
),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
void main() {
|
|
53
|
+
testWidgets(
|
|
54
|
+
'admin section (desktop) renders the real KasySidebar + KasyWebHeader',
|
|
55
|
+
(tester) async {
|
|
56
|
+
tester.view.physicalSize = const Size(1400, 900);
|
|
57
|
+
tester.view.devicePixelRatio = 1.0;
|
|
58
|
+
addTearDown(tester.view.resetPhysicalSize);
|
|
59
|
+
addTearDown(tester.view.resetDevicePixelRatio);
|
|
60
|
+
|
|
61
|
+
await tester.pumpPage(
|
|
62
|
+
userState: _adminUser(),
|
|
63
|
+
routerConfig: _adminTestRouter('/admin'),
|
|
64
|
+
);
|
|
65
|
+
await tester.pump(const Duration(milliseconds: 300));
|
|
66
|
+
|
|
67
|
+
// The console uses the app's real chrome components, not a bespoke copy.
|
|
68
|
+
expect(find.byType(KasySidebar), findsOneWidget);
|
|
69
|
+
expect(find.byType(KasyWebHeader), findsOneWidget);
|
|
70
|
+
expect(find.text('section-overview'), findsOneWidget);
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
testWidgets(
|
|
75
|
+
'a Ferramentas sub-screen (desktop) is a real section: same rail + header, '
|
|
76
|
+
'submenu open',
|
|
77
|
+
(tester) async {
|
|
78
|
+
tester.view.physicalSize = const Size(1400, 900);
|
|
79
|
+
tester.view.devicePixelRatio = 1.0;
|
|
80
|
+
addTearDown(tester.view.resetPhysicalSize);
|
|
81
|
+
addTearDown(tester.view.resetDevicePixelRatio);
|
|
82
|
+
|
|
83
|
+
await tester.pumpPage(
|
|
84
|
+
userState: _adminUser(),
|
|
85
|
+
routerConfig: _adminTestRouter(adminRouteSendPush),
|
|
86
|
+
);
|
|
87
|
+
await tester.pump(const Duration(milliseconds: 300));
|
|
88
|
+
|
|
89
|
+
// Tools sub-screens get the SAME chrome as every other section now (the
|
|
90
|
+
// whole point of this change): the persistent rail AND the web header.
|
|
91
|
+
expect(find.byType(KasySidebar), findsOneWidget);
|
|
92
|
+
expect(find.byType(KasyWebHeader), findsOneWidget);
|
|
93
|
+
expect(find.text('section-sendPush'), findsOneWidget);
|
|
94
|
+
|
|
95
|
+
// The rail shows the "Ferramentas" group, auto-expanded because one of its
|
|
96
|
+
// children (Send push) is the active screen.
|
|
97
|
+
expect(find.text(t.admin_console.tabs.tools), findsOneWidget);
|
|
98
|
+
expect(
|
|
99
|
+
find.text(t.home.features_page.send_push_title),
|
|
100
|
+
findsWidgets,
|
|
101
|
+
);
|
|
102
|
+
},
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import 'package:flutter/material.dart';
|
|
2
|
-
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
3
|
-
import 'package:go_router/go_router.dart';
|
|
4
|
-
import 'package:kasy_kit/components/kasy_app_bar.dart';
|
|
5
|
-
import 'package:kasy_kit/core/theme/theme.dart';
|
|
6
|
-
import 'package:kasy_kit/core/widgets/kasy_scroll_behavior.dart';
|
|
7
|
-
import 'package:kasy_kit/features/settings/ui/components/admin/admin_routes.dart';
|
|
8
|
-
import 'package:kasy_kit/features/settings/ui/widgets/settings_tile.dart';
|
|
9
|
-
import 'package:kasy_kit/features/subscriptions/ui/component/premium_page_factory.dart';
|
|
10
|
-
import 'package:kasy_kit/i18n/translations.g.dart';
|
|
11
|
-
|
|
12
|
-
class AdminPaywalls extends ConsumerWidget {
|
|
13
|
-
const AdminPaywalls({super.key});
|
|
14
|
-
|
|
15
|
-
@override
|
|
16
|
-
Widget build(BuildContext context, WidgetRef ref) {
|
|
17
|
-
return ScrollConfiguration(
|
|
18
|
-
behavior: const KasyKitScrollBehavior(),
|
|
19
|
-
child: KasyOverlayScaffold(
|
|
20
|
-
title: t.settings.admin.paywalls_title,
|
|
21
|
-
onBack: () => context.pop(),
|
|
22
|
-
slivers: [
|
|
23
|
-
SliverToBoxAdapter(
|
|
24
|
-
child: Container(
|
|
25
|
-
padding: const EdgeInsets.symmetric(
|
|
26
|
-
vertical: KasySpacing.smd,
|
|
27
|
-
horizontal: KasySpacing.md,
|
|
28
|
-
),
|
|
29
|
-
decoration: BoxDecoration(
|
|
30
|
-
borderRadius: KasyRadius.smBorderRadius,
|
|
31
|
-
color: context.colors.surface,
|
|
32
|
-
),
|
|
33
|
-
child: Wrap(
|
|
34
|
-
children: [
|
|
35
|
-
for (final paywall in PaywallFactory.values) ...[
|
|
36
|
-
SettingsTile(
|
|
37
|
-
icon: KasyIcons.payment,
|
|
38
|
-
title: paywall.name,
|
|
39
|
-
onTap: () => context.push(
|
|
40
|
-
adminRoutePremiumPreview(paywall.name),
|
|
41
|
-
),
|
|
42
|
-
),
|
|
43
|
-
const SettingsDivider(),
|
|
44
|
-
],
|
|
45
|
-
],
|
|
46
|
-
),
|
|
47
|
-
),
|
|
48
|
-
),
|
|
49
|
-
],
|
|
50
|
-
),
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
}
|