trial choice

This commit is contained in:
dev.daminik00 2025-10-23 02:03:31 +02:00
parent 91211ddfbf
commit c7d6f049b0
3 changed files with 0 additions and 160 deletions

View File

@ -1,160 +0,0 @@
# 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 используются