4.9 Rated By Customers

Embroidered Couple Portrait Sweatshirt with Flower,Couples Gift

$32.99
$59.99
Save 45%

Worldwide shipping

Handmade and 100% Custom

Worry-Free Purchase Available with Seel

Style : T-shirt
Quantity
const getPluginI18nMessages = (message, replaceObj = {}) => { const lang = document.documentElement.lang || "en-US"; const [form, key] = message.split('.') let text = window.payment_plugin_message['en-US'][form][key]; if (window.payment_plugin_message[lang][form].hasOwnProperty(key)) { text = window.payment_plugin_message[lang][form][key]; } Object.keys(replaceObj).forEach(key => { text = text.replace(new RegExp(`\{${key}\}`, 'gi'), replaceObj[key]); }) return text; } const zhCN = { ec: { not_active_channel: "请到收款设置中{channelName}或在「快捷支付按钮」设置中选择其他的服务提供方,否则按钮将无法展示", not_support_theme: "当前主题不支持添加「快捷支付按钮」", more_button: "更多支付方式", skeleton_layer_tips_title: "快捷支付按钮", skeleton_layer_tips_content: "请点击左侧列表中的「快捷支付按钮」,在设置页面开启想要的展示的支付按钮", mock_tips: "快捷支付按钮是否展示还取决于买家使用的浏览器以及商品的货币、金额", not_find_form_tips: "快捷支付按钮组件仅支持配置到商品详情卡片内", } }; const zhTW = { ec: { not_active_channel: "请到收款设置中{channelName}或在「快捷支付按钮」设置中选择其他的服务提供方,否则按钮将无法展示", not_support_theme: "当前主题不支持添加「快捷支付按钮」", more_button: "更多付款方式", } }; const arSA = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "المزيد من خيارات الدفع", } }; const deDE = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "Weitere Bezahlmöglichkeiten", } }; const esES = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "Más opciones de pago", } }; const frFR = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "Plus d'options de paiement", } }; const idID = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "Opsi pembayaran lainnya", } }; const itIT = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "Altre opzioni di pagamento", } }; const jaJP = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "その他の支払いオプション", } }; const koKR = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "더 많은 결제 옵션", } }; const enUS = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "More payment options", skeleton_layer_tips_title: "Express Checkout Button", skeleton_layer_tips_content: "Please click the「Express checkout button」on the block list,then you could enable the payment option you want to display in settings.", mock_tips: "Whether the Express checkout button is displayed also depends on the browser used by the buyer and the currency and amount of the product.", not_find_form_tips: "Express Checkout Button could only be added to Product details block.", } }; const nlNL = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "Meer betalingsmogelijkheden", } }; const plPL = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "Więcej Opcji Płatności", } }; const ptPT = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "Mais opções de pagamento", } }; const ruRU = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "Другие варианты оплаты", } }; const thTH = { ec: { not_active_channel: "Please activate {channelName} on B Admin or select another provider in the「Express checkout button」 settings, otherwise it will not display.", not_support_theme: "This Theme doesn't support adding「Express checkout button」", more_button: "ตัวเลือกการชำระเงินเพิ่มเติม", } }; window.payment_plugin_message = { getPluginI18nMessages, "zh-CN": zhCN, "zh-TW": zhTW, "ar-SA": arSA, "de-DE": deDE, "es-ES": esES, "fr-FR": frFR, "id-ID": idID, "it-IT": itIT, "ja-JP": jaJP, "ko-KR": koKR, "en-US": enUS, "nl-NL": nlNL, "pl-PL": plPL, "pt-PT": ptPT, "ru-RU": ruRU, "th-TH": thTH, } document.dispatchEvent(new CustomEvent('payment_plugin_message_reader'));
try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); dom.i18n = window?.payment_plugin_message?.getPluginI18nMessages; if (dom.i18n) { document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { i18n: true } })) } else { document.addEventListener('payment_plugin_message_reader', () => { dom.i18n = window?.payment_plugin_message?.getPluginI18nMessages; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { i18n: true } })) }, {once: true}); } } catch (e) { } // 通用工具方法 try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12') const ROOT_URL = (C_SETTINGS && C_SETTINGS.routes && C_SETTINGS.routes.root) || ''; const eventListeners = {}; const commonUtils = function () { return { getProduct() { const productJson = document.querySelector('#product-json'); if (productJson?.textContent) { return JSON.parse(productJson.textContent); } if (window.jQuery) { const $product = window.jQuery?.(document)?.data('djproduct'); const productData = JSON.parse(JSON.stringify($product || {})); return productData || {}; } return {}; }, isChrome() { return navigator?.userAgent?.indexOf('Chrome') > -1 || navigator?.userAgent?.indexOf('CriOS') > -1; }, isSafari() { let userAgentString = navigator.userAgent; let chromeAgent = userAgentString.indexOf('Chrome') > -1 || navigator?.userAgent?.indexOf('CriOS') > -1; let safariAgent = userAgentString.indexOf('Safari') > -1; if (chromeAgent && safariAgent) { safariAgent = false; } return safariAgent; }, isPreview() { return !!window?.C_EDITING_SETTINGS?.oseid; }, multiply(a, b) { const precision = 2; // 保留两位小数 return Number((a * b).toFixed(precision)); }, loadScript(fnReady, id, src, datasets, onError, attributeConfig = {}) { const sdkDomId = id + '-sdk'; if (fnReady() || document.getElementById(sdkDomId)) { return Promise.resolve({id: true}); } return new Promise((resolve) => { const s = document.createElement('script'); s.id = sdkDomId; s.src = src; s.defer = true; if (datasets) { Object.keys(datasets).map((item) => { s.dataset[item] = datasets[item]; }); } s.onload = function () { window.dispatchEvent(new CustomEvent(`${id}-loaded`)); resolve({id: true}); }; s.onerror = function () { resolve({id: false}); onError && onError(); }; Object.keys(attributeConfig).forEach((key) => { s.setAttribute(key, attributeConfig[key]); }); document.head.appendChild(s); }); }, track(eventName, data) { window.sa && window?.sa?.track('pm_' + eventName, JSON.parse(JSON.stringify(data))); }, getExtUrl(name) { const url = document.cookie.match(new RegExp('\\b' + name.replace(/_/g, '-') + '-(v[s0-9]+)')); if (url && url[1]) { return `${name}.${url[1]}.js`; } else { return window?.exts?.[name]; } }, req: { post: async (url, data = {}) => { try { const response = await fetch(req.ROOT_URL + url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, ...data, body: JSON.stringify(data.body), }); return await response.json() } catch (error) { throw new Error('post request error' + error); } }, get: async (url, data = {}) => { try { const response = await fetch(ROOT_URL + url); return await response.json() } catch (error) { throw new Error('get request error' + error); } } }, debounce(fn, wait) { let timeout = null; return function () { if (timeout !== null) { clearTimeout(timeout); } timeout = setTimeout(function () { fn.apply(this, arguments); }, wait); } }, delayCallback(cb) { window.requestIdleCallback ? requestIdleCallback(cb, {timeout: 50}) : setTimeout(cb, 50); }, loadFilly(tag, cb) { if (!tag) { return } const script = document.createElement('script'); script.type = 'text/javaScript'; script.src = `//static.staticdj.com/${tag}`; script.onload = cb; document.getElementsByTagName('head')[0].appendChild(script); }, ecEvent: { on: (eventName, listener, useCapture) => { eventListeners[eventName] = listener; window.addEventListener(eventName, listener, useCapture); }, emit: (eventName, data) => window.dispatchEvent(new CustomEvent(eventName, {detail: data})), } } } dom.commonUtilsFn = commonUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { commonUtils: true } })) } catch (e) { } // 核心数据 try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); const coreData = function () { const {getProduct} = dom.commonUtils; let productDetail = getProduct(); let productPrice = productDetail?.selected?.price || 32.99; const shopCurrencyCode = "USD"; const expressCheckoutList = { sdkErrorList: [], paymentChannelList: [], disabledChannelList: [], showChannelList: [], blockChannelList: [], extraChannelList: [], }; const channelType = { googlepay: ['shoplazzagoogle'], applepay: ['shoplazzaapple'], credit: ['paypal'] }; const ecGlobalVarEnums = { paypal: 'pluginPaypalEC' }; const providerEnums = { SHOPLAZZA: 'shoplazza', STRIPE: 'stripe', PAYPAL: 'paypal' }; const channelEnums = { SHOPLAZZA_GOOGLE: 'shoplazzagoogle', SHOPLAZZA_APPLE: 'shoplazzaapple', STRIPE_GOOGLE: 'stripegoogle', STRIPE_APPLE: 'stripeapple', PAYPAL: 'paypal' }; const channelThemeConfig = { [channelEnums.PAYPAL]: { default: { url: 'oss/operation/f557c83808e1cd456411170286a1ea95.svg', classList: ['paypal-card'], }, }, [channelEnums.SHOPLAZZA_GOOGLE]: { light: { url: 'oss/operation/778afb93da43adf75bdc80b078e5d4fd.svg', classList: ['googlepay-light'], }, dark: { url: 'oss/operation/e53180c224f0b0af44b44663775aa930.svg', classList: ['googlepay-dark'], }, }, [channelEnums.SHOPLAZZA_APPLE]: { light: { url: 'oss/operation/dadceb884044e0a9bbfe26c15192f542.svg', classList: ['applepay-light'], }, dark: { url: 'oss/operation/6597f66eac8b0681ebfb75941e8f6f52.svg', classList: ['applepay-dark'], }, }, }; function getContainerDomId() { const domIdObj = {}; Object.keys(providerEnums).forEach(key => { domIdObj[providerEnums[key]] = FormatterContainerDomId(providerEnums[key]) }) return domIdObj; } function FormatterContainerDomId(provider) { const domIDSuffix = '-express-button-container'; const prefix = 'pm-'; return `${prefix}${provider}${domIDSuffix}-1539149753700-12` } return { ecGlobalVarEnums, providerEnums, channelEnums, productPrice, shopCurrencyCode, getChannelThemeConfig(ecName) { const themeType = window.PaymentEC?.settings?.express_theme_configs?.[ecName]?.theme_type?.toLowerCase() || 'default'; return channelThemeConfig[ecName][themeType] || channelThemeConfig[ecName]['dark']; }, getProductPrice() { return productDetail?.selected?.price; }, getProductDetail() { return productDetail; }, setProductDetail(data) { productDetail = data; }, isRequiresShipping() { return productDetail?.product?.requires_shipping }, getOpenChannelType() { const {paymentChannelList, blockChannelList} = expressCheckoutList const openList = paymentChannelList.filter(item => blockChannelList.includes(item)) || []; return { hasApplepay: openList.filter(item => channelType.applepay.includes(item))?.length > 0, hasGooglepay: openList.filter(item => channelType.googlepay.includes(item))?.length > 0, hasCredit: openList.filter(item => channelType.credit.includes(item))?.length > 0 } }, containerDomId: getContainerDomId(), channel2ProviderEnums: { [channelEnums.PAYPAL]: providerEnums.PAYPAL, [channelEnums.SHOPLAZZA_GOOGLE]: providerEnums.SHOPLAZZA, [channelEnums.SHOPLAZZA_APPLE]: providerEnums.SHOPLAZZA, [channelEnums.STRIPE_GOOGLE]: providerEnums.STRIPE, [channelEnums.STRIPE_APPLE]: providerEnums.STRIPE, }, getExpressCheckoutList() { return expressCheckoutList; }, setShowChannel(showChannelList = []) { expressCheckoutList.showChannelList = showChannelList; return expressCheckoutList; }, setBlockChannel(blockChannelList = []) { expressCheckoutList.blockChannelList = blockChannelList; return expressCheckoutList; }, setPaymentChannelList(paymentChannelList = []) { expressCheckoutList.paymentChannelList = paymentChannelList; return expressCheckoutList; }, setSdkErrorList(paymentChannelList = []) { expressCheckoutList.sdkErrorList = paymentChannelList; return expressCheckoutList; }, setExtraChannelList(extraChannelList = []) { expressCheckoutList.extraChannelList = extraChannelList; return expressCheckoutList; }, setDisabledChannelList(disabledChannelList = []) { expressCheckoutList.disabledChannelList = disabledChannelList; return expressCheckoutList; } } } dom.coreDataFn = coreData; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { coreData: true } })) } catch (e) { console.log(e); } // 通用业务数据处理方法 try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12') const businessUtils = function () { const {track, isChrome, isSafari, req, isPreview, multiply} = dom.commonUtils; const {getProductPrice, containerDomId, ecGlobalVarEnums} = dom.coreData; const { channelEnums, shopCurrencyCode, isRequiresShipping, getProductDetail, setShowChannel, setBlockChannel, setSdkErrorList, setExtraChannelList, setDisabledChannelList, setPaymentChannelList, getExpressCheckoutList } = dom.coreData; const _businessUtils = { getECConfig: async () => { if (window.PaymentEC?.settings) { return window.PaymentEC?.settings; } const result = await req.get('/api/payment/settings'); const ecConfig = result?.settings?.express_checkout_config || {}; const {blockChannelList} = getExpressCheckoutList(); setPaymentChannelList(blockChannelList.filter(ecName => ecConfig?.express_channels?.includes(ecName)) || []); window.PaymentEC.settings = {...ecConfig, currencyCode: shopCurrencyCode}; return window.PaymentEC.settings; }, getAttributeConfig(channelInfo) { const {ecGlobalVar, ecName} = channelInfo; const config = { paypal: { 'data-namespace': ecGlobalVar } }; return config[ecName] || {}; }, getThemeFormData() { let themeFormData = {}; const formDOM = dom.closest("form"); if (formDOM) { themeFormData = { note: '', product_id: '', variant_id: '', quantity: 1, properties: {}, }; const formData = new FormData(formDOM); const formDataKey = formData.keys(); for (const key of formDataKey) { const value = formData.get(key); const propertiesKey = key.match(/^properties(?:\.(\w+)$|\[(\w+)\]$)/); if (!propertiesKey) { themeFormData[key] = value; continue; } const objKey = propertiesKey[1] || propertiesKey[2]; themeFormData['properties'] = {...themeFormData['properties'], [objKey]: value}; } } return themeFormData; }, getProductFormData() { const themeFormData = _businessUtils.getThemeFormData() return [{ ...themeFormData, note: themeFormData?.note || "", product_id: themeFormData?.product_id || "", variant_id: themeFormData?.variant_id || "", quantity: themeFormData?.quantity || 1, // 与主题确认,只以一个为准,防止form不存在的数据仍被传递 properties: themeFormData?.properties || {}, }] }, getOrderFetchParams(data) { if (!data) { return {}; } return { line_items: data.map((item) => ({ ...item, note: item?.note || "", quantity: item?.quantity || 1, product_id: item?.product_id, variant_id: item?.variant_id, properties: item?.properties, })), refer_info: { source: 'buy_now', }, customer_note: '', }; }, isAllowTheme() { const allowThemeList = ['Nova 2023', 'Dropshiping', 'Geek', 'Hero', 'Eva']; const currentTheme = window?.C_SETTINGS?.theme?.merchant_theme_name; return allowThemeList.includes(currentTheme); }, getSubscriptionIdInit() { let defaultID; const selectSubscriptionEnum = { CLOSE: 1, ACTIVE: 2, } const productDetail = getProductDetail(); const sellingPlan = ""; if (!sellingPlan || typeof sellingPlan !== "object") { return null; } let sellingItems; if (sellingPlan?.spu?.[productDetail?.product?.id]) { sellingItems = sellingPlan.spu[productDetail?.product?.id] } if (sellingPlan?.sku?.[productDetail?.selected?.id]) { sellingItems = sellingPlan.sku[productDetail?.product?.id] } if (sellingItems?.cycles === selectSubscriptionEnum.ACTIVE && sellingItems?.selected_selling_plan_option_id) { defaultID = sellingItems?.selected_selling_plan_option_id } return defaultID ?? null }, getSubscriptionId() { const formData = _businessUtils.getThemeFormData(); const defaultID = _businessUtils.getSubscriptionIdInit(); console.log(`[paymentEC]订阅信息:form-${formData?.properties?._selling_plan_option_id},默认-${defaultID}`); if (formData?.properties) { return formData?.properties?._selling_plan_option_id } return defaultID ?? null; }, isSubscription() { return !!_businessUtils.getSubscriptionId(); }, isAllowSubscriptionPay(channel) { if (!_businessUtils.isSubscription()) { return true; } return [channelEnums.PAYPAL].includes(channel); }, blockChannelHandler() { const block_googlePay = false && "shoplazzagoogle"; const block_applePay = true && "shoplazzaapple"; const block_credit = false && "paypal"; const blockChannel = { googlepay: (isPreview() || isChrome()) && block_googlePay, applepay: (isPreview() || isSafari()) && block_applePay, credit: block_credit }; const sortList = ['credit', 'googlepay', 'applepay']; const methodSort = Object.keys(blockChannel).filter(key => blockChannel[key] && key).sort((a, b) => { const indexA = sortList.indexOf(a); const indexB = sortList.indexOf(b); return indexA - indexB; }).map(key => blockChannel[key]); const result = setBlockChannel(methodSort); track('setBlockChannel', result); return result; }, showECButtonHandler() { const { paymentChannelList, sdkErrorList, disabledChannelList, extraChannelList, } = getExpressCheckoutList(); const showChannelList = paymentChannelList.filter((ecName) => !sdkErrorList.includes(ecName) && !disabledChannelList.includes(ecName) && !extraChannelList.includes(ecName)) || []; const result = setShowChannel(showChannelList); track('showECButton', result); return result; }, filterECButtonHandler({type}, cb) { const { paymentChannelList, sdkErrorList, disabledChannelList, extraChannelList, } = getExpressCheckoutList(); const showChannelList = paymentChannelList.filter((ecName) => !sdkErrorList.includes(ecName) && !disabledChannelList.includes(ecName) && !extraChannelList.includes(ecName)) || []; const result = setShowChannel(showChannelList.filter((ecName) => ecName !== type) || []); cb && cb(); track('filterECButton', result); return result; }, loadSDKErrorHandler(type) { const {sdkErrorList} = getExpressCheckoutList(); const result = setSdkErrorList([...sdkErrorList, type]); track('loadSDKError', result); return result; }, extraFilterShowHandler(channel) { const {extraChannelList} = getExpressCheckoutList(); const result = setExtraChannelList(extraChannelList.filter(ecName => ecName !== channel)); track('extraFilterEvent_show', result); return result; }, extraFilterHideHandler(channel) { const {extraChannelList} = getExpressCheckoutList(); const result = setExtraChannelList([...extraChannelList, channel]); track('extraFilterEvent_hide', result); return result; }, disabledChannelListHandler(checkoutData = {}, cb) { const {paymentChannelList} = getExpressCheckoutList(); const productDetail = getProductDetail(); const disabledChannelList = paymentChannelList.filter(ecName => { let mustDisable = false; if (!isRequiresShipping() && ecName !== channelEnums.PAYPAL) { mustDisable = true; } if (!_businessUtils.isAllowSubscriptionPay(ecName)) { mustDisable = true; } if (!productDetail?.selected?.available) { mustDisable = true; } const {payment_due} = checkoutData?.prices; const paymentDueNum = Number(payment_due || 0) * 100; const showFlag = paymentDueNum > 0; return mustDisable || !showFlag; }) const result = setDisabledChannelList(disabledChannelList) result?.disabledChannelList?.forEach(ecName => { cb && cb(ecName); }) track('disabledChannelListEvent', result); }, async getCheckoutData() { const formData = _businessUtils.getProductFormData(); const totalPrice = multiply(getProductPrice(), formData?.[0]?.quantity || 0); return { prices: {payment_due: totalPrice, subtotal_price: totalPrice}, orderParams: _businessUtils.getOrderFetchParams(_businessUtils.getProductFormData()), containerDOMIdEnums: containerDomId, ecGlobalVarEnums } }, } return _businessUtils } dom.businessUtilsFn = businessUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { businessUtils: true } })) } catch (e) { } // 通用渲染方法 try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); const containerDOM = 'pm-payment-express-button-container-1539149753700-12'; const commonRenderUtils = function () { return { addChildrenDOM(id, allowShow, options = {}) { if (!id) { return; } const paymentEl = document.getElementById(containerDOM); const childrenEL = document.getElementById(id); if (paymentEl && childrenEL) { childrenEL.style.display = allowShow ? 'block' : 'none'; return; } if (paymentEl && !childrenEL) { const dom = document.createElement('div'); dom.id = id; dom.style.display = allowShow ? 'block' : 'none'; if (options?.style) { Object.keys(options?.style).forEach(key => { dom.style[key] = options.style[key]; }) } if (Array.isArray(options?.classList)) { dom.classList.add(...options.classList) } paymentEl.appendChild(dom); } }, removeChildrenDOM(id) { if (!id) { return; } const paymentEl = document.getElementById(containerDOM); const childrenEL = document.getElementById(id); if (paymentEl && childrenEL) { // childrenEL.remove(); childrenEL.style.display = 'none'; } }, mockAddChildrenDOM(id, allowShow, options = {}) { if (!id) { return; } const paymentEl = document.getElementById(containerDOM); const childrenEL = document.getElementById(id); if (paymentEl && childrenEL) { childrenEL.style.display = allowShow ? 'flex' : 'none'; return; } if (paymentEl && !childrenEL) { const dom = document.createElement('div'); dom.id = id; dom.style.display = allowShow ? 'flex' : 'none'; if (options?.style) { Object.keys(options?.style).forEach(key => { dom.style[key] = options.style[key]; }) } if (Array.isArray(options?.classList)) { dom.classList.add(...options.classList) } dom.classList.add('mock-img'); const img = document.createElement('img'); img.src = `//static.staticdj.com/${options?.url}`; dom.appendChild(img); paymentEl.appendChild(dom); } }, resetRenderDOM() { const resetStyleList = [ "pm-payment-express-error-tips-1539149753700-12", "pm-payment-express-more-button-1539149753700-12", "pm-payment-express-mock-tips-1539149753700-12", "pm-payment-express-skeletonLayer-1539149753700-12", ] const resetHtmlList = [ "pm-payment-express-skeletonLayer-title-content-1539149753700-12", "pm-payment-express-skeletonLayer-content-1539149753700-12", "pm-payment-express-mock-tips-1539149753700-12", "pm-payment-express-error-tips-1539149753700-12", "pm-payment-express-button-container-1539149753700-12", "pm-payment-express-more-button-1539149753700-12", ] resetStyleList.forEach(domID => { const content = document.getElementById(domID); if (content) { content.style.display = 'none'; } }) resetHtmlList.forEach(domID => { const content = document.getElementById(domID); if (content) { content.innerHTML = ''; } }) } } } dom.commonRenderUtilsFn = commonRenderUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { commonRenderUtils: true } })) } catch (e) { } // 错误提示渲染 try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); const renderTipsUtils = function () { const {i18n} = dom; const {isPreview} = dom.commonUtils; const {channelEnums} = dom.coreData; return { showChannelNotOpenTips(channelList) { const tipsDom = document.getElementById('pm-payment-express-error-tips-1539149753700-12'); if (!isPreview()) { return; } if (!tipsDom) { return; } tipsDom.style.display = channelList.length > 0 ? 'block' : 'none'; const channelName = { [channelEnums.SHOPLAZZA_GOOGLE]: "ShoplazzaPayments - GooglePay", [channelEnums.SHOPLAZZA_APPLE]: "ShoplazzaPayments - ApplePay", [channelEnums.PAYPAL]: "PayPal", } channelList.forEach(ecName => { const id = `pm-payment-express-error-tips-1539149753700-12-${ecName}`; const hasDom = document.getElementById(id) if (!hasDom) { const dom = document.createElement('div'); dom.id = id; dom.innerHTML = i18n('ec.not_active_channel', {channelName: channelName[ecName]}); tipsDom.appendChild(dom); } }) }, disabledThemTips() { const tipsDom = document.getElementById('pm-payment-express-error-tips-1539149753700-12'); if (!isPreview()) { return; } if (!tipsDom) { return; } tipsDom.style.display = 'block'; const id = 'pm-payment-express-error-tips-1539149753700-12-theme'; const hasDom = document.getElementById(id); if (!hasDom) { const dom = document.createElement('div'); dom.id = id; dom.innerHTML = i18n('ec.not_support_theme'); tipsDom.appendChild(dom); } }, notFindFormTips() { const tipsDom = document.getElementById('pm-payment-express-error-tips-1539149753700-12'); if (!isPreview()) { return; } if (!tipsDom) { return; } tipsDom.style.display = 'block'; const id = 'pm-payment-express-error-tips-1539149753700-12-theme'; const hasDom = document.getElementById(id); if (!hasDom) { const dom = document.createElement('div'); dom.id = id; dom.innerHTML = i18n('ec.not_find_form_tips'); tipsDom.appendChild(dom); } }, showSkeletonLayerTips() { const skeletonLayerDOMId = 'pm-payment-express-skeletonLayer-1539149753700-12'; const skeletonLayerDOM = document.getElementById(skeletonLayerDOMId); const titleDOM = document.getElementById('pm-payment-express-skeletonLayer-title-content-1539149753700-12'); const contentDOM = document.getElementById('pm-payment-express-skeletonLayer-content-1539149753700-12'); if (!skeletonLayerDOM || !titleDOM || !contentDOM) { return; } skeletonLayerDOM.style.display = 'block'; titleDOM.innerHTML = i18n('ec.skeleton_layer_tips_title'); contentDOM.innerHTML = i18n('ec.skeleton_layer_tips_content'); }, showMockTips() { const tipsDOM = document.getElementById('pm-payment-express-mock-tips-1539149753700-12'); if (!tipsDOM) { return; } tipsDOM.style.display = 'block'; tipsDOM.innerHTML = i18n('ec.mock_tips'); } } } dom.renderTipsUtilsFn = renderTipsUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { renderTipsUtils: true } })) } catch (e) { } // 更多信息渲染 try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); const moreDOM = document.getElementById('pm-payment-express-more-button-1539149753700-12'); const moreButtonConfig = { firstClick: true, maxSize: isNaN(1) ? 1 : 1 }; const renderMoreUtils = function () { const {i18n} = dom; const {getExpressCheckoutList} = dom.coreData; function moreButtonEvent(cb) { if (!moreDOM) { return; } moreDOM.style.display = 'none'; moreButtonConfig.firstClick = false; cb && cb(); } return { getMoreButtonConfig() { return moreButtonConfig }, showMoreButton(cb) { if (!moreDOM) { return; } const {showChannelList} = getExpressCheckoutList(); const showLength = showChannelList.length; const {firstClick, maxSize} = moreButtonConfig; moreDOM.style.display = (firstClick && showLength > 0 && showLength > maxSize) ? 'block' : 'none'; moreDOM.innerHTML = i18n('ec.more_button'); moreDOM.onclick = () => moreButtonEvent(cb); }, } } dom.renderMoreUtilsFn = renderMoreUtils; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { renderMoreUtils: true } })) } catch (e) { } try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); function start() { const { getExtUrl, loadFilly, delayCallback, ecEvent, track, loadScript, debounce } = dom.commonUtils; const { blockChannelHandler, getAttributeConfig, showECButtonHandler, filterECButtonHandler, loadSDKErrorHandler, extraFilterShowHandler, extraFilterHideHandler, disabledChannelListHandler, getECConfig, isAllowTheme, getCheckoutData, getThemeFormData } = dom.businessUtils; const {addChildrenDOM, removeChildrenDOM} = dom.commonRenderUtils; const {getMoreButtonConfig, showMoreButton} = dom.renderMoreUtils; const { ecGlobalVarEnums, getExpressCheckoutList, getProductPrice, getProductDetail, setProductDetail, containerDomId, channel2ProviderEnums, getChannelThemeConfig } = dom.coreData; function getFilly() { const fillyTag = getExtUrl('filly'); if (fillyTag) { loadFilly(fillyTag, init); } } function extraFilterEvent(e) { const {channel, domId, allowShow} = e?.detail || {}; if (channel && domId) { if (allowShow) { extraFilterShowHandler(channel); } else { extraFilterHideHandler(channel); filterECButtonHandler({type: channel}, () => removeChildrenDOM(domId) ); } renderEC(); } } const renderEC = () => { showECButtonHandler(); const {showChannelList} = getExpressCheckoutList(); const {firstClick, maxSize} = getMoreButtonConfig(); if (showChannelList.length === 0) { showMoreButton(renderEC); } showChannelList.forEach((ecName, index) => { const disableShow = firstClick && index >= maxSize; addChildrenDOM(containerDomId[channel2ProviderEnums[ecName]], !disableShow, getChannelThemeConfig(ecName)); showMoreButton(renderEC); }); } const loadErrorEvent = (type) => { const domID = containerDomId[type]; if (!domID) { return; } loadSDKErrorHandler(type); filterECButtonHandler({type}, () => removeChildrenDOM(domID) ); showMoreButton(renderEC); }; async function loadEC() { const themeFormData = getThemeFormData?.() || {}; if (!themeFormData?.product_id || !themeFormData?.variant_id) { console.log('[paymentEC]hide:未找到form表单或必要信息') return; } const ecConfig = await getECConfig(); const expressCheckoutList = getExpressCheckoutList(); track('loadEC', expressCheckoutList); if (ecConfig) { const checkoutData = await getCheckoutData(); disabledChannelListHandler(checkoutData, (ecName) => { filterECButtonHandler({type: ecName}, () => removeChildrenDOM(containerDomId[channel2ProviderEnums[ecName]]) ); }); renderEC(); window.PaymentEC.handleEcPluginsLoad = ({ channelInfos = [], loadedCbFn = () => { } }) => { const expressCheckoutLoadList = []; channelInfos.map((channelInfo) => { const {ecGlobalVar, ecName = '', sdkPath = '', datasets} = channelInfo; if (!document.getElementById(containerDomId[ecName])) { return; } const attributeConfig = getAttributeConfig(channelInfo) || {}; expressCheckoutLoadList.push( loadScript(() => window[ecGlobalVar], ecGlobalVar, sdkPath, datasets, () => { loadErrorEvent(ecName); }, attributeConfig) ); }); Promise.all(expressCheckoutLoadList).then(() => { loadedCbFn(checkoutData); }); }; // 通知外部数据变更 ecEvent.emit('tc_payment_ec_data_change', { ecGlobalVarEnums, containerDOMIdEnums: containerDomId }); } } const loadECDebounce = debounce(loadEC, 300) async function refreshEC(data = {}, sources) { if (!sources) { console.warn('[paymentEC]hide: sources is null'); return; } if (data?.detail?.selected?.price) { setProductDetail(data?.detail) } loadECDebounce(); } function init() { ecEvent.on('shoplazza_express_channels_change', extraFilterEvent, false); ecEvent.on('shoplazza_express_channels_change_ready', extraFilterEvent, false); if (typeof window.PaymentEC === 'object') { window.PaymentEC.getCheckoutData = getCheckoutData; } else { console.warn("[payment]window.PaymentEC is null"); } document.addEventListener('dj.variantChange', (data) => refreshEC(data, 'variantChange')); document.addEventListener('payment_ec_refresh', (data) => refreshEC(data, data?.detail?.sources)); refreshEC({}, 'init'); } if (isAllowTheme()) { blockChannelHandler(); if (document.readyState === 'complete') { delayCallback(getFilly); return; } window.addEventListener('load', () => delayCallback(getFilly), {once: true}); } } dom.startFn = start; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { start: true } })) } catch (e) { console.log(e); } // 预览模式 try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); function start() { const {track} = dom.commonUtils; const {showMoreButton, getMoreButtonConfig} = dom.renderMoreUtils; const { showECButtonHandler, getECConfig, blockChannelHandler, isAllowTheme, getThemeFormData } = dom.businessUtils; const { disabledThemTips, showChannelNotOpenTips, showSkeletonLayerTips, showMockTips, notFindFormTips } = dom.renderTipsUtils; const {mockAddChildrenDOM, resetRenderDOM} = dom.commonRenderUtils; const { channelEnums, getChannelThemeConfig, getExpressCheckoutList, getOpenChannelType } = dom.coreData; const mockDomId = { [channelEnums.PAYPAL]: channelEnums.PAYPAL, [channelEnums.SHOPLAZZA_GOOGLE]: channelEnums.SHOPLAZZA_GOOGLE, [channelEnums.SHOPLAZZA_APPLE]: channelEnums.SHOPLAZZA_APPLE, [channelEnums.STRIPE_GOOGLE]: channelEnums.STRIPE_GOOGLE, [channelEnums.STRIPE_APPLE]: channelEnums.STRIPE_APPLE, } const renderNotOpenTips = () => { const {blockChannelList, paymentChannelList} = getExpressCheckoutList(); const notOpenChannel = blockChannelList.filter(ecName => !paymentChannelList.includes(ecName)); showChannelNotOpenTips(notOpenChannel); } const renderMockTips = () => { const {hasApplepay, hasGooglepay} = getOpenChannelType(); if (hasApplepay || hasGooglepay) { showMockTips(); } } const renderEC = () => { showECButtonHandler(); const {showChannelList} = getExpressCheckoutList(); const {firstClick, maxSize} = getMoreButtonConfig(); if (showChannelList.length === 0) { showMoreButton(renderEC); } showChannelList.forEach((ecName, index) => { const disableShow = firstClick && index >= maxSize; mockAddChildrenDOM(mockDomId[ecName], !disableShow, getChannelThemeConfig(ecName)); showMoreButton(renderEC); }); } async function loadEC() { const date = new Date().getTime(); dom.loadEC_timestamp = date const ecConfig = await getECConfig(); if (date !== dom.loadEC_timestamp) { return; } const expressCheckoutList = getExpressCheckoutList(); track('preview-loadEC', expressCheckoutList); resetRenderDOM(); // 初始化时没有事件推送 if (ecConfig) { renderNotOpenTips(); renderEC(); renderMockTips(); } } const init = () => { blockChannelHandler(); const {blockChannelList} = getExpressCheckoutList(); if (!isAllowTheme()) { disabledThemTips() return; } const themeFormData = getThemeFormData?.() || {}; if (!themeFormData?.product_id || !themeFormData?.variant_id) { notFindFormTips(); return; } if (blockChannelList.length > 0) { loadEC(); } else { showSkeletonLayerTips() } } init(); } dom.mockStartFn = start; document.dispatchEvent(new CustomEvent('payment_ec_core_ready', { detail: { start: true } })) } catch (e) { } try { const dom = document.getElementById('pm-payment-express-button-1539149753700-12'); window.PaymentEC = {} const delayCallback = (cb) => { window.requestIdleCallback ? requestIdleCallback(cb, {timeout: 50}) : setTimeout(cb, 50); } const checkReady = function (data) { const { i18n, commonUtilsFn, coreDataFn, businessUtilsFn, commonRenderUtilsFn, renderTipsUtilsFn, renderMoreUtilsFn, startFn, mockStartFn } = dom let readyData = { commonUtils: !!(commonUtilsFn) || false, coreData: !!(coreDataFn) || false, businessUtils: !!(businessUtilsFn) || false, commonRenderUtils: !!(commonRenderUtilsFn) || false, renderTipsUtils: !!(renderTipsUtilsFn) || false, renderMoreUtils: !!(renderMoreUtilsFn) || false, start: !!(startFn) || false, mockStart: !!(mockStartFn) || false, i18n: !!(i18n) || false } if (data?.detail) { Object.keys(data.detail).forEach(key => { readyData[key] = data.detail[key] }) } let isReady = true; Object.keys(readyData).forEach(key => { if (!readyData[key]) { isReady = false } }) return isReady } const readyFn = () => { if (!checkReady()) { return; } document.removeEventListener('payment_ec_core_ready', readyFn); dom.commonUtils = dom.commonUtilsFn(); dom.coreData = dom.coreDataFn(); dom.businessUtils = dom.businessUtilsFn(); dom.commonRenderUtils = dom.commonRenderUtilsFn(); dom.renderTipsUtils = dom.renderTipsUtilsFn(); dom.renderMoreUtils = dom.renderMoreUtilsFn(); const productData = dom?.commonUtils?.getProduct?.() || {}; if (JSON.stringify(productData) === '{}') { console.log('[paymentEC]hide: product data is {}') return; } if (dom?.commonUtils?.isPreview()) { dom.mockStartFn() } else { dom.startFn(); } } const init = () => { if (checkReady()) { readyFn(); } else { document.addEventListener('payment_ec_core_ready', readyFn) } } if (document.readyState === 'complete') { delayCallback(init); } else { window.addEventListener('load', () => delayCallback(init), {once: true}); } } catch (e) { }
Estimated Delivery Date
The estimated delivery time provided is subject to potential variations due to shipping carrier processing and excludes weekends and holidays.

Order On

Production

Shipped

Delivered
Description

Embroidered Couple Portrait Sweatshirt with Flower – The Perfect Valentine’s & Anniversary Gift 🌹💑

Celebrate your love in a truly personal way with our Embroidered Couple Portrait Sweatshirt. This custom-designed sweatshirt features a beautifully embroidered portrait of you and your partner, surrounded by delicate flowers to symbolize your blooming love. Perfect for Valentine’s Day, anniversaries, or just to show your partner how much they mean to you. 💖✨

Why You'll Fall in Love with This Sweatshirt:

🌸 Personalized Embroidery:
Crafted with love, this sweatshirt features a custom embroidered portrait of you and your partner, adorned with a beautiful floral design. Add your names, special dates, or a sweet message to make it even more personal. 🧵💌

💎 Premium Quality:
Made from a soft, high-quality cotton blend, this sweatshirt is comfortable enough for lounging and stylish enough for outings. The embroidered portrait and flowers are designed to last, ensuring this special gift stays vibrant through countless washes.

🎁 Thoughtful & Heartfelt Gift:
This personalized sweatshirt is the perfect gift to celebrate anniversaries, Valentine’s Day, or any romantic occasion. It’s a meaningful way to say, “I love you,” with a gift that captures the essence of your relationship. 🎉

🌿 Romantic and Unique Design:
The combination of your custom portrait and the soft floral accents creates a warm, romantic vibe that will always remind you and your partner of the love you share. 🌸

👫 Match Made in Heaven:
Ideal for couples who love to match, this sweatshirt makes a stylish statement while celebrating your love story.

Product Details:

  • Material: Soft cotton-blend fabric for maximum comfort
  • Customization Options: Personalized couple portrait and flower embroidery, plus names, dates, or messages
  • Available Sizes: Unisex sizing (XS to 4XL)
  • Care Instructions: Machine washable (see below for detailed care instructions)

How to Order:
1️⃣ Choose your size and color.
2️⃣ Upload a photo or provide a description of the couple portrait you'd like embroidered.
3️⃣ Add your custom text (names, date, or message).
4️⃣ Place your order and get ready to cherish this personalized gift for years!

SIZE:

Care Instructions:
To keep your Embroidered Couple Portrait Sweatshirt looking its best:

  • Washing: Machine wash on a gentle cycle with cold water. Turn the sweatshirt inside out to protect the embroidery.
  • Drying: Air dry to preserve the fabric and embroidery. If using a dryer, opt for a low heat setting.
  • Ironing: Iron on the reverse side of the sweatshirt, avoiding direct contact with the embroidery.

🌹 Make Your Love Blossom with This Special Gift
This Embroidered Couple Portrait Sweatshirt with Flowers is more than just a piece of clothing; it’s a keepsake that will carry your love story for years to come. 💕 Click now to create a personalized gift that speaks from the heart!

✨Risk-free Policy:
Worldwide Express Shipping Available.
The tracking number will be provided by email.

🎈Our Guarantee
Tracking number for every order
Secure payment Visa, Paypal, Mastercard
No refund or return for non-quality issues
Free replacement if eligible ❤️
24/7 assistance service @customygifts.com
No hidden fees!

Shipping & Return

Estimate Time Of Arrival Includes Production Time + Delivery Time

1 - Production Time (2 to 5 days): After we receive your order, we shift into production mode. During busy seasons, the process typically takes 1-2 days longer. Please understand.

2 - Shipping Time (7-10 Days or Faster): Want to get your item faster? Select the 'VIP Service' option after adding your product to the cart for the fastest shipping method we can provide. There are also different shipping options available at checkout.

Please Note:

  • The above time frame is only applied for orders to the US with standard shipping methods.
  • International orders: It may take 2-5 days longer due to the customs clearance process.
  • When order is ready to be shipped, a tracking link will be sent to your email so you can follow your package all the way home.
  • The estimated delivery time for our order will depend on your location. While we work closely with our logistics partners to provide you accurate delivery information, delivery times are estimates only and cannot be guaranteed. Once your product(s) are in transit, any delays are outside our control.
  • For more information about Shipping and Delivery, visit here.
  • Learn more Returns and Refunds here.
Customer Sharing

Let Customer Speaks For Us

Write a Review
Customer Reviews
Wow you reached the bottom
Newest
Most liked
Highest ratings
Lowest ratings
×
class SpzCustomFileUpload extends SPZ.BaseElement { constructor(element) { super(element); this.uploadCount_ = 0; this.fileList_ = []; } buildCallback() { this.action = SPZServices.actionServiceForDoc(this.element); this.registerAction('upload', (data) => { this.handleFileUpload_(data.event?.detail?.data || []); }); this.registerAction('delete', (data) => { this.handleFileDelete_(data?.args?.data); }); this.registerAction('preview', (data) => { this.handleFilePreview_(data?.args?.data); }); this.registerAction('limit', (data) => { this.handleFileLimit_(); }); this.registerAction('sizeLimit', (data) => { this.handleFileSizeLimit_(); }); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } setData_(count, file) { this.uploadCount_ = count; this.fileList_ = file; } handleFileUpload_(data) { data.forEach(i => { if(this.fileList_.some(j => j.url === i.url)) return; this.fileList_.push(i); }) this.uploadCount_++; sessionStorage.setItem('fileList', JSON.stringify(this.fileList_)); this.triggerEvent_("handleFileUpload", { count: this.uploadCount_, files: this.fileList_}); if(this.fileList_.length >= 5){ document.querySelector('#review_upload').style.display = 'none'; } if(this.fileList_.length > 0){ document.querySelector('.apps-reviews-write-anonymous-box').style.marginTop = '8px'; } } handleFileDelete_(index) { this.fileList_.splice(index, 1); this.uploadCount_--; sessionStorage.setItem('fileList', JSON.stringify(this.fileList_)); this.triggerEvent_("handleFileDelete", { count: this.uploadCount_, files: this.fileList_}); document.querySelector('#review_upload').style.display = 'block'; if(this.fileList_?.length === 0){ document.querySelector('.apps-reviews-write-anonymous-box').style.marginTop = '132px'; } } handleFilePreview_(index) { const finalPreviewData = this.fileList_[index]; const filePreviewModal = document.getElementById('filePreviewModal'); const fullScreenVideo = document.getElementById('fullScreenVideo'); const fullScreenImage = document.getElementById('fullScreenImage'); const previewModalClose = document.getElementById('previewModalClose'); const previewLoading = document.getElementById('previewLoading'); filePreviewModal.style.display = 'block'; previewLoading.style.display = 'flex'; if(finalPreviewData?.type === 'video'){ const media = this.mediaParse_(this.fileList_[index]?.url); fullScreenVideo.addEventListener('canplaythrough', function() { previewLoading.style.display = 'none'; }); fullScreenImage.src = ''; fullScreenImage.style.display = 'none'; fullScreenVideo.style.display = 'block'; fullScreenVideo.src = media.mp4 || ''; } else { fullScreenImage.onload = function() { previewLoading.style.display = 'none'; }; fullScreenVideo.src = ''; fullScreenVideo.style.display = 'none'; fullScreenImage.style.display = 'block'; fullScreenImage.src = finalPreviewData.url; } previewModalClose.addEventListener('click', function() { filePreviewModal.style.display = 'none'; }); } handleFileLimit_() { alert(window.AppReviewsLocale.comment_file_limit || 'please do not upload files more than 5'); this.triggerEvent_("handleFileLimit"); } handleFileSizeLimit_() { alert(window.AppReviewsLocale.comment_file_size_limit || 'File size does not exceed 10M'); } clear(){ this.fileList_ = []; this.uploadCount_ = 0; sessionStorage.setItem('fileList', JSON.stringify(this.fileList_)); this.triggerEvent_("handleClear", { count: this.uploadCount_, files: this.fileList_}); document.querySelector('#review_upload').style.display = 'block'; } mediaParse_(url) { var result = {}; try { url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) { try { result[key] = decodeURIComponent(value); } catch (e) { result[key] = value; } }); result.preview_image = url.split('?')[0]; } catch (e) {}; return result; } triggerEvent_(name, data) { const event = SPZUtils.Event.create(this.win, name, data); this.action.trigger(this.element, name, event); } } SPZ.defineElement('spz-custom-file-upload', SpzCustomFileUpload);
The review would not show in product details on storefront since it does not support to.