kasy-cli 1.21.9 → 1.23.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.
Files changed (269) hide show
  1. package/lib/commands/add.js +93 -80
  2. package/lib/commands/configure.js +100 -32
  3. package/lib/commands/doctor.js +28 -2
  4. package/lib/commands/new.js +80 -37
  5. package/lib/commands/notifications.js +1 -1
  6. package/lib/commands/remove.js +43 -15
  7. package/lib/commands/run.js +2 -2
  8. package/lib/commands/update.js +2 -2
  9. package/lib/scaffold/CHANGELOG.json +14 -0
  10. package/lib/scaffold/backends/api/generator.js +14 -14
  11. package/lib/scaffold/backends/api/patch/README.md +83 -0
  12. package/lib/scaffold/backends/api/patch/lib/core/data/api/storage_api.dart +1 -1
  13. package/lib/scaffold/backends/api/patch/lib/core/data/entities/user_entity.dart +5 -0
  14. package/lib/scaffold/backends/api/patch/lib/{environnements.dart → environments.dart} +3 -11
  15. package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_api.dart +108 -0
  16. package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +51 -0
  17. package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +5 -5
  18. package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +71 -38
  19. package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +2 -2
  20. package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_request_api.dart +54 -0
  21. package/lib/scaffold/backends/api/patch/lib/features/onboarding/models/user_info.dart +16 -16
  22. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  23. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  24. package/lib/scaffold/backends/api/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +100 -0
  25. package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
  26. package/lib/scaffold/backends/api/patch/lib/features/subscriptions/api/stripe_backend_api.dart +60 -0
  27. package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  28. package/lib/scaffold/backends/api/pubspec.yaml.tpl +4 -5
  29. package/lib/scaffold/backends/firebase/deploy.js +87 -13
  30. package/lib/scaffold/backends/firebase/generator.js +5 -5
  31. package/lib/scaffold/backends/firebase/tokens.js +4 -4
  32. package/lib/scaffold/backends/supabase/deploy.js +63 -11
  33. package/lib/scaffold/backends/supabase/edge-functions/admin-list-users/index.ts +149 -0
  34. package/lib/scaffold/backends/supabase/edge-functions/{llm-chat → ai-chat}/index.ts +19 -19
  35. package/lib/scaffold/backends/supabase/edge-functions/revenuecat-webhook/index.ts +2 -0
  36. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-checkout-session/index.ts +123 -0
  37. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-portal-session/index.ts +97 -0
  38. package/lib/scaffold/backends/supabase/edge-functions/stripe-list-prices/index.ts +83 -0
  39. package/lib/scaffold/backends/supabase/edge-functions/stripe-webhook/index.ts +138 -0
  40. package/lib/scaffold/backends/supabase/generator.js +17 -17
  41. package/lib/scaffold/backends/supabase/migrations/20240101000009_ai_messages.sql +50 -0
  42. package/lib/scaffold/backends/supabase/migrations/20240101000012_stripe_customers.sql +36 -0
  43. package/lib/scaffold/backends/supabase/migrations/20240101000013_admin_role.sql +62 -0
  44. package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +4 -0
  45. package/lib/scaffold/backends/supabase/patch/lib/{environnements.dart → environments.dart} +3 -13
  46. package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_api.dart +95 -0
  47. package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +52 -0
  48. package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
  49. package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +63 -35
  50. package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +1 -1
  51. package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/feature_request_api.dart +46 -0
  52. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/models/user_info.dart +16 -16
  53. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  54. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  55. package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +93 -0
  56. package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
  57. package/lib/scaffold/backends/supabase/patch/lib/features/subscriptions/api/stripe_backend_api.dart +52 -0
  58. package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  59. package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +4 -5
  60. package/lib/scaffold/backends/supabase/tokens.js +3 -3
  61. package/lib/scaffold/catalog.js +9 -11
  62. package/lib/scaffold/generate.js +45 -31
  63. package/lib/scaffold/shared/generator-utils.js +188 -81
  64. package/lib/scaffold/shared/sort-imports.js +191 -0
  65. package/lib/scaffold/shared/template-strings.js +3 -3
  66. package/lib/utils/checks.js +22 -6
  67. package/lib/utils/env-tools.js +7 -0
  68. package/lib/utils/flutter-install.js +114 -0
  69. package/lib/utils/i18n/messages-en.js +52 -35
  70. package/lib/utils/i18n/messages-es.js +52 -35
  71. package/lib/utils/i18n/messages-pt.js +54 -37
  72. package/lib/utils/updates.js +15 -15
  73. package/package.json +1 -1
  74. package/templates/firebase/.env.example +2 -2
  75. package/templates/firebase/android/app/src/main/res/drawable/background.png +0 -0
  76. package/templates/firebase/android/app/src/main/res/drawable-night/background.png +0 -0
  77. package/templates/firebase/android/app/src/main/res/drawable-night-v21/background.png +0 -0
  78. package/templates/firebase/android/app/src/main/res/drawable-v21/background.png +0 -0
  79. package/templates/firebase/android/app/src/main/res/values-night-v31/styles.xml +1 -1
  80. package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +1 -1
  81. package/templates/firebase/assets/images/logo_wordmark_dark.png +0 -0
  82. package/templates/firebase/assets/images/logo_wordmark_light.png +0 -0
  83. package/templates/firebase/docs/revenuecat-setup.es.md +1 -1
  84. package/templates/firebase/docs/revenuecat-setup.pt.md +1 -1
  85. package/templates/firebase/firestore.rules +24 -5
  86. package/templates/firebase/functions/package-lock.json +22 -1
  87. package/templates/firebase/functions/package.json +2 -1
  88. package/templates/firebase/functions/src/admin/functions.ts +113 -0
  89. package/templates/firebase/functions/src/{llm_chat → ai_chat}/index.ts +16 -16
  90. package/templates/firebase/functions/src/index.ts +8 -2
  91. package/templates/firebase/functions/src/notifications/device_triggers.ts +2 -2
  92. package/templates/firebase/functions/src/notifications/triggers.ts +3 -3
  93. package/templates/firebase/functions/src/subscriptions/models/subscription_status.ts +2 -0
  94. package/templates/firebase/functions/src/subscriptions/stripe_functions.ts +222 -0
  95. package/templates/firebase/functions/src/subscriptions/subscriptions_functions.ts +2 -2
  96. package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png +0 -0
  97. package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png +0 -0
  98. package/templates/firebase/lib/components/components.dart +4 -1
  99. package/templates/firebase/lib/components/kasy_app_bar.dart +22 -7
  100. package/templates/firebase/lib/components/kasy_avatar.dart +7 -6
  101. package/templates/firebase/lib/components/kasy_button.dart +23 -99
  102. package/templates/firebase/lib/components/kasy_dialog.dart +11 -11
  103. package/templates/firebase/lib/components/kasy_image_viewer.dart +84 -0
  104. package/templates/firebase/lib/components/{kasy_sidebar_pro.dart → kasy_sidebar.dart} +702 -425
  105. package/templates/firebase/lib/components/kasy_status_tag.dart +91 -0
  106. package/templates/firebase/lib/components/kasy_text_area.dart +1 -3
  107. package/templates/firebase/lib/components/kasy_text_field.dart +5 -6
  108. package/templates/firebase/lib/components/kasy_text_field_otp.dart +1 -3
  109. package/templates/firebase/lib/components/kasy_toast.dart +2 -2
  110. package/templates/firebase/lib/components/kasy_web_header.dart +209 -0
  111. package/templates/firebase/lib/core/ads/ads_provider.dart +1 -1
  112. package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +136 -23
  113. package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +19 -91
  114. package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +196 -96
  115. package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +54 -0
  116. package/templates/firebase/lib/core/config/app_env.dart +5 -11
  117. package/templates/firebase/lib/core/config/features.dart +5 -4
  118. package/templates/firebase/lib/core/data/api/analytics_api.dart +1 -1
  119. package/templates/firebase/lib/core/data/api/http_client.dart +1 -1
  120. package/templates/firebase/lib/core/data/entities/user_entity.dart +3 -0
  121. package/templates/firebase/lib/core/data/models/entitlement.dart +35 -0
  122. package/templates/firebase/lib/core/data/models/subscription.dart +13 -186
  123. package/templates/firebase/lib/core/data/models/user.dart +11 -0
  124. package/templates/firebase/lib/core/data/repositories/user_repository.dart +1 -1
  125. package/templates/firebase/lib/core/home_widgets/home_widget_background_task.dart +1 -1
  126. package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +1 -1
  127. package/templates/firebase/lib/core/icons/kasy_icons.dart +31 -1
  128. package/templates/firebase/lib/core/rating/api/rating_api.dart +2 -2
  129. package/templates/firebase/lib/core/states/logout_action.dart +25 -0
  130. package/templates/firebase/lib/core/states/user_state_notifier.dart +3 -3
  131. package/templates/firebase/lib/core/theme/colors.dart +488 -188
  132. package/templates/firebase/lib/core/theme/radius.dart +22 -11
  133. package/templates/firebase/lib/core/theme/shadows.dart +66 -0
  134. package/templates/firebase/lib/core/theme/texts.dart +75 -41
  135. package/templates/firebase/lib/core/theme/universal_theme.dart +9 -4
  136. package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +5 -4
  137. package/templates/firebase/lib/core/web_viewport_scale.dart +52 -0
  138. package/templates/firebase/lib/core/widgets/kasy_brand_badge.dart +118 -0
  139. package/templates/firebase/lib/core/widgets/kasy_brand_logo.dart +40 -0
  140. package/templates/firebase/lib/core/widgets/kasy_focus_ring.dart +125 -0
  141. package/templates/firebase/lib/core/widgets/kasy_hover.dart +53 -14
  142. package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +18 -13
  143. package/templates/firebase/lib/{environnements.dart → environments.dart} +3 -14
  144. package/templates/firebase/lib/features/ai_chat/ai_chat_page.dart +159 -0
  145. package/templates/firebase/lib/features/ai_chat/api/ai_chat_api.dart +107 -0
  146. package/templates/firebase/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +64 -0
  147. package/templates/firebase/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
  148. package/templates/firebase/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +73 -38
  149. package/templates/firebase/lib/features/ai_chat/providers/ai_conversations_notifier.dart +103 -0
  150. package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_avatars.dart → ai_chat/ui/widgets/ai_chat_avatars.dart} +13 -13
  151. package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_composer.dart → ai_chat/ui/widgets/ai_chat_composer.dart} +10 -10
  152. package/templates/firebase/lib/features/{llm_chat/llm_chat_page.dart → ai_chat/ui/widgets/ai_chat_conversation_view.dart} +80 -67
  153. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +285 -0
  154. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +163 -0
  155. package/templates/firebase/lib/features/authentication/api/authentication_api.dart +52 -13
  156. package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher.dart +12 -0
  157. package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher_web.dart +35 -0
  158. package/templates/firebase/lib/features/authentication/ui/recover_password_page.dart +108 -68
  159. package/templates/firebase/lib/features/authentication/ui/signin_page.dart +38 -51
  160. package/templates/firebase/lib/features/authentication/ui/signup_page.dart +38 -51
  161. package/templates/firebase/lib/features/authentication/ui/widgets/auth_card_scaffold.dart +128 -0
  162. package/templates/firebase/lib/features/authentication/ui/widgets/recover_password_result.dart +61 -44
  163. package/templates/firebase/lib/features/feedbacks/api/feature_request_api.dart +32 -0
  164. package/templates/firebase/lib/features/feedbacks/models/feedback_state.dart +5 -5
  165. package/templates/firebase/lib/features/feedbacks/providers/feedback_page_notifier.dart +2 -2
  166. package/templates/firebase/lib/features/home/design_system_page.dart +808 -170
  167. package/templates/firebase/lib/features/home/home_components_page.dart +6 -3
  168. package/templates/firebase/lib/features/home/home_components_preview_page.dart +6 -6
  169. package/templates/firebase/lib/features/home/home_components_preview_registry.dart +325 -186
  170. package/templates/firebase/lib/features/home/home_feed.dart +289 -0
  171. package/templates/firebase/lib/features/home/home_image_grid.dart +355 -0
  172. package/templates/firebase/lib/features/home/home_page.dart +11 -250
  173. package/templates/firebase/lib/features/{local_reminder → local_reminders}/providers/reminder_notifier.dart +1 -1
  174. package/templates/firebase/lib/features/{local_reminder → local_reminders}/ui/reminder_page.dart +2 -2
  175. package/templates/firebase/lib/features/notifications/shared/att_permission.dart +1 -1
  176. package/templates/firebase/lib/features/notifications/ui/request_notification_permission.dart +25 -61
  177. package/templates/firebase/lib/features/notifications/ui/widgets/permission_request_view.dart +117 -0
  178. package/templates/firebase/lib/features/onboarding/models/user_info.dart +16 -16
  179. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  180. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_features.dart +7 -9
  181. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_loader.dart +71 -48
  182. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +3 -2
  183. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_questions.dart +5 -5
  184. package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +4 -4
  185. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_background.dart +4 -2
  186. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_feature.dart +39 -121
  187. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +105 -70
  188. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_module_mockups.dart +639 -0
  189. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_progress.dart +62 -50
  190. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  191. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_step_header.dart +75 -0
  192. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_sticky_footer.dart +16 -5
  193. package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +26 -22
  194. package/templates/firebase/lib/features/settings/settings_page.dart +601 -90
  195. package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +1193 -0
  196. package/templates/firebase/lib/features/settings/ui/components/admin/admin_paywalls.dart +1 -1
  197. package/templates/firebase/lib/features/settings/ui/components/admin/admin_routes.dart +2 -3
  198. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_api.dart +86 -0
  199. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_tab.dart +1215 -0
  200. package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +236 -0
  201. package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +3 -3
  202. package/templates/firebase/lib/features/settings/ui/widgets/kasy_user_avatar.dart +77 -0
  203. package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +1 -0
  204. package/templates/firebase/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +17 -0
  205. package/templates/firebase/lib/features/{subscription → subscriptions}/api/inapp_subscription_api.dart +67 -46
  206. package/templates/firebase/lib/features/subscriptions/api/revenuecat_product.dart +189 -0
  207. package/templates/firebase/lib/features/subscriptions/api/stripe_backend_api.dart +55 -0
  208. package/templates/firebase/lib/features/subscriptions/api/stripe_payment_api.dart +82 -0
  209. package/templates/firebase/lib/features/subscriptions/api/stripe_product.dart +178 -0
  210. package/templates/firebase/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  211. package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api.dart +53 -0
  212. package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api_provider.dart +21 -0
  213. package/templates/firebase/lib/features/{subscription → subscriptions}/providers/premium_page_provider.dart +9 -6
  214. package/templates/firebase/lib/features/{subscription → subscriptions}/repositories/subscription_repository.dart +26 -30
  215. package/{lib/scaffold/backends/supabase/patch/lib/features/subscription → templates/firebase/lib/features/subscriptions}/shared/maybeshow_premium.dart +0 -2
  216. package/templates/firebase/lib/features/subscriptions/shared/subscription_management.dart +45 -0
  217. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/active_premium_content.dart +28 -4
  218. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_minimal.dart +7 -7
  219. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_row.dart +8 -8
  220. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_with_switch.dart +7 -7
  221. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_content.dart +7 -7
  222. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_page_factory.dart +5 -5
  223. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/premium_page.dart +5 -5
  224. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/comparison_table.dart +1 -1
  225. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/paywall_empty_state.dart +4 -4
  226. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_bottom_menu.dart +3 -4
  227. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_col.dart +1 -1
  228. package/templates/firebase/lib/i18n/en.i18n.json +171 -46
  229. package/templates/firebase/lib/i18n/es.i18n.json +175 -50
  230. package/templates/firebase/lib/i18n/pt.i18n.json +166 -41
  231. package/templates/firebase/lib/main.dart +6 -3
  232. package/templates/firebase/lib/router.dart +15 -23
  233. package/templates/firebase/pubspec.yaml +5 -6
  234. package/templates/firebase/test/core/data/repositories/user_repository_test.dart +3 -3
  235. package/templates/firebase/test/core/states/user_state_notifier_test.dart +4 -4
  236. package/templates/firebase/test/core/widgets/focus_ring_shape_test.dart +55 -0
  237. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_inapp_subscription_api.dart +11 -4
  238. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_revenuecat_product.dart +1 -0
  239. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_subscription_api.dart +2 -2
  240. package/templates/firebase/test/features/{subscription → subscriptions}/subscription_page_test.dart +4 -4
  241. package/templates/firebase/test/test_utils.dart +6 -6
  242. package/templates/firebase/web/index.html +5 -2
  243. package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -58
  244. package/lib/scaffold/backends/api/patch/lib/features/subscription/shared/maybeshow_premium.dart +0 -86
  245. package/lib/scaffold/backends/supabase/migrations/20240101000009_llm_messages.sql +0 -22
  246. package/lib/scaffold/backends/supabase/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -47
  247. package/templates/firebase/assets/images/onboarding/authentication-login-template.jpg +0 -0
  248. package/templates/firebase/assets/images/onboarding/img2.jpg +0 -0
  249. package/templates/firebase/assets/images/onboarding/img3.jpg +0 -0
  250. package/templates/firebase/assets/images/onboarding/notifications.png +0 -0
  251. package/templates/firebase/assets/images/onboarding/purchase.png +0 -0
  252. package/templates/firebase/lib/core/sidebar/kasy_sidebar.dart +0 -2021
  253. package/templates/firebase/lib/features/authentication/ui/widgets/auth_brand.dart +0 -35
  254. package/templates/firebase/lib/features/home/home_features_page.dart +0 -207
  255. package/templates/firebase/lib/features/llm_chat/api/llm_chat_api.dart +0 -50
  256. package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +0 -316
  257. package/templates/firebase/lib/features/subscription/shared/maybeshow_premium.dart +0 -85
  258. /package/templates/firebase/lib/features/{local_reminder → local_reminders}/repositories/reminder_preferences.dart +0 -0
  259. /package/templates/firebase/lib/features/{subscription → subscriptions}/providers/models/premium_state.dart +0 -0
  260. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/feature_line.dart +0 -0
  261. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background.dart +0 -0
  262. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background_gradient.dart +0 -0
  263. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_banner.dart +0 -0
  264. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_card.dart +0 -0
  265. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_close_button.dart +0 -0
  266. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_feature.dart +0 -0
  267. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_row.dart +0 -0
  268. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/trial_switcher.dart +0 -0
  269. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/unsubscribe_feedback_popup.dart +0 -0
@@ -8,13 +8,13 @@ import 'package:kasy_kit/core/data/models/user.dart';
8
8
  import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
9
9
  import 'package:kasy_kit/core/states/user_state_notifier.dart';
10
10
  import 'package:kasy_kit/core/theme/theme.dart';
11
+ import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
11
12
  import 'package:kasy_kit/core/widgets/kasy_pressable_depth.dart';
12
- import 'package:kasy_kit/core/widgets/page_background.dart';
13
13
  import 'package:kasy_kit/features/authentication/providers/models/email.dart';
14
14
  import 'package:kasy_kit/features/authentication/providers/models/password.dart';
15
15
  import 'package:kasy_kit/features/authentication/providers/models/signin_state.dart';
16
16
  import 'package:kasy_kit/features/authentication/providers/signin_state_provider.dart';
17
- import 'package:kasy_kit/features/authentication/ui/widgets/auth_brand.dart';
17
+ import 'package:kasy_kit/features/authentication/ui/widgets/auth_card_scaffold.dart';
18
18
  import 'package:kasy_kit/features/authentication/ui/widgets/auth_page_back_button.dart';
19
19
  import 'package:kasy_kit/features/authentication/ui/widgets/social_separator.dart';
20
20
  import 'package:kasy_kit/i18n/translations.g.dart';
@@ -56,33 +56,13 @@ class SigninPage extends ConsumerWidget {
56
56
  resizeToAvoidBottomInset: false,
57
57
  body: Stack(
58
58
  children: [
59
- Background(
60
- child: Form(
61
- autovalidateMode: AutovalidateMode.disabled,
62
- key: _formKey,
63
- child: AuthFormScrollView(
64
- children: [
65
- const AuthBrand(),
66
- const SizedBox(height: KasySpacing.xl),
67
- Text(
68
- t.auth.signin.title,
69
- textAlign: TextAlign.center,
70
- style: context.textTheme.headlineMedium?.copyWith(
71
- fontWeight: FontWeight.w600,
72
- ),
73
- ),
74
- const SizedBox(height: KasySpacing.xs),
75
- Text(
76
- t.auth.signin.subtitle,
77
- textAlign: TextAlign.center,
78
- style: context.textTheme.bodyMedium?.copyWith(
79
- color: context.colors.onSurface.withValues(
80
- alpha: 0.62,
81
- ),
82
- fontWeight: FontWeight.w500,
83
- ),
84
- ),
85
- const SizedBox(height: KasySpacing.xl),
59
+ Form(
60
+ autovalidateMode: AutovalidateMode.disabled,
61
+ key: _formKey,
62
+ child: AuthCardScaffold(
63
+ title: t.auth.signin.title,
64
+ subtitle: t.auth.signin.subtitle,
65
+ children: [
86
66
  KasyTextField(
87
67
  key: const Key('email_input'),
88
68
  onChanged: (value) => ref
@@ -159,8 +139,7 @@ class SigninPage extends ConsumerWidget {
159
139
  const SocialSeparator(),
160
140
  const SizedBox(height: KasySpacing.md),
161
141
  const _SocialSigninRow(),
162
- ],
163
- ),
142
+ ],
164
143
  ),
165
144
  ),
166
145
  const AuthPageBackButton(),
@@ -292,27 +271,35 @@ class _SocialSigninTile extends StatelessWidget {
292
271
  @override
293
272
  Widget build(BuildContext context) {
294
273
  final bool enabled = onPressed != null;
295
- return Material(
296
- color: Colors.transparent,
297
- child: InkWell(
298
- onTap: enabled
299
- ? () {
300
- KasyHaptics.medium(context);
301
- onPressed?.call();
302
- }
303
- : null,
304
- borderRadius: BorderRadius.circular(KasyRadius.md),
305
- child: Ink(
306
- height: 44,
307
- decoration: BoxDecoration(
308
- color: context.colors.surface,
309
- borderRadius: BorderRadius.circular(KasyRadius.sm),
310
- border: Border.all(
311
- color: context.colors.outline.withValues(alpha: 0.38),
274
+ void handleTap() {
275
+ KasyHaptics.medium(context);
276
+ onPressed?.call();
277
+ }
278
+ return KasyFocusRing(
279
+ enabled: enabled,
280
+ onActivate: handleTap,
281
+ borderRadius: BorderRadius.circular(KasyRadius.sm),
282
+ child: Material(
283
+ color: Colors.transparent,
284
+ child: InkWell(
285
+ // Focus + keyboard activation live in KasyFocusRing; the InkWell keeps
286
+ // its tap ripple but doesn't take focus, so the ring is the only Tab
287
+ // stop and matches every other button's focus outline.
288
+ canRequestFocus: false,
289
+ onTap: enabled ? handleTap : null,
290
+ borderRadius: BorderRadius.circular(KasyRadius.md),
291
+ child: Ink(
292
+ height: 44,
293
+ decoration: BoxDecoration(
294
+ color: context.colors.surface,
295
+ borderRadius: BorderRadius.circular(KasyRadius.sm),
296
+ border: Border.all(
297
+ color: context.colors.outline.withValues(alpha: 0.38),
298
+ ),
299
+ ),
300
+ child: Center(
301
+ child: Semantics(button: true, label: label, child: icon),
312
302
  ),
313
- ),
314
- child: Center(
315
- child: Semantics(button: true, label: label, child: icon),
316
303
  ),
317
304
  ),
318
305
  ),
@@ -8,15 +8,15 @@ import 'package:kasy_kit/core/data/models/user.dart';
8
8
  import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
9
9
  import 'package:kasy_kit/core/states/user_state_notifier.dart';
10
10
  import 'package:kasy_kit/core/theme/theme.dart';
11
+ import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
11
12
  import 'package:kasy_kit/core/widgets/kasy_pressable_depth.dart';
12
- import 'package:kasy_kit/core/widgets/page_background.dart';
13
13
  import 'package:kasy_kit/features/authentication/providers/models/email.dart';
14
14
  import 'package:kasy_kit/features/authentication/providers/models/password.dart';
15
15
  import 'package:kasy_kit/features/authentication/providers/models/signin_state.dart';
16
16
  import 'package:kasy_kit/features/authentication/providers/models/signup_state.dart';
17
17
  import 'package:kasy_kit/features/authentication/providers/signin_state_provider.dart';
18
18
  import 'package:kasy_kit/features/authentication/providers/signup_state_provider.dart';
19
- import 'package:kasy_kit/features/authentication/ui/widgets/auth_brand.dart';
19
+ import 'package:kasy_kit/features/authentication/ui/widgets/auth_card_scaffold.dart';
20
20
  import 'package:kasy_kit/features/authentication/ui/widgets/auth_page_back_button.dart';
21
21
  import 'package:kasy_kit/features/authentication/ui/widgets/social_separator.dart';
22
22
  import 'package:kasy_kit/i18n/translations.g.dart';
@@ -52,33 +52,13 @@ class SignupPage extends ConsumerWidget {
52
52
  resizeToAvoidBottomInset: false,
53
53
  body: Stack(
54
54
  children: [
55
- Background(
56
- child: Form(
57
- autovalidateMode: AutovalidateMode.disabled,
58
- key: _formKey,
59
- child: AuthFormScrollView(
60
- children: [
61
- const AuthBrand(),
62
- const SizedBox(height: KasySpacing.xl),
63
- Text(
64
- t.auth.signup.title,
65
- textAlign: TextAlign.center,
66
- style: context.textTheme.headlineMedium?.copyWith(
67
- fontWeight: FontWeight.w600,
68
- ),
69
- ),
70
- const SizedBox(height: KasySpacing.xs),
71
- Text(
72
- t.auth.signup.subtitle,
73
- textAlign: TextAlign.center,
74
- style: context.textTheme.bodyMedium?.copyWith(
75
- color: context.colors.onSurface.withValues(
76
- alpha: 0.62,
77
- ),
78
- fontWeight: FontWeight.w500,
79
- ),
80
- ),
81
- const SizedBox(height: KasySpacing.xl),
55
+ Form(
56
+ autovalidateMode: AutovalidateMode.disabled,
57
+ key: _formKey,
58
+ child: AuthCardScaffold(
59
+ title: t.auth.signup.title,
60
+ subtitle: t.auth.signup.subtitle,
61
+ children: [
82
62
  KasyTextField(
83
63
  key: const Key('email_input'),
84
64
  onChanged: (value) => ref
@@ -148,8 +128,7 @@ class SignupPage extends ConsumerWidget {
148
128
  const SocialSeparator(),
149
129
  const SizedBox(height: KasySpacing.md),
150
130
  const _SocialSignupRow(),
151
- ],
152
- ),
131
+ ],
153
132
  ),
154
133
  ),
155
134
  const AuthPageBackButton(),
@@ -281,27 +260,35 @@ class _SocialSignupTile extends StatelessWidget {
281
260
  @override
282
261
  Widget build(BuildContext context) {
283
262
  final bool enabled = onPressed != null;
284
- return Material(
285
- color: Colors.transparent,
286
- child: InkWell(
287
- onTap: enabled
288
- ? () {
289
- KasyHaptics.medium(context);
290
- onPressed?.call();
291
- }
292
- : null,
293
- borderRadius: BorderRadius.circular(KasyRadius.md),
294
- child: Ink(
295
- height: 44,
296
- decoration: BoxDecoration(
297
- color: context.colors.surface,
298
- borderRadius: BorderRadius.circular(KasyRadius.sm),
299
- border: Border.all(
300
- color: context.colors.outline.withValues(alpha: 0.38),
263
+ void handleTap() {
264
+ KasyHaptics.medium(context);
265
+ onPressed?.call();
266
+ }
267
+ return KasyFocusRing(
268
+ enabled: enabled,
269
+ onActivate: handleTap,
270
+ borderRadius: BorderRadius.circular(KasyRadius.sm),
271
+ child: Material(
272
+ color: Colors.transparent,
273
+ child: InkWell(
274
+ // Focus + keyboard activation live in KasyFocusRing; the InkWell keeps
275
+ // its tap ripple but doesn't take focus, so the ring is the only Tab
276
+ // stop and matches every other button's focus outline.
277
+ canRequestFocus: false,
278
+ onTap: enabled ? handleTap : null,
279
+ borderRadius: BorderRadius.circular(KasyRadius.md),
280
+ child: Ink(
281
+ height: 44,
282
+ decoration: BoxDecoration(
283
+ color: context.colors.surface,
284
+ borderRadius: BorderRadius.circular(KasyRadius.sm),
285
+ border: Border.all(
286
+ color: context.colors.outline.withValues(alpha: 0.38),
287
+ ),
288
+ ),
289
+ child: Center(
290
+ child: Semantics(button: true, label: label, child: icon),
301
291
  ),
302
- ),
303
- child: Center(
304
- child: Semantics(button: true, label: label, child: icon),
305
292
  ),
306
293
  ),
307
294
  ),
@@ -0,0 +1,128 @@
1
+ import 'package:flutter/foundation.dart' show kIsWeb;
2
+ import 'package:flutter/material.dart';
3
+ import 'package:flutter_animate/flutter_animate.dart';
4
+ import 'package:kasy_kit/components/kasy_card.dart';
5
+ import 'package:kasy_kit/core/theme/theme.dart';
6
+ import 'package:kasy_kit/core/widgets/kasy_brand_logo.dart';
7
+ import 'package:kasy_kit/core/widgets/page_background.dart';
8
+ import 'package:kasy_kit/core/widgets/responsive_layout.dart';
9
+ import 'package:kasy_kit/features/authentication/ui/widgets/auth_page_back_button.dart';
10
+
11
+ /// Premium shell shared by the auth screens (sign in / sign up / recover).
12
+ ///
13
+ /// Follows the home design language: a soft, elevated [KasyCard] panel that
14
+ /// floats over the page background. The brand logo (same artwork as the splash)
15
+ /// sits INSIDE the card, centered, just above the title — it fades in gently.
16
+ /// Fully responsive: centered with a max width on web/desktop, top‑aligned and
17
+ /// edge‑to‑edge (minus the page gutter) on mobile.
18
+ ///
19
+ /// The painted skeleton: pass a [title], a [subtitle] and the form body in
20
+ /// [children]; tune the look with the knobs below without touching layout.
21
+ class AuthCardScaffold extends StatelessWidget {
22
+ const AuthCardScaffold({
23
+ super.key,
24
+ required this.title,
25
+ required this.subtitle,
26
+ required this.children,
27
+ this.showLogo = true,
28
+ this.logoHeight = 96,
29
+ this.maxContentWidth = 420,
30
+ });
31
+
32
+ /// Headline inside the card.
33
+ final String title;
34
+
35
+ /// Supporting line under the headline.
36
+ final String subtitle;
37
+
38
+ /// Form body: fields, primary button, prompts, social row, …
39
+ final List<Widget> children;
40
+
41
+ /// Show the brand logo above the title.
42
+ final bool showLogo;
43
+
44
+ /// Brand logo height.
45
+ final double logoHeight;
46
+
47
+ /// Card width cap on wide screens.
48
+ final double maxContentWidth;
49
+
50
+ @override
51
+ Widget build(BuildContext context) {
52
+ final EdgeInsets padding = authFormListPadding(context);
53
+ return Background(
54
+ child: LayoutBuilder(
55
+ builder: (context, constraints) {
56
+ final double minHeight = (constraints.maxHeight - padding.vertical)
57
+ .clamp(0.0, double.infinity);
58
+ // On the mobile breakpoint (small, < 768) the card container is
59
+ // dropped: the form sits directly over the page background,
60
+ // edge‑to‑edge minus the page gutter. The elevated card stays on
61
+ // tablet/desktop (medium and up).
62
+ final bool isMobile =
63
+ DeviceType.fromWidth(constraints.maxWidth) == DeviceType.small;
64
+ final Widget content = Column(
65
+ crossAxisAlignment: CrossAxisAlignment.stretch,
66
+ mainAxisSize: MainAxisSize.min,
67
+ children: [
68
+ if (showLogo) ...[
69
+ Center(
70
+ child: KasyBrandLogo(height: logoHeight)
71
+ .animate()
72
+ .fadeIn(
73
+ duration: const Duration(milliseconds: 420),
74
+ curve: Curves.easeOut,
75
+ ),
76
+ ),
77
+ const SizedBox(height: KasySpacing.lg),
78
+ ],
79
+ Text(
80
+ title,
81
+ textAlign: TextAlign.center,
82
+ style: context.textTheme.headlineSmall?.copyWith(
83
+ fontWeight: FontWeight.w700,
84
+ ),
85
+ ),
86
+ const SizedBox(height: KasySpacing.xs),
87
+ Text(
88
+ subtitle,
89
+ textAlign: TextAlign.center,
90
+ style: context.textTheme.bodyMedium?.copyWith(
91
+ color: context.colors.onSurface.withValues(
92
+ alpha: 0.62,
93
+ ),
94
+ fontWeight: FontWeight.w500,
95
+ ),
96
+ ),
97
+ const SizedBox(height: KasySpacing.xl),
98
+ ...children,
99
+ ],
100
+ );
101
+ return SingleChildScrollView(
102
+ physics: const ClampingScrollPhysics(),
103
+ keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
104
+ padding: padding,
105
+ child: ConstrainedBox(
106
+ constraints: BoxConstraints(minHeight: minHeight),
107
+ child: Align(
108
+ alignment: kIsWeb ? Alignment.center : Alignment.topCenter,
109
+ child: ConstrainedBox(
110
+ constraints: BoxConstraints(maxWidth: maxContentWidth),
111
+ child: isMobile
112
+ ? content
113
+ : KasyCard(
114
+ padding: const EdgeInsets.symmetric(
115
+ horizontal: KasySpacing.lg,
116
+ vertical: KasySpacing.xl,
117
+ ),
118
+ child: content,
119
+ ),
120
+ ),
121
+ ),
122
+ ),
123
+ );
124
+ },
125
+ ),
126
+ );
127
+ }
128
+ }
@@ -2,60 +2,77 @@ import 'package:flutter/material.dart';
2
2
  import 'package:go_router/go_router.dart';
3
3
  import 'package:kasy_kit/components/components.dart';
4
4
  import 'package:kasy_kit/core/theme/theme.dart';
5
+ import 'package:kasy_kit/core/widgets/kasy_brand_badge.dart';
5
6
  import 'package:kasy_kit/i18n/translations.g.dart';
6
7
 
8
+ /// Success state after a reset link is sent. Mirrors the auth card language:
9
+ /// a centered, width‑capped column topped by a success badge.
7
10
  class RecoverPasswordSent extends StatelessWidget {
8
11
  const RecoverPasswordSent({super.key});
9
12
 
10
13
  @override
11
14
  Widget build(BuildContext context) {
12
- return Center(
13
- child: Column(
14
- children: [
15
- const Spacer(),
16
- Icon(
17
- KasyIcons.checkCircle,
18
- color: context.colors.success,
19
- size: 64,
15
+ final KasyColors colors = context.colors;
16
+ return SafeArea(
17
+ child: Center(
18
+ child: SingleChildScrollView(
19
+ padding: const EdgeInsets.symmetric(
20
+ horizontal: KasySpacing.pageHorizontalGutter,
21
+ vertical: KasySpacing.xl,
20
22
  ),
21
- const SizedBox(height: KasySpacing.md),
22
- Text(
23
- t.recover_password_result.title,
24
- style: context.textTheme.headlineMedium!.copyWith(
25
- color: context.colors.success,
23
+ child: ConstrainedBox(
24
+ constraints: const BoxConstraints(maxWidth: 420),
25
+ child: Column(
26
+ mainAxisSize: MainAxisSize.min,
27
+ children: [
28
+ KasyBrandBadge(
29
+ icon: KasyIcons.checkCircle,
30
+ size: 72,
31
+ glyphSize: 36,
32
+ gradient: LinearGradient(
33
+ begin: Alignment.topLeft,
34
+ end: Alignment.bottomRight,
35
+ colors: [
36
+ colors.success,
37
+ Color.lerp(colors.success, Colors.black, 0.18)!,
38
+ ],
39
+ ),
40
+ ),
41
+ const SizedBox(height: KasySpacing.lg),
42
+ Text(
43
+ t.recover_password_result.title,
44
+ textAlign: TextAlign.center,
45
+ style: context.textTheme.headlineSmall?.copyWith(
46
+ fontWeight: FontWeight.w700,
47
+ ),
48
+ ),
49
+ const SizedBox(height: KasySpacing.smd),
50
+ Text(
51
+ t.recover_password_result.description,
52
+ textAlign: TextAlign.center,
53
+ style: context.textTheme.bodyLarge?.copyWith(
54
+ color: colors.muted,
55
+ height: 1.45,
56
+ ),
57
+ ),
58
+ const SizedBox(height: KasySpacing.xl),
59
+ KasyButton(
60
+ label: t.recover_password_result.back_to_signin,
61
+ expand: true,
62
+ onPressed: () => context.pop(),
63
+ ),
64
+ const SizedBox(height: KasySpacing.lg),
65
+ Text(
66
+ t.recover_password_result.note,
67
+ textAlign: TextAlign.center,
68
+ style: context.textTheme.bodySmall?.copyWith(
69
+ color: colors.muted,
70
+ ),
71
+ ),
72
+ ],
26
73
  ),
27
74
  ),
28
- const SizedBox(height: KasySpacing.md),
29
- Padding(
30
- padding: const EdgeInsets.symmetric(horizontal: KasySpacing.pageHorizontalGutter),
31
- child: Text(
32
- t.recover_password_result.description,
33
- textAlign: TextAlign.center,
34
- style: context.textTheme.titleMedium!.copyWith(
35
- color: context.colors.onBackground,
36
- ),
37
- ),
38
- ),
39
- const SizedBox(height: KasySpacing.md),
40
- KasyButton(
41
- label: t.recover_password_result.back_to_signin,
42
- onPressed: () => context.pop(),
43
- ),
44
- const Spacer(),
45
- Padding(
46
- padding: const EdgeInsets.symmetric(
47
- horizontal: KasySpacing.pageHorizontalGutter,
48
- vertical: KasySpacing.lg,
49
- ),
50
- child: Text(
51
- t.recover_password_result.note,
52
- textAlign: TextAlign.center,
53
- style: context.textTheme.titleMedium!.copyWith(
54
- color: context.colors.muted,
55
- ),
56
- ),
57
- ),
58
- ],
75
+ ),
59
76
  ),
60
77
  );
61
78
  }
@@ -48,4 +48,36 @@ class FeatureRequestApi {
48
48
  final docRef = await _collection.add(entity);
49
49
  return docRef.id;
50
50
  }
51
+
52
+ /// Admin: every request (active + hidden), highest-voted first.
53
+ Future<List<FeatureRequestEntity>> getAll() async {
54
+ final snapshot = await _collection.get();
55
+ final list = snapshot.docs
56
+ .map((e) => e.data())
57
+ .whereType<FeatureRequestEntity>()
58
+ .toList();
59
+ list.sort((a, b) => b.votes.compareTo(a.votes));
60
+ return list;
61
+ }
62
+
63
+ /// Admin: toggle whether a request is visible (and votable) to users.
64
+ Future<void> setActive(String id, bool active) {
65
+ return _client
66
+ .collection('feature_requests')
67
+ .doc(id)
68
+ .update({'active': active});
69
+ }
70
+
71
+ /// Admin: update the localized title/description maps (en/pt/es).
72
+ Future<void> updateTexts({
73
+ required String id,
74
+ required Map<String, String> title,
75
+ required Map<String, String> description,
76
+ }) {
77
+ return _client.collection('feature_requests').doc(id).update({
78
+ 'title': title,
79
+ 'description': description,
80
+ 'lastUpdateDate': FieldValue.serverTimestamp(),
81
+ });
82
+ }
51
83
  }
@@ -1,25 +1,25 @@
1
1
  import 'package:kasy_kit/features/feedbacks/models/feature_requests.dart';
2
2
 
3
- class FeebackPageState {
3
+ class FeedbackPageState {
4
4
  List<FeatureRequestVote> userVotes;
5
5
  List<FeatureRequest> featureRequests;
6
6
 
7
- FeebackPageState({
7
+ FeedbackPageState({
8
8
  required this.featureRequests,
9
9
  required this.userVotes,
10
10
  });
11
11
 
12
- FeebackPageState copyWith({
12
+ FeedbackPageState copyWith({
13
13
  List<FeatureRequest>? featureRequests,
14
14
  List<FeatureRequestVote>? userVotes,
15
15
  }) {
16
- return FeebackPageState(
16
+ return FeedbackPageState(
17
17
  featureRequests: featureRequests ?? this.featureRequests,
18
18
  userVotes: userVotes ?? this.userVotes,
19
19
  );
20
20
  }
21
21
 
22
- FeebackPageState addVote(FeatureRequest feature, int vote) {
22
+ FeedbackPageState addVote(FeatureRequest feature, int vote) {
23
23
  final index =
24
24
  featureRequests.indexWhere((element) => element.id == feature.id);
25
25
  if (index == -1) {
@@ -14,7 +14,7 @@ class FeedbackPageNotifier extends _$FeedbackPageNotifier {
14
14
  bool _isVoting = false;
15
15
 
16
16
  @override
17
- Future<FeebackPageState> build() async {
17
+ Future<FeedbackPageState> build() async {
18
18
  final featureRequestRepository = ref.read(featureRequestRepositoryProvider);
19
19
  final userId = ref.read(userStateNotifierProvider).user.idOrNull;
20
20
 
@@ -24,7 +24,7 @@ class FeedbackPageNotifier extends _$FeedbackPageNotifier {
24
24
  final features = await featureRequestRepository.getActiveFeatureRequests();
25
25
  features.sort((a, b) => b.votes.compareTo(a.votes));
26
26
 
27
- return FeebackPageState(
27
+ return FeedbackPageState(
28
28
  featureRequests: features,
29
29
  userVotes: userVotes,
30
30
  );