trial choice
This commit is contained in:
parent
91211ddfbf
commit
c7d6f049b0
@ -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 используются
|
|
||||||
Loading…
Reference in New Issue
Block a user