vibefast-cli 1.1.5 → 1.3.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 (301) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +63 -169
  3. package/dist/__tests__/recipes.test.js +89 -85
  4. package/dist/__tests__/recipes.test.js.map +1 -1
  5. package/dist/commands/add.d.ts +1 -1
  6. package/dist/commands/add.d.ts.map +1 -1
  7. package/dist/commands/add.js +576 -588
  8. package/dist/commands/add.js.map +1 -1
  9. package/dist/commands/checklist.d.ts +1 -1
  10. package/dist/commands/checklist.d.ts.map +1 -1
  11. package/dist/commands/checklist.js +40 -39
  12. package/dist/commands/checklist.js.map +1 -1
  13. package/dist/commands/doctor.d.ts +1 -1
  14. package/dist/commands/doctor.js +22 -22
  15. package/dist/commands/doctor.js.map +1 -1
  16. package/dist/commands/env.d.ts +1 -1
  17. package/dist/commands/env.d.ts.map +1 -1
  18. package/dist/commands/env.js +58 -53
  19. package/dist/commands/env.js.map +1 -1
  20. package/dist/commands/health.d.ts +1 -1
  21. package/dist/commands/health.d.ts.map +1 -1
  22. package/dist/commands/health.js +101 -93
  23. package/dist/commands/health.js.map +1 -1
  24. package/dist/commands/init.d.ts +1 -1
  25. package/dist/commands/init.d.ts.map +1 -1
  26. package/dist/commands/init.js +416 -296
  27. package/dist/commands/init.js.map +1 -1
  28. package/dist/commands/remove.d.ts +1 -1
  29. package/dist/commands/remove.d.ts.map +1 -1
  30. package/dist/commands/remove.js +77 -64
  31. package/dist/commands/remove.js.map +1 -1
  32. package/dist/commands/status.d.ts +1 -1
  33. package/dist/commands/status.d.ts.map +1 -1
  34. package/dist/commands/status.js +15 -14
  35. package/dist/commands/status.js.map +1 -1
  36. package/dist/core/__tests__/detect.test.js +68 -34
  37. package/dist/core/__tests__/detect.test.js.map +1 -1
  38. package/dist/core/ast.d.ts +14 -0
  39. package/dist/core/ast.d.ts.map +1 -0
  40. package/dist/core/ast.js +239 -0
  41. package/dist/core/ast.js.map +1 -0
  42. package/dist/core/codemod.d.ts.map +1 -1
  43. package/dist/core/codemod.js +62 -44
  44. package/dist/core/codemod.js.map +1 -1
  45. package/dist/core/config.d.ts +10 -0
  46. package/dist/core/config.d.ts.map +1 -0
  47. package/dist/core/config.js +51 -0
  48. package/dist/core/config.js.map +1 -0
  49. package/dist/core/detect.d.ts +8 -2
  50. package/dist/core/detect.d.ts.map +1 -1
  51. package/dist/core/detect.js +52 -21
  52. package/dist/core/detect.js.map +1 -1
  53. package/dist/core/errors.d.ts.map +1 -1
  54. package/dist/core/errors.js +9 -8
  55. package/dist/core/errors.js.map +1 -1
  56. package/dist/core/exec.d.ts +16 -0
  57. package/dist/core/exec.d.ts.map +1 -0
  58. package/dist/core/exec.js +48 -0
  59. package/dist/core/exec.js.map +1 -0
  60. package/dist/core/manualSteps.d.ts +7 -0
  61. package/dist/core/manualSteps.d.ts.map +1 -0
  62. package/dist/core/manualSteps.js +59 -0
  63. package/dist/core/manualSteps.js.map +1 -0
  64. package/dist/core/paths.d.ts +3 -1
  65. package/dist/core/paths.d.ts.map +1 -1
  66. package/dist/core/paths.js +14 -10
  67. package/dist/core/paths.js.map +1 -1
  68. package/dist/core/spinner.d.ts +1 -1
  69. package/dist/core/spinner.d.ts.map +1 -1
  70. package/dist/core/spinner.js +38 -8
  71. package/dist/core/spinner.js.map +1 -1
  72. package/dist/core/vosk.d.ts.map +1 -1
  73. package/dist/core/vosk.js +50 -39
  74. package/dist/core/vosk.js.map +1 -1
  75. package/docs/manual-testing.md +91 -0
  76. package/package.json +6 -3
  77. package/recipes/audio-recorder/apps/native/src/app/audio-recorder/index.tsx +5 -0
  78. package/recipes/audio-recorder/recipe.json +3 -3
  79. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-player.tsx +301 -0
  80. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +373 -0
  81. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-waveform.tsx +270 -0
  82. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/index.ts +4 -0
  83. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/recording-list.tsx +89 -0
  84. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-player-demo.tsx +66 -0
  85. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-cloud.tsx +68 -0
  86. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-interview.tsx +102 -0
  87. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/basic.tsx +27 -0
  88. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/index.ts +5 -0
  89. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +82 -0
  90. package/recipes/audio-recorder-supabase/packages/backend/src/services/recordings.ts +369 -0
  91. package/recipes/audio-recorder-supabase/packages/backend/supabase/migrations/recordings.sql +70 -0
  92. package/recipes/audio-recorder-supabase/recipe.json +52 -0
  93. package/recipes/audio-recorder-supabase@latest.zip +0 -0
  94. package/recipes/audio-recorder@latest.zip +0 -0
  95. package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +3 -3
  96. package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +2 -2
  97. package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +5 -5
  98. package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +3 -3
  99. package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +20 -4
  100. package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +7 -6
  101. package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +6 -4
  102. package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +1 -1
  103. package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +5 -4
  104. package/recipes/charts/recipe.json +4 -13
  105. package/recipes/charts@latest.zip +0 -0
  106. package/recipes/chatbot/apps/native/src/app/chatbot/index.tsx +1 -0
  107. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +86 -86
  108. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +86 -53
  109. package/recipes/chatbot/recipe.json +26 -92
  110. package/recipes/chatbot-supabase/apps/native/src/api-client/supabase/chatbot.ts +515 -0
  111. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/app/index.tsx +257 -0
  112. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +59 -0
  113. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-input-bar.tsx +485 -0
  114. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-markdown.tsx +575 -0
  115. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +223 -0
  116. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +161 -0
  117. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/image-preview-list.tsx +116 -0
  118. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/code-block.tsx +165 -0
  119. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/index.ts +10 -0
  120. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +129 -0
  121. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-error-boundary.tsx +78 -0
  122. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-list.tsx +170 -0
  123. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/model-selector.tsx +283 -0
  124. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/report-content-modal.tsx +188 -0
  125. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/suggested-messages.tsx +67 -0
  126. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/models.ts +20 -0
  127. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/report-reasons.ts +9 -0
  128. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +142 -0
  129. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-config.ts +458 -0
  130. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +429 -0
  131. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +89 -0
  132. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-conversation.ts +90 -0
  133. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-image-picker.ts +122 -0
  134. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +161 -0
  135. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +213 -0
  136. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/index.ts +86 -0
  137. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/models.ts +162 -0
  138. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/providers.ts +62 -0
  139. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/types.ts +40 -0
  140. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/file-uploader.ts +287 -0
  141. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/message-handler-service.ts +189 -0
  142. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/types/index.ts +70 -0
  143. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/utils/chat-telemetry.ts +91 -0
  144. package/recipes/chatbot-supabase/packages/backend/src/services/conversations.ts +243 -0
  145. package/recipes/chatbot-supabase/packages/backend/src/services/messages.ts +327 -0
  146. package/recipes/chatbot-supabase/packages/backend/supabase/functions/chat-stream/index.ts +347 -0
  147. package/recipes/chatbot-supabase/packages/backend/supabase/migrations/chatbot.sql +104 -0
  148. package/recipes/chatbot-supabase/recipe.json +106 -0
  149. package/recipes/chatbot-supabase@latest.zip +0 -0
  150. package/recipes/chatbot.zip +0 -0
  151. package/recipes/chatbot@latest.zip +0 -0
  152. package/recipes/image-analysis/packages/backend/convex/imageAnalysis/index.ts +2 -2
  153. package/recipes/image-analysis/packages/backend/convex/imageAnalysis.ts +0 -1
  154. package/recipes/image-analysis/recipe.json +15 -55
  155. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/analysis-options-screen.tsx +304 -0
  156. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/camera.tsx +221 -0
  157. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/image-capture-screen.tsx +333 -0
  158. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading-screen.tsx +214 -0
  159. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading.tsx +191 -0
  160. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/results.tsx +137 -0
  161. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/trait-details.tsx +172 -0
  162. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-analysis-data.ts +160 -0
  163. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-results-screen.ts +151 -0
  164. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-badge.tsx +77 -0
  165. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-card.tsx +75 -0
  166. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-unlocked-modal.tsx +162 -0
  167. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievements-section.tsx +44 -0
  168. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/advice-list.tsx +42 -0
  169. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/circular-progress.tsx +233 -0
  170. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/content-card.tsx +38 -0
  171. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/error-state.tsx +42 -0
  172. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/index.ts +9 -0
  173. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/loading-state.tsx +26 -0
  174. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/profile-image.tsx +60 -0
  175. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/results-header.tsx +62 -0
  176. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/score-display.tsx +54 -0
  177. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/share-options-modal.tsx +110 -0
  178. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/traits-grid.tsx +74 -0
  179. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/analysis-config.ts +80 -0
  180. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/master-analysis-config.ts +157 -0
  181. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/index.ts +1 -0
  182. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-analysis.ts +38 -0
  183. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-image-analysis.ts +208 -0
  184. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/analysis-service.ts +262 -0
  185. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/share-service.ts +176 -0
  186. package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/trait-details-service.ts +289 -0
  187. package/recipes/image-analysis-supabase/packages/backend/src/services/image-analyses.ts +132 -0
  188. package/recipes/image-analysis-supabase/packages/backend/supabase/functions/analyze-image/index.ts +312 -0
  189. package/recipes/image-analysis-supabase/packages/backend/supabase/migrations/image_analysis.sql +42 -0
  190. package/recipes/image-analysis-supabase/recipe.json +90 -0
  191. package/recipes/image-analysis-supabase@latest.zip +0 -0
  192. package/recipes/image-analysis@latest.zip +0 -0
  193. package/recipes/image-generator/apps/native/src/features/image-generator/app/index.tsx +16 -2
  194. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-model-selector.tsx +11 -5
  195. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator.ts +11 -5
  196. package/recipes/image-generator/packages/backend/convex/imageGeneration/index.ts +2 -2
  197. package/recipes/image-generator/recipe.json +16 -39
  198. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/_layout.tsx +26 -0
  199. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/gallery.tsx +217 -0
  200. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/index.tsx +251 -0
  201. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/gallery-image.tsx +25 -0
  202. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-detail-modal.tsx +215 -0
  203. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-model-selector.tsx +216 -0
  204. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-placeholder.tsx +26 -0
  205. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-gallery.ts +71 -0
  206. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator-settings.ts +152 -0
  207. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator.ts +103 -0
  208. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/models/models.ts +66 -0
  209. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-gallery-service.ts +96 -0
  210. package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-save-service.ts +120 -0
  211. package/recipes/image-generator-supabase/packages/backend/supabase/functions/generate-image/index.ts +291 -0
  212. package/recipes/image-generator-supabase/packages/backend/supabase/migrations/image_generator.sql +71 -0
  213. package/recipes/image-generator-supabase/recipe.json +86 -0
  214. package/recipes/image-generator-supabase@latest.zip +0 -0
  215. package/recipes/image-generator@latest.zip +0 -0
  216. package/recipes/ios-widget/recipe.json +15 -24
  217. package/recipes/ios-widget@latest.zip +0 -0
  218. package/recipes/onboarding/apps/native/src/features/onboarding/analytics/index.ts +9 -0
  219. package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding-with-analytics.tsx +141 -0
  220. package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding.tsx +173 -0
  221. package/recipes/onboarding/apps/native/src/features/onboarding/config/onboarding-flow-config.ts +189 -0
  222. package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/app/index.tsx +42 -0
  223. package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/data.ts +32 -0
  224. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/app/index.tsx +43 -0
  225. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/interactive-onboarding.tsx +222 -0
  226. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/ai-tone-step.tsx +133 -0
  227. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/currency-step.tsx +165 -0
  228. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-ai-step.tsx +199 -0
  229. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-chatbot-step.tsx +154 -0
  230. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-manual-step.tsx +156 -0
  231. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-scan-step.tsx +158 -0
  232. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/main-reason-step.tsx +139 -0
  233. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/notification-step.tsx +129 -0
  234. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/overspend-step.tsx +138 -0
  235. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/personalizing-step.tsx +190 -0
  236. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/rating-step.tsx +98 -0
  237. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/reminder-step.tsx +181 -0
  238. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/safety-step.tsx +110 -0
  239. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/struggle-step.tsx +139 -0
  240. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/welcome-step.tsx +217 -0
  241. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/ui/onboarding-header.tsx +58 -0
  242. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/constants.ts +179 -0
  243. package/recipes/onboarding/apps/native/src/features/onboarding/hooks/use-onboarding-analytics.ts +323 -0
  244. package/recipes/onboarding/apps/native/src/features/onboarding/services/onboarding-analytics.ts +432 -0
  245. package/recipes/onboarding/recipe.json +15 -0
  246. package/recipes/onboarding@latest.zip +0 -0
  247. package/recipes/payments/recipe.json +28 -61
  248. package/recipes/payments-supabase/apps/native/src/features/payments/README.md +200 -0
  249. package/recipes/payments-supabase/apps/native/src/features/payments/app/local-paywall.tsx +194 -0
  250. package/recipes/payments-supabase/apps/native/src/features/payments/app/remote-paywall.tsx +79 -0
  251. package/recipes/payments-supabase/apps/native/src/features/payments/components/payment-initializer.tsx +95 -0
  252. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-error-state.tsx +60 -0
  253. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-local-mode.tsx +116 -0
  254. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-product-card.tsx +133 -0
  255. package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-remote-mode.tsx +146 -0
  256. package/recipes/payments-supabase/apps/native/src/features/payments/hooks/use-entitlement.ts +63 -0
  257. package/recipes/payments-supabase/apps/native/src/features/payments/index.ts +8 -0
  258. package/recipes/payments-supabase/apps/native/src/features/payments/services/revenuecat-adapter.ts +407 -0
  259. package/recipes/payments-supabase/packages/backend/src/services/payments.ts +201 -0
  260. package/recipes/payments-supabase/packages/backend/supabase/migrations/payments.sql +35 -0
  261. package/recipes/payments-supabase/recipe.json +72 -0
  262. package/recipes/payments-supabase@latest.zip +0 -0
  263. package/recipes/payments@latest.zip +0 -0
  264. package/recipes/quiz/apps/native/src/features/quiz/index.tsx +1 -2
  265. package/recipes/quiz/recipe.json +6 -9
  266. package/recipes/quiz@latest.zip +0 -0
  267. package/recipes/tracker-app/apps/native/src/features/tracker-app/app/index.tsx +1 -2
  268. package/recipes/tracker-app/recipe.json +7 -10
  269. package/recipes/tracker-app@latest.zip +0 -0
  270. package/recipes/voice-bot/recipe.json +8 -68
  271. package/recipes/voice-bot.zip +0 -0
  272. package/recipes/voice-bot@latest.zip +0 -0
  273. package/recipes/wake-word/recipe.json +10 -9
  274. package/recipes/wake-word.zip +0 -0
  275. package/recipes/wake-word@latest.zip +0 -0
  276. package/recipes/charts/apps/native/src/app/(root)/(protected)/charts/index.tsx +0 -3
  277. package/recipes/chatbot/packages/backend/convex/lib/rateLimit.ts +0 -100
  278. package/recipes/chatbot/packages/backend/convex/lib/telemetry.ts +0 -29
  279. package/recipes/chatbot/packages/backend/convex/ragKnowledge.ts +0 -0
  280. package/recipes/image-analysis/apps/native/assets/features/image-analyzer/front.jpg +0 -0
  281. package/recipes/image-analysis/apps/native/assets/features/image-analyzer/side.jpg +0 -0
  282. package/recipes/image-analysis/apps/native/assets/features/image-analyzer/threeQuarter.jpg +0 -0
  283. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/_layout.tsx +0 -5
  284. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/analysis-options.tsx +0 -50
  285. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/camera.tsx +0 -2
  286. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/index.tsx +0 -50
  287. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/loading.tsx +0 -50
  288. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/results.tsx +0 -2
  289. package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/trait-details.tsx +0 -3
  290. package/recipes/image-analysis/packages/backend/convex/imageAnalysisFunctions.ts +0 -325
  291. package/recipes/image-analysis/packages/backend/convex/lib/ai/imageAnalysisAdapter.ts +0 -200
  292. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/index.tsx +0 -74
  293. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/local.tsx +0 -25
  294. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/remote.tsx +0 -23
  295. package/recipes/quiz/apps/native/src/app/(root)/(protected)/quiz/index.tsx +0 -47
  296. package/recipes/tracker-app/apps/native/src/app/(root)/(protected)/tracker-app/index.tsx +0 -1
  297. package/recipes/voice-bot/apps/native/src/app/(root)/(protected)/voice-bot/index.tsx +0 -27
  298. package/recipes/voice-bot/packages/backend/convex/router.ts +0 -81
  299. /package/recipes/{chatbot/apps/native/src/app/(root)/(protected) → chatbot-supabase/apps/native/src/app}/chatbot/index.tsx +0 -0
  300. /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/gallery.tsx +0 -0
  301. /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/index.tsx +0 -0
@@ -0,0 +1,189 @@
1
+ import type { OnboardingFlowConfig } from '../services/onboarding-analytics';
2
+
3
+ /**
4
+ * Demo One: Multi-step animated onboarding flow
5
+ * A comprehensive onboarding with multiple screens and Lottie animations
6
+ */
7
+ export const DEMO_ONE_ONBOARDING_FLOW: OnboardingFlowConfig = {
8
+ flowId: 'demo_one_flow',
9
+ flowName: 'Multi-Step Animated Onboarding',
10
+ version: '1.0',
11
+ steps: [
12
+ {
13
+ id: 'welcome_screen',
14
+ name: 'Welcome to VibeFast',
15
+ index: 0,
16
+ category: 'intro',
17
+ isOptional: false,
18
+ },
19
+ {
20
+ id: 'ai_features',
21
+ name: 'AI-Powered Development',
22
+ index: 1,
23
+ category: 'features',
24
+ isOptional: false,
25
+ },
26
+ {
27
+ id: 'production_ready',
28
+ name: 'Production Ready',
29
+ index: 2,
30
+ category: 'features',
31
+ isOptional: false,
32
+ },
33
+ {
34
+ id: 'developer_experience',
35
+ name: 'Developer Experience',
36
+ index: 3,
37
+ category: 'features',
38
+ isOptional: false,
39
+ },
40
+ ],
41
+ };
42
+
43
+ /**
44
+ * Demo Two: Simple single-screen onboarding
45
+ * A minimal onboarding with feature highlights and direct CTA
46
+ */
47
+ export const DEMO_TWO_ONBOARDING_FLOW: OnboardingFlowConfig = {
48
+ flowId: 'demo_two_flow',
49
+ flowName: 'Simple Feature Highlights Onboarding',
50
+ version: '1.0',
51
+ steps: [
52
+ {
53
+ id: 'feature_overview',
54
+ name: 'Feature Overview Screen',
55
+ index: 0,
56
+ category: 'overview',
57
+ isOptional: false,
58
+ },
59
+ ],
60
+ };
61
+
62
+ /**
63
+ * Feature-specific onboarding flows for different parts of your app
64
+ */
65
+ export const FEATURE_ONBOARDING_FLOWS = {
66
+ imageAnalyzer: {
67
+ flowId: 'image_analyzer_onboarding',
68
+ flowName: 'Image Analyzer Onboarding',
69
+ version: '1.0',
70
+ steps: [
71
+ {
72
+ id: 'camera_permission',
73
+ name: 'Camera Permission Request',
74
+ index: 0,
75
+ category: 'permissions',
76
+ isOptional: false,
77
+ },
78
+ {
79
+ id: 'first_analysis',
80
+ name: 'First Image Analysis',
81
+ index: 1,
82
+ category: 'tutorial',
83
+ isOptional: false,
84
+ },
85
+ {
86
+ id: 'results_explanation',
87
+ name: 'Understanding Results',
88
+ index: 2,
89
+ category: 'tutorial',
90
+ isOptional: true,
91
+ },
92
+ ],
93
+ },
94
+ payments: {
95
+ flowId: 'payments_onboarding',
96
+ flowName: 'Premium Features Onboarding',
97
+ version: '1.0',
98
+ steps: [
99
+ {
100
+ id: 'paywall_intro',
101
+ name: 'Premium Features Introduction',
102
+ index: 0,
103
+ category: 'monetization',
104
+ isOptional: false,
105
+ },
106
+ {
107
+ id: 'subscription_selection',
108
+ name: 'Subscription Plan Selection',
109
+ index: 1,
110
+ category: 'monetization',
111
+ isOptional: false,
112
+ },
113
+ {
114
+ id: 'payment_completion',
115
+ name: 'Payment Completion',
116
+ index: 2,
117
+ category: 'monetization',
118
+ isOptional: false,
119
+ },
120
+ ],
121
+ },
122
+ } as const satisfies Record<string, OnboardingFlowConfig>;
123
+
124
+ /**
125
+ * A/B test variants for different onboarding approaches
126
+ */
127
+ export const ONBOARDING_VARIANTS = {
128
+ demoOneControl: {
129
+ ...DEMO_ONE_ONBOARDING_FLOW,
130
+ variant: 'control',
131
+ },
132
+ demoOneExperimental: {
133
+ ...DEMO_ONE_ONBOARDING_FLOW,
134
+ flowId: 'demo_one_flow_experimental',
135
+ variant: 'experimental',
136
+ // Add experimental steps or modify existing ones
137
+ steps: [
138
+ ...DEMO_ONE_ONBOARDING_FLOW.steps,
139
+ {
140
+ id: 'personalization_survey',
141
+ name: 'Quick Personalization Survey',
142
+ index: 4,
143
+ category: 'personalization',
144
+ isOptional: true,
145
+ },
146
+ ],
147
+ },
148
+ demoTwoControl: {
149
+ ...DEMO_TWO_ONBOARDING_FLOW,
150
+ variant: 'control',
151
+ },
152
+ demoTwoExperimental: {
153
+ ...DEMO_TWO_ONBOARDING_FLOW,
154
+ flowId: 'demo_two_flow_experimental',
155
+ variant: 'experimental',
156
+ // Could add more steps to test if single-screen vs multi-screen performs better
157
+ },
158
+ };
159
+
160
+ /**
161
+ * Helper function to get onboarding flow config based on choice and variant
162
+ */
163
+ export function getOnboardingFlowConfig(
164
+ flowType: 'demoOne' | 'demoTwo' | 'imageAnalyzer' | 'payments' = 'demoOne',
165
+ variant?: 'control' | 'experimental',
166
+ ): OnboardingFlowConfig {
167
+ if (flowType === 'demoOne') {
168
+ if (variant === 'experimental') {
169
+ return ONBOARDING_VARIANTS.demoOneExperimental;
170
+ }
171
+ return variant
172
+ ? ONBOARDING_VARIANTS.demoOneControl
173
+ : DEMO_ONE_ONBOARDING_FLOW;
174
+ }
175
+
176
+ if (flowType === 'demoTwo') {
177
+ if (variant === 'experimental') {
178
+ return ONBOARDING_VARIANTS.demoTwoExperimental;
179
+ }
180
+ return variant
181
+ ? ONBOARDING_VARIANTS.demoTwoControl
182
+ : DEMO_TWO_ONBOARDING_FLOW;
183
+ }
184
+
185
+ return FEATURE_ONBOARDING_FLOWS[flowType];
186
+ }
187
+
188
+ // Export the main flows for easy access
189
+ export const MAIN_ONBOARDING_FLOW = DEMO_ONE_ONBOARDING_FLOW; // Default export for backward compatibility
@@ -0,0 +1,42 @@
1
+ import { useLocalSearchParams, useRouter } from 'expo-router';
2
+ import React from 'react';
3
+
4
+ import { FocusAwareStatusBar, SafeAreaView } from '@/components/ui';
5
+ import { useIsFirstTime } from '@/lib/hooks';
6
+
7
+ import { Onboarding } from '../../components/onboarding';
8
+ import { AppOnboardingData } from '../data';
9
+
10
+ /**
11
+ * Demo One Onboarding Screen
12
+ * Displays the new multi-step onboarding flow with animations
13
+ */
14
+ export default function DemoOneOnboarding() {
15
+ const router = useRouter();
16
+ const params = useLocalSearchParams<{ returnTo?: string }>();
17
+ const [, completeOnboarding] = useIsFirstTime();
18
+
19
+ const handleComplete = () => {
20
+ console.log('[DemoOneOnboarding] Completing onboarding…');
21
+ completeOnboarding(); // ← writes flag & flushes
22
+ const returnTo = params.returnTo as string | undefined;
23
+ if (returnTo) {
24
+ console.log(`[DemoOneOnboarding] Returning to ${returnTo}…`);
25
+ router.replace(returnTo as any);
26
+ return;
27
+ }
28
+ console.log('[DemoOneOnboarding] Navigating to login…');
29
+ router.replace('/(auth)/login'); // default behavior
30
+ };
31
+
32
+ return (
33
+ <SafeAreaView className="flex-1">
34
+ <FocusAwareStatusBar />
35
+ <Onboarding
36
+ data={AppOnboardingData}
37
+ onComplete={handleComplete}
38
+ testID="demo-one-onboarding"
39
+ />
40
+ </SafeAreaView>
41
+ );
42
+ }
@@ -0,0 +1,32 @@
1
+ import type { OnboardingItem } from '../components/onboarding';
2
+
3
+ export const AppOnboardingData: OnboardingItem[] = [
4
+ {
5
+ id: '1',
6
+ title: 'Welcome to VibeFast',
7
+ description:
8
+ 'Build and ship your React Native apps faster with our production-ready starter kit. Save weeks of development time with our proven architecture.',
9
+ lottieAnim: require('@assets/lottie-animations/onboarding-1.json'),
10
+ },
11
+ {
12
+ id: '2',
13
+ title: 'AI-Powered Development',
14
+ description:
15
+ 'Leverage cutting-edge AI features built right into your app. From chatbots to image analysis, everything is ready to use out of the box.',
16
+ lottieAnim: require('@assets/lottie-animations/onboarding-2.json'),
17
+ },
18
+ {
19
+ id: '3',
20
+ title: 'Production Ready',
21
+ description:
22
+ 'Complete with authentication, payments, push notifications, and more. Deploy to the App Store and Google Play with confidence.',
23
+ lottieAnim: require('@assets/lottie-animations/onboarding-3.json'),
24
+ },
25
+ {
26
+ id: '4',
27
+ title: 'Developer Experience',
28
+ description:
29
+ 'TypeScript, Testing, Linting, and CI/CD all configured. Focus on building features, not setting up tooling.',
30
+ lottieAnim: require('@assets/lottie-animations/onboarding-4.json'),
31
+ },
32
+ ];
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Expense Tracker Demo Onboarding Screen
3
+ * Entry point that wraps InteractiveOnboarding with navigation handling.
4
+ */
5
+ import { useLocalSearchParams, useRouter } from 'expo-router';
6
+ import React from 'react';
7
+ import { View } from 'react-native';
8
+
9
+ import { FocusAwareStatusBar } from '@/components/ui';
10
+ import { useIsFirstTime } from '@/lib/hooks';
11
+
12
+ import { InteractiveOnboarding } from '../components/interactive-onboarding';
13
+
14
+ export default function ExpenseTrackerOnboarding() {
15
+ const router = useRouter();
16
+ const params = useLocalSearchParams<{ returnTo?: string }>();
17
+ const [, completeOnboarding] = useIsFirstTime();
18
+
19
+ const handleComplete = () => {
20
+ completeOnboarding();
21
+ const returnTo = params.returnTo as string | undefined;
22
+ if (returnTo) {
23
+ router.replace(returnTo as any);
24
+ return;
25
+ }
26
+ router.replace('/(auth)/welcome-signup');
27
+ };
28
+
29
+ const handleSignIn = () => {
30
+ completeOnboarding();
31
+ router.replace('/(auth)/login');
32
+ };
33
+
34
+ return (
35
+ <View className="flex-1 bg-background">
36
+ <FocusAwareStatusBar />
37
+ <InteractiveOnboarding
38
+ onComplete={handleComplete}
39
+ onSignIn={handleSignIn}
40
+ />
41
+ </View>
42
+ );
43
+ }
@@ -0,0 +1,222 @@
1
+ import React, { useState } from 'react';
2
+ import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
3
+
4
+ import { OnboardingHeader } from './ui/onboarding-header';
5
+
6
+ import { WelcomeStep } from './steps/welcome-step';
7
+ import { FeatureAIStep } from './steps/feature-ai-step';
8
+ import { FeatureScanStep } from './steps/feature-scan-step';
9
+ import { FeatureManualStep } from './steps/feature-manual-step';
10
+ import { FeatureChatbotStep } from './steps/feature-chatbot-step';
11
+ import { CurrencyStep } from './steps/currency-step';
12
+ import { MainReasonStep } from './steps/main-reason-step';
13
+ import { StruggleStep } from './steps/struggle-step';
14
+ import { OverspendStep } from './steps/overspend-step';
15
+ import { AIToneStep } from './steps/ai-tone-step';
16
+ import { ReminderStep } from './steps/reminder-step';
17
+ import { NotificationStep } from './steps/notification-step';
18
+ import { SafetyStep } from './steps/safety-step';
19
+ import { RatingStep } from './steps/rating-step';
20
+ import { PersonalizingStep } from './steps/personalizing-step';
21
+ import { SafeAreaView } from '@/components/ui';
22
+
23
+ type OnboardingStep =
24
+ | 'welcome'
25
+ | 'feature_ai'
26
+ | 'feature_scan'
27
+ | 'feature_manual'
28
+ | 'feature_chatbot'
29
+ | 'currency'
30
+ | 'main_reason'
31
+ | 'struggle'
32
+ | 'overspend'
33
+ | 'spend_level'
34
+ | 'ai_tone'
35
+ | 'reminder'
36
+ | 'notification'
37
+ | 'safety'
38
+ | 'rating'
39
+ | 'personalizing';
40
+
41
+ const STEPS_ORDER: OnboardingStep[] = [
42
+ 'welcome',
43
+ 'feature_ai',
44
+ 'feature_scan',
45
+ 'feature_manual',
46
+ 'feature_chatbot',
47
+ 'currency',
48
+ 'main_reason',
49
+ 'struggle',
50
+ 'overspend',
51
+ // 'spend_level',
52
+ 'ai_tone',
53
+ 'reminder',
54
+ 'notification',
55
+ 'safety',
56
+ 'rating',
57
+ 'personalizing',
58
+ ];
59
+
60
+ interface InteractiveOnboardingProps {
61
+ onComplete: () => void;
62
+ onSignIn: () => void;
63
+ }
64
+
65
+ export function InteractiveOnboarding({
66
+ onComplete,
67
+ onSignIn,
68
+ }: InteractiveOnboardingProps) {
69
+ const [currentStepIndex, setCurrentStepIndex] = useState(0);
70
+ const [direction, setDirection] = useState<'forward' | 'backward'>('forward');
71
+
72
+ // State for all steps
73
+ const [currency, setCurrency] = useState<string | null>(null);
74
+ const [mainReason, setMainReason] = useState<string | null>(null);
75
+ const [struggle, setStruggle] = useState<string | null>(null);
76
+ const [overspendCategories, setOverspendCategories] = useState<string[]>([]);
77
+ const [aiTone, setAiTone] = useState<string | null>(null);
78
+ const [reminderFreq, setReminderFreq] = useState<string | null>(null);
79
+ const [reminderTime, setReminderTime] = useState<string>('9 PM');
80
+
81
+ // Spend Level State (Min/Max)
82
+ const [minSpend, setMinSpend] = useState('');
83
+ const [maxSpend, setMaxSpend] = useState('');
84
+
85
+ const currentStep = STEPS_ORDER[currentStepIndex];
86
+
87
+ const handleNext = () => {
88
+ if (currentStepIndex < STEPS_ORDER.length - 1) {
89
+ setDirection('forward');
90
+ setCurrentStepIndex((prev) => prev + 1);
91
+ } else {
92
+ onComplete();
93
+ }
94
+ };
95
+
96
+ const handleBack = () => {
97
+ if (currentStepIndex > 0) {
98
+ setDirection('backward');
99
+ setCurrentStepIndex((prev) => prev - 1);
100
+ }
101
+ };
102
+
103
+ const toggleOverspendCategory = (id: string) => {
104
+ setOverspendCategories((prev) =>
105
+ prev.includes(id) ? prev.filter((c) => c !== id) : [...prev, id],
106
+ );
107
+ };
108
+
109
+ // Custom entering/exiting animations based on direction
110
+ // Using Fade for premium feel as requested
111
+ return (
112
+ <SafeAreaView className="flex-1 bg-background items-center">
113
+ <Animated.View className="flex-1 w-full md:max-w-4xl">
114
+ {currentStep !== 'welcome' && currentStep !== 'personalizing' && (
115
+ <OnboardingHeader
116
+ onBack={handleBack}
117
+ canGoBack={currentStepIndex > 0}
118
+ progress={(currentStepIndex + 1) / STEPS_ORDER.length}
119
+ />
120
+ )}
121
+
122
+ {/* We use a key to force re-render and trigger animations */}
123
+ <Animated.View
124
+ key={currentStep}
125
+ className="flex-1"
126
+ entering={FadeIn.duration(600)}
127
+ exiting={FadeOut.duration(400)}
128
+ >
129
+ {currentStep === 'welcome' && (
130
+ <WelcomeStep onNext={handleNext} onSignIn={onSignIn} />
131
+ )}
132
+
133
+ {currentStep === 'feature_ai' && (
134
+ <FeatureAIStep onNext={handleNext} />
135
+ )}
136
+ {currentStep === 'feature_scan' && (
137
+ <FeatureScanStep onNext={handleNext} />
138
+ )}
139
+ {currentStep === 'feature_manual' && (
140
+ <FeatureManualStep onNext={handleNext} />
141
+ )}
142
+ {currentStep === 'feature_chatbot' && (
143
+ <FeatureChatbotStep onNext={handleNext} />
144
+ )}
145
+
146
+ {currentStep === 'currency' && (
147
+ <CurrencyStep
148
+ selectedCurrency={currency}
149
+ onSelectCurrency={setCurrency}
150
+ onNext={handleNext}
151
+ />
152
+ )}
153
+
154
+ {currentStep === 'main_reason' && (
155
+ <MainReasonStep
156
+ selectedReason={mainReason}
157
+ onSelectReason={setMainReason}
158
+ onNext={handleNext}
159
+ />
160
+ )}
161
+
162
+ {currentStep === 'struggle' && (
163
+ <StruggleStep
164
+ selectedStruggle={struggle}
165
+ onSelectStruggle={setStruggle}
166
+ onNext={handleNext}
167
+ />
168
+ )}
169
+
170
+ {currentStep === 'overspend' && (
171
+ <OverspendStep
172
+ selectedCategories={overspendCategories}
173
+ onToggleCategory={toggleOverspendCategory}
174
+ onNext={handleNext}
175
+ />
176
+ )}
177
+
178
+ {/* {currentStep === 'spend_level' && (
179
+ <SpendLevelStep
180
+ currencyCode={currency}
181
+ minSpend={minSpend}
182
+ maxSpend={maxSpend}
183
+ onSetMinSpend={setMinSpend}
184
+ onSetMaxSpend={setMaxSpend}
185
+ onNext={handleNext}
186
+ />
187
+ )} */}
188
+
189
+ {currentStep === 'ai_tone' && (
190
+ <AIToneStep
191
+ selectedTone={aiTone}
192
+ onSelectTone={setAiTone}
193
+ onNext={handleNext}
194
+ />
195
+ )}
196
+
197
+ {currentStep === 'reminder' && (
198
+ <ReminderStep
199
+ selectedFrequency={reminderFreq}
200
+ selectedTime={reminderTime}
201
+ onSelectFrequency={setReminderFreq}
202
+ onSelectTime={setReminderTime}
203
+ onNext={handleNext}
204
+ />
205
+ )}
206
+
207
+ {currentStep === 'notification' && (
208
+ <NotificationStep onEnable={handleNext} onSkip={handleNext} />
209
+ )}
210
+
211
+ {currentStep === 'safety' && <SafetyStep onComplete={handleNext} />}
212
+
213
+ {currentStep === 'rating' && <RatingStep onNext={handleNext} />}
214
+
215
+ {currentStep === 'personalizing' && (
216
+ <PersonalizingStep onComplete={onComplete} />
217
+ )}
218
+ </Animated.View>
219
+ </Animated.View>
220
+ </SafeAreaView>
221
+ );
222
+ }
@@ -0,0 +1,133 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+ import Animated, { FadeIn, FadeOut, FadeInDown } from 'react-native-reanimated';
4
+ import { Text, Button, Pressable } from '@/components/ui';
5
+ import { useThemeConfig } from '@/lib/use-theme-config';
6
+ import { MaterialCommunityIcons } from '@expo/vector-icons';
7
+ import * as Haptics from 'expo-haptics';
8
+
9
+ interface AIToneStepProps {
10
+ selectedTone: string | null;
11
+ onSelectTone: (tone: string) => void;
12
+ onNext: () => void;
13
+ }
14
+
15
+ const TONES = [
16
+ {
17
+ id: 'gentle',
18
+ label: 'Gentle and encouraging',
19
+ emoji: '😊',
20
+ desc: 'Positive reinforcement, soft nudges.',
21
+ color: '#10B981',
22
+ },
23
+ {
24
+ id: 'honest',
25
+ label: 'Honest but respectful',
26
+ emoji: '💬',
27
+ desc: 'Direct facts, no fluff.',
28
+ color: '#3B82F6',
29
+ },
30
+ {
31
+ id: 'brutal',
32
+ label: 'Brutally honest',
33
+ emoji: '🔥',
34
+ desc: 'Roast me if I overspend.',
35
+ color: '#EF4444',
36
+ },
37
+ ];
38
+
39
+ export function AIToneStep({
40
+ selectedTone,
41
+ onSelectTone,
42
+ onNext,
43
+ }: AIToneStepProps) {
44
+ const theme = useThemeConfig();
45
+
46
+ return (
47
+ <Animated.View
48
+ entering={FadeIn}
49
+ exiting={FadeOut}
50
+ className="flex-1 px-6 pt-4"
51
+ >
52
+ <Text className="text-3xl font-bold mb-3">
53
+ How honest should the AI be?
54
+ </Text>
55
+ <Text className="text-lg text-muted-foreground mb-8">
56
+ Choose your coach's personality.
57
+ </Text>
58
+
59
+ <View className="gap-4 mt-auto">
60
+ {TONES.map((item, index) => (
61
+ <Animated.View
62
+ entering={FadeInDown.delay(index * 100).duration(400)}
63
+ key={item.id}
64
+ >
65
+ <Pressable
66
+ onPress={() => onSelectTone(item.id)}
67
+ className={`p-5 rounded-3xl border relative overflow-hidden ${
68
+ selectedTone === item.id
69
+ ? 'border-transparent'
70
+ : 'border-border bg-card'
71
+ }`}
72
+ style={
73
+ selectedTone === item.id
74
+ ? { borderColor: item.color, borderWidth: 1 }
75
+ : {}
76
+ }
77
+ >
78
+ {selectedTone === item.id && (
79
+ <View
80
+ className="absolute inset-0 opacity-10"
81
+ style={{ backgroundColor: item.color }}
82
+ />
83
+ )}
84
+
85
+ <View className="flex-row items-center mb-2">
86
+ <View
87
+ className="w-12 h-12 rounded-full items-center justify-center mr-4"
88
+ style={{ backgroundColor: item.color + '20' }}
89
+ >
90
+ <Text className="text-2xl">{item.emoji}</Text>
91
+ </View>
92
+ <View className="flex-1">
93
+ <Text
94
+ className={`text-xl font-bold ${
95
+ selectedTone === item.id
96
+ ? 'text-foreground'
97
+ : 'text-foreground'
98
+ }`}
99
+ >
100
+ {item.label}
101
+ </Text>
102
+ <Text className="text-muted-foreground leading-5">
103
+ {item.desc}
104
+ </Text>
105
+ </View>
106
+ {selectedTone === item.id && (
107
+ <MaterialCommunityIcons
108
+ name="check-circle"
109
+ size={24}
110
+ color={item.color}
111
+ />
112
+ )}
113
+ </View>
114
+ </Pressable>
115
+ </Animated.View>
116
+ ))}
117
+ </View>
118
+
119
+ <View className="pt-4 border-t border-border bg-background mt-auto">
120
+ <Button
121
+ label="Continue"
122
+ onPress={() => {
123
+ Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
124
+ onNext();
125
+ }}
126
+ disabled={!selectedTone}
127
+ size="lg"
128
+ className="w-full m-0"
129
+ />
130
+ </View>
131
+ </Animated.View>
132
+ );
133
+ }