base.handle === $event.detail.handle); if (index >= 0 && index !== activeBase) selectBase(index)"
x-effect="const panels = previewPanels(); if (centeredArtIndex !== 99 && centeredArtIndex >= panels.length) centeredArtIndex = panels.length ? 0 : 99"
x-data="{
requestedPanels: [],
examplePanels: [],
failedPanels: [],
destroyed: false,
urlBundleRestored: false,
init() {
this.examplePanels = JSON.parse(this.$el.dataset.examplePanels || '[]');
this.loadRequestedPanels();
},
destroy() { this.destroyed = true; },
async loadRequestedPanels() {
const panels = await window.swapwearBundleJourney?.loadRequestedSwapPreviews();
if (this.destroyed || !panels?.length) return;
this.requestedPanels = panels;
this.centeredArtIndex = 0;
this.publishPreviewLink();
},
previewPanels() {
const count = this.scatteredArtCount();
const cartPanels = (window.swapwearBundleJourney?.panels?.(this.cart || {}) || []).slice().reverse()
.flatMap(panel => Array.from({ length: Math.min(count, Math.max(0, Number(panel.quantity) || 0)) }, () => ({
...panel, title: panel.product_title || panel.title,
image: typeof panel.image === 'string' ? panel.image : panel.image?.src || panel.featured_image?.url || ''
})));
const requested = this.requestedPanels.map(panel => {
const match = cartPanels.findIndex(item => item.handle === panel.handle);
return match >= 0 ? cartPanels.splice(match, 1)[0] : panel;
});
const selected = [...requested, ...cartPanels];
const examples = this.examplePanels.filter((panel, index, panels) => !selected.some(item => item.handle === panel.handle) && panels.findIndex(item => item.handle === panel.handle) === index);
return [...selected, ...examples].filter(panel => panel.image && !this.failedPanels.includes(panel.handle)).slice(0, count);
},
rejectPanelImage(handle) {
if (!this.failedPanels.includes(handle)) this.failedPanels.push(handle);
this.requestedPanels = this.requestedPanels.filter(panel => panel.handle !== handle);
this.examplePanels = this.examplePanels.filter(panel => panel.handle !== handle);
if (this.centeredArtIndex !== 99 && this.centeredArtIndex >= this.previewPanels().length) this.centeredArtIndex = this.previewPanels().length ? 0 : 99;
},
bundle: (() => {
const profile = window.__initialData?.sale_profile || {};
const key = ['build_bundle_index', profile.id || 'default', profile.start || '', profile.end || ''].join(':');
const explicitKey = ['build_bundle_index_explicit', profile.id || 'default', profile.start || '', profile.end || ''].join(':');
const hasExplicitSelection = window.swapwearStorage?.get?.(explicitKey, '') === 'true';
const saved = Number(window.swapwearStorage?.get?.(key, ''));
return hasExplicitSelection && Number.isFinite(saved) ? saved : 1;
})(),
hideFirstTier: false,
shopPayDetailsOpen: false,
centeredArtIndex: Math.floor(Math.random() * (sale_profile?.tiers?.[0]?.req_art || 1)),
// local mirror of global selection
activeBase: (typeof selected_base === 'number' ? selected_base : 0),
// pricing/product state
productCache: {},
baseRequestId: 0,
baseCanPrev: false,
baseCanNext: false,
baseProduct: null,
basePrice: null,
baseCompareAt: null,
clamp(i, min, max) { return Math.max(min, Math.min(max, i)); },
bundleStorageKey() {
const profile = (typeof sale_profile !== 'undefined' && sale_profile)
? sale_profile
: (window.__initialData?.sale_profile || {});
return ['build_bundle_index', profile.id || 'default', profile.start || '', profile.end || ''].join(':');
},
bundleExplicitStorageKey() {
const profile = (typeof sale_profile !== 'undefined' && sale_profile)
? sale_profile
: (window.__initialData?.sale_profile || {});
return ['build_bundle_index_explicit', profile.id || 'default', profile.start || '', profile.end || ''].join(':');
},
hasExplicitBundleSelection() {
return window.swapwearStorage?.get?.(this.bundleExplicitStorageKey(), '') === 'true';
},
handle() {
return bases[this.clamp(this.activeBase, 0, bases.length - 1)]?.handle || null;
},
baseLabel(base) {
return base?.short_name || base?.display_title || base?.title || base?.alt || base?.handle || '';
},
baseDisplayOrder() {
return window.swapwearOrderBases(bases).map(base => bases.indexOf(base));
},
updateBaseCarousel() {
const rail = this.$refs.baseCarousel;
if (!rail) return;
const maxScroll = Math.max(0, rail.scrollWidth - rail.clientWidth);
this.baseCanPrev = rail.scrollLeft > 2;
this.baseCanNext = rail.scrollLeft < maxScroll - 2;
},
moveBaseCarousel(direction) {
const rail = this.$refs.baseCarousel;
if (!rail) return;
const behavior = window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth';
rail.scrollBy({ left: direction * rail.clientWidth * 0.75, behavior });
},
revealActiveBase() {
const rail = this.$refs.baseCarousel;
if (!rail) return;
const selected = rail.querySelector('[aria-pressed=true]');
if (selected) {
const left = selected.offsetLeft;
const right = left + selected.offsetWidth;
if (left < rail.scrollLeft || right > rail.scrollLeft + rail.clientWidth) {
rail.scrollTo({ left: left - (rail.clientWidth - selected.offsetWidth) / 2, behavior: 'instant' });
}
}
this.updateBaseCarousel();
},
selectBase(index) {
const nextIndex = Number(index);
if (!Number.isInteger(nextIndex) || nextIndex < 0 || nextIndex >= bases.length) return;
const base = bases[nextIndex];
if (!base?.handle || base.productAvailable === false) return;
if (this.activeBase === nextIndex) {
this.goToBuildBundle();
return;
}
this.activeBase = nextIndex;
selected_base = nextIndex;
window.swapwearStorage?.setJSON?.('selected_base', nextIndex);
window.dispatchEvent(new CustomEvent('build-base-selection-change', {
detail: { index: nextIndex, handle: base.handle, source: 'bundle-banner' }
}));
},
async loadBaseProduct() {
const requestId = ++this.baseRequestId;
const h = this.handle();
this.baseProduct = null; this.basePrice = null; this.baseCompareAt = null;
if (!h) { this.baseProduct = null; this.basePrice = null; this.baseCompareAt = null; return; }
if (this.productCache[h]) { this.useProduct(this.productCache[h]); return; }
const registryBase = bases[this.clamp(this.activeBase, 0, bases.length - 1)];
if (registryBase && Number(registryBase.price) > 0) {
this.useProduct({
handle: registryBase.handle,
variants: [{
price: registryBase.price,
compare_at_price: registryBase.compareAtPrice || null
}]
});
return;
}
try {
const res = await window.swapwearFetch(`/products/${encodeURIComponent(h)}.js`);
const p = await res.json();
if (requestId !== this.baseRequestId) return;
this.productCache[h] = p;
this.useProduct(p);
} catch(e) {
if (requestId !== this.baseRequestId) return;
console.error('Failed to load product', h, e);
this.baseProduct = null; this.basePrice = null; this.baseCompareAt = null;
}
},
useProduct(p) {
this.baseProduct = p;
const v = Array.isArray(p?.variants) ? p.variants[0] : null;
const toCents = (val) => val == null ? null : Math.round(Number(val));
this.basePrice = toCents(v?.price);
this.baseCompareAt = toCents(v?.compare_at_price);
},
getTier(index) {
const list = this.tiersToShow();
return list[index] || { req_art: 1, req_jackets: 0, discount: 0, name: 'Default' };
},
defaultBundleIndex() {
const list = this.tiersToShow();
if (!Array.isArray(list) || list.length === 0) return 0;
if (this.isPanelBaseTier()) return 0;
const popularIndex = this.popularBundleIndex(list);
if (popularIndex >= 0) return popularIndex;
return Math.min(1, list.length - 1);
},
popularBundleIndex(list = this.tiersToShow()) {
return list.findIndex(tier => {
const label = [tier?.name, tier?.label].filter(Boolean).join(' ');
return String(label).toLowerCase().includes('popular');
});
},
buildCurrentOffer() {
return (typeof window !== 'undefined' && window.swapwearCurrentOffer?.()) || { profile: sale_profile, gift: this.mystery_data?.[2], pending: false };
},
buildOfferPending() {
return this.buildCurrentOffer().pending;
},
buildGiftAvailable(tier = this.getBuildTier()) {
const offer = this.buildCurrentOffer();
return !offer.pending && offer.gift?.active && Number(tier?.req_art || 0) >= Number(offer.gift.req || 0);
},
buildTiersToShow() {
const sale_profile = this.buildCurrentOffer().profile;
let tiers = [];
const mode = String(sale_profile?.tierMode || sale_profile?.offer?.tier_mode || '').toLowerCase();
const discountsBase = mode === 'panel_and_base';
const normalizeTier = (tier) => ({
...tier,
discount: Number(tier?.discount || 0),
req_art: Number(tier?.req_art || 0),
discounts_base: mode ? discountsBase : Number(tier?.req_jackets || 0) > 0,
req_jackets: mode ? (discountsBase ? 1 : 0) : Number(tier?.req_jackets || 0)
});
const uniqueTiers = (items) => {
const byRequirement = new Map();
items.map(normalizeTier).forEach((tier) => {
const key = tier?.base_only
? 'base-only'
: [Number(tier.req_jackets || 0), Number(tier.req_art || 0)].join(':');
const existing = byRequirement.get(key);
if (!existing || Number(tier.discount || 0) > Number(existing.discount || 0)) {
byRequirement.set(key, tier);
}
});
return Array.from(byRequirement.values())
.sort((a, b) => Number(a?.req_art || 0) - Number(b?.req_art || 0))
.slice(0, 3);
};
if (String(sale_profile?.type || '').toLowerCase() === 'panel_base_tier') {
const rows = typeof panelBaseTierRows === 'function' ? panelBaseTierRows(sale_profile) : [];
const baseRow = rows.find(row => row.kind === 'base');
tiers = rows.map((row) => ({
name: row.kind === 'base' ? 'Base Offer' : `${row.panelQuantity} ${Number(row.panelQuantity) === 1 ? 'Swap' : 'Swaps'}`,
req_jackets: row.kind === 'base' ? Number(row.baseQuantity || 1) : 0,
req_art: Number(row.panelQuantity || 0),
discount: row.kind === 'panels' ? Number(row.percentageOff || 0) : 0,
base_discount: Number(baseRow?.percentageOff || 0),
discounts_base: false,
panel_base_kind: row.kind
}));
} else if (String(sale_profile?.type || '').toLowerCase() === 'bogo') {
const config = typeof bogoConfig === 'function'
? bogoConfig(sale_profile)
: { getQuantity: Number(sale_profile?.bogo?.getQuantity || sale_profile?.offer?.get_quantity || 1) || 1 };
const label = typeof bogoOfferLabel === 'function'
? bogoOfferLabel(sale_profile)
: (sale_profile?.discountLabel || sale_profile?.checkoutLabel || 'Free panel');
tiers = [{
name: label,
req_jackets: 1,
req_art: Math.max(1, Number(config.getQuantity || 1)),
discount: 0,
discounts_base: false,
bogo: true
}];
} else if (sale_profile?.type === 'sitewide') {
const discount = Number(sale_profile?.discount || 0);
tiers = [
{ name: 'Starter', req_jackets: discountsBase ? 1 : 0, req_art: 2, discount },
{ name: 'Most Popular', req_jackets: discountsBase ? 1 : 0, req_art: 3, discount },
{ name: 'Best Value', req_jackets: discountsBase ? 1 : 0, req_art: 5, discount }
];
} else if (Array.isArray(sale_profile?.tiers)) {
tiers = sale_profile.tiers
.filter(tier => Number(tier?.discount || 0) > 0);
}
tiers = uniqueTiers(tiers);
if (sale_profile?.acquisition) tiers = tiers.filter(tier => Number(tier.req_art) <= 3);
if (!tiers.length) {
tiers = uniqueTiers([
{ name: 'Starter', req_jackets: 0, req_art: 2, discount: 0, discounts_base: false },
{ name: 'Most Popular', req_jackets: 0, req_art: 3, discount: 0, discounts_base: false },
{ name: 'Best Value', req_jackets: 0, req_art: 5, discount: 0, discounts_base: false }
]);
}
if (!sale_profile?.active || (sale_profile?.end && Date.parse(sale_profile.end) <= Date.now())) {
tiers = tiers.map(tier => ({ ...tier, discount: 0, base_discount: 0, bogo: false }));
}
return tiers;
},
tiersToShow() { return this.buildTiersToShow(); },
hasDiscountedTiers() {
return this.tiersToShow().some(t => Number(t?.discount) > 0 || Number(t?.base_discount) > 0);
},
isPanelBaseTier() {
return typeof isPanelBaseTierOffer === 'function'
? isPanelBaseTierOffer()
: String(sale_profile?.type || '').toLowerCase() === 'panel_base_tier';
},
isBogo() {
return typeof isBogoOffer === 'function'
? isBogoOffer()
: String(sale_profile?.type || '').toLowerCase() === 'bogo';
},
bogoLabel() {
return typeof bogoOfferLabel === 'function'
? bogoOfferLabel()
: (sale_profile?.discountLabel || sale_profile?.checkoutLabel || 'Free panel');
},
bogoDetail() {
return typeof bogoOfferDetail === 'function'
? bogoOfferDetail()
: (sale_profile?.detailLine || sale_profile?.accordionContent || '');
},
promoCopyActive() {
return Boolean(
sale_profile?.active &&
Number(sale_profile?.id || 0) > 0 &&
String(sale_profile?.type || '').toLowerCase() !== 'none'
);
},
promoBadgeLabel() {
if (!this.promoCopyActive()) return '';
return String(sale_profile?.badge || sale_profile?.messaging?.badge || '').trim();
},
promoEyebrowLabel() {
if (!this.promoCopyActive()) return '';
return String(sale_profile?.messaging?.eyebrow || sale_profile?.announcement || sale_profile?.discountLabel || '').trim();
},
offerBadgeStarActive(index) {
if (this.hasDiscountedTiers() && index === this.popularBundleIndex()) return true;
return !this.hasDiscountedTiers() && Boolean(this.promoBadgeLabel());
},
offerBadgeTagActive(index) {
return this.hasDiscountedTiers() &&
index === this.tiersToShow().length - 1 &&
index !== this.popularBundleIndex() &&
!this.offerBadgeStarActive(index);
},
offerBadgeLabel(tier) {
if (this.isPanelBaseTier()) return this.promoBadgeLabel() || sale_profile?.messaging?.eyebrow || tier?.name || 'Set offer';
if (this.hasDiscountedTiers()) {
return String(tier?.name || tier?.label || 'Bundle deal').trim().replace(/\bstarter\b/ig, 'Beginner');
}
const promoBadge = this.promoBadgeLabel();
if (promoBadge) return promoBadge;
if (this.isBogo()) return this.bogoLabel();
return 'Beginner Set';
},
activeTier() {
return this.getTier(this.bundle);
},
tierIconKind(index) {
const tierIndex = Number(index);
const popularIndex = this.popularBundleIndex();
const lastIndex = this.tiersToShow().length - 1;
const tier = this.tiersToShow()[tierIndex] || {};
const label = String(tier?.name || tier?.label || '').toLowerCase();
if (tierIndex === popularIndex) return 'star';
if (tierIndex === 0 || label.includes('beginner') || label.includes('starter')) return 'smiley';
if (tierIndex === lastIndex && tierIndex !== popularIndex && this.hasDiscountedTiers()) return 'discount';
return 'none';
},
activeTierIconKind() {
return this.tierIconKind(this.bundle);
},
tierKicker(tier = this.activeTier()) {
if (this.isPanelBaseTier()) {
const looks = this.stylesInSet(tier);
return `${looks} ${looks === 1 ? 'Look' : 'Looks'}`;
}
const label = String(tier?.name || tier?.label || '').trim();
const normalized = label || (this.hasDiscountedTiers() ? 'Bundle' : 'Beginner set');
const lower = normalized.toLowerCase();
if (lower.includes('popular')) return 'Most popular';
if (lower.includes('best')) return 'Best value';
if (lower.includes('starter') || lower.includes('beginner')) return 'Beginner';
return normalized.replace(/\bstarter\b/ig, 'Beginner').replace(/\s+set$/i, '');
},
ctaLabel() {
if (this.isPanelBaseTier()) return 'Build My Set';
if (this.promoCopyActive()) {
const label = String(sale_profile?.messaging?.cta || sale_profile?.ctaLabel || '').trim();
if (label) return label;
}
return 'Build Bundle';
},
stageSetLabel(tier = this.activeTier()) {
return this.isPanelBaseTier() ? this.packLabel(tier) : this.setLabel(tier);
},
fallbackHeadline() {
if (this.isPanelBaseTier()) return sale_profile?.messaging?.headline || sale_profile?.title || 'Build Your Set';
if (this.isBogo()) return sale_profile?.title || this.bogoLabel();
return 'Start Your Collection';
},
fallbackSubhead() {
if (this.isBogo()) return this.bogoDetail();
return 'Choose a base, pick art panels, and start building new combinations over time.';
},
setLabel(tier) {
if (this.isPanelBaseTier()) return sale_profile?.messaging?.headline || sale_profile?.title || 'Build Your Set';
const count = Number(tier?.req_art || 0);
if (count <= 0) return 'Beginner Set';
return this.packLabel(tier);
},
shortSetLabel(tier) {
if (this.isPanelBaseTier()) return tier?.panel_base_kind === 'base'
? 'Base Offer'
: `${Number(tier?.req_art || 0)} ${Number(tier?.req_art || 0) === 1 ? 'Swap' : 'Swaps'}`;
const count = Number(tier?.req_art || 0);
if (count <= 0) return 'Beginner Set';
return this.packLabel(tier);
},
packLabel(tier) {
return "__COUNT__ in 1".replace('__COUNT__', this.stylesInSet(tier));
},
stylesInSet(tier) {
return Number(tier?.req_art || 0) + 1;
},
bundlePricePerStyle(tier) {
const styles = Math.max(1, this.stylesInSet(tier));
return Math.round(this.bundlePrice(tier) / styles);
},
installmentPrice(tier) {
return Math.round(this.bundlePrice(tier) / 4);
},
bundlePanelPrice(tier) {
const discountMultiplier = (100 - Number(tier?.discount || 0)) / 100;
return Math.round(2500 * discountMultiplier);
},
bundlePanelComparePrice() {
return 2500;
},
bundleBaseComparePrice() {
const current = Number(this.basePrice ?? 11900);
return Math.max(current, Number(this.baseCompareAt || 0));
},
bundleBasePrice(tier) {
const current = Number(this.basePrice ?? 11900);
const original = this.bundleBaseComparePrice();
const discount = this.tierDiscountsBase(tier) ? Number(tier?.discount || 0) : 0;
if (discount <= 0) return current;
return Math.min(current, Math.round(original * ((100 - discount) / 100)));
},
bundleBaseHasDiscount(tier) {
return this.bundleBaseComparePrice() > this.bundleBasePrice(tier);
},
bundleHasDiscount(tier) {
return this.bundleComparePrice(tier) > this.bundlePrice(tier);
},
bundleSavings(tier) {
return Math.max(0, this.bundleComparePrice(tier) - this.bundlePrice(tier));
},
bundleSavingsLabel(tier) {
const savings = this.bundleSavings(tier);
const discount = Number(tier?.discount || 0);
return (savings / 100) < discount
? `Save ${discount}%${this.tierDiscountsBase(tier) ? '' : ' On Swaps'}`
: `Save ${Shopify.formatMoney(savings, false)}`;
},
bundleComparePrice(tier) {
const base = this.basePrice ?? 11900;
return Math.round(base + (2500 * Number(tier?.req_art || 0)));
},
tierDiscountsBase(tier) {
if (typeof tier?.discounts_base !== 'undefined') return tier.discounts_base === true;
return Number(tier?.req_jackets || 0) > 0;
},
savingsBadgeLabel(tier) {
if (this.isPanelBaseTier()) {
return tier?.panel_base_kind === 'base'
? `${Number(tier?.base_discount || 0)}% Off Base`
: `${Number(tier?.discount || 0)}% Off Swaps`;
}
const discount = Number(tier?.discount || 0);
return discount + (this.tierDiscountsBase(tier) ? '% Savings' : '% Swap Savings');
},
promoSaleLabel() {
const label = sale_profile?.checkoutLabel || sale_profile?.eventLabel || sale_profile?.title || 'Limited-time';
if (this.isBogo()) return label;
return String(label).replace(/\s+sale$/i, '') + ' Sale';
},
panelBaseTierDetail(tier) {
const rows = typeof panelBaseTierRows === 'function' ? panelBaseTierRows() : [];
const row = rows.find((item) => item.kind === tier?.panel_base_kind && Number(item.panelQuantity) === Number(tier?.req_art));
return typeof panelBaseTierRowTitle === 'function' ? panelBaseTierRowTitle(row) : '';
},
panelBaseBundleSummary() {
const rows = typeof panelBaseTierRows === 'function' ? panelBaseTierRows() : [];
const baseOffer = rows.find(row => row?.kind === 'base') || null;
const panelTier = rows.find(row => row?.kind === 'panels') || null;
const panelQuantity = Math.max(1, Number(panelTier?.panelQuantity || baseOffer?.panelQuantity || 1));
return { baseOffer, panelTier, panelQuantity };
},
panelBaseBundleLabel() {
const quantity = this.panelBaseBundleSummary().panelQuantity;
return `1 Base + ${quantity} Art ${quantity === 1 ? 'Panel' : 'Panels'}`;
},
panelBaseBundleMsrp() {
const summary = this.panelBaseBundleSummary();
const regularBase = Math.max(Number(this.basePrice ?? 11900), Number(this.baseCompareAt || 0));
return Math.round(regularBase + (2500 * summary.panelQuantity));
},
panelBaseBundleOfferPrice() {
const summary = this.panelBaseBundleSummary();
const regularBase = Number(this.basePrice ?? 11900);
const baseDiscount = Number(summary.baseOffer?.percentageOff || 0);
const discountedBase = Math.round(regularBase * ((100 - baseDiscount) / 100));
const panelDiscount = Number(summary.panelTier?.percentageOff || 0);
const discountedPanelCount = summary.panelTier
? Math.max(0, summary.panelQuantity - Number(summary.panelTier.panelQuantity || 0) + 1)
: 0;
const regularPanelCount = summary.panelQuantity - discountedPanelCount;
const discountedPanelPrice = Math.round(2500 * ((100 - panelDiscount) / 100));
return discountedBase + (regularPanelCount * 2500) + (discountedPanelCount * discountedPanelPrice);
},
panelBaseBundleSavings() {
return Math.max(0, this.panelBaseBundleMsrp() - this.panelBaseBundleOfferPrice());
},
panelBaseBundleSavingsPercent() {
const msrp = this.panelBaseBundleMsrp();
return msrp > 0 ? Math.round((this.panelBaseBundleSavings() / msrp) * 100) : 0;
},
displayYOffset(base) {
return String(base?.yoffset || '0%');
},
bannerImageWidth(mobileWidth, desktopWidth) {
const mobile = window.matchMedia
? window.matchMedia('(max-width: 767px)').matches
: window.innerWidth < 768;
return mobile ? mobileWidth : desktopWidth;
},
bannerImageUrl(src, mobileWidth, desktopWidth) {
return window.buildImageUrlWithWidth(
src,
this.bannerImageWidth(mobileWidth, desktopWidth)
);
},
bundleUrl() {
const baseHandle = this.handle();
const root = window.Shopify?.routes?.root || '/';
const destination = baseHandle ? `${root}products/${encodeURIComponent(baseHandle)}` : `${root}collections/bases`;
const handles = window.swapwearBundleJourney?.requestedSwapHandles() || [];
const params = new URLSearchParams({ set_panels: String(this.getTier(this.bundle).req_art) });
if (handles.length) params.set('swap', handles.join(','));
return destination + '?' + params;
},
publishPreviewLink() {
window.dispatchEvent(new CustomEvent('homepage:set-preview', { detail: { url: this.bundleUrl() } }));
},
goToBuildBundle() {
this.persistBundleSelection();
window.location.assign(this.bundleUrl());
},
bundlePrice(tier) {
const base = this.basePrice ?? 11900;
const artTotal = 2500 * Number(tier?.req_art || 0);
if (tier?.bogo) {
const profile = this.buildCurrentOffer().profile;
const config = typeof bogoConfig === 'function' ? bogoConfig(profile) : profile?.bogo || {};
return Math.max(0, Math.round(base + artTotal - 2500 * Math.min(Number(tier.req_art), Number(config.getQuantity || 1)) * Number(config.discountPercentage ?? 100) / 100));
}
const discountMultiplier = (100 - Number(tier?.discount || 0)) / 100;
if (this.isPanelBaseTier()) {
const baseMultiplier = (100 - Number(tier?.base_discount || 0)) / 100;
return Math.round((base * baseMultiplier) + (artTotal * discountMultiplier));
}
return this.tierDiscountsBase(tier)
? Math.round((base + artTotal) * discountMultiplier)
: Math.round(base + (artTotal * discountMultiplier));
},
choosePanel(index) {
this.centeredArtIndex = index;
},
setBundle(index) {
const nextIndex = Number(index);
if (!Number.isInteger(nextIndex) || nextIndex < 0 || nextIndex >= this.tiersToShow().length) return;
if (this.bundle === nextIndex) {
this.goToBuildBundle();
return;
}
this.bundle = nextIndex;
this.centeredArtIndex = Math.max(0, (Number(this.getTier(nextIndex).req_art) || 1) - 1);
this.persistBundleSelection();
},
scatteredArtCount(tier = this.getTier(this.bundle)) {
return Math.max(0, Math.min(Number(tier?.req_art || 0), 5));
},
freeBadgePanelIndex() {
if (!this.isBogo() || !this.promoCopyActive()) return -1;
const count = this.scatteredArtCount();
const active = Number(this.centeredArtIndex);
for (let index = 0; index < count; index += 1) {
if (index !== active) return index;
}
return -1;
},
mysteryGiftForTier(tier) {
const showGiftLabel = true;
const giftAvailable = true;
const mystery = (typeof mystery_data !== 'undefined' && mystery_data?.[2]) ? mystery_data[2] : {};
const requirement = Number(mystery?.req || 0);
return showGiftLabel && giftAvailable && Boolean(mystery?.active) && requirement > 0 && Number(tier?.req_art || 0) >= requirement;
},
persistBundleSelection() {
window.swapwearStorage?.set?.(this.bundleStorageKey(), String(this.bundle));
window.swapwearStorage?.set?.(this.bundleExplicitStorageKey(), 'true');
window.swapwearBundleJourney?.setTarget?.(Number(this.getTier(this.bundle).req_art), false);
},
panelPosition(index) {
return `--panel-index: ${Number(index) || 0}; --panel-rotate: 0deg;`;
},
ensureValidBundle() {
const list = this.tiersToShow();
if (!Array.isArray(list) || list.length === 0) return;
const requestedCount = Number(new URLSearchParams(window.location?.search || '').get('set_panels'));
const requestedIndex = list.findIndex(tier => Number(tier.req_art) === requestedCount);
if (!this.urlBundleRestored && requestedCount > 0 && requestedIndex >= 0) {
this.bundle = requestedIndex;
this.urlBundleRestored = true;
}
if (this.isPanelBaseTier()) {
this.bundle = list.length - 1;
this.centeredArtIndex = Math.max(0, Number(list[this.bundle]?.req_art || 1) - 1);
return;
}
if ((!this.hasExplicitBundleSelection() && !this.urlBundleRestored) || typeof this.bundle !== 'number' || this.bundle < 0 || this.bundle >= list.length) {
this.bundle = this.defaultBundleIndex();
}
}
}"
x-init="
loadBaseProduct();
$watch('activeBase', () => { loadBaseProduct(); $nextTick(() => revealActiveBase()); });
$watch(() => selected_base, v => { activeBase = (typeof v === 'number' ? v : 0); });
// Ensure bundle index is valid once tiers are available
ensureValidBundle();
$nextTick(() => publishPreviewLink());
$watch('bundle', () => publishPreviewLink());
$watch('activeBase', () => publishPreviewLink());
// If sale_profile loads after Alpine init, re-validate
$watch(() => sale_profile, () => {
ensureValidBundle();
});
// ----- tier visibility logic -----
(function() {
const tiers = tiersToShow(); // IMPORTANT: use filtered tiers
const visibleCount = Math.min(tiers.length, 7);
const firstReqArt = Number(tiers[0]?.req_art || 0);
if (firstReqArt === 1 && visibleCount > 3) {
hideFirstTier = true;
if (bundle === 0 && visibleCount > 1) bundle = 1;
}
})();
"
>
Bundle & Save
Most Popular Starter Bundle
Choose your base
Choose your base
Sold Out
Pay in 4 interest-free installments of
with
shop Pay
Select installments at checkout to split your purchase into 4 interest-free payments of
every 2 weeks.
Choose your plan at checkout
No hidden fees, ever
Applying won’t affect your credit score
The estimated payment amount excludes taxes and shipping. Rates from 0–36% APR. Payment options through Shop Pay Installments are subject to an eligibility check and are provided by
Affirm’s lending partners .
Options depend on your purchase amount, and a down payment may be required.
State notices to consumers .
Choose from 1,000+ art panels!