w-funnel/docs/TRIAL_CHOICE_PAYMENT_INTEGRATION.md
2025-10-23 02:02:49 +02:00

161 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Trial Choice & Payment Integration
## Проблемы которые решены
### 1. Связь выбора Trial Choice → Payment
**Проблема**: Пользователь выбирает вариант триала на экране TrialChoice, но на экране Payment всегда отображался первый вариант.
**Решение**:
- Создан `TrialVariantSelectionContext` для хранения выбранного `variantId`
- `TrialChoiceTemplate` сохраняет выбор пользователя в контекст
- `TrialPaymentTemplate` читает выбранный вариант из контекста и использует его вместо первого
### 2. Общая логика загрузки и кеширование
**Проблема**:
- Каждый экран (TrialChoice, Payment) делал отдельный запрос к API
- TrialChoice показывал неправильные данные до завершения загрузки
- Payment уже имел loader, но TrialChoice — нет
**Решение**:
- Создан `PaymentPlacementProvider` для кеширования загруженных placement данных
- `usePaymentPlacement` hook теперь использует кеш из контекста
- Повторные запросы к 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`
- **Изменения**: Обернут в два новых провайдера:
```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
1. Открыть воронку с Trial Choice
2. Дождаться загрузки вариантов
3. Выбрать второй вариант (не первый)
4. Нажать Continue
5. **Ожидается**: На Payment отображается выбранный (второй) вариант
### Сценарий 2: Прямой переход на Payment
1. Открыть воронку без Trial Choice или перейти прямо на Payment
2. **Ожидается**: На Payment отображается первый вариант (дефолт)
### Сценарий 3: Кеширование
1. Открыть Trial Choice → загрузка placement
2. Перейти на Payment
3. **Ожидается**: Payment загружается мгновенно (из кеша), без повторного API запроса
### Сценарий 4: Special Offer
1. Открыть Special Offer
2. **Ожидается**: Всегда показывается первый вариант, независимо от выбора в Trial Choice
## API изменения (Backend)
### session.controller.ts
- **Изменения**: Добавлены `title` и `accent` поля в варианты
- **Поведение**: Возвращает все планы (не ограничивает до 4)
- **Дефолты**: `title` использует `["Basic", "Standard", "Popular", "Premium"]` с fallback `"Premium"`
## Файлы созданы/изменены
### Новые файлы
- `src/entities/session/payment/PaymentPlacementProvider.tsx`
- `src/entities/session/payment/TrialVariantSelectionContext.tsx`
- `src/entities/session/payment/index.ts`
### Измененные файлы
- `src/hooks/payment/usePaymentPlacement.ts` - использует контекст вместо локального state
- `src/components/funnel/templates/TrialChoiceTemplate/TrialChoiceTemplate.tsx` - loader + сохранение выбора
- `src/components/funnel/templates/TrialPaymentTemplate/TrialPaymentTemplate.tsx` - использует выбранный вариант
- `src/app/[funnelId]/layout.tsx` - обернут в провайдеры
## Будущие улучшения
1. **Персистентность**: Сохранять выбор в localStorage/sessionStorage для сохранения при перезагрузке
2. **Аналитика**: Трекинг выбора вариантов для A/B тестирования
3. **Валидация**: Проверять что выбранный variant все еще существует в placement
4. **Типизация**: Усилить типы для garantie что только валидные paymentId используются