8.4 KiB
8.4 KiB
Trial Choice & Payment Integration
Проблемы которые решены
1. Связь выбора Trial Choice → Payment
Проблема: Пользователь выбирает вариант триала на экране TrialChoice, но на экране Payment всегда отображался первый вариант.
Решение:
- Создан
TrialVariantSelectionContextдля хранения выбранногоvariantId TrialChoiceTemplateсохраняет выбор пользователя в контекстTrialPaymentTemplateчитает выбранный вариант из контекста и использует его вместо первого
2. Общая логика загрузки и кеширование
Проблема:
- Каждый экран (TrialChoice, Payment) делал отдельный запрос к API
- TrialChoice показывал неправильные данные до завершения загрузки
- Payment уже имел loader, но TrialChoice — нет
Решение:
- Создан
PaymentPlacementProviderдля кеширования загруженных placement данных usePaymentPlacementhook теперь использует кеш из контекста- Повторные запросы к API не выполняются если данные уже загружены
TrialChoiceTemplateпоказывает loader (как Payment) до загрузки данных
Архитектура
Контексты
PaymentPlacementProvider
- Путь:
src/entities/session/payment/PaymentPlacementProvider.tsx - Назначение: Кеширует результаты
loadFunnelPaymentByIdчтобы избежать повторных запросов - Ключ кеша:
${funnelKey}:${paymentId} - Состояние:
{ placement, isLoading, error }
TrialVariantSelectionProvider
- Путь:
src/entities/session/payment/TrialVariantSelectionContext.tsx - Назначение: Хранит выбранный пользователем
variantIdдля передачи между экранами - Состояние:
{ selectedVariantId, setSelectedVariantId }
Обновленные компоненты
TrialChoiceTemplate
- Изменения:
- Добавлен loader (Spinner) до загрузки placement
- Сохраняет выбор в
TrialVariantSelectionContext - Использует
usePaymentPlacementс кешированием - Инициализирует локальный
selectedIdизselectedVariantIdконтекста
TrialPaymentTemplate
- Изменения:
- Читает
selectedVariantIdизTrialVariantSelectionContext - Использует выбранный вариант, если доступен:
placement?.variants?.find((v) => v.id === selectedVariantId) - Fallback на первый вариант если выбор отсутствует
- Использует
usePaymentPlacementс кешированием
- Читает
SpecialOfferTemplate
- Изменения: Нет (специально)
- Поведение: Продолжает использовать первый вариант
placement?.variants?.[0] - Причина: Использует другой
paymentId("main_secret_discount") и не должен зависеть от выбора Trial
usePaymentPlacement Hook
- Изменения:
- Теперь использует
PaymentPlacementContextдля получения/загрузки данных - Упрощена логика: нет локального state, все в контексте
- Автоматически триггерит загрузку если данных нет
- Теперь использует
Layout Integration
- Файл:
src/app/[funnelId]/layout.tsx - Изменения: Обернут в два новых провайдера:
<PaymentPlacementProvider> <TrialVariantSelectionProvider> {children} </TrialVariantSelectionProvider> </PaymentPlacementProvider>
Потоки данных
Поток 1: Воронка С экраном Trial Choice
1. User открывает Trial Choice
→ PaymentPlacementProvider загружает "main" placement (если еще нет в кеше)
→ TrialChoiceTemplate показывает loader
→ После загрузки отображаются варианты
2. User выбирает вариант (например, id="plan-123")
→ setSelectedVariantId("plan-123") в TrialVariantSelectionContext
3. User переходит на Payment
→ PaymentPlacementProvider возвращает "main" placement из кеша (без запроса)
→ TrialPaymentTemplate читает selectedVariantId="plan-123"
→ Использует вариант с id="plan-123" вместо первого
Поток 2: Воронка БЕЗ экрана Trial Choice
1. User сразу открывает Payment
→ PaymentPlacementProvider загружает "main" placement
→ TrialPaymentTemplate показывает loader
→ selectedVariantId === null
→ Использует первый вариант (дефолт)
Поток 3: Special Offer
1. User открывает Special Offer
→ PaymentPlacementProvider загружает "main_secret_discount" placement
→ SpecialOfferTemplate показывает loader
→ Всегда использует первый вариант (не зависит от Trial Choice)
Тестирование
Сценарий 1: Trial Choice → Payment
- Открыть воронку с Trial Choice
- Дождаться загрузки вариантов
- Выбрать второй вариант (не первый)
- Нажать Continue
- Ожидается: На Payment отображается выбранный (второй) вариант
Сценарий 2: Прямой переход на Payment
- Открыть воронку без Trial Choice или перейти прямо на Payment
- Ожидается: На Payment отображается первый вариант (дефолт)
Сценарий 3: Кеширование
- Открыть Trial Choice → загрузка placement
- Перейти на Payment
- Ожидается: Payment загружается мгновенно (из кеша), без повторного API запроса
Сценарий 4: Special Offer
- Открыть Special Offer
- Ожидается: Всегда показывается первый вариант, независимо от выбора в Trial Choice
API изменения (Backend)
session.controller.ts
- Изменения: Добавлены
titleиaccentполя в варианты - Поведение: Возвращает все планы (не ограничивает до 4)
- Дефолты:
titleиспользует["Basic", "Standard", "Popular", "Premium"]с fallback"Premium"
Файлы созданы/изменены
Новые файлы
src/entities/session/payment/PaymentPlacementProvider.tsxsrc/entities/session/payment/TrialVariantSelectionContext.tsxsrc/entities/session/payment/index.ts
Измененные файлы
src/hooks/payment/usePaymentPlacement.ts- использует контекст вместо локального statesrc/components/funnel/templates/TrialChoiceTemplate/TrialChoiceTemplate.tsx- loader + сохранение выбораsrc/components/funnel/templates/TrialPaymentTemplate/TrialPaymentTemplate.tsx- использует выбранный вариантsrc/app/[funnelId]/layout.tsx- обернут в провайдеры
Будущие улучшения
- Персистентность: Сохранять выбор в localStorage/sessionStorage для сохранения при перезагрузке
- Аналитика: Трекинг выбора вариантов для A/B тестирования
- Валидация: Проверять что выбранный variant все еще существует в placement
- Типизация: Усилить типы для garantie что только валидные paymentId используются