@megaads/wm
Version:
To install the library, use npm:
1,154 lines (973 loc) • 41.6 kB
text/typescript
// @ts-nocheck
import _ from 'lodash';
import { getCdn } from "./helper";
type TeeinblueInitOptions = {
campaignProductIndex?: number;
campaignMockupId?: string | number;
mockupId?: string | number;
printareaId?: string | number;
templateId?: string | number;
state?: any;
};
class CustomizationTeeInBlue
{
private campaign;
private options: TeeinblueInitOptions;
private campaignProduct;
private campaignMockupId;
private mockupId;
private printareaId;
private campaignMockup;
private template;
private artworks = [];
private artwork;
private customFontFamilies = {};
private googleFontFamilies = {};
private designLayers = [];
private templateOptions = [];
private layerOptions = [];
private templateLayers = [];
private layerById = {};
private clipartCategoryById = {};
private groupedClipartsByParentId = {};
private printAreaIds = [];
private printAreas = [];
constructor(campaign, options: TeeinblueInitOptions = {})
{
this.campaign = _.cloneDeep(campaign?.result || campaign || {});
this.options = options || {};
this.prepareCampaignLookups();
this.selectCampaignProduct();
this.selectCampaignMockup();
this.initPrintAreas();
this.loadArtworks();
this.applyInitialState(options.state);
this.rebuild();
}
private rebuild()
{
this.prepareTemplateLookups();
this.bindDefaultLayersValue();
this.buildOptionsList();
this.buildDesignLayers();
this.buildPrintAreas();
}
private prepareCampaignLookups()
{
const categories = this.campaign.clipart_categories || [];
this.clipartCategoryById = {};
this.groupedClipartsByParentId = {};
for (let i = 0; i < categories.length; i++) {
const category = categories[i];
this.clipartCategoryById[category.id] = category;
if (category.parent_id) {
if (!this.groupedClipartsByParentId[category.parent_id]) {
this.groupedClipartsByParentId[category.parent_id] = [];
}
this.groupedClipartsByParentId[category.parent_id].push(category);
}
}
}
private selectCampaignProduct()
{
const products = this.campaign.campaign_products || [];
this.campaignProduct = products[this.options.campaignProductIndex || 0] || products[0] || null;
}
private selectCampaignMockup()
{
if (!this.campaignProduct) return;
const campaignMockups = this.campaignProduct.campaign_mockups || [];
const campaignVariants = this.campaignProduct.campaign_variants || [];
this.campaignMockupId = this.options.campaignMockupId;
this.mockupId = this.options.mockupId;
this.printareaId = this.options.printareaId;
if (!this.campaignMockupId && !this.mockupId && campaignVariants.length) {
for (let i = 0; i < campaignVariants.length; i++) {
const campaignVariant = campaignVariants[i];
if (campaignVariant.campaign_mockup_id) {
this.campaignMockupId = campaignVariant.campaign_mockup_id;
break;
}
if (campaignVariant.variant?.mockup_id && campaignVariant.variant?.printarea_id) {
this.mockupId = campaignVariant.variant.mockup_id;
this.printareaId = campaignVariant.variant.printarea_id;
break;
}
}
}
if (this.mockupId && this.printareaId) {
this.campaignMockup = campaignMockups.find(cpm => cpm.mockup_id == this.mockupId);
}
if (!this.campaignMockup && this.campaignMockupId) {
this.campaignMockup = campaignMockups.find(cpm => cpm.id == this.campaignMockupId);
}
if (!this.campaignMockup && campaignMockups.length == 1) {
this.campaignMockup = campaignMockups[0];
}
if (!this.campaignMockup) {
this.campaignMockup = campaignMockups.find(cpm => cpm.mockup_id != null || cpm.old_campaign_mockup_id != null);
}
if (!this.campaignMockup) {
this.campaignMockup = campaignMockups.find(cpm => {
return (cpm.layers || []).find(layer => layer.printarea_id);
}) || campaignMockups[0] || null;
}
if (this.campaignMockup?.layers) {
this.campaignMockup.layers = this.campaignMockup.layers.map(layer => this.normalizeMockupLayer(layer));
}
}
private normalizeMockupLayer(layer)
{
const normalized = _.cloneDeep(layer);
if (normalized.url) normalized.url = getCdn(normalized.url);
if (normalized.masked_image) normalized.masked_image = getCdn(normalized.masked_image);
return normalized;
}
private initPrintAreas()
{
this.printAreaIds = [];
const layers = this.campaignMockup?.layers || [];
for (let i = 0; i < layers.length; i++) {
const layer = layers[i];
if (layer.visible === false) continue;
if (!layer.url && layer.printarea_id) this.printAreaIds.push(layer.id);
}
}
private loadArtworks()
{
const artworkCampaigns = this.findActiveCampaignArtwork();
const artworkIds = artworkCampaigns.map(pa => pa.artwork_id);
const activeArtworks = (this.campaign.artworks || []).filter(artwork => artworkIds.includes(artwork.id));
this.artworks = activeArtworks.length ? activeArtworks : (this.campaign.artworks || []);
if (!this.artworks.length) return;
let selectedArtwork = null;
let selectedTemplate = null;
if (this.options.templateId) {
for (let i = 0; i < this.artworks.length; i++) {
const artwork = this.artworks[i];
const template = (artwork.data || []).find(item => item.id == this.options.templateId);
if (template) {
selectedArtwork = artwork;
selectedTemplate = template;
break;
}
}
}
// Auto-select template chỉ khi có duy nhất 1 artwork.
// Nếu có nhiều artwork và user chưa chọn (không truyền templateId), validate() sẽ yêu cầu user chọn.
if (!selectedTemplate && this.artworks.length === 1) {
selectedArtwork = this.artworks[0];
selectedTemplate = selectedArtwork.data?.[0] || null;
}
if (selectedArtwork && selectedTemplate) {
this.setActiveArtworkTemplate(selectedArtwork, selectedTemplate);
}
}
private findActiveCampaignArtwork()
{
const campaignArtworks = this.campaign.campaign_artworks || [];
if (this.printareaId) {
const foundArtwork = campaignArtworks.filter(cp => cp.printarea_id == this.printareaId);
if (foundArtwork.length) return foundArtwork;
}
const printareaIds = [];
const mockupLayers = this.campaignMockup?.layers || [];
for (let i = 0; i < mockupLayers.length; i++) {
if (mockupLayers[i].printarea_id) printareaIds.push(mockupLayers[i].printarea_id);
}
const matched = campaignArtworks.filter(cp => printareaIds.includes(cp.printarea_id));
return matched.length ? matched : campaignArtworks;
}
private setActiveArtworkTemplate(artwork, template)
{
if (!artwork || !template) return;
this.artwork = artwork;
this.template = template;
this.templateLayers = _.cloneDeep(template.layers || []);
// Lưu base position để applyReposition reset đúng, tránh cộng dồn offset qua nhiều lần đổi option.
for (let i = 0; i < this.templateLayers.length; i++) {
const layer = this.templateLayers[i];
layer._baseTop = layer.top || 0;
layer._baseLeft = layer.left || 0;
}
for (let i = 0; i < (artwork.data || []).length; i++) {
artwork.data[i].active = artwork.data[i].id == template.id;
}
}
private prepareTemplateLookups()
{
this.layerById = {};
for (let i = 0; i < this.templateLayers.length; i++) {
this.layerById[this.templateLayers[i].id] = this.templateLayers[i];
}
}
// Tạo bản shallow-clone cho từng templateLayer trước khi mutator chạy.
// Giữ cho ref cũ (đang được snapshot trước đó nắm) không bị thay đổi → React/RN
// memo/PureComponent thấy ref mới ở các layer được sửa và re-render đúng.
private cloneTemplateLayers()
{
this.templateLayers = this.templateLayers.map(layer => ({ ...layer }));
this.prepareTemplateLookups();
}
private bindDefaultLayersValue()
{
for (let i = 0; i < this.templateLayers.length; i++) {
const layer = this.templateLayers[i];
if (typeof layer.form_visibility != 'undefined' && typeof layer.form_visibility_value == 'undefined') {
layer.form_visibility_value = layer.form_visibility;
}
if (typeof layer.value != 'undefined' || typeof layer.show_value != 'undefined') continue;
if (layer.default_value) {
layer.show_value = layer.default_value;
let value = layer.default_value;
if (layer.form_type == 'grouped_clipart') {
const groupedCliparts = this.getGroupedClipart(layer);
for (let j = 0; j < groupedCliparts.length; j++) {
const elementClipart = groupedCliparts[j];
const optionValue = (elementClipart.options || []).find(opt => {
return opt.url == layer.default_value || getCdn(opt.url) == getCdn(layer.default_value);
});
if (optionValue) {
value = elementClipart.id;
elementClipart.show_value = optionValue.url;
} else if (elementClipart.options?.[0]) {
elementClipart.show_value = elementClipart.options[0].url;
}
}
}
layer.value = value;
} else if (layer.url) {
layer.show_value = layer.url;
}
}
}
private applyInitialState(state)
{
if (!state) return;
if (state.templateId) this.selectTemplate(state.templateId, false);
if (state.layers) {
for (let i = 0; i < this.templateLayers.length; i++) {
const layer = this.templateLayers[i];
const savedLayer = state.layers[layer.id];
if (!savedLayer) continue;
if (savedLayer.value !== undefined) layer.value = savedLayer.value;
if (savedLayer.show_value !== undefined) layer.show_value = savedLayer.show_value;
if (savedLayer.form_visibility_value !== undefined) layer.form_visibility_value = savedLayer.form_visibility_value;
if (savedLayer.selected_name !== undefined) layer.selected_name = savedLayer.selected_name;
if (savedLayer.optionItem !== undefined) layer.optionItem = savedLayer.optionItem;
}
}
}
private buildOptionsList()
{
this.templateOptions = this.buildTemplateOptions();
this.layerOptions = this.buildLayerOptions();
}
private buildTemplateOptions()
{
return this.artworks.map(artwork => {
const optionValues = (artwork.data || []).map(template => ({
id: template.id,
name: template.name,
title: template.title || template.name,
url: template.url ? getCdn(template.url) : null,
thumbnail: template.thumbnail ? getCdn(template.thumbnail) : (template.url ? getCdn(template.url) : null),
active: this.template?.id == template.id,
artworkId: artwork.id,
}));
return {
artworkId: artwork.id,
label: artwork.template_settings?.label || artwork.name,
optionValues,
values: optionValues,
};
});
}
private buildLayerOptions()
{
const layerOptions = [];
const positions = this.template?.positions || this.templateLayers.map(layer => layer.id);
for (let index = 0; index < positions.length; index++) {
const layer = this.layerById[positions[index]];
if (!this.shouldRenderOptionLayer(layer)) continue;
const option = this.normalizeOptionLayer(layer);
layerOptions.push(option);
}
return layerOptions;
}
private normalizeOptionLayer(layer)
{
const option = _.cloneDeep(layer);
option.isShow = this.shouldRenderOptionLayer(layer);
option.input_type = this.getLayerInputType(layer);
option.option_items = [];
if (option.type == 'option') {
option.option_items = this.getAdditionOptions(layer);
} else if (option.form_type == 'clipart') {
option.option_items = this.getClipartOptions(layer);
} else if (option.form_type == 'grouped_clipart') {
option.option_items = this.getGroupedClipart(layer);
}
option.options = option.option_items;
return option;
}
private getLayerInputType(layer)
{
if (layer.type == 'text') return 'text';
if (layer.form_type == 'photo') return 'photo';
if (layer.form_type == 'grouped_clipart') return 'grouped_clipart';
if (layer.form_type == 'clipart') return 'clipart';
if (layer.type == 'option') return 'option';
return layer.form_type || layer.type;
}
private shouldRenderOptionLayer(layer)
{
return !!(layer
&& layer.visible
&& layer.form_type != 'static'
&& this.isShowLayer(layer)
&& layer.form_type != 'linked'
&& layer.type != 'group'
&& (layer.form_label || layer.form_type || layer.additional_option));
}
private buildDesignLayers()
{
this.designLayers = [];
this.googleFontFamilies = {};
this.customFontFamilies = {};
for (let i = 0; i < this.templateLayers.length; i++) {
const layer = this.templateLayers[i];
const designLayer = this.toDesignLayer(layer, i);
if (designLayer) this.designLayers.push(designLayer);
}
}
private toDesignLayer(layer, orderFallback = 0)
{
if (!layer || !layer.visible) return null;
let isShowLayer = this.isShowLayer(layer);
if (layer.form_visibility && typeof layer.form_visibility_value == 'boolean') {
isShowLayer = layer.form_visibility_value && isShowLayer;
} else if (layer.form_visibility_value === false) {
isShowLayer = false;
}
if (!isShowLayer) return null;
const base = {
uid: layer.id,
id: layer.id,
name: layer.name,
layerType: layer.type,
formType: layer.form_type || null,
s_width: layer.width,
s_height: layer.height,
width: layer.width,
height: layer.height,
top: layer.top || 0,
left: layer.left || 0,
order: layer.order ?? orderFallback,
angle: layer.rotate || 0,
rotate: layer.rotate || 0,
opacity: 1,
locked: layer.form_type == 'photo' ? false : true,
value: layer.value,
show_value: layer.show_value,
selected_name: layer.selected_name || null,
linked: layer.linked || null,
group_id: layer.group_id || null,
};
if (layer.url || layer.type == 'clipart') {
const src = layer.show_value || layer.url;
if (!src) return null;
return {
...base,
type: 'image',
src: getCdn(src),
url: getCdn(src),
masked_enable: layer.masked_enable || false,
masked_url: layer.masked_url ? getCdn(layer.masked_url) : null,
masked_image: layer.masked_image ? getCdn(layer.masked_image) : null,
};
}
if (layer.type == 'text') {
const text = this.getLayerText(layer);
const renderConfig = {
...base,
type: 'text',
text,
defaultText: layer.text,
align: layer.align,
color: layer.color,
max_length: layer.max_length,
typography: layer.typography,
custom_font: layer.custom_font ? {
...layer.custom_font,
url: layer.custom_font.url ? getCdn(String(layer.custom_font.url).replace(/\.(otf|ttf)$/i, '.woff2')) : layer.custom_font.url,
} : null,
color_option: layer.color_option,
stroke_color: layer.stroke_color,
stroke_width: layer.stroke_width,
stroke_enabled: layer.stroke_enabled ?? false,
typography_type: layer.typography_type ?? 'google',
autoscale_enabled: layer.autoscale_enabled,
autoscale_max_width: layer.autoscale_max_width,
form_input_textcase: layer.form_input_textcase ?? null,
prefix: layer.prefix ?? null,
suffix: layer.suffix ?? null,
};
this.collectFont(renderConfig);
return renderConfig;
}
return null;
}
private getLayerText(layer)
{
let text = layer.value !== undefined && layer.value !== null ? String(layer.value) : (layer.text || '');
if (layer.form_input_textcase == 'uppercase') text = text.toUpperCase();
if (layer.prefix) text = layer.prefix + text;
if (layer.suffix) text = text + layer.suffix;
return text;
}
private collectFont(layer)
{
const typographyType = layer.typography_type ?? 'google';
if (typographyType == 'google' && layer.typography?.family) {
if (typeof this.googleFontFamilies[layer.typography.family] == "undefined") {
this.googleFontFamilies[layer.typography.family] = [];
}
if (layer.typography.variant && this.googleFontFamilies[layer.typography.family].indexOf(layer.typography.variant) == -1) {
this.googleFontFamilies[layer.typography.family].push(layer.typography.variant);
}
} else if (typographyType == 'custom' && layer.custom_font?.family) {
this.customFontFamilies[layer.custom_font.family] = layer.custom_font;
}
}
private buildPrintAreas()
{
this.printAreas = [];
const mockupLayers = this.campaignMockup?.layers || [];
for (let i = 0; i < mockupLayers.length; i++) {
const mockupLayer = mockupLayers[i];
if (mockupLayer.visible === false || !mockupLayer.printarea_id) continue;
const campaignArtwork = (this.campaign.campaign_artworks || []).find(item => item.printarea_id == mockupLayer.printarea_id);
this.printAreas.push({
id: mockupLayer.id,
printarea_id: mockupLayer.printarea_id,
artwork_id: campaignArtwork?.artwork_id || this.artwork?.id || null,
top: mockupLayer.top || 0,
left: mockupLayer.left || 0,
width: mockupLayer.width,
height: mockupLayer.height,
rotate: mockupLayer.rotate || 0,
opacity: mockupLayer.opacity ?? 1,
masked_enable: mockupLayer.masked_enable || false,
masked_image: mockupLayer.masked_image || null,
masked_top: mockupLayer.masked_top || 0,
masked_left: mockupLayer.masked_left || 0,
masked_width: mockupLayer.masked_width || mockupLayer.width,
masked_height: mockupLayer.masked_height || mockupLayer.height,
artwork: {
width: this.artwork?.width,
height: this.artwork?.height,
},
layers: this.designLayers,
});
}
}
public isShowLayer(optionLayer)
{
if (!optionLayer) return false;
if (!optionLayer.dependency) return true;
const dependency = optionLayer.dependency;
const dependencies = dependency.dependencies;
const defaultCondition = dependency.show_by_default ? true : false;
const conditions = [];
if (typeof dependencies != 'undefined' && dependencies.length) {
const dependencyItemConditions = [];
for (let i = 0; i < dependencies.length; i++) {
const dependencyItem = dependencies[i];
const refLayer = this.layerById[dependencyItem.element];
if (refLayer && !this.isShowLayer(refLayer)) {
dependencyItemConditions.push(false);
} else if (refLayer && typeof refLayer.value != 'undefined' && refLayer.value !== null && refLayer.value !== '') {
if (Array.isArray(dependencyItem.value)) {
dependencyItemConditions.push(dependencyItem.value.includes(refLayer.value));
} else {
dependencyItemConditions.push(dependencyItem.value == refLayer.value);
}
} else {
dependencyItemConditions.push(defaultCondition);
}
}
if (dependencyItemConditions.length) {
const reducer = dependency.match_type == 'any'
? (accumulator, currentValue) => accumulator || currentValue
: (accumulator, currentValue) => accumulator && currentValue;
conditions.push(dependencyItemConditions.reduce(reducer));
}
} else if (dependency.value && dependency.element) {
const refLayer = this.layerById[dependency.element];
let condition = false;
if (typeof refLayer != 'undefined' && typeof refLayer.value != 'undefined' && refLayer.value !== null && refLayer.value !== '') {
if (Array.isArray(dependency.value)) {
condition = dependency.value.includes(refLayer.value);
} else {
condition = dependency.value == refLayer.value;
}
} else if (refLayer && this.isShowLayer(refLayer)) {
condition = dependency.show_by_default ?? false;
}
conditions.push(condition);
} else {
conditions.push(true);
}
if (conditions.length) {
const reducer = dependency.match_type == 'any'
? (accumulator, currentValue) => accumulator || currentValue
: (accumulator, currentValue) => accumulator && currentValue;
return conditions.reduce(reducer);
}
return defaultCondition;
}
public isShowGroupedClipart(option, layer)
{
if (!option) return false;
for (let i = 0; i < (option.options || []).length; i++) {
const optionItem = option.options[i];
if (option.id == layer.value) return true;
if (optionItem.url == layer.show_value) return true;
if (getCdn(optionItem.url) == layer.show_value) return true;
}
return false;
}
public selectTemplate(templateId, rebuild = true)
{
for (let i = 0; i < this.artworks.length; i++) {
const artwork = this.artworks[i];
const template = (artwork.data || []).find(item => item.id == templateId);
if (!template) continue;
this.setActiveArtworkTemplate(artwork, template);
if (rebuild) this.rebuild();
return this.getSnapshot();
}
return this.getSnapshot();
}
public changeLayerOptionValue(optionItem, option, parentLayer = null)
{
return this.changeOptionValue(optionItem, option, parentLayer);
}
public changeOptionValue(optionItem, option, parentLayer = null)
{
if (!optionItem || !option) return this.getSnapshot();
this.cloneTemplateLayers();
const targetLayer = this.layerById[option.id] || option;
const resolvedParentLayer = parentLayer ? (this.layerById[parentLayer.id] || parentLayer) : null;
const linkedLayers = [targetLayer];
const parentIds = [];
if (resolvedParentLayer) {
linkedLayers.push(resolvedParentLayer);
parentIds.push(resolvedParentLayer.id);
}
for (let i = 0; i < this.templateLayers.length; i++) {
const linkLayer = this.templateLayers[i];
if (linkLayer.linked == targetLayer.id || (resolvedParentLayer && linkLayer.linked == resolvedParentLayer.id)) {
linkedLayers.push(linkLayer);
}
}
const showValue = optionItem.url ?? optionItem.show_value ?? optionItem.value ?? null;
const optionName = optionItem.name ?? optionItem.value_name ?? null;
if (targetLayer.clipart_reposition) {
this.applyReposition(targetLayer, targetLayer.clipart_reposition);
}
if (targetLayer.grouped_reposition) {
const repositionConfig = targetLayer.grouped_reposition.find(item => item.id == optionItem.id);
if (repositionConfig) this.applyReposition(targetLayer, repositionConfig);
}
for (let i = 0; i < linkedLayers.length; i++) {
const linkLayer = linkedLayers[i];
if (!linkLayer) continue;
linkLayer.optionItem = _.cloneDeep(optionItem);
linkLayer.selected_name = optionName;
if (parentIds.includes(linkLayer.id)) {
// Parent layer (thường là form_type='grouped_clipart').
// show_value = URL của item được chọn (để render).
// value = id để định danh lựa chọn (cần thiết cho validation và payload).
linkLayer.show_value = showValue;
if (linkLayer.form_type == 'grouped_clipart') {
// Với grouped_clipart, value = id của group chứa item được chọn (option = group).
linkLayer.value = option?.id ?? showValue;
} else if (typeof optionItem.id !== 'undefined' && optionItem.id !== null) {
linkLayer.value = optionItem.id;
} else {
linkLayer.value = showValue;
}
linkLayer.validated = true;
continue;
}
if (linkLayer.type == 'option') {
linkLayer.value = optionItem.id;
linkLayer.show_value = optionItem.id;
linkLayer.validated = true;
} else if (linkLayer.type == 'clipart') {
linkLayer.show_value = showValue;
linkLayer.value = linkLayer.show_value;
if (linkLayer.form_type == 'grouped_clipart') {
linkLayer.value = optionItem.id;
linkLayer.show_value = optionItem.show_value;
}
linkLayer.validated = true;
}
}
this.rebuild();
return this.getSnapshot();
}
private applyReposition(layer, repositionConfig)
{
if (!layer || !repositionConfig) return;
// Khởi tạo base nếu layer chưa được track (ví dụ: layer được set qua setTemplateLayers).
if (typeof layer._baseTop === 'undefined') layer._baseTop = layer.top || 0;
if (typeof layer._baseLeft === 'undefined') layer._baseLeft = layer.left || 0;
layer.width = repositionConfig.width ?? layer.width;
layer.height = repositionConfig.height ?? layer.height;
layer.top = layer._baseTop + (repositionConfig.top || 0);
layer.left = layer._baseLeft + (repositionConfig.left || 0);
}
public changeOptionGroupClipartValue(optionItem, option)
{
return this.changeOptionValue(optionItem, option);
}
public changeInputValue(layerOption, value)
{
this.cloneTemplateLayers();
const targetLayer = this.layerById[layerOption.id] || layerOption;
for (let i = 0; i < this.templateLayers.length; i++) {
const layer = this.templateLayers[i];
if (layer.id == targetLayer.id || layer.linked == targetLayer.id) {
layer.value = value;
layer.show_value = value;
layer.validated = true;
}
}
this.rebuild();
return this.getSnapshot();
}
public changeUploadValue(layerOption, imageUrl, metadata = {})
{
this.cloneTemplateLayers();
const targetLayer = this.layerById[layerOption.id] || layerOption;
targetLayer.upload_image_url = imageUrl;
targetLayer.upload_file = metadata.file || targetLayer.upload_file;
const linkedLayers = [targetLayer];
let parentLayer = null;
if (targetLayer.parent_id) {
parentLayer = this.templateLayers.find(layer => layer.grouped_clipart == targetLayer.parent_id);
}
for (let i = 0; i < this.templateLayers.length; i++) {
const linkLayer = this.templateLayers[i];
if (linkLayer.linked == targetLayer.id || (parentLayer && linkLayer.linked == parentLayer.id)) {
linkedLayers.push(linkLayer);
}
}
for (let i = 0; i < linkedLayers.length; i++) {
linkedLayers[i].show_value = imageUrl;
linkedLayers[i].value = imageUrl;
linkedLayers[i].validated = true;
}
this.rebuild();
return this.getSnapshot();
}
public changeLayerVisibility(layerOption, value)
{
this.cloneTemplateLayers();
const targetLayer = this.layerById[layerOption.id] || layerOption;
targetLayer.form_visibility_value = !!value;
this.rebuild();
return this.getSnapshot();
}
public getClipart(layer)
{
return this.clipartCategoryById[layer.clipart] || { options: [] };
}
public getClipartOptions(layer)
{
const clipart = this.getClipart(layer);
return this.normalizeOptionItems(clipart.options || [], layer, 'url');
}
public getGroupedClipart(layer)
{
if (!layer.grouped_clipart) return [];
const groups = this.groupedClipartsByParentId[layer.grouped_clipart] || [];
return _.cloneDeep(groups).map(group => {
group.thumbnail = group.thumbnail ? getCdn(group.thumbnail) : null;
const normalizedOptions = this.normalizeOptionItems(group.options || [], layer, 'url');
const selectedOption = normalizedOptions.find(option => {
return option.url == layer.show_value || option.url == getCdn(layer.show_value);
});
group.show_value = selectedOption?.url || normalizedOptions[0]?.url || group.show_value || null;
group.options = normalizedOptions.map(option => {
option.active = option.url == layer.show_value || option.url == getCdn(layer.show_value);
if (layer.value == group.id && !layer.show_value && option.url == group.show_value) {
option.active = true;
}
return option;
});
group.active = layer.value == group.id || !!selectedOption;
group.isShow = this.isShowGroupedClipart(group, layer);
return group;
});
}
public getAdditionOptions(layer)
{
if (!layer.additional_option) return [];
const category = this.clipartCategoryById[layer.additional_option];
return this.normalizeOptionItems(category?.options || [], layer, 'id');
}
private normalizeOptionItems(options, layer, activeBy = 'id')
{
return _.cloneDeep(options).map(option => {
if (option.thumbnail) option.thumbnail = getCdn(option.thumbnail);
if (option.url) option.url = getCdn(option.url);
if (option.show_value) option.show_value = getCdn(option.show_value);
option.active = false;
if (activeBy == 'url') {
option.active = option.url == layer.show_value || option.url == getCdn(layer.show_value);
} else {
option.active = option.id == layer.value || option.id == layer.show_value;
}
return option;
});
}
public getSnapshot()
{
return {
campaign: this.campaign,
campaignProduct: this.campaignProduct,
campaignMockup: this.campaignMockup,
mockup: this.getMockupPreview(),
printAreas: this.printAreas,
artwork: this.artwork,
template: this.getTemplate(),
templateOptions: this.templateOptions,
layerOptions: this.layerOptions,
designLayers: this.designLayers,
fonts: this.getFonts(),
config: this.getCustomizationConfig(),
validation: this.validate(),
};
}
public getMockupPreview()
{
const layers = (this.campaignMockup?.layers || []).filter(layer => layer.visible !== false).map(layer => {
if (layer.url) {
return {
id: layer.id,
type: 'image',
src: layer.url,
url: layer.url,
top: layer.top || 0,
left: layer.left || 0,
width: layer.width,
height: layer.height,
opacity: layer.opacity ?? 1,
position: layer.position ?? null,
rotate: layer.rotate || 0,
};
}
if (layer.printarea_id) {
return {
id: layer.id,
type: 'printarea',
printarea_id: layer.printarea_id,
top: layer.top || 0,
left: layer.left || 0,
width: layer.width,
height: layer.height,
opacity: layer.opacity ?? 1,
position: layer.position ?? null,
rotate: layer.rotate || 0,
masked_enable: layer.masked_enable || false,
masked_image: layer.masked_image || null,
layers: this.designLayers,
};
}
return null;
}).filter(Boolean);
return {
id: this.campaignMockup?.id,
width: this.campaignMockup?.width,
height: this.campaignMockup?.height,
preview_url: this.campaignMockup?.preview_url ? getCdn(this.campaignMockup.preview_url) : null,
preview_thumbnail: this.campaignMockup?.preview_thumbnail ? getCdn(this.campaignMockup.preview_thumbnail) : null,
layers,
};
}
public getCustomizationConfig()
{
const configs = {
disable_make_change: true,
layers: [],
options: [],
custom_type: {
name: 'teeinblue'
}
};
for (let i = 0; i < this.layerOptions.length; i++) {
const optionLayer = this.layerOptions[i];
if (!optionLayer.show_value) continue;
if (!optionLayer.form_label) continue;
const opt = {
name: optionLayer.form_label,
value: optionLayer.show_value,
};
if (optionLayer.optionItem) {
opt.optionItem = _.cloneDeep(optionLayer.optionItem);
delete opt.optionItem.options;
if (optionLayer.optionItem.selected_name) opt.selected_name = optionLayer.optionItem.selected_name;
}
configs.options.push(opt);
}
for (let i = 0; i < this.templateLayers.length; i++) {
const layer = _.cloneDeep(this.templateLayers[i]);
let isShowLayer = this.isShowLayer(layer);
if (typeof layer.form_visibility_value == 'boolean') {
isShowLayer = layer.form_visibility_value && isShowLayer;
}
if (!layer.visible || !isShowLayer) continue;
let layerConfig = {
name: layer.name,
type: layer.type,
value: layer.value,
};
const transformConfigs = _.cloneDeep(layer);
delete transformConfigs.value;
delete transformConfigs.show_value;
delete transformConfigs.url;
delete transformConfigs.name;
delete transformConfigs.custom_type;
delete transformConfigs.optionItem;
if (layer.type == 'text' && typeof layer.value != 'undefined') {
layerConfig.value = layer.value;
} else if (layer.type == 'option') {
layerConfig.value = layer.value ?? layer.show_value;
} else {
if (layer.show_value) layerConfig.value = getCdn(layer.show_value);
if (layer.url && !layer.show_value) layerConfig.value = getCdn(layer.url);
if (!layerConfig.value) continue;
}
configs.layers.push({ ...layerConfig, ...transformConfigs });
}
return configs;
}
public validate()
{
const errors = [];
for (let i = 0; i < this.artworks.length; i++) {
const artwork = this.artworks[i];
if (!artwork.template_settings || (artwork.data || []).length <= 1) continue;
const hasValue = (artwork.data || []).some(template => template.active);
if (!hasValue) {
errors.push({
type: 'template',
artworkId: artwork.id,
message: artwork.template_settings?.label || 'Template is required',
});
}
}
for (let i = 0; i < this.layerOptions.length; i++) {
const layer = this.layerOptions[i];
const hasValue = !!(layer.value || layer.upload_image_url);
if (!hasValue && layer.required == true && layer.visible && layer.form_type != 'static'
&& layer.form_type != 'linked' && layer.form_label
&& this.isShowLayer(layer)
&& (layer.form_visibility_value !== false || layer.form_type == 'text')) {
errors.push({
type: 'layer',
layerId: layer.id,
label: layer.form_label,
message: `${layer.form_label} is required`,
});
}
}
return {
isValid: errors.length === 0,
errors,
};
}
public getState()
{
const layers = {};
for (let i = 0; i < this.templateLayers.length; i++) {
const layer = this.templateLayers[i];
layers[layer.id] = {
value: layer.value,
show_value: layer.show_value,
form_visibility_value: layer.form_visibility_value,
selected_name: layer.selected_name,
optionItem: layer.optionItem,
};
}
return {
templateId: this.template?.id,
layers,
};
}
public getFonts()
{
return {
google: this.googleFontFamilies,
custom: this.customFontFamilies,
};
}
public getMockupLayers()
{
return this.campaignMockup?.layers || [];
}
public getDesignLayers()
{
return this.designLayers;
}
public getArtwork()
{
return this.artwork;
}
public getTemplate()
{
if (!this.template) return null;
return {
...this.template,
layers: this.templateLayers,
};
}
public getLayerOptions()
{
return this.layerOptions;
}
public getTemplateOptions()
{
return this.templateOptions;
}
public getPrintAreas()
{
return this.printAreas;
}
public getPreview()
{
return this.getMockupPreview();
}
public getData()
{
return this.getSnapshot();
}
public setTemplateOptions(options)
{
this.templateOptions = options;
}
public setTemplateLayers(layers)
{
this.templateLayers = layers || [];
this.rebuild();
}
public getTemplateLayers()
{
return this.templateLayers;
}
}
export default CustomizationTeeInBlue;