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.
- package/CHANGELOG.md +32 -0
- package/README.md +63 -169
- package/dist/__tests__/recipes.test.js +89 -85
- package/dist/__tests__/recipes.test.js.map +1 -1
- package/dist/commands/add.d.ts +1 -1
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +576 -588
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/checklist.d.ts +1 -1
- package/dist/commands/checklist.d.ts.map +1 -1
- package/dist/commands/checklist.js +40 -39
- package/dist/commands/checklist.js.map +1 -1
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +22 -22
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/env.d.ts +1 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +58 -53
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/health.d.ts +1 -1
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +101 -93
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +416 -296
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/remove.d.ts +1 -1
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/remove.js +77 -64
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +15 -14
- package/dist/commands/status.js.map +1 -1
- package/dist/core/__tests__/detect.test.js +68 -34
- package/dist/core/__tests__/detect.test.js.map +1 -1
- package/dist/core/ast.d.ts +14 -0
- package/dist/core/ast.d.ts.map +1 -0
- package/dist/core/ast.js +239 -0
- package/dist/core/ast.js.map +1 -0
- package/dist/core/codemod.d.ts.map +1 -1
- package/dist/core/codemod.js +62 -44
- package/dist/core/codemod.js.map +1 -1
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +51 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/detect.d.ts +8 -2
- package/dist/core/detect.d.ts.map +1 -1
- package/dist/core/detect.js +52 -21
- package/dist/core/detect.js.map +1 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +9 -8
- package/dist/core/errors.js.map +1 -1
- package/dist/core/exec.d.ts +16 -0
- package/dist/core/exec.d.ts.map +1 -0
- package/dist/core/exec.js +48 -0
- package/dist/core/exec.js.map +1 -0
- package/dist/core/manualSteps.d.ts +7 -0
- package/dist/core/manualSteps.d.ts.map +1 -0
- package/dist/core/manualSteps.js +59 -0
- package/dist/core/manualSteps.js.map +1 -0
- package/dist/core/paths.d.ts +3 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +14 -10
- package/dist/core/paths.js.map +1 -1
- package/dist/core/spinner.d.ts +1 -1
- package/dist/core/spinner.d.ts.map +1 -1
- package/dist/core/spinner.js +38 -8
- package/dist/core/spinner.js.map +1 -1
- package/dist/core/vosk.d.ts.map +1 -1
- package/dist/core/vosk.js +50 -39
- package/dist/core/vosk.js.map +1 -1
- package/docs/manual-testing.md +91 -0
- package/package.json +6 -3
- package/recipes/audio-recorder/apps/native/src/app/audio-recorder/index.tsx +5 -0
- package/recipes/audio-recorder/recipe.json +3 -3
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-player.tsx +301 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +373 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-waveform.tsx +270 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/index.ts +4 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/recording-list.tsx +89 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-player-demo.tsx +66 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-cloud.tsx +68 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-interview.tsx +102 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/basic.tsx +27 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/index.ts +5 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +82 -0
- package/recipes/audio-recorder-supabase/packages/backend/src/services/recordings.ts +369 -0
- package/recipes/audio-recorder-supabase/packages/backend/supabase/migrations/recordings.sql +70 -0
- package/recipes/audio-recorder-supabase/recipe.json +52 -0
- package/recipes/audio-recorder-supabase@latest.zip +0 -0
- package/recipes/audio-recorder@latest.zip +0 -0
- package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +3 -3
- package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +2 -2
- package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +5 -5
- package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +3 -3
- package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +20 -4
- package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +7 -6
- package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +6 -4
- package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +1 -1
- package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +5 -4
- package/recipes/charts/recipe.json +4 -13
- package/recipes/charts@latest.zip +0 -0
- package/recipes/chatbot/apps/native/src/app/chatbot/index.tsx +1 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +86 -86
- package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +86 -53
- package/recipes/chatbot/recipe.json +26 -92
- package/recipes/chatbot-supabase/apps/native/src/api-client/supabase/chatbot.ts +515 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/app/index.tsx +257 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +59 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-input-bar.tsx +485 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-markdown.tsx +575 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +223 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +161 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/image-preview-list.tsx +116 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/code-block.tsx +165 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/index.ts +10 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +129 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-error-boundary.tsx +78 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-list.tsx +170 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/model-selector.tsx +283 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/report-content-modal.tsx +188 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/suggested-messages.tsx +67 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/models.ts +20 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/report-reasons.ts +9 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +142 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-config.ts +458 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +429 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +89 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-conversation.ts +90 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-image-picker.ts +122 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +161 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +213 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/index.ts +86 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/models.ts +162 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/providers.ts +62 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/types.ts +40 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/file-uploader.ts +287 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/message-handler-service.ts +189 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/types/index.ts +70 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/utils/chat-telemetry.ts +91 -0
- package/recipes/chatbot-supabase/packages/backend/src/services/conversations.ts +243 -0
- package/recipes/chatbot-supabase/packages/backend/src/services/messages.ts +327 -0
- package/recipes/chatbot-supabase/packages/backend/supabase/functions/chat-stream/index.ts +347 -0
- package/recipes/chatbot-supabase/packages/backend/supabase/migrations/chatbot.sql +104 -0
- package/recipes/chatbot-supabase/recipe.json +106 -0
- package/recipes/chatbot-supabase@latest.zip +0 -0
- package/recipes/chatbot.zip +0 -0
- package/recipes/chatbot@latest.zip +0 -0
- package/recipes/image-analysis/packages/backend/convex/imageAnalysis/index.ts +2 -2
- package/recipes/image-analysis/packages/backend/convex/imageAnalysis.ts +0 -1
- package/recipes/image-analysis/recipe.json +15 -55
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/analysis-options-screen.tsx +304 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/camera.tsx +221 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/image-capture-screen.tsx +333 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading-screen.tsx +214 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading.tsx +191 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/results.tsx +137 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/trait-details.tsx +172 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-analysis-data.ts +160 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-results-screen.ts +151 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-badge.tsx +77 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-card.tsx +75 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-unlocked-modal.tsx +162 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievements-section.tsx +44 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/advice-list.tsx +42 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/circular-progress.tsx +233 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/content-card.tsx +38 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/error-state.tsx +42 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/index.ts +9 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/loading-state.tsx +26 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/profile-image.tsx +60 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/results-header.tsx +62 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/score-display.tsx +54 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/share-options-modal.tsx +110 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/traits-grid.tsx +74 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/analysis-config.ts +80 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/master-analysis-config.ts +157 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/index.ts +1 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-analysis.ts +38 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-image-analysis.ts +208 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/analysis-service.ts +262 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/share-service.ts +176 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/trait-details-service.ts +289 -0
- package/recipes/image-analysis-supabase/packages/backend/src/services/image-analyses.ts +132 -0
- package/recipes/image-analysis-supabase/packages/backend/supabase/functions/analyze-image/index.ts +312 -0
- package/recipes/image-analysis-supabase/packages/backend/supabase/migrations/image_analysis.sql +42 -0
- package/recipes/image-analysis-supabase/recipe.json +90 -0
- package/recipes/image-analysis-supabase@latest.zip +0 -0
- package/recipes/image-analysis@latest.zip +0 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/app/index.tsx +16 -2
- package/recipes/image-generator/apps/native/src/features/image-generator/components/image-model-selector.tsx +11 -5
- package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator.ts +11 -5
- package/recipes/image-generator/packages/backend/convex/imageGeneration/index.ts +2 -2
- package/recipes/image-generator/recipe.json +16 -39
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/_layout.tsx +26 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/gallery.tsx +217 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/index.tsx +251 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/gallery-image.tsx +25 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-detail-modal.tsx +215 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-model-selector.tsx +216 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-placeholder.tsx +26 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-gallery.ts +71 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator-settings.ts +152 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator.ts +103 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/models/models.ts +66 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-gallery-service.ts +96 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-save-service.ts +120 -0
- package/recipes/image-generator-supabase/packages/backend/supabase/functions/generate-image/index.ts +291 -0
- package/recipes/image-generator-supabase/packages/backend/supabase/migrations/image_generator.sql +71 -0
- package/recipes/image-generator-supabase/recipe.json +86 -0
- package/recipes/image-generator-supabase@latest.zip +0 -0
- package/recipes/image-generator@latest.zip +0 -0
- package/recipes/ios-widget/recipe.json +15 -24
- package/recipes/ios-widget@latest.zip +0 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/analytics/index.ts +9 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding-with-analytics.tsx +141 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding.tsx +173 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/config/onboarding-flow-config.ts +189 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/app/index.tsx +42 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/data.ts +32 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/app/index.tsx +43 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/interactive-onboarding.tsx +222 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/ai-tone-step.tsx +133 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/currency-step.tsx +165 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-ai-step.tsx +199 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-chatbot-step.tsx +154 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-manual-step.tsx +156 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-scan-step.tsx +158 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/main-reason-step.tsx +139 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/notification-step.tsx +129 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/overspend-step.tsx +138 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/personalizing-step.tsx +190 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/rating-step.tsx +98 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/reminder-step.tsx +181 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/safety-step.tsx +110 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/struggle-step.tsx +139 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/welcome-step.tsx +217 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/ui/onboarding-header.tsx +58 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/constants.ts +179 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/hooks/use-onboarding-analytics.ts +323 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/services/onboarding-analytics.ts +432 -0
- package/recipes/onboarding/recipe.json +15 -0
- package/recipes/onboarding@latest.zip +0 -0
- package/recipes/payments/recipe.json +28 -61
- package/recipes/payments-supabase/apps/native/src/features/payments/README.md +200 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/app/local-paywall.tsx +194 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/app/remote-paywall.tsx +79 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/payment-initializer.tsx +95 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-error-state.tsx +60 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-local-mode.tsx +116 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-product-card.tsx +133 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-remote-mode.tsx +146 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/hooks/use-entitlement.ts +63 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/index.ts +8 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/services/revenuecat-adapter.ts +407 -0
- package/recipes/payments-supabase/packages/backend/src/services/payments.ts +201 -0
- package/recipes/payments-supabase/packages/backend/supabase/migrations/payments.sql +35 -0
- package/recipes/payments-supabase/recipe.json +72 -0
- package/recipes/payments-supabase@latest.zip +0 -0
- package/recipes/payments@latest.zip +0 -0
- package/recipes/quiz/apps/native/src/features/quiz/index.tsx +1 -2
- package/recipes/quiz/recipe.json +6 -9
- package/recipes/quiz@latest.zip +0 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/app/index.tsx +1 -2
- package/recipes/tracker-app/recipe.json +7 -10
- package/recipes/tracker-app@latest.zip +0 -0
- package/recipes/voice-bot/recipe.json +8 -68
- package/recipes/voice-bot.zip +0 -0
- package/recipes/voice-bot@latest.zip +0 -0
- package/recipes/wake-word/recipe.json +10 -9
- package/recipes/wake-word.zip +0 -0
- package/recipes/wake-word@latest.zip +0 -0
- package/recipes/charts/apps/native/src/app/(root)/(protected)/charts/index.tsx +0 -3
- package/recipes/chatbot/packages/backend/convex/lib/rateLimit.ts +0 -100
- package/recipes/chatbot/packages/backend/convex/lib/telemetry.ts +0 -29
- package/recipes/chatbot/packages/backend/convex/ragKnowledge.ts +0 -0
- package/recipes/image-analysis/apps/native/assets/features/image-analyzer/front.jpg +0 -0
- package/recipes/image-analysis/apps/native/assets/features/image-analyzer/side.jpg +0 -0
- package/recipes/image-analysis/apps/native/assets/features/image-analyzer/threeQuarter.jpg +0 -0
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/_layout.tsx +0 -5
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/analysis-options.tsx +0 -50
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/camera.tsx +0 -2
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/index.tsx +0 -50
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/loading.tsx +0 -50
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/results.tsx +0 -2
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/trait-details.tsx +0 -3
- package/recipes/image-analysis/packages/backend/convex/imageAnalysisFunctions.ts +0 -325
- package/recipes/image-analysis/packages/backend/convex/lib/ai/imageAnalysisAdapter.ts +0 -200
- package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/index.tsx +0 -74
- package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/local.tsx +0 -25
- package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/remote.tsx +0 -23
- package/recipes/quiz/apps/native/src/app/(root)/(protected)/quiz/index.tsx +0 -47
- package/recipes/tracker-app/apps/native/src/app/(root)/(protected)/tracker-app/index.tsx +0 -1
- package/recipes/voice-bot/apps/native/src/app/(root)/(protected)/voice-bot/index.tsx +0 -27
- package/recipes/voice-bot/packages/backend/convex/router.ts +0 -81
- /package/recipes/{chatbot/apps/native/src/app/(root)/(protected) → chatbot-supabase/apps/native/src/app}/chatbot/index.tsx +0 -0
- /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/gallery.tsx +0 -0
- /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/index.tsx +0 -0
package/recipes/image-generator-supabase/packages/backend/supabase/migrations/image_generator.sql
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
-- Image Generator Feature Migration
|
|
2
|
+
-- Creates tables for AI-generated images
|
|
3
|
+
-- Run this migration when adding the image-generator feature via CLI
|
|
4
|
+
|
|
5
|
+
-- ============================================================================
|
|
6
|
+
-- GENERATED_IMAGES TABLE
|
|
7
|
+
-- Stores AI-generated images metadata
|
|
8
|
+
-- ============================================================================
|
|
9
|
+
CREATE TABLE IF NOT EXISTS generated_images (
|
|
10
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
11
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
12
|
+
prompt TEXT NOT NULL,
|
|
13
|
+
image_url TEXT,
|
|
14
|
+
storage_id TEXT,
|
|
15
|
+
mime_type TEXT,
|
|
16
|
+
provider TEXT NOT NULL,
|
|
17
|
+
model TEXT NOT NULL,
|
|
18
|
+
created_at TIMESTAMPTZ DEFAULT now()
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
-- ============================================================================
|
|
22
|
+
-- INDEXES
|
|
23
|
+
-- ============================================================================
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_generated_images_user_id ON generated_images(user_id);
|
|
25
|
+
|
|
26
|
+
-- ============================================================================
|
|
27
|
+
-- RLS POLICIES
|
|
28
|
+
-- ============================================================================
|
|
29
|
+
ALTER TABLE generated_images ENABLE ROW LEVEL SECURITY;
|
|
30
|
+
|
|
31
|
+
CREATE POLICY "generated_images_select_own" ON generated_images
|
|
32
|
+
FOR SELECT USING (auth.uid() = user_id);
|
|
33
|
+
|
|
34
|
+
CREATE POLICY "generated_images_insert_own" ON generated_images
|
|
35
|
+
FOR INSERT WITH CHECK (auth.uid() = user_id);
|
|
36
|
+
|
|
37
|
+
CREATE POLICY "generated_images_update_own" ON generated_images
|
|
38
|
+
FOR UPDATE USING (auth.uid() = user_id);
|
|
39
|
+
|
|
40
|
+
CREATE POLICY "generated_images_delete_own" ON generated_images
|
|
41
|
+
FOR DELETE USING (auth.uid() = user_id);
|
|
42
|
+
|
|
43
|
+
-- ============================================================================
|
|
44
|
+
-- STORAGE BUCKET - generated-images
|
|
45
|
+
-- ============================================================================
|
|
46
|
+
INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)
|
|
47
|
+
VALUES (
|
|
48
|
+
'generated-images',
|
|
49
|
+
'generated-images',
|
|
50
|
+
false,
|
|
51
|
+
10485760, -- 10MB limit
|
|
52
|
+
ARRAY['image/jpeg', 'image/png', 'image/webp']
|
|
53
|
+
) ON CONFLICT (id) DO NOTHING;
|
|
54
|
+
|
|
55
|
+
-- Storage RLS for generated-images
|
|
56
|
+
CREATE POLICY "Users can view their own generated images"
|
|
57
|
+
ON storage.objects FOR SELECT TO authenticated
|
|
58
|
+
USING (bucket_id = 'generated-images' AND (storage.foldername(name))[1] = auth.uid()::text);
|
|
59
|
+
|
|
60
|
+
CREATE POLICY "Users can upload their own generated images"
|
|
61
|
+
ON storage.objects FOR INSERT TO authenticated
|
|
62
|
+
WITH CHECK (bucket_id = 'generated-images' AND (storage.foldername(name))[1] = auth.uid()::text);
|
|
63
|
+
|
|
64
|
+
CREATE POLICY "Users can update their own generated images"
|
|
65
|
+
ON storage.objects FOR UPDATE TO authenticated
|
|
66
|
+
USING (bucket_id = 'generated-images' AND (storage.foldername(name))[1] = auth.uid()::text)
|
|
67
|
+
WITH CHECK (bucket_id = 'generated-images' AND (storage.foldername(name))[1] = auth.uid()::text);
|
|
68
|
+
|
|
69
|
+
CREATE POLICY "Users can delete their own generated images"
|
|
70
|
+
ON storage.objects FOR DELETE TO authenticated
|
|
71
|
+
USING (bucket_id = 'generated-images' AND (storage.foldername(name))[1] = auth.uid()::text);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "image-generator",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AI-powered image generation with Supabase backend",
|
|
5
|
+
"copy": [
|
|
6
|
+
{
|
|
7
|
+
"from": "apps/native/src/app/image-generator",
|
|
8
|
+
"to": "apps/native/src/app/(root)/(protected)/image-generator"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"from": "apps/native/src/features/image-generator",
|
|
12
|
+
"to": "apps/native/src/features/image-generator"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"from": "apps/native/src/api-client/supabase/image-generator.ts",
|
|
16
|
+
"to": "apps/native/src/api-client/supabase/image-generator.ts"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"from": "apps/native/src/api-client/supabase/reporting.ts",
|
|
20
|
+
"to": "apps/native/src/api-client/supabase/reporting.ts"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"from": "apps/native/src/api-client/supabase/shared.ts",
|
|
24
|
+
"to": "apps/native/src/api-client/supabase/shared.ts"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"from": "apps/native/src/api-client/reporting.ts",
|
|
28
|
+
"to": "apps/native/src/api-client/reporting.ts"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"from": "apps/native/src/api-client/shared.ts",
|
|
32
|
+
"to": "apps/native/src/api-client/shared.ts"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"from": "packages/backend/supabase/functions/generate-image",
|
|
36
|
+
"to": "packages/backend/supabase/functions/generate-image"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"from": "packages/backend/supabase/migrations/image_generator.sql",
|
|
40
|
+
"to": "packages/backend/supabase/migrations/image_generator.sql"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"nav": {
|
|
44
|
+
"href": "/(root)/(protected)/image-generator",
|
|
45
|
+
"label": "Image Generator",
|
|
46
|
+
"icon": "🎨",
|
|
47
|
+
"color": "#8B5CF6"
|
|
48
|
+
},
|
|
49
|
+
"target": "native",
|
|
50
|
+
"configuration": {
|
|
51
|
+
"apiClient": {
|
|
52
|
+
"exports": [
|
|
53
|
+
"export { type SupabaseImageGeneratorApi as ImageGeneratorApi, supabaseImageGeneratorApi as imageGeneratorApi } from './supabase/image-generator';"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"expo": [
|
|
59
|
+
"@supabase/supabase-js",
|
|
60
|
+
"@tanstack/react-query",
|
|
61
|
+
"expo-file-system",
|
|
62
|
+
"expo-media-library",
|
|
63
|
+
"expo-sharing"
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
"env": [
|
|
67
|
+
{
|
|
68
|
+
"key": "OPENAI_API_KEY",
|
|
69
|
+
"description": "OpenAI API key for DALL-E image generation",
|
|
70
|
+
"example": "sk-...",
|
|
71
|
+
"link": "https://platform.openai.com/api-keys",
|
|
72
|
+
"file": "packages/backend/supabase/.env",
|
|
73
|
+
"required": true
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"manualSteps": [
|
|
77
|
+
{
|
|
78
|
+
"title": "Apply Supabase migration",
|
|
79
|
+
"description": "Run: cd packages/backend && supabase db push"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"title": "Deploy Edge Function",
|
|
83
|
+
"description": "Run: cd packages/backend && supabase functions deploy generate-image"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -96,44 +96,35 @@
|
|
|
96
96
|
"dependencies": {
|
|
97
97
|
"expo": ["@bacons/apple-targets"]
|
|
98
98
|
},
|
|
99
|
+
"plugins": [
|
|
100
|
+
{
|
|
101
|
+
"name": "@bacons/apple-targets",
|
|
102
|
+
"config": "{\n targets: [\n {\n name: 'VibeFastWidget',\n type: 'widget',\n bundleIdentifier: `${Env.BUNDLE_ID}.widget`,\n entitlements: {\n 'com.apple.security.application-groups': [\n `group.${Env.BUNDLE_ID}.shared`,\n ],\n },\n },\n ],\n }"
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"iosConfig": {
|
|
106
|
+
"appleTeamId": "Env.APPLE_TEAM_ID",
|
|
107
|
+
"entitlements": "{\n 'com.apple.security.application-groups': [`group.${Env.BUNDLE_ID}.shared`],\n }"
|
|
108
|
+
},
|
|
99
109
|
"env": [
|
|
100
110
|
{
|
|
101
111
|
"key": "APPLE_TEAM_ID",
|
|
102
112
|
"description": "Apple Developer Team ID (used to sign widgets).",
|
|
103
113
|
"example": "ABCDE12345",
|
|
104
114
|
"link": "https://developer.apple.com/account/#/membership",
|
|
105
|
-
"file": "apps/native
|
|
115
|
+
"file": "apps/native/env.js"
|
|
106
116
|
}
|
|
107
117
|
],
|
|
108
118
|
"configuration": {
|
|
109
119
|
"env": {
|
|
110
|
-
"constants": [
|
|
111
|
-
"const APPLE_TEAM_ID = 'replace_me';"
|
|
112
|
-
],
|
|
120
|
+
"constants": ["const APPLE_TEAM_ID = 'replace_me';"],
|
|
113
121
|
"buildTime": {
|
|
114
|
-
"schema": [
|
|
115
|
-
|
|
116
|
-
],
|
|
117
|
-
"env": [
|
|
118
|
-
" APPLE_TEAM_ID: process.env.APPLE_TEAM_ID,"
|
|
119
|
-
]
|
|
122
|
+
"schema": [" APPLE_TEAM_ID: z.string(),"],
|
|
123
|
+
"env": [" APPLE_TEAM_ID,"]
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
},
|
|
123
|
-
"manualSteps": [
|
|
124
|
-
{
|
|
125
|
-
"title": "Verify widget plugin",
|
|
126
|
-
"description": "The CLI adds the @bacons/apple-targets plugin automatically. Confirm it exists in app.config.ts.",
|
|
127
|
-
"file": "apps/native/app.config.ts",
|
|
128
|
-
"content": "[\n '@bacons/apple-targets',\n {\n targets: [\n {\n name: 'VibeFastWidget',\n type: 'widget',\n bundleIdentifier: `${Env.BUNDLE_ID}.widget`,\n entitlements: {\n 'com.apple.security.application-groups': [\n 'group.com.vibefast.vibefast',\n ],\n },\n },\n ],\n },\n]"
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
"title": "Configure App Groups",
|
|
132
|
-
"description": "Ensure your main app has App Groups entitlements in app.config.ts",
|
|
133
|
-
"file": "apps/native/app.config.ts",
|
|
134
|
-
"content": "ios: {\n entitlements: {\n 'com.apple.security.application-groups': ['group.com.vibefast.shared'],\n },\n}"
|
|
135
|
-
}
|
|
136
|
-
],
|
|
127
|
+
"manualSteps": [],
|
|
137
128
|
"postInstall": {
|
|
138
129
|
"instructions": [
|
|
139
130
|
"Widget target files have been added",
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Export analytics service and types
|
|
2
|
+
|
|
3
|
+
// Export enhanced components
|
|
4
|
+
export * from '../components/onboarding-with-analytics';
|
|
5
|
+
// Export configuration
|
|
6
|
+
export * from '../config/onboarding-flow-config';
|
|
7
|
+
// Export React hooks
|
|
8
|
+
export * from '../hooks/use-onboarding-analytics';
|
|
9
|
+
export * from '../services/onboarding-analytics';
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import React, { useCallback, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { MAIN_ONBOARDING_FLOW } from '../config/onboarding-flow-config';
|
|
4
|
+
import { useOnboardingAnalytics } from '../hooks/use-onboarding-analytics';
|
|
5
|
+
import { Onboarding } from './onboarding';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Props for the analytics-enabled onboarding component
|
|
9
|
+
*/
|
|
10
|
+
export type OnboardingWithAnalyticsProps = {
|
|
11
|
+
userType?: 'new' | 'returning' | 'migrated';
|
|
12
|
+
variant?: 'control' | 'experimental';
|
|
13
|
+
onComplete?: () => void;
|
|
14
|
+
onSkip?: () => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Enhanced onboarding component that automatically tracks user progress
|
|
19
|
+
* and behavior through the onboarding flow with PostHog analytics.
|
|
20
|
+
*
|
|
21
|
+
* This component wraps your existing Onboarding component and adds:
|
|
22
|
+
* - Automatic step tracking
|
|
23
|
+
* - Flow completion analytics
|
|
24
|
+
* - User abandonment detection
|
|
25
|
+
* - A/B test variant tracking
|
|
26
|
+
*
|
|
27
|
+
* Usage:
|
|
28
|
+
* ```tsx
|
|
29
|
+
* <OnboardingWithAnalytics
|
|
30
|
+
* userType="new"
|
|
31
|
+
* variant="experimental"
|
|
32
|
+
* onComplete={() => router.push('/home')}
|
|
33
|
+
* />
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function OnboardingWithAnalytics({
|
|
37
|
+
userType = 'new',
|
|
38
|
+
variant,
|
|
39
|
+
onComplete,
|
|
40
|
+
onSkip,
|
|
41
|
+
}: OnboardingWithAnalyticsProps) {
|
|
42
|
+
// Get the appropriate flow configuration
|
|
43
|
+
const flowConfig = variant
|
|
44
|
+
? { ...MAIN_ONBOARDING_FLOW, variant }
|
|
45
|
+
: MAIN_ONBOARDING_FLOW;
|
|
46
|
+
|
|
47
|
+
// Initialize onboarding analytics
|
|
48
|
+
const analytics = useOnboardingAnalytics({
|
|
49
|
+
flowConfig,
|
|
50
|
+
userType,
|
|
51
|
+
autoStart: true, // Automatically start tracking when component mounts
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Track when component mounts (onboarding starts)
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
// Analytics are auto-started, but we can add additional properties
|
|
57
|
+
analytics.startFlow().then((sessionId) => {
|
|
58
|
+
console.log(`Onboarding session started: ${sessionId}`);
|
|
59
|
+
});
|
|
60
|
+
}, [analytics]);
|
|
61
|
+
|
|
62
|
+
// Enhanced completion handler with analytics
|
|
63
|
+
const handleComplete = useCallback(async () => {
|
|
64
|
+
await analytics.completeFlow();
|
|
65
|
+
onComplete?.();
|
|
66
|
+
}, [analytics, onComplete]);
|
|
67
|
+
|
|
68
|
+
// Enhanced skip handler with analytics (unused but kept for future use)
|
|
69
|
+
// const handleSkip = useCallback(async () => {
|
|
70
|
+
// await analytics.abandonFlow('user_skipped');
|
|
71
|
+
// onSkip?.();
|
|
72
|
+
// }, [analytics, onSkip]);
|
|
73
|
+
|
|
74
|
+
// Example handlers for step-level tracking (unused but kept for future use)
|
|
75
|
+
// const handleStepTransition = useCallback(
|
|
76
|
+
// async (stepId: string, action: 'viewed' | 'completed') => {
|
|
77
|
+
// if (action === 'viewed') {
|
|
78
|
+
// await analytics.trackStepViewed(stepId, {
|
|
79
|
+
// timestamp: new Date().toISOString(),
|
|
80
|
+
// user_type: userType,
|
|
81
|
+
// variant: variant || 'default',
|
|
82
|
+
// });
|
|
83
|
+
// } else if (action === 'completed') {
|
|
84
|
+
// await analytics.trackStepCompleted(stepId, {
|
|
85
|
+
// timestamp: new Date().toISOString(),
|
|
86
|
+
// interaction_method: 'button', // Could be 'swipe', 'tap', etc.
|
|
87
|
+
// });
|
|
88
|
+
// }
|
|
89
|
+
// },
|
|
90
|
+
// [analytics, userType, variant]
|
|
91
|
+
// );
|
|
92
|
+
|
|
93
|
+
// Pass enhanced handlers to your existing Onboarding component
|
|
94
|
+
// Note: You'll need to provide the actual onboarding data
|
|
95
|
+
return (
|
|
96
|
+
<Onboarding
|
|
97
|
+
data={
|
|
98
|
+
[
|
|
99
|
+
// Add your actual onboarding data here
|
|
100
|
+
// This is just a placeholder structure
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
onComplete={handleComplete}
|
|
104
|
+
testID="onboarding-with-analytics"
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Example of how to integrate with your demo screens:
|
|
111
|
+
* You can enhance your existing demo-one.tsx and demo-two.tsx files
|
|
112
|
+
* to include step tracking like this:
|
|
113
|
+
*/
|
|
114
|
+
|
|
115
|
+
/*
|
|
116
|
+
// In your demo-one.tsx file:
|
|
117
|
+
export default function DemoOneScreen() {
|
|
118
|
+
const { trackStepViewed, trackStepCompleted } = useContext(OnboardingAnalyticsContext);
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
trackStepViewed('demo_one');
|
|
122
|
+
}, []);
|
|
123
|
+
|
|
124
|
+
const handleContinue = () => {
|
|
125
|
+
trackStepCompleted('demo_one', {
|
|
126
|
+
interaction_method: 'button',
|
|
127
|
+
time_spent_seconds: Math.floor((Date.now() - startTime) / 1000)
|
|
128
|
+
});
|
|
129
|
+
// Navigate to next step
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const handleSkip = () => {
|
|
133
|
+
trackStepSkipped('demo_one', 'user_choice');
|
|
134
|
+
// Skip to end or next step
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
// Your existing UI
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
*/
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import LottieView from 'lottie-react-native';
|
|
2
|
+
import React, { useRef, useState } from 'react';
|
|
3
|
+
import { Dimensions, View, type ViewToken } from 'react-native';
|
|
4
|
+
import Animated, {
|
|
5
|
+
useAnimatedScrollHandler,
|
|
6
|
+
useSharedValue,
|
|
7
|
+
} from 'react-native-reanimated';
|
|
8
|
+
|
|
9
|
+
import { Button, Text } from '@/components/ui';
|
|
10
|
+
import ScrollingPaginationDots from '@/components/ui/core/pagination-dots';
|
|
11
|
+
import { translate } from '@/lib';
|
|
12
|
+
import { useThemeConfig } from '@/lib/use-theme-config';
|
|
13
|
+
|
|
14
|
+
const { width: SCREEN_WIDTH } = Dimensions.get('window');
|
|
15
|
+
|
|
16
|
+
export type OnboardingItem = {
|
|
17
|
+
id: string;
|
|
18
|
+
title: string;
|
|
19
|
+
description: string;
|
|
20
|
+
lottieAnim: any; // Lottie animation source
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type OnboardingProps = {
|
|
24
|
+
data: OnboardingItem[];
|
|
25
|
+
onComplete: () => void;
|
|
26
|
+
testID?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Reusable Onboarding component with horizontal swipeable screens,
|
|
31
|
+
* Lottie animations, and progress dots
|
|
32
|
+
*/
|
|
33
|
+
export function Onboarding({ data, onComplete, testID }: OnboardingProps) {
|
|
34
|
+
const theme = useThemeConfig();
|
|
35
|
+
const scrollX = useSharedValue(0);
|
|
36
|
+
const flatListRef = useRef<Animated.FlatList<OnboardingItem>>(null);
|
|
37
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
38
|
+
|
|
39
|
+
const handleScroll = useAnimatedScrollHandler((event) => {
|
|
40
|
+
scrollX.value = event.contentOffset.x;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const onViewableItemsChanged = ({
|
|
44
|
+
viewableItems,
|
|
45
|
+
}: {
|
|
46
|
+
viewableItems: ViewToken[];
|
|
47
|
+
}) => {
|
|
48
|
+
if (viewableItems.length > 0) {
|
|
49
|
+
const index = viewableItems[0].index || 0;
|
|
50
|
+
setCurrentIndex(index);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const handleNext = () => {
|
|
55
|
+
if (currentIndex < data.length - 1) {
|
|
56
|
+
flatListRef.current?.scrollToIndex({
|
|
57
|
+
index: currentIndex + 1,
|
|
58
|
+
animated: true,
|
|
59
|
+
});
|
|
60
|
+
} else {
|
|
61
|
+
onComplete();
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const handleSkip = () => {
|
|
66
|
+
onComplete();
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const renderItem = ({ item }: { item: OnboardingItem }) => (
|
|
70
|
+
<View
|
|
71
|
+
style={{ width: SCREEN_WIDTH }}
|
|
72
|
+
className="flex-1 items-center justify-center px-8"
|
|
73
|
+
>
|
|
74
|
+
{/* Lottie Animation */}
|
|
75
|
+
<View className="h-80 w-full items-center justify-center">
|
|
76
|
+
<LottieView
|
|
77
|
+
source={item.lottieAnim}
|
|
78
|
+
autoPlay
|
|
79
|
+
loop
|
|
80
|
+
style={{
|
|
81
|
+
width: 250,
|
|
82
|
+
height: 250,
|
|
83
|
+
}}
|
|
84
|
+
testID={`${testID}-lottie-${item.id}`}
|
|
85
|
+
/>
|
|
86
|
+
</View>
|
|
87
|
+
|
|
88
|
+
{/* Title */}
|
|
89
|
+
<Text
|
|
90
|
+
className="my-4 text-center text-4xl font-bold"
|
|
91
|
+
testID={`${testID}-title-${item.id}`}
|
|
92
|
+
>
|
|
93
|
+
{item.title}
|
|
94
|
+
</Text>
|
|
95
|
+
|
|
96
|
+
{/* Description */}
|
|
97
|
+
<Text
|
|
98
|
+
className="text-center text-lg leading-6"
|
|
99
|
+
style={{ color: theme.colors.mutedForeground }}
|
|
100
|
+
testID={`${testID}-description-${item.id}`}
|
|
101
|
+
>
|
|
102
|
+
{item.description}
|
|
103
|
+
</Text>
|
|
104
|
+
</View>
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const isLastSlide = currentIndex === data.length - 1;
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<View className="flex-1" testID={testID}>
|
|
111
|
+
{/* Main Content */}
|
|
112
|
+
<View className="flex-1">
|
|
113
|
+
<Animated.FlatList
|
|
114
|
+
ref={flatListRef}
|
|
115
|
+
data={data}
|
|
116
|
+
keyExtractor={(item) => item.id}
|
|
117
|
+
renderItem={renderItem}
|
|
118
|
+
horizontal
|
|
119
|
+
pagingEnabled
|
|
120
|
+
showsHorizontalScrollIndicator={false}
|
|
121
|
+
onScroll={handleScroll}
|
|
122
|
+
onViewableItemsChanged={onViewableItemsChanged}
|
|
123
|
+
viewabilityConfig={{
|
|
124
|
+
itemVisiblePercentThreshold: 50,
|
|
125
|
+
}}
|
|
126
|
+
scrollEventThrottle={16}
|
|
127
|
+
testID={`${testID}-flatlist`}
|
|
128
|
+
/>
|
|
129
|
+
</View>
|
|
130
|
+
|
|
131
|
+
{/* Progress Dots */}
|
|
132
|
+
<View className="items-center py-6">
|
|
133
|
+
<ScrollingPaginationDots
|
|
134
|
+
count={data.length}
|
|
135
|
+
scrollX={scrollX}
|
|
136
|
+
slideWidth={SCREEN_WIDTH}
|
|
137
|
+
dotColor={theme.colors.primary}
|
|
138
|
+
inactiveDotColor={theme.colors.mutedForeground}
|
|
139
|
+
dotSize={10}
|
|
140
|
+
spacing={12}
|
|
141
|
+
inactiveDotOpacity={0.3}
|
|
142
|
+
maxVisibleDots={5}
|
|
143
|
+
/>
|
|
144
|
+
</View>
|
|
145
|
+
|
|
146
|
+
{/* Action Buttons */}
|
|
147
|
+
<View className="flex-row items-center justify-between px-8 pb-8">
|
|
148
|
+
<Button
|
|
149
|
+
variant="ghost"
|
|
150
|
+
label={translate('onboarding.skip')}
|
|
151
|
+
onPress={handleSkip}
|
|
152
|
+
testID={`${testID}-skip-button`}
|
|
153
|
+
className="flex-1"
|
|
154
|
+
/>
|
|
155
|
+
|
|
156
|
+
<View className="w-4" />
|
|
157
|
+
|
|
158
|
+
<Button
|
|
159
|
+
label={
|
|
160
|
+
isLastSlide
|
|
161
|
+
? translate('onboarding.get_started')
|
|
162
|
+
: translate('onboarding.next')
|
|
163
|
+
}
|
|
164
|
+
onPress={handleNext}
|
|
165
|
+
testID={`${testID}-${isLastSlide ? 'complete' : 'next'}-button`}
|
|
166
|
+
className="flex-1"
|
|
167
|
+
/>
|
|
168
|
+
</View>
|
|
169
|
+
</View>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export default Onboarding;
|