Гендерная сегментация
Концепция
Одно письмо может содержать блоки для женской и мужской аудитории. При рендере выбирается header/footer по гендеру, а блоки могут переставляться местами.
Сегменты блоков
Каждый блок имеет свойство segment:
'common'(по умолчанию) — общий блок, показывается в обеих версиях'female'— только для женской версии'male'— только для мужской версии
Кнопки О / Ж / М в шапке каждого блока устанавливают сегмент (setBlockSegment).
Кнопки Жен / Муж
Переключают currentGenderVersion ('female' / 'male') и перерендеривают превью.
Функция assembleGenderVersion(target):
- Меняет
currentGenderVersion = target - Не переставляет блоки в конструкторе
- При рендере backend подставит нужный header/footer
Кнопка ⇅ (Flip)
Переставляет блоки местами и переключает гендер.
Функция flipSegmentOrder():
- Вызывает
buildVersion(assembledBlocks, target) - Физически перестраивает массив
assembledBlocks[] - Переключает
segmentFlipped(boolean toggle) - Синхронно меняет
currentGenderVersion
Алгоритм buildVersion
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:
{
"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 при рендере
- App.svelte →
apiRenderEmail(..., { gender: currentGenderVersion }) - vite.config.js → читает
genderPathsиз settings.json, форвардит в email-gen-api с{ gender, genderPaths } - email-gen-api/server.js →
rewriteHtmlPug()— записываетhtml.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 товаров для быстрого заполнения блоков:
- Ввод — textarea, по одному ID на строку или через запятую
- Из Yonote — кнопка
refreshIdsFromYonote():- Берёт ID из
assemblyInfo.extra(свойство "ID товаров") - Женские ID первыми (filter по
/жен|female|ж\b/i) - Затем неразмеченные, затем мужские
- Берёт ID из
- Распределение —
distributeIds():- Проходит по блокам с полем
mixin-ids - Вставляет 3 или 4 ID в зависимости от имени миксина (products3 → 3, products4 → 4)
- Последовательно из очереди
idPoolQueue[]
- Проходит по блокам с полем