(function(){ class SPZCustomSubscribeList extends SPZ.BaseElement { trackMode = 1; trackProductId = undefined; constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.CONTAINER; } buildCallback() { this.registerAction('onRender', (invocation) => { this.fixHandleChange(); this.handleConfirm(); const data = invocation?.args?.data?.data || {}; this.listData = invocation?.args?.data?.data || []; this.refreshSubscribeList(data); }); this.registerAction('track', (invocation) => { if ('currentVideoPlayer' in window) { this.trackMode = 2; this.trackProductId = window.currentVideoPlayer.getCurrentVideoId(); } else { this.trackMode = 1; this.trackProductId = undefined; } this.trackViewContent(); setTimeout(()=>{ this.trackImpression(); }, 2000); }); this.registerAction('onCloseClick', (invocation) => { this.onCloseClick(); }); this.registerAction('onOpen', (invocation) => { const list = document.querySelector('#subscribe_list_render .subscribe_list'); if(list){ list.scrollTo(0,0); } }); } refreshSubscribeList(data){ const plans = data.subscribe_plans || []; const info = data.selling_plan_info || {}; const items = data.line_items || []; const mergedPlans = plans.map(plan=>{ let finalPrice = plan.price; const discount = info[plan.id] || {}; const item = items.find(i=>i.product_id === plan.id); finalPrice = item?.final_line_price; return { ...plan, final_price: finalPrice, selling_plan_info: discount } }); this.subscribeList = mergedPlans; } onCloseClick(){ const listBox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(listBox).then(apis=>{ apis.close(); }) const abandonActivityId = this.listData?.market_activity?.entitled_product_ids?.[0]; let abandonActivity = null; if(abandonActivityId){ const subscribePlan = this.listData.subscribe_plans?.find(ele=>ele.id == abandonActivityId); if(!subscribePlan) return; const item = this.listData.line_items.find(ele=>ele.product_id == abandonActivityId) || {}; const info = this.subscribeList.find(ele=>ele.id == abandonActivityId); const config = this.listData?.market_activity?.config; const sellingPlan = this.listData?.selling_plan_info?.[abandonActivityId]; const sellingPlanId = sellingPlan?.selling_plan_options?.[0]?.selling_plan_option_id; abandonActivity = {...item, ...info, config, _selling_plan_option_id: sellingPlanId}; const abandonBox = document.querySelector('#subscribe_ab_dis_box'); SPZ.whenApiDefined(abandonBox).then(apis=>{ apis.open(); }) const abandonLogic = document.querySelector('#subscribe_ab_discount_logic'); SPZ.whenApiDefined(abandonLogic).then(apis=>{ apis.renderContent(abandonActivity); }) this.pureTrackAddToCart({ id: item.product_id, title: item.product_title, price: item.final_line_price, variant_id: item.variant_id, variant: item.variant_id }); } } trackImpression() { window.csTracker.track('function_expose', { event_name: 'function_expose', event_type: 'popup_expose', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, product_id: this.trackProductId, }), }, ['sa']); /* 需要排除掉支付挽留,默认第二个 */ let showList = this.listData?.subscribe_plans || []; const line_items = this.listData?.line_items; const abandonActivityId = this.listData?.market_activity?.entitled_product_ids?.[0]; if(abandonActivityId){ showList = showList.filter(item=>item.id != abandonActivityId); } let defaultItem = showList?.[0]; if(showList.length > 1){ let defaultItem = showList?.[1]; } const defaultLineItem = this.listData?.line_items.find(ele=>ele.product_id == defaultItem?.id) || {}; defaultItem = { ...defaultItem, ...defaultLineItem} if(defaultItem){ this.pureTrackAddToCart({ id: defaultItem.id, title: defaultItem.title, price: defaultItem.final_line_price, variant_id: defaultItem.variant_id, }); } window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 5, product_id: this.trackProductId, plan_id: defaultItem.id }), }, ['sa']); if(location.pathname.includes('/products/')){ window.sa.track('add_to_cart', { product_id: "65c9cbf7-6c3d-47d2-9815-ee4a24654265", product_title: "Breathless Desire", price: "0", variant_id: window.currentVideoPlayer.getCurrentEpisodeId(), quantity: 1, sku_quantity: 1, entrance: 'product', currency: window.C_SETTINGS.currency_code, }); const gtagAdsCountry = "shoplaza_" + (window.ADS_COUNTRY || "US") + "_"; const variantId = window.currentVideoPlayer.getCurrentEpisodeId(); const trackId = gtagAdsCountry + variantId; window.csTracker.track('add_to_cart', { currency: window.C_SETTINGS.currency_code, value: "0", name: "Breathless Desire", user_id: window.csTracker.getClientId(), items: [ { id: trackId, item_id: trackId, item_name: "Breathless Desire", item_list_name: 'product', item_brand: "", item_category: "", item_variant: window.currentVideoPlayer.getCurrentEpisode().no.toString(), price: "0", quantity: 1, google_business_vertical: 'retail', } ] }, ['ga']); } } trackViewContent(){ let showlist = this.subscribeList.slice(); const abandonActivityId = this.listData?.market_activity?.entitled_product_ids?.[0]; if(abandonActivityId){ showlist = showlist.filter(item=>item.id != abandonActivityId); } showlist = showlist.filter(ele=>!!ele.final_price); const maxCount = Number("4") || 4; showlist = showlist.slice(0,maxCount); showlist.forEach(item=>{ window.csTracker.track('ViewContent', { name: item.title, id: item.variant_id, content_ids: [item.variant_id], content_name: item.title, num_items: 1, currency: window.C_SETTINGS.currency_code, value: item.final_price }, ['fb']); }); /* 套餐曝光 */ const product_ids = showlist.map(item=>item.id); window.csTracker.track('function_expose', { event_name: 'function_expose', event_type: 'expose', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), product_ids, expose_type: 2 }), }, ['sa']); } pureTrackAddToCart(item) { document.dispatchEvent(new CustomEvent('dj.addToCart', { detail: { event_time: new Date().getTime(), product_id: item.id, name: item.title, item_price: item.price, variant_id: item.variant_id, variant: { option1: item.title, }, quantity: '1', number: '1' } })); } /* 上报 initiateCheckRate */ trackOrder(name, pid){ /* window.csTracker.track('initiateCheck', { name: name, id: pid }, ['ga','fb']); */ window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), opt_type: 1, mode: this.trackMode, product_id: this.trackProductId, }), }, ['sa']); /* if(location.pathname.includes('/products/')){ const name = "Breathless Desire"; const id = window.currentVideoPlayer.getCurrentVideoId(); window.csTracker.track('initiateCheck', { name: name, id: id }, ['ga','fb']); } */ } showLoading(){ const loading = document.querySelector('#subscribe_loading'); SPZ.whenApiDefined(loading).then(apis=>{ apis.show_(); }) } hideLoading(){ const loading = document.querySelector('#subscribe_loading'); SPZ.whenApiDefined(loading).then(apis=>{ apis.close_(); }) } mountCallback() { const loading = document.querySelector('#subscribe_list_render'); SPZ.whenApiDefined(loading).then(apis=>{ apis.render(); }) } fixHandleChange(){ const list = document.querySelectorAll('#subscribe_lightbox .subscribe_list .item-wrapper'); list.forEach(item => { item.onclick = () => { const checkedItem = document.querySelector('.subscribe_list .item-checked'); if(item.dataset.pid == checkedItem.dataset.pid){ return; } const list = document.querySelectorAll('#subscribe_lightbox .subscribe_list .item-wrapper'); list.forEach(item=>{ item.classList.remove('item-checked')}) item.classList.add('item-checked'); const listItem = this.subscribeList.find(ele=>ele.id === item.dataset.pid); this.pureTrackAddToCart({ id: listItem.id, title: listItem.title, price: listItem.final_price, variant_id: listItem.variant_id, }); window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 5, product_id: this.trackProductId, plan_id: listItem.id }), }, ['sa']); } }) } getCookie(name) { // 创建正则表达式来匹配指定名称的 Cookie const regex = new RegExp('(^|; )' + encodeURIComponent(name) + '=([^;]*)'); const match = document.cookie.match(regex); // 如果找到匹配项,则返回解码后的值,否则返回 null return match ? decodeURIComponent(match[2]) : null; } handleConfirm(){ const skit_uid = this.getCookie('skit-uid'); const confirm = document.querySelector('#subscribe_lightbox .confirm'); confirm.onclick = async()=>{ document.dispatchEvent(new CustomEvent('dj.checkoutSubmit', { detail: {} })); this.showLoading(); const checked = document.querySelector('#subscribe_lightbox .subscribe_list .item-checked'); const pid = checked.dataset.pid; const vid = checked.dataset.vid; const name = checked.dataset.name; let userEmail = ''; let lastName = ''; try{ await fetch(location.origin+'/api/customers/show').then(res=>res.json()).then(res=>{ if(res && res.customer && res.customer.id){ userEmail = res.customer.email; lastName = res.customer.last_name; localStorage.setItem('CUSTOMER_INFO', JSON.stringify(res.customer)); }else{ localStorage.removeItem('CUSTOMER_INFO'); } }) }catch(e){ console.error('[customer-show]', e) } window._local_id_email = userEmail; window._local_last_name = lastName; window._disable_show_agree = true; let params = {_best_short_uid: skit_uid}; const listItem = this.subscribeList.find(ele=>ele.id == pid); params['_selling_plan_option_id'] = listItem.selling_plan_info.selected_selling_plan_option_id; params['link'] = location.href; params['entry'] = '权益中心'; params['short_id'] = ''; if(location.pathname.includes('/products/')){ params['entry'] = '短剧'; params['short_id'] = window.currentVideoPlayer.getCurrentVideoId(); } const referrer = decodeURIComponent(this.getCookie('latest_referrer') || ''); if(referrer){ const referrerHost = new URL(referrer).hostname; params["_ad_from"] = referrerHost; } /* https://feature-v1-3---short-best.dev.myshoplaza.com/apps/best-short-pay/api/v1/checkout/order */ fetch(`${location.origin}/apps/bs-pay/api/v1/checkout/order`, { method: 'POST', headers:{ "Content-Type": "application/json" }, body: JSON.stringify({ line_items: [{quantity:"1", product_id: pid, properties: params, note:"",variant_id:vid }], refer_info: { source :"buy_now", create_identity: btoa(window.C_SETTINGS.shop.shop_id)}, options: { with_uid: true } }) }) .then(response => response.json()) .then(res=>{ if(res && res.check_out_url){ const lightbox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(lightbox).then((box)=>{ box.close(); this.hideLoading(); localStorage.setItem('COMMON_NAMESPACE', window.SHOPLAZZA.namespace); localStorage.setItem('BS_PREV_URL', location.href); localStorage.setItem('SHOP_ID', window.C_SETTINGS.shop.shop_id); localStorage.setItem('BS_TRACK_PARAMS', JSON.stringify(window.sa.trackParams)); if(window.fbq){ localStorage.setItem('FBQ_PIXELS', JSON.stringify(window.fbq?.getState?.() || {})); } if (location.pathname.includes('/products/')) { const name = "Breathless Desire"; const videoId = window.currentVideoPlayer.getCurrentVideoId(); localStorage.setItem('BS_PRODUCT_VIDEO', JSON.stringify({ name, id: videoId })); localStorage.setItem('BS_VIDEO_VARIANT_ID', JSON.stringify(window.currentVideoPlayer?.getCurrentEpisodeId?.())); } else { localStorage.removeItem('BS_PRODUCT_VIDEO'); localStorage.removeItem('BS_VIDEO_VARIANT_ID'); } window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 1, product_id: this.trackProductId, plan_id: pid }), }, ['sa']); let orderId = ''; if (res && res.check_out_url) { const match = res.check_out_url.match(/\/order\/(\d+)/); if (match && match[1]) { orderId = `/order/${match[1]}`; } } document.dispatchEvent(new CustomEvent('dj.initiateCheckout', { detail: { id: orderId, checkout_page_type: 'single', order_id: orderId, currency: window.C_SETTINGS.market.market_currency, quantity: '1', line_items: [{ product_id: pid, variant_id: vid, quantity: 1, properties: params, }], prices: { total_price: this.subscribeList.find(item => item.id === pid).final_price, } } })); if(location.pathname.includes('/products/')){ window.sa.track('begin_checkout', { product_id: "65c9cbf7-6c3d-47d2-9815-ee4a24654265", product_title: "Breathless Desire", price: "0", variant_id: window.currentVideoPlayer.getCurrentEpisodeId(), quantity: 1, sku_quantity: 1, entrance: 'product', currency: window.C_SETTINGS.currency_code, content_ids: "65c9cbf7-6c3d-47d2-9815-ee4a24654265" }); const gtagAdsCountry = "shoplaza_" + (window.ADS_COUNTRY || "US") + "_"; const variantId = window.currentVideoPlayer.getCurrentEpisodeId(); const trackId = gtagAdsCountry + variantId; window.csTracker.track('begin_checkout', { name: "Breathless Desire", value: "0", coupon: "", currency: window.C_SETTINGS.currency_code, user_id: window.csTracker.getClientId(), item_id: trackId, items:{ id: trackId, item_id: trackId, item_name: "Breathless Desire", item_brand: "", item_category: "", item_variant: window.currentVideoPlayer.getCurrentEpisode().no.toString(), price: "0", quantity:1, google_business_vertical: "retail", } }, ['ga']); } location.href=`${location.origin}${res.check_out_url}`; }); }else{ console.error('[order-error]', res); if(res.message || res.error){ window.customToast(res.message || res.error,'error'); }else{ window.customToast('Order failed','error'); } this.hideLoading(); } }).catch((error)=>{ console.error('[error-fetch]', error); }) /* .finally(()=>{ this.trackOrder(name, pid); }) */ } } } SPZ.defineElement('spz-custom-subscribe-list', SPZCustomSubscribeList); })() (function(){ class SPZCustomAbandonDiscount extends SPZ.BaseElement { trackMode = 1; trackProductId = undefined; constructor(element) { super(element); this.activity = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } getCookie(name) { // 创建正则表达式来匹配指定名称的 Cookie const regex = new RegExp('(^|; )' + encodeURIComponent(name) + '=([^;]*)'); const match = document.cookie.match(regex); // 如果找到匹配项,则返回解码后的值,否则返回 null return match ? decodeURIComponent(match[2]) : null; } buildCallback(){ this.registerAction('onPayNow', (invocation) => { this.onPayNow(); }); this.registerAction('onOpen', (invocation) => { this.onOpen(); }); if ('currentVideoPlayer' in window) { this.trackMode = 2; this.trackProductId = window.currentVideoPlayer.getCurrentVideoId(); } else { this.trackMode = 1; this.trackProductId = undefined; } } onOpen(){ window.csTracker.track('function_expose', { event_name: 'function_expose', event_type: 'expose', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), product_ids: [this.activity?.product_id], expose_type: 2 }), }, ['sa']); window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 5, product_id: this.trackProductId, plan_id: this.activity?.product_id }), }, ['sa']); } async onPayNow(){ if(!this.activity) return; const pid = this.activity.product_id; const vid = this.activity.variant_id; const name = this.activity.product_title; let userEmail = ''; let lastName = ''; try{ await fetch(location.origin+'/api/customers/show').then(res=>res.json()).then(res=>{ if(res && res.customer && res.customer.id){ userEmail = res.customer.email; lastName = res.customer.last_name; localStorage.setItem('CUSTOMER_INFO', JSON.stringify(res.customer)); }else{ localStorage.removeItem('CUSTOMER_INFO'); } }) }catch(e){ console.error('[customer-show]', e) } window._local_id_email = userEmail; window._local_last_name = lastName; window._disable_show_agree = true; const skit_uid = this.getCookie('skit-uid'); let params = {_best_short_uid: skit_uid}; params['_selling_plan_option_id'] = this.activity._selling_plan_option_id; params['link'] = location.href; params['entry'] = '权益中心'; params['short_id'] = ''; if(location.pathname.includes('/products/')){ params['entry'] = '短剧'; params['short_id'] = window.currentVideoPlayer.getCurrentVideoId(); } const referrer = decodeURIComponent(this.getCookie('latest_referrer') || ''); if(referrer){ const referrerHost = new URL(referrer).hostname; params["_ad_from"] = referrerHost; } fetch(`${location.origin}/apps/bs-pay/api/v1/checkout/order`, { method: 'POST', headers:{ "Content-Type": "application/json" }, body: JSON.stringify({ line_items: [{quantity:"1", product_id: pid, properties: params, note:"",variant_id:vid }], refer_info: { source :"buy_now", create_identity: btoa(window.C_SETTINGS.shop.shop_id)}, options: { with_uid: true } }) }) .then(response => response.json()) .then(res=>{ if(res && res.check_out_url){ const lightbox = document.querySelector('#subscribe_ab_dis_box'); SPZ.whenApiDefined(lightbox).then((box)=>{ box.close(); localStorage.setItem('COMMON_NAMESPACE', window.SHOPLAZZA.namespace); localStorage.setItem('BS_PREV_URL', location.href); localStorage.setItem('SHOP_ID', window.C_SETTINGS.shop.shop_id); if (location.pathname.includes('/products/')) { const name = "Breathless Desire"; const videoId = window.currentVideoPlayer.getCurrentVideoId(); localStorage.setItem('BS_PRODUCT_VIDEO', JSON.stringify({ name, id: videoId })); } else { localStorage.removeItem('BS_PRODUCT_VIDEO'); } window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 1, product_id: window.currentVideoPlayer?.getCurrentVideoId?.(), plan_id: this.activity?.product_id }), }, ['sa']); let orderId = ''; if (res && res.check_out_url) { const match = res.check_out_url.match(/\/order\/(\d+)/); if (match && match[1]) { orderId = `/order/${match[1]}`; } } document.dispatchEvent(new CustomEvent('dj.initiateCheckout', { detail: { checkout_page_type: 'single', order_id: orderId, id: orderId, currency: window.C_SETTINGS.market.market_currency, quantity: '1', line_items: [{ product_id: pid, variant_id: vid, quantity: 1, properties: params, }], prices: { total_price: this.activity.final_line_price, } } })); location.href=`${location.origin}${res.check_out_url}`; }); }else{ console.error('[order-error]', res); if(res.message || res.error){ window.customToast(res.message || res.error,'error'); }else{ window.customToast('Order failed','error'); } this.hideLoading(); } }).catch((error)=>{ console.error('[error-fetch]', error); }) /* .finally(()=>{ this.trackOrder(name, pid); }) */ } /* 上报 initiateCheckRate */ trackOrder(name, pid){ /* window.csTracker.track('initiateCheck', { name: name, id: pid }, ['ga','fb']); */ window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), opt_type: 1, mode: this.trackMode, product_id: this.trackProductId, }), }, ['sa']); } /* 在 subscribe list 中调用渲染 */ renderContent(abandonActivity){ this.activity = abandonActivity; const boxRender = document.querySelector('#subscribe_ab_dis_box_render'); SPZ.whenApiDefined(boxRender).then(apis=>{ apis.render(abandonActivity); }) } mountCallback() { } } SPZ.defineElement('spz-custom-subscribe-ab-discount', SPZCustomAbandonDiscount); })() (function(){ class SPZCustomPaySuccess extends SPZ.BaseElement { constructor(element) { super(element); this.payResult = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.registerAction('onOpen', (invocation) => { const btn = document.querySelector('#subscribe_success_box .seconds_btn'); btn && (btn.innerText = '3 seconds to close'); let count = 2; let interval = setInterval(()=>{ if(count==0){ clearInterval(interval); const box = document.querySelector('#subscribe_success_box'); SPZ.whenApiDefined(box).then((apis) => { apis.close(); }); } btn && (btn.innerText = `${count} second${count>1?'s':''} to close`); count--; },1000); }); this.registerAction('reloadstate', (invocation) => { this.reloadstate(); }); } async reloadstate(){ const newUrl = location.href.replace('?success=true','').replace('&success=true',''); if(location.href.includes('success=true')){ location.href = newUrl; } let res = {}; try{ const data = await fetch(location.origin+'/api/customers/show',{cache: 'no-store'}); res = await data.json(); }catch(e){} /* console.info('[res]', res); */ if(res && res.customer && res.customer.id){ location.href = newUrl; }else{ if(!this.payResult?.customer?.registered){ location.href = '/account/register'; }else{ location.href = '/account/login'; } this.payResult = null; } } trackPaySuccess(payResult){ document.dispatchEvent(new CustomEvent('dj.purchase', { detail: { id: payResult?.orderData?.order?.id || '', checkout_page_type: 'single', order_id: payResult?.orderData?.order_id, currency_code: window.C_SETTINGS.market.market_currency, quantity: '1', line_items: [payResult?.orderData?.line_item], prices: { total_price: payResult.orderData?.order?.total, }, config:{ page_type: "single", }, shipping_address:{ email: payResult?.customer?.email || '', phone: '' } } })); const vid = localStorage.getItem('BS_VIDEO_VARIANT_ID') || ''; if(location.pathname.includes('/products/')){ window.sa.track('purchase', { product_id: "65c9cbf7-6c3d-47d2-9815-ee4a24654265", product_title: "Breathless Desire", price: "0", variant_id: vid, quantity: 1, sku_quantity: 1, entrance: 'product', currency: window.C_SETTINGS.currency_code, content_ids: "65c9cbf7-6c3d-47d2-9815-ee4a24654265" }); const gtagAdsCountry = "shoplaza_" + (window.ADS_COUNTRY || "US") + "_"; const variantId = vid; const trackId = gtagAdsCountry + variantId; window.csTracker.track('purchase', { transaction_id: trackId, affiliation: window.C_SETTINGS.shop.shop_id, name: "Breathless Desire", value: "0", coupon: "", currency: window.C_SETTINGS.currency_code, user_id: window.csTracker.getClientId(), item_id: trackId, items:{ id: trackId, item_id: trackId, item_name: "Breathless Desire", item_brand: "", item_category: "", item_variant: vid, price: "0", quantity:1, google_business_vertical: "retail", } }, ['ga']); } localStorage.removeItem('BS_VIDEO_VARIANT_ID'); /* window.csTracker.track('Purchase', { value: payResult.orderData?.order?.total, currency: payResult.orderData?.order?.currency_code, contents: [ { id: payResult?.orderData?.line_item?.product_id, quantity: 1 }], content_type: 'product' }, ['fb']); */ } mountCallback(){ const hasSuccess = location.search.includes('success=true'); let payResult = localStorage.getItem('BS_PAY_RESULT'); if(payResult){ payResult = JSON.parse(payResult); } /* 3DS */ if( (hasSuccess && payResult?.type=='3ds' ) || payResult?.type=='normal'){ this.payResult = payResult; const box = document.querySelector('#subscribe_success_box'); SPZ.whenApiDefined(box).then((apis) => { apis.open(); }); } localStorage.removeItem('BS_PAY_RESULT'); payResult && this.trackPaySuccess(payResult) } } SPZ.defineElement('spz-custom-subscribe-success', SPZCustomPaySuccess); })() (function(){ class SPZCustomSubscribeCheckout extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.CONTAINER; } buildCallback() { /* console.info('[window]', window); */ this.addIFrameCallback(); } hideLoading(){ const loading = document.querySelector('#subscribe_loading'); SPZ.whenApiDefined(loading).then(apis=>{ apis.close_(); }) } trackPayCount(params){ window.csTracker.track('checkoutStepPayment', params, ['ga','fb']); if(location.pathname.includes('/products/')){ const name = "Breathless Desire"; const id = window.currentVideoPlayer.getCurrentVideoId(); window.csTracker.track('checkoutStepPayment', { name: name, id: id }, ['ga','fb']); } } trackPaySuccess(params){ window.csTracker.track('purchase', params, ['ga','fb']); if(location.pathname.includes('/products/')){ const name = "Breathless Desire"; const id = window.currentVideoPlayer.getCurrentVideoId(); window.csTracker.track('purchase', { ...params, name: name, id: id }, ['ga','fb']); } } payCallback(val){ if(val.res.state == 'success'){ const checkout = document.querySelector('#subscribe_checkout_lightbox'); SPZ.whenApiDefined(checkout).then(async(apis)=>{ apis.close(); let hasLoggedIn = false; try{ await fetch(location.origin+'/api/customers/show').then(res=>res.json()).then(res=>{ if(res && res.customer && res.customer.id){ hasLoggedIn = true; } }) }catch(e){ console.error('[pay-customers/show]', e); } if(location.pathname.includes('pages/short-me')){ const customer = document.querySelector('#me_customer_info'); SPZ.whenApiDefined(customer).then((apis) => { apis.fresh(); }); } /* 已登录 提示成功,未登录 让注册 */ if(hasLoggedIn){ const okBox = document.querySelector('#subscribe_pay_logged_ok_box'); SPZ.whenApiDefined(okBox).then((apis) => { apis.open(); }); }else{ location.href = '/account/register'; /* const meElement =document.querySelector('#me_account_element'); SPZ.whenApiDefined(meElement).then((apis)=>{ if(val.res.email){ apis.presetEmail(val.res.email); } apis.showType('account_register'); }) const accountBox = document.querySelector('#me_account_lightbox'); SPZ.whenApiDefined(accountBox).then((apis)=>{ apis.open(); }) */ } }); this.trackPaySuccess(val.params) } } addIFrameCallback(){ window.receivedata = (val) => { console.info('[receive]', val); /* Checkout Ready */ if(val && val.type=='READY'){ const lightbox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(lightbox).then((box)=>{ box.close(); const checkout = document.querySelector('#subscribe_checkout_lightbox'); SPZ.whenApiDefined(checkout).then((apis)=>{ apis.open(); this.hideLoading(); }) }); const loader = document.querySelector('#subscribe_checkout_lightbox .cs_checkout_mask'); loader && (loader.style = 'display: none') } /* 支付结果 */ if(val && val.type=='PAY'){ this.payCallback(val); } /* LOADING */ if(val && val.type=="LOADING"){ const loader = document.querySelector('#subscribe_checkout_lightbox .cs_checkout_mask'); loader && (loader.style = 'display: flex'); } /* 上报 */ if(val && val.type=="PAY_TRACK"){ this.trackPayCount(val.params); } } } } SPZ.defineElement('spz-custom-subscribe-checkout', SPZCustomSubscribeCheckout); })() (function(){ class SPZCustomMeAccount extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.registerAction('showType', (invocation) => { this.showType(invocation.args.showclass); }); this.registerAction('reset', (invocation) => { this.reset(); }); this.registerAction('signin', (invocation) => { this.signIn(); }); this.registerAction('register', (invocation) => { this.register(); }); this.registerAction('sendemail', (invocation) => { this.sendEmail(); }); this.registerAction('resetpassword', (invocation) => { this.resetpassword(); }); this.registerAction('signout', (invocation) => { this.signOut(); }); } reset(){ const inputs = document.querySelectorAll('#me_account_lightbox input'); inputs.forEach(ele=>{ ele.value = ''; ele.disabled = false; }); this.showType('account_login'); } presetEmail(resetEmail){ const loginEmailDom = document.querySelector('#me_account_lightbox .account_login .email'); if(loginEmailDom){ loginEmailDom.value = resetEmail; loginEmailDom.disabled = true; } const registerEmailDom = document.querySelector('#me_account_lightbox .account_register .email'); if(registerEmailDom){ registerEmailDom.value = resetEmail; registerEmailDom.disabled = true; } const setEmailDom = document.querySelector('#me_account_lightbox .account_email .email'); if(setEmailDom){ setEmailDom.value = resetEmail; setEmailDom.disabled = true; } const pass = document.querySelectorAll('#me_account_lightbox .password'); pass.forEach(ele=>{ ele.value = ''; }); } getCookie(name) { // 创建正则表达式来匹配指定名称的 Cookie const regex = new RegExp('(^|; )' + encodeURIComponent(name) + '=([^;]*)'); const match = document.cookie.match(regex); // 如果找到匹配项,则返回解码后的值,否则返回 null return match ? decodeURIComponent(match[2]) : null; } showType(showclass){ const modules = document.querySelectorAll('.box_content'); modules.forEach(ele=>{ if(ele.classList.contains(showclass)){ ele.classList.remove('hide'); ele.classList.add('show'); }else{ ele.classList.remove('show'); ele.classList.add('hide') } }) } signIn(){ const email = document.querySelector('.account_login .email').value; const password = document.querySelector('.account_login .password').value; const formData = new URLSearchParams(); formData.append('email', email); formData.append('password', password); fetch(location.origin+'/api/customers/sign_in',{ method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: formData }).then(res=>res.json()) .then(res=>{ if(res && res.customer && res.customer.id){ const box = document.querySelector('#me_account_lightbox'); SPZ.whenApiDefined(box).then(apis=>{ apis.close(); }) location.reload(); }else if(res && res.errors && res.errors[0]){ window.customToast(res.errors[0], 'error') } }).catch(err=>console.error('[signIn-err]', err)) } register(){ const email = document.querySelector('.account_register .email').value; const password = document.querySelector('.account_register .password').value; const checked = document.querySelector('.account_register .email_subscribe .check').checked; const regex = /^([^@]+)/; const match = email.match(regex); const name = match ? match[1] : '-'; // 返回用户名或 null const formData = new FormData(); formData.append('email', email); formData.append('password', password); formData.append('first_name', 'Guest'); formData.append('last_name', name); formData.append('newsletter', checked); fetch(location.origin+'/api/customers/sign_up',{ method: 'POST', body: formData }).then(res=>res.json()) .then(res=>{ if(res && res.customer && res.customer.id){ const box = document.querySelector('#me_account_lightbox'); SPZ.whenApiDefined(box).then(apis=>{ apis.close(); }) location.reload(); }else if(res && res.errors && res.errors[0]){ window.customToast(res.errors[0], 'error') } }).catch(err=>console.error('[signIn-err]', err)) } sendEmail(){ const email = document.querySelector('.account_email .email').value; const formData = new FormData(); formData.append('email', email); fetch(location.origin+'/api/customers/password_reset_email',{body: formData, method: 'POST'}) .then(res=>res.json()) .then(res=>{ if(res.errors && res.errors[0]){ window.customToast(res.errors[0], 'error'); if(res.errors[0].includes('This email has not been registered')){ this.showType('account_register'); } }else{ this.to_reset_email = email; this.showType('account_reset'); window.customToast('send successful'); } }).catch(err=>console.error('[sendEmail-err]', err)); } resetpassword(){ const formData = new FormData(); const verifyCode = document.querySelector('.account_reset .verifycode').value; const pwd1 = document.querySelector('.account_reset .pwd1').value; const pwd2 = document.querySelector('.account_reset .pwd2').value; if(pwd1!==pwd2){ /* TODO toast */ window.customToast('Your password and confirmation password do not match', 'error'); return; } formData.append('email', this.to_reset_email); formData.append('code', verifyCode); formData.append('password', pwd1); formData.append('confirm_password', pwd2); fetch(location.origin+'/api/customers/password_reset', { method: 'PATCH', body: formData, }) .then(res => res.json()) .then(res=>{ if(res.errors && res.errors[0]){ window.customToast(res.errors[0], 'error'); }else{ const box = document.querySelector('#me_account_lightbox'); SPZ.whenApiDefined(box).then(apis=>{ apis.close(); }); location.reload(); } }) .catch(err => console.error('[resetpassword-err]:', err)); } expireCookie(){ const cookies = document.cookie.split("; "); for (let cookie of cookies) { const eqPos = cookie.indexOf("="); const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; // 删除 Cookie:设置过期时间为过去的日期 document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;`; } } /* 在 我的 页面调用 */ signOut(){ const token = this.getCookie('CSRF-TOKEN'); fetch(location.origin+'/api/customers/sign_out', { method: 'POST', headers: { "x-csrf-token": token }, }).then(res=>res.json()) .then(res=>{ console.info('[signout res]', res); }) .catch(err=>console.error('[signOut-err]', err)) .finally(()=>{ this.expireCookie(); localStorage.removeItem('csp-video-progress'); location.reload(); /** const user = document.querySelector('#me_customer_info'); SPZ.whenApiDefined(user).then(apis=>{ apis.fresh(); }); const box = document.querySelector('#account_logout_box'); SPZ.whenApiDefined(box).then(apis=>{ apis.close(); }); **/ }) } } SPZ.defineElement('spz-custom-me-account', SPZCustomMeAccount); })() (function(){ class SPZCustomSubscribeUtilize extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.registerAction('confirm', (invocation) => { this.confirmUtilize(); }); } showUtilizeBox(pid, vid, cost_info){ const {currently_available, maximum_available} = cost_info || {}; const leftTime = Number(maximum_available||0) - Number(currently_available||0); this.pid = pid; this.vid = vid; const desc2 = document.querySelector('#subscribe_utilization_box .desc2'); desc2.innerText = `You still have 3 benefits remaining, and you have used ${leftTime}/3 times.`; const useBox = document.querySelector('#subscribe_utilization_box'); SPZ.whenApiDefined(useBox).then(apis=>{ apis.open(); }) } confirmUtilize(){ fetch(location.origin+'/apps/best-short/api/v1/preview/submit', {method: 'POST', body: JSON.stringify({skit_id: this.pid, skit_series_id: this.vid})}) .then(res=>res.json()) .then(res=>{ if(res && res.is_subscription){ /* 解锁成功 */ const useBox = document.querySelector('#subscribe_utilization_box'); SPZ.whenApiDefined(useBox).then(apis=>{ apis.close(); }) location.reload(); }else{ window.customToast('unlock fails', 'error') } }).catch(err=> console.error('[confirmUtilize-err]', err)) } } SPZ.defineElement('spz-custom-subscribe-utilize', SPZCustomSubscribeUtilize); })() (function(){ class SPZCustomCheckRight extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } /* 唤起列表 */ showSubscribeList(){ const listDom = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(listDom).then(apis=>{ apis.open(); }) } checkright(pid, vid){ fetch(location.origin+'/apps/best-short/api/v1/customer/information') .then(res=>res.json()) .then(res=>{ if(res){ const info = res.information; const right = res.subscription_info; /* 已经有了权益 */ if(right){ if(right.subscribe_type == "term_num"){ if(Number(right?.cost_info?.currently_available) > 0 ){ const useBox = document.querySelector('#subscribe_utilize_logic'); SPZ.whenApiDefined(useBox).then(apis=>{ apis.showUtilizeBox(pid, vid, right.cost_info); }) }else{ this.showSubscribeList(); } } }else{ this.showSubscribeList(); } } }) } } SPZ.defineElement('spz-custom-check-right', SPZCustomCheckRight); })() (function(){ class SPZCustomProductShare extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.request(); this.registerAction('finish', (invocation) => { this.finish(); }); } request () { const { productId } = document.querySelector('#bs-player').dataset; this.productId = productId; fetch(`/api/products/${productId}?extra_fields=description`) .then(res => res.json()) .then(res => { const { product = {} } = res.data; const container = document.querySelector('#custom_product_share_render_container'); SPZ.whenApiDefined(container).then((apis) => { apis.render({ product }).then(() => { const descDom = container.querySelector('.share-desc'); if (descDom) { container.querySelector('.share-desc').innerHTML = product.description; } }); }); }) .catch(err => { console.log('request error:', err); }) } finish () { const trackShare = async () => { await fetch('/apps/best-short/api/v1/preview/share', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ event_type: "PET_SHARE", msg: { skit_id: this.productId, skit_series_id: window.currentVideoPlayer.getCurrentEpisodeId(), } }) }).catch(err => {}) }; const box = document.querySelector('#custom-solution-product-share'); const copyBtn = box.querySelector('.copy-link'); copyBtn.addEventListener('click', function() { const url = window.location.href; trackShare(); navigator.clipboard.writeText(url).then(function() { window.C_APPS_COMMON.plugin_toast.show({content:'Copy link success'}); }); }); const shareFacebook = box.querySelector('.share-facebook'); const shareTwitter = box.querySelector('.share-twitter'); const onClick = function(e) { const url = window.location.href; const originHref = this.getAttribute('href') + encodeURIComponent(url); trackShare(); window.open(originHref, '_blank'); }; shareFacebook.addEventListener('click', onClick); shareTwitter.addEventListener('click', onClick); } } SPZ.defineElement('spz-custom-product-share', SPZCustomProductShare); })()