# Registration Field Key для List Single Selection ## Описание Функциональность `registrationFieldKey` позволяет автоматически передавать выбранные значения из list single selection экранов в payload регистрации пользователя при авторизации через email экран. ## Как это работает ### 1. Настройка в админке Для list экранов с `selectionType: "single"` в админке появляется дополнительное поле **"Ключ поля для регистрации"**. В это поле можно указать путь к полю в объекте регистрации, используя точечную нотацию для вложенных объектов. **Примеры:** - `profile.gender` → `{ profile: { gender: "selected-id" } }` - `profile.relationship_status` → `{ profile: { relationship_status: "selected-id" } }` - `partner.gender` → `{ partner: { gender: "selected-id" } }` ### 2. Пример JSON конфигурации ```json { "id": "gender-screen", "template": "list", "title": { "text": "What is your gender?" }, "list": { "selectionType": "single", "registrationFieldKey": "profile.gender", "options": [ { "id": "male", "label": "Male", "emoji": "👨" }, { "id": "female", "label": "Female", "emoji": "👩" }, { "id": "other", "label": "Other", "emoji": "🧑" } ] } } ``` ### 3. Как данные попадают в регистрацию и сессию #### **Передача в сессию (на каждом экране):** 1. **Пользователь выбирает вариант** на экране (например, "Male" с id "male") 2. **Ответ сохраняется** в `FunnelAnswers` под ключом экрана: `{ "gender-screen": ["male"] }` 3. **При переходе вперед** (нажатие Continue или автопереход): - Вызывается `buildSessionDataFromScreen()` для текущего экрана - Создается объект с вложенной структурой: `{ profile: { gender: "male" } }` - Вызывается `updateSession()` с данными: ```typescript { answers: { "gender-screen": ["male"] }, // Старая логика profile: { gender: "male" } // Новая логика с registrationFieldKey } ``` 4. **Данные отправляются в API** и сохраняются в сессии пользователя #### **Передача в регистрацию (при авторизации):** 1. **При переходе на email экран** вызывается функция `buildRegistrationDataFromAnswers()` 2. **Функция обрабатывает** все list single selection экраны с `registrationFieldKey` 3. **Создается объект** с вложенной структурой из всех экранов: `{ profile: { gender: "male", relationship_status: "single" } }` 4. **При авторизации** этот объект объединяется с базовым payload 5. **Отправляется на сервер** в составе `ICreateAuthorizeRequest` ### 4. Структура payload регистрации **Базовый payload (без registrationFieldKey):** ```typescript { email: "user@example.com", timezone: "Europe/Moscow", locale: "en", source: "funnel-id", sign: true, signDate: "2024-01-01T00:00:00.000Z", feature: "stripe" } ``` **С registrationFieldKey (profile.gender = "male"):** ```typescript { email: "user@example.com", timezone: "Europe/Moscow", locale: "en", source: "funnel-id", sign: true, signDate: "2024-01-01T00:00:00.000Z", feature: "stripe", profile: { gender: "male" } } ``` **С несколькими registrationFieldKey:** ```typescript { email: "user@example.com", timezone: "Europe/Moscow", locale: "en", source: "funnel-id", sign: true, signDate: "2024-01-01T00:00:00.000Z", feature: "stripe", profile: { gender: "male", relationship_status: "single" }, partner: { gender: "female" } } ``` ## Полный пример воронки ```json { "meta": { "id": "dating-funnel", "title": "Dating Profile", "firstScreenId": "gender" }, "screens": [ { "id": "gender", "template": "list", "title": { "text": "What is your gender?" }, "list": { "selectionType": "single", "registrationFieldKey": "profile.gender", "options": [ { "id": "male", "label": "Male", "emoji": "👨" }, { "id": "female", "label": "Female", "emoji": "👩" } ] }, "navigation": { "defaultNextScreenId": "relationship-status" } }, { "id": "relationship-status", "template": "list", "title": { "text": "What is your relationship status?" }, "list": { "selectionType": "single", "registrationFieldKey": "profile.relationship_status", "options": [ { "id": "single", "label": "Single" }, { "id": "relationship", "label": "In a relationship" }, { "id": "married", "label": "Married" } ] }, "navigation": { "defaultNextScreenId": "partner-gender" } }, { "id": "partner-gender", "template": "list", "title": { "text": "What is your partner's gender?" }, "list": { "selectionType": "single", "registrationFieldKey": "partner.gender", "options": [ { "id": "male", "label": "Male", "emoji": "👨" }, { "id": "female", "label": "Female", "emoji": "👩" } ] }, "navigation": { "defaultNextScreenId": "email" } }, { "id": "email", "template": "email", "title": { "text": "Enter your email" }, "emailInput": { "label": "Email", "placeholder": "your@email.com" } } ] } ``` **Результат после прохождения воронки:** Если пользователь выбрал: - Gender: Male - Relationship Status: Single - Partner Gender: Female - Email: user@example.com Payload регистрации будет: ```typescript { email: "user@example.com", timezone: "Europe/Moscow", locale: "en", source: "dating-funnel", sign: true, signDate: "2024-01-01T00:00:00.000Z", feature: "stripe", profile: { gender: "male", relationship_status: "single" }, partner: { gender: "female" } } ``` ## Ограничения 1. **Только для single selection** - работает только с `selectionType: "single"` 2. **Только ID опции** - передается именно `id` выбранной опции, а не `label` или `value` 3. **Перезапись значений** - если несколько экранов используют один и тот же ключ, последний перезапишет предыдущий 4. **Обязательный email экран** - данные передаются только при авторизации через email экран ## Техническая реализация ### Файлы - **types.ts** - добавлено поле `registrationFieldKey` в `ListScreenDefinition` - **ListScreenConfig.tsx** - UI для настройки ключа в админке - **registrationHelpers.ts** - утилиты `buildRegistrationDataFromAnswers()` и `buildSessionDataFromScreen()` - **FunnelRuntime.tsx** - вызывает `buildSessionDataFromScreen()` при переходе вперед и передает в `updateSession()` - **useAuth.ts** - принимает `registrationData` и объединяет с базовым payload - **EmailTemplate.tsx** - вызывает `buildRegistrationDataFromAnswers()` и передает в `useAuth` - **screenRenderer.tsx** - передает `answers` в `EmailTemplate` ### Функция buildRegistrationDataFromAnswers Используется при авторизации для сбора данных со всех экранов воронки: ```typescript export function buildRegistrationDataFromAnswers( funnel: FunnelDefinition, answers: FunnelAnswers ): RegistrationDataObject { const registrationData: RegistrationDataObject = {}; for (const screen of funnel.screens) { if (screen.template === "list") { const listScreen = screen as ListScreenDefinition; if ( listScreen.list.selectionType === "single" && listScreen.list.registrationFieldKey && answers[screen.id] && answers[screen.id].length > 0 ) { const selectedId = answers[screen.id][0]; const fieldKey = listScreen.list.registrationFieldKey; // Устанавливаем значение по многоуровневому ключу setNestedValue(registrationData, fieldKey, selectedId); } } } return registrationData; } ``` ### Функция buildSessionDataFromScreen Используется при переходе вперед для сбора данных с текущего экрана: ```typescript export function buildSessionDataFromScreen( screen: { template: string; id: string; list?: { selectionType?: string; registrationFieldKey?: string } }, selectedIds: string[] ): RegistrationDataObject { const sessionData: RegistrationDataObject = {}; if (screen.template === "list" && screen.list) { const { selectionType, registrationFieldKey } = screen.list; if ( selectionType === "single" && registrationFieldKey && selectedIds.length > 0 ) { const selectedId = selectedIds[0]; setNestedValue(sessionData, registrationFieldKey, selectedId); } } return sessionData; } ``` ## Best Practices 1. **Используйте понятные ID** - ID опций должны соответствовать ожидаемым значениям на сервере 2. **Документируйте ключи** - ведите список используемых `registrationFieldKey` для избежания конфликтов 3. **Проверяйте типы** - убедитесь что ID опций соответствуют типам полей в `ICreateAuthorizeRequest` 4. **Тестируйте payload** - проверяйте что данные корректно попадают в регистрацию ## Примеры использования ### Простой профиль ```json { "list": { "selectionType": "single", "registrationFieldKey": "profile.gender", "options": [...] } } ``` ### Вложенная структура ```json { "list": { "selectionType": "single", "registrationFieldKey": "partner.birthplace.country", "options": [ { "id": "US", "label": "United States" }, { "id": "UK", "label": "United Kingdom" } ] } } ``` ### Без регистрации (обычный list) ```json { "list": { "selectionType": "single", // registrationFieldKey не указан - данные не попадут в регистрацию "options": [...] } } ```