Add "Gender"

2026-04-12 20:46:36 +00:00
parent b4603fbecc
commit dc07929326

108
Gender.md Normal file

@@ -0,0 +1,108 @@
# Гендерная сегментация
## Концепция
Одно письмо может содержать блоки для женской и мужской аудитории. При рендере выбирается header/footer по гендеру, а блоки могут переставляться местами.
## Сегменты блоков
Каждый блок имеет свойство `segment`:
- `'common'` (по умолчанию) — общий блок, показывается в обеих версиях
- `'female'` — только для женской версии
- `'male'` — только для мужской версии
Кнопки **О / Ж / М** в шапке каждого блока устанавливают сегмент (`setBlockSegment`).
## Кнопки Жен / Муж
Переключают `currentGenderVersion` ('female' / 'male') и перерендеривают превью.
Функция `assembleGenderVersion(target)`:
- Меняет `currentGenderVersion = target`
- **Не переставляет блоки** в конструкторе
- При рендере backend подставит нужный header/footer
## Кнопка ⇅ (Flip)
Переставляет блоки местами и переключает гендер.
Функция `flipSegmentOrder()`:
1. Вызывает `buildVersion(assembledBlocks, target)`
2. Физически перестраивает массив `assembledBlocks[]`
3. Переключает `segmentFlipped` (boolean toggle)
4. Синхронно меняет `currentGenderVersion`
## Алгоритм buildVersion
```javascript
buildVersion(list, target):
1. Ищет блок с swapCenter = true (divider-ось)
ЕСЛИ ось найдена:
- Блоки ДО оси группа A
- Блоки ПОСЛЕ оси группа B
- target === 'male' [B, ось, A]
- target === 'female' [A, ось, B]
ЕСЛИ оси нет:
- commonsPrefix = общие блоки до первого сегментированного
- segmentA = блоки с segment === target
- commonsMid = общие блоки между сегментами
- segmentB = блоки с противоположным segment
- commonsSuffix = общие блоки после последнего сегментированного
- Результат: [commonsPrefix, segmentA, commonsMid, segmentB, commonsSuffix]
```
## Разделитель (swapCenter)
Блок типа "dividerVA" (разделитель) может иметь флаг `swapCenter = true`:
- Устанавливается кнопкой **⊕** в шапке блока-разделителя
- Только один блок может быть осью одновременно
- Служит центральной точкой для `buildVersion()` — блоки до и после оси меняются местами
## Gender Paths
Настройки в `settings.genderPaths`:
```json
{
"headerFemale": "./parts/header/header-woman",
"headerMale": "./parts/header/header-man",
"footerFemale": "./parts/footer/footer-woman",
"footerMale": "./parts/footer/footer-man"
}
```
В UI — dropdown-пикеры, список файлов из `/api/parts-files` (сканирует `email-gen/emails/vipavenue/parts/`).
## Цепочка передачи gender при рендере
1. **App.svelte**`apiRenderEmail(..., { gender: currentGenderVersion })`
2. **vite.config.js** → читает `genderPaths` из settings.json, форвардит в email-gen-api с `{ gender, genderPaths }`
3. **email-gen-api/server.js**`rewriteHtmlPug()` — записывает `html.pug` с нужными путями:
```pug
block header
include ./parts/header/header-woman // или header-man
block footer
include ./parts/footer/footer-woman // или footer-man
```
## Кэш рендера и gender
Хэш кэша: `MD5(slug + pug + gender + JSON(genderPaths))`
Female и male версии кэшируются **отдельно**.
## ID Pool
Пул ID товаров для быстрого заполнения блоков:
1. **Ввод** — textarea, по одному ID на строку или через запятую
2. **Из Yonote** — кнопка `refreshIdsFromYonote()`:
- Берёт ID из `assemblyInfo.extra` (свойство "ID товаров")
- Женские ID первыми (filter по `/жен|female|ж\b/i`)
- Затем неразмеченные, затем мужские
3. **Распределение** — `distributeIds()`:
- Проходит по блокам с полем `mixin-ids`
- Вставляет 3 или 4 ID в зависимости от имени миксина (products3 → 3, products4 → 4)
- Последовательно из очереди `idPoolQueue[]`