Add "Gender"
108
Gender.md
Normal file
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[]`
|
||||||
Reference in New Issue
Block a user