UNPKG

@megaads/wm

Version:

To install the library, use npm:

1,154 lines (973 loc) 41.6 kB
// @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;