SAVE 10% SITEWIDE WITH CODE: RIDGE10

SAVE 10% SITEWIDE WITH CODE: RIDGE10

SAVE 10% SITEWIDE WITH CODE: RIDGE10

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

HOW DOES IT WORK

We’re going above and beyond this year with bigger, faster cars and TWO winners.

Colorful car with speech bubble graphic and the word

ENTER FOR FREE

With Email & SMS

Person holding a blue Ridge wallet in their hands.

EARN MORE ENTRIES

Buying gear you’ll love.

Orange smartphone case, smartwatch, and cardholder on a black background.

GET 2-4X ENTRIES

On Exclusive Collections.

Wooden crate with

SPEND MORE

For Mystery entries and gear.

HOW DOES IT WORK

We’re going above and beyond this year with bigger, faster cars and TWO winners.

Icon of two speech bubbles with colorful background.

ENTER FOR FREE

With Email & SMS

Person holding a blue card-like object with a smooth surface.

EARN MORE ENTRIES

Buying gear you’ll love.

Orange phone case and accessories on a textured black background.

GET 2-4X ENTRIES

On Exclusive Collections.

Wooden crate with

SPEND MORE

For Mystery entries and gear.

GEAR BUILT BETTER

HIGH-GRADE MATERIALS

Custom designs with military-grade construction.

LIFETIME
WARRANTY

Not just gear built to last — but guaranteed for life.

99 DAY RISK-FREE TRIAL

Don't love it after 99 days? Send it right back, no questions asked.

, 'CA': '

SAVE 10% SITEWIDE WITH CODE: RIDGE10

SAVE 10% SITEWIDE WITH CODE: RIDGE10

SAVE 10% SITEWIDE WITH CODE: RIDGE10

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

HOW DOES IT WORK

We’re going above and beyond this year with bigger, faster cars and TWO winners.

Colorful car with speech bubble graphic and the word

ENTER FOR FREE

With Email & SMS

Person holding a blue Ridge wallet in their hands.

EARN MORE ENTRIES

Buying gear you’ll love.

Orange smartphone case, smartwatch, and cardholder on a black background.

GET 2-4X ENTRIES

On Exclusive Collections.

Wooden crate with

SPEND MORE

For Mystery entries and gear.

HOW DOES IT WORK

We’re going above and beyond this year with bigger, faster cars and TWO winners.

Icon of two speech bubbles with colorful background.

ENTER FOR FREE

With Email & SMS

Person holding a blue card-like object with a smooth surface.

EARN MORE ENTRIES

Buying gear you’ll love.

Orange phone case and accessories on a textured black background.

GET 2-4X ENTRIES

On Exclusive Collections.

Wooden crate with

SPEND MORE

For Mystery entries and gear.

GEAR BUILT BETTER

HIGH-GRADE MATERIALS

Custom designs with military-grade construction.

LIFETIME
WARRANTY

Not just gear built to last — but guaranteed for life.

99 DAY RISK-FREE TRIAL

Don't love it after 99 days? Send it right back, no questions asked.

, 'GB': '£', 'EU': '€', 'AU': '

SAVE 10% SITEWIDE WITH CODE: RIDGE10

SAVE 10% SITEWIDE WITH CODE: RIDGE10

SAVE 10% SITEWIDE WITH CODE: RIDGE10

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

HOW DOES IT WORK

We’re going above and beyond this year with bigger, faster cars and TWO winners.

Colorful car with speech bubble graphic and the word

ENTER FOR FREE

With Email & SMS

Person holding a blue Ridge wallet in their hands.

EARN MORE ENTRIES

Buying gear you’ll love.

Orange smartphone case, smartwatch, and cardholder on a black background.

GET 2-4X ENTRIES

On Exclusive Collections.

Wooden crate with

SPEND MORE

For Mystery entries and gear.

HOW DOES IT WORK

We’re going above and beyond this year with bigger, faster cars and TWO winners.

Icon of two speech bubbles with colorful background.

ENTER FOR FREE

With Email & SMS

Person holding a blue card-like object with a smooth surface.

EARN MORE ENTRIES

Buying gear you’ll love.

Orange phone case and accessories on a textured black background.

GET 2-4X ENTRIES

On Exclusive Collections.

Wooden crate with

SPEND MORE

For Mystery entries and gear.

GEAR BUILT BETTER

HIGH-GRADE MATERIALS

Custom designs with military-grade construction.

LIFETIME
WARRANTY

Not just gear built to last — but guaranteed for life.

99 DAY RISK-FREE TRIAL

Don't love it after 99 days? Send it right back, no questions asked.

}; return currencySymbols[countryCode] || '

SAVE 10% SITEWIDE WITH CODE: RIDGE10

SAVE 10% SITEWIDE WITH CODE: RIDGE10

SAVE 10% SITEWIDE WITH CODE: RIDGE10

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

100,000+ 5 Star Reviews

5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

BUY NOW
Orange sports car and blue truck on a rocky terrain under a clear sky.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


Two winners. Ends soon. Don’t wait to make your move.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

2. SLIM, BUT BUILT TO DO MORE

Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


No fraying seams. No folded leather. Just modern efficiency.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

3. ENGINEERED FROM MILITARY-GRADE MATERIALS

Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


It’s performance you’ll feel every day.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

4. SECURITY THAT BLOCKS DIGITAL THEFT

Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


Form meets function, and security comes standard.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

5. 100,000+ 5-STAR REVIEWS BACK IT UP

With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

 

It’s a product people trust enough to gift, replace, and recommend.

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

UP TO 44% OFF

EARN 4x ENTRIES

HOW DOES IT WORK

We’re going above and beyond this year with bigger, faster cars and TWO winners.

Colorful car with speech bubble graphic and the word

ENTER FOR FREE

With Email & SMS

Person holding a blue Ridge wallet in their hands.

EARN MORE ENTRIES

Buying gear you’ll love.

Orange smartphone case, smartwatch, and cardholder on a black background.

GET 2-4X ENTRIES

On Exclusive Collections.

Wooden crate with

SPEND MORE

For Mystery entries and gear.

HOW DOES IT WORK

We’re going above and beyond this year with bigger, faster cars and TWO winners.

Icon of two speech bubbles with colorful background.

ENTER FOR FREE

With Email & SMS

Person holding a blue card-like object with a smooth surface.

EARN MORE ENTRIES

Buying gear you’ll love.

Orange phone case and accessories on a textured black background.

GET 2-4X ENTRIES

On Exclusive Collections.

Wooden crate with

SPEND MORE

For Mystery entries and gear.

GEAR BUILT BETTER

HIGH-GRADE MATERIALS

Custom designs with military-grade construction.

LIFETIME
WARRANTY

Not just gear built to last — but guaranteed for life.

99 DAY RISK-FREE TRIAL

Don't love it after 99 days? Send it right back, no questions asked.

; // Default to USD if not found } let CURRENCY_SYMBOL = getCurrencySymbol(); function generatePdpFlareHtml(productData) { if (!productData) return ''; const metafields = productData.metafields || []; const flareToggle = metafields.find(m => m && m.key === 'flare_toggle_for_pdp_only')?.value; const flareText = metafields.find(m => m && m.key === 'flare_text_for_pdp_page')?.value; const flareStyle = metafields.find(m => m && m.key === 'pdp_page_flare_style_selection')?.value; if (flareToggle && flareText && flareText.trim() !== '' && flareStyle) { return `
${flareText}
`; } if (!flareText || flareText.trim() === '') { const currentPrice = productData.price?.amount ? parseFloat(productData.price.amount) : 0; const compareAtPrice = productData.compareAtPrice?.amount ? parseFloat(productData.compareAtPrice.amount) : 0; if (compareAtPrice && compareAtPrice > currentPrice) { const discountAmount = compareAtPrice - currentPrice; const discountPercentage = Math.round((discountAmount / compareAtPrice) * 100); if (discountPercentage > 0) { return `
${discountPercentage}% OFF
`; } } } return ''; } function generateFlareForVariant(variant) { if (!variant) return ''; const currentPrice = parseFloat(variant.price.amount); const compareAtPrice = variant.compareAtPrice ? parseFloat(variant.compareAtPrice.amount) : null; if (compareAtPrice && compareAtPrice > currentPrice) { const discountAmount = compareAtPrice - currentPrice; const discountPercentage = Math.round((discountAmount / compareAtPrice) * 100); return `
${discountPercentage}% OFF
`; } return ''; } let productDataGlobal = null; let flickityInstances = {}; let currentVisibleAlt = null; let currentSelectedOptions = {}; let collectionDataGlobal = null; let productCache = {}; let singularCollectionData = null; let kitCollectionData = null; let currentActiveCollection = null; let productDescriptionsCache = {}; let initialPageLoadComplete = false; if (!window.pdpComponentRegistry) { window.pdpComponentRegistry = {}; } let upsellSliderFlickity = null; const selectedUpsellProducts = []; const pdpmod16DiscountCodesArr = []; let globalMetafields = {}; const PRODUCT_GRAPHQL_METAFIELD_QUERY = ` metafields(identifiers: [ {key: "product_archetype", namespace: "accentuate"}, {key: "pdp_swatch_selector_material", namespace: "accentuate"}, {key: "collection_page_subtext", namespace: "collection_page"}, {key: "upsell_slider_title", namespace: "accentuate"}, {key: "upsell_slider_badge_title", namespace: "accentuate"}, {key: "upsell_slider_modal_text", namespace: "accentuate"}, {key: "upsell_slider_quick_view_click_behavior", namespace: "accentuate"}, {key: "product_1_title_override", namespace: "accentuate"}, {key: "product_2_title_override", namespace: "accentuate"}, {key: "product_3_title_override", namespace: "accentuate"}, {key: "product_4_title_override", namespace: "accentuate"}, {key: "ring__i_dont_know_my_size_modal_image", namespace: "accentuate"}, {key: "colorway", namespace: "accentuate"}, {key: "minicart_discount_section_toggle", namespace: "accentuate"}, {key: "toggle_to_turn_on_adding_manual_discount_code", namespace: "accentuate"}, {key: "select_minicart_discount_product", namespace: "accentuate"}, {key: "select_discount_product_percent_off", namespace: "accentuate"}, {key: "dollar_amount_off", namespace: "accentuate"}, {key: "discount_section_main_header", namespace: "accentuate"}, {key: "manual_discount_code", namespace: "accentuate"}, {key: "best_seller", namespace: "accentuate"}, {key: "matching_kit_product", namespace: "accentuate"}, {key: "product_type", namespace: "accentuate"}, {key: "shogun_swatch_image_selected", namespace: "accentuate"}, {key: "shogun_swatch_image_not_select", namespace: "accentuate"}, {key: "kit_tab_title", namespace: "accentuate"}, {key: "kit_selector_toggle", namespace: "accentuate"}, {key: "override_singular_tab_title", namespace: "accentuate"}, {key: "swatch_selector_collection", namespace: "accentuate"}, {key: "pdp_features", namespace: "accentuate"}, {key: "pdp_description", namespace: "accentuate"}, {key: "pdp_shipping", namespace: "accentuate"}, {key: "features_alternative_title", namespace: "accentuate"}, {key: "description_alternative_title", namespace: "accentuate"}, {key: "shipping_alternative_title", namespace: "accentuate"}, {key: "is_jtb_customizable", namespace: "accentuate"}, {key: "toggle_silhouette_selector", namespace: "accentuate"}, {key: "products_for_silhouette_selector_page_version__4_max", namespace: "accentuate"}, {key: "mod14_title", namespace: "accentuate"}, {key: "info_icon_toggle", namespace: "accentuate"}, {key: "info_icon_image", namespace: "accentuate"}, {key: "upsell_slider_pdpmod16_master_toggle", namespace: "accentuate"}, {key: "upsell_slider_collection_selection__page_version", namespace: "accentuate"}, {key: "whats_in_the_kit_v2_toggle", namespace: "accentuate"}, {key: "whats_in_the_kit_v2_warranty_message", namespace: "accentuate"}, {key: "whats_in_the_kit_v2_modal_image", namespace: "accentuate"}, {key: "whats_in_the_kit_v2_warranty_section_toggle", namespace: "accentuate"}, {key: "whats_in_the_kit_v2_warranty_badge", namespace: "accentuate"}, {key: "whats_in_the_kit_v2_native", namespace: "accentuate"} ]){ key value }, `; async function fetchGlobalMetafields() { const query = ` query { shop { metafields(identifiers: [ {key: "shogun_product_default_feature", namespace: "globals"}, {key: "shogun_product_default_desc", namespace: "globals"}, {key: "shogun_product_def_shipping", namespace: "globals"}, {key: "generic_default_features", namespace: "globals"}, {key: "generic_default_description", namespace: "globals"}, {key: "generic_default_shipping", namespace: "globals"} ]){ key value } } } `; try { const response = await fetch(GRAPHQL_URL_VERSION, { method: 'POST', headers: graphqlHeadersObj, body: query }); const res = await response.json(); if (res.data && res.data.shop && res.data.shop.metafields) { res.data.shop.metafields.forEach(metafield => { if (metafield && metafield.key && metafield.value) { globalMetafields[metafield.key] = metafield.value; } }); } else { console.warn("fetchGlobalMetafields: No metafields found in response"); } } catch (error) { console.error('fetchGlobalMetafields: Error fetching global metafields:', error); } } async function fetchSingleProductData(handle) { const query = ` query @inContext(country: ${COUNTRY_ISO_CODE}) { product(handle: "${handle}") { id title availableForSale handle tags descriptionHtml onlineStoreUrl featuredImage { url altText } images(first: 200) { edges { node { url altText } } } options { name values } ${PRODUCT_GRAPHQL_METAFIELD_QUERY} variants(first: 200) { edges { node { id title availableForSale price { amount } compareAtPrice { amount } selectedOptions { name value } image { url altText } } } } } }`; try { const response = await fetch(GRAPHQL_URL_VERSION, { method: 'POST', headers: graphqlHeadersObj, body: query }); const res = await response.json(); if (res.data && res.data.product) { processProductDescriptions(res.data.product); return res.data.product; } else { console.warn(`Product data not found for handle: ${handle}`); return null; } } catch (error) { console.error(`Fetch error for product ${handle}:`, error); return null; } } function processProductDescriptions(product) { if (!product || !product.handle) return; const metafields = product.metafields || []; const productType = getMetafieldValue(product, 'product_type') || ''; const isWallet = productType === 'Wallet'; const featuresField = getMetafieldValue(product, 'pdp_features'); const descriptionField = getMetafieldValue(product, 'pdp_description'); const shippingField = getMetafieldValue(product, 'pdp_shipping'); const featuresTitle = getMetafieldValue(product, 'features_alternative_title') || 'Features'; const descriptionTitle = getMetafieldValue(product, 'description_alternative_title') || 'Description'; const shippingTitle = getMetafieldValue(product, 'shipping_alternative_title') || 'Shipping & Warranty'; let defaultFeatures, defaultDescription, defaultShipping; if (isWallet) { defaultFeatures = globalMetafields['shogun_product_default_feature'] || ''; defaultDescription = globalMetafields['shogun_product_default_desc'] || ''; defaultShipping = globalMetafields['shogun_product_def_shipping'] || ''; } else { defaultFeatures = globalMetafields['generic_default_features'] || ''; defaultDescription = globalMetafields['generic_default_description'] || ''; defaultShipping = globalMetafields['generic_default_shipping'] || ''; } function processMetafieldContent(fieldValue, defaultValue) { let content = fieldValue || defaultValue || ''; if (content && typeof content === 'string' && content.trim().startsWith('{')) { try { const parsed = JSON.parse(content); if (parsed && typeof parsed === 'object' && parsed.type === 'root') { content = parseRichTextToHTML(parsed); } } catch (error) { } } return content; } const featuresContent = processMetafieldContent(featuresField, defaultFeatures); const descriptionContent = processMetafieldContent(descriptionField, defaultDescription); const shippingContent = processMetafieldContent(shippingField, defaultShipping); const featuresHtml = buildSectionHtml(featuresContent, featuresTitle); const descriptionHtml = buildSectionHtml(descriptionContent, descriptionTitle); const shippingHtml = buildSectionHtml(shippingContent, shippingTitle); productDescriptionsCache[product.handle] = { features: featuresHtml, description: descriptionHtml, shipping: shippingHtml, fullHtml: `
${featuresHtml} ${descriptionHtml} ${shippingHtml}
` }; } function buildSectionHtml(content, title) { if (!content) return ''; if (content.includes("hide-this-block")) { return ''; } else if (content.includes("use-just-text")) { return content.replace(/use-just-text/g, '').trim(); } else { return `
${title}
${content}
`; } } async function preloadAllProducts(collectionData) { if (!collectionData || !collectionData.products) { console.warn('No collection data available for preloading'); return; } const productHandles = collectionData.products.edges .map(edge => edge.node.handle) .filter(handle => handle && !productCache[handle]); const fetchPromises = productHandles.map(handle => fetchSingleProductData(handle).then(productData => ({ handle, data: productData })) ); try { const results = await Promise.all(fetchPromises); results.forEach(result => { if (result.data) { productCache[result.handle] = result.data; } }); } catch (error) { console.error('Error preloading products:', error); } } async function cacheSilhouetteProducts() { const allCollectionProducts = []; if (singularCollectionData && singularCollectionData.products) { allCollectionProducts.push(...singularCollectionData.products.edges.map(edge => edge.node)); } if (kitCollectionData && kitCollectionData.products) { allCollectionProducts.push(...kitCollectionData.products.edges.map(edge => edge.node)); } if (allCollectionProducts.length === 0) { console.log('cacheSilhouetteProducts: No collection products found'); return; } const allSilhouetteProductIds = new Set(); allCollectionProducts.forEach(product => { const silhouetteProductsString = getMetafieldValue(product, 'products_for_silhouette_selector_page_version__4_max'); if (silhouetteProductsString) { try { const productIds = JSON.parse(silhouetteProductsString); if (Array.isArray(productIds)) { productIds.forEach(id => allSilhouetteProductIds.add(id)); } } catch (error) { console.warn(`cacheSilhouetteProducts: Error parsing silhouette products for ${product.handle}:`, error); } } }); if (allSilhouetteProductIds.size === 0) { console.log('cacheSilhouetteProducts: No silhouette products found in any collection products'); return; } const uniqueSilhouetteIds = Array.from(allSilhouetteProductIds); const silhouetteFetchPromises = uniqueSilhouetteIds.map(productId => fetchProductById(productId).then(productData => ({ id: productId, data: productData })) ); try { const silhouetteResults = await Promise.all(silhouetteFetchPromises); let cachedCount = 0; for (const result of silhouetteResults) { if (result.data && result.data.handle) { if (!productCache[result.data.handle]) { productCache[result.data.handle] = result.data; cachedCount++; const matchingSilhouetteProductId = getMetafieldValue(result.data, 'matching_kit_product'); if (matchingSilhouetteProductId) { try { const matchingSilhouetteProduct = await fetchProductById(matchingSilhouetteProductId); if (matchingSilhouetteProduct && matchingSilhouetteProduct.handle && !productCache[matchingSilhouetteProduct.handle]) { productCache[matchingSilhouetteProduct.handle] = matchingSilhouetteProduct; cachedCount++; } } catch (error) { console.warn(`cacheSilhouetteProducts: Failed to fetch matching product for silhouette ${result.data.handle}:`, error); } } const silhouetteCollectionHandle = getMetafieldValue(result.data, 'swatch_selector_collection'); if (silhouetteCollectionHandle) { try { const silhouetteCollectionData = await fetchCollectionData(silhouetteCollectionHandle); if (silhouetteCollectionData && silhouetteCollectionData.products) { for (const edge of silhouetteCollectionData.products.edges) { const collectionProduct = edge.node; if (collectionProduct.handle && !productCache[collectionProduct.handle]) { const fullProductData = await fetchSingleProductData(collectionProduct.handle); if (fullProductData) { productCache[collectionProduct.handle] = fullProductData; cachedCount++; } } } } } catch (error) { console.warn(`cacheSilhouetteProducts: Failed to fetch collection for silhouette ${result.data.handle}:`, error); } } } } } } catch (error) { console.error('cacheSilhouetteProducts: Error caching silhouette products:', error); } } const pendingRequests = new Map(); async function deduplicatedFetch(key, fetchFunction) { if (pendingRequests.has(key)) { return pendingRequests.get(key); } const promise = fetchFunction().finally(() => { pendingRequests.delete(key); }); pendingRequests.set(key, promise); return promise; } async function fetchProductData(handle) { if (!handle) { console.error('Product handle is missing. Cannot fetch product data.'); return null; } if (productCache[handle]) { productDataGlobal = productCache[handle]; await setCurrentActiveCollectionForProduct(productDataGlobal); await renderProductUI(productDataGlobal); console.log("productDataGlobal: ", productDataGlobal); return productDataGlobal; } const cacheKey = `product-${handle}`; return deduplicatedFetch(cacheKey, async () => { const query = ` query @inContext(country: ${COUNTRY_ISO_CODE}) { product(handle: "${handle}") { id title availableForSale handle tags descriptionHtml onlineStoreUrl featuredImage { url altText } images(first: 15) { edges { node { url altText } } } options { name values } ${PRODUCT_GRAPHQL_METAFIELD_QUERY} variants(first: 50) { edges { node { id title availableForSale price { amount } compareAtPrice { amount } selectedOptions { name value } image { url altText } } } } } } `; try { const response = await fetch(GRAPHQL_URL_VERSION, { method: 'POST', headers: graphqlHeadersObj, body: query }); const res = await response.json(); console.log("global product data res: ", res.data.product); if (res.data && res.data.product) { productDataGlobal = res.data.product; productCache[handle] = productDataGlobal; processProductDescriptions(productDataGlobal); await setCurrentActiveCollectionForProduct(productDataGlobal); await renderProductUI(productDataGlobal); console.log("productDataGlobal: ", productDataGlobal); return productDataGlobal; } else if (res.errors) { console.error('GraphQL Errors:', res.errors); document.querySelector(`.pdp-container[data-component-id="${componentId}"]`).innerHTML = '

Error: Could not load product data (GraphQL error). Check console.

'; } else { console.warn('Product data not found in GraphQL response, or response structure unexpected.', res); document.querySelector(`.pdp-container[data-component-id="${componentId}"]`).innerHTML = '

Error: Product data not found. Check console.

'; } } catch (error) { console.error('Fetch error in query: ', error); document.querySelector(`.pdp-container[data-component-id="${componentId}"]`).innerHTML = '

Error: Failed to load product data (Fetch error). Please try again later.

'; } return null; }); } async function lazyLoadFullProductData(handle) { if (!handle || productCache[handle]?.fullDataLoaded) { return productCache[handle]; } const cacheKey = `product-full-${handle}`; return deduplicatedFetch(cacheKey, async () => { const query = ` query @inContext(country: ${COUNTRY_ISO_CODE}) { product(handle: "${handle}") { images(first: 200) { edges { node { url altText } } } variants(first: 200) { edges { node { id title availableForSale price { amount } compareAtPrice { amount } selectedOptions { name value } image { url altText } } } } } } `; try { const response = await fetch(GRAPHQL_URL_VERSION, { method: 'POST', headers: graphqlHeadersObj, body: query }); const res = await response.json(); if (res.data && res.data.product && productCache[handle]) { productCache[handle].images = res.data.product.images; productCache[handle].variants = res.data.product.variants; productCache[handle].fullDataLoaded = true; return productCache[handle]; } } catch (error) { console.error(`Error lazy loading full data for ${handle}:`, error); } return productCache[handle]; }); } function setupLazyLoading() { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const handle = entry.target.dataset.productHandle; if (handle && !productCache[handle]?.fullDataLoaded) { lazyLoadFullProductData(handle); observer.unobserve(entry.target); } } }); }, { rootMargin: '100px' }); document.querySelectorAll('[data-product-handle]').forEach(element => { observer.observe(element); }); } async function renderProductUI(product) { let pdpContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"]`); if (!pdpContainer) { console.warn(`PDP container not found with component ID "${componentId}", trying fallback selector`); pdpContainer = document.querySelector('.pdp-container'); } if (pdpContainer && product) { pdpContainer.setAttribute('data-current-product', product.handle); const productType = getMetafieldValue(product, 'product_type') || ''; pdpContainer.setAttribute('data-product-type', productType); } const imageContainer = pdpContainer?.querySelector('.pdp-image-container'); const infoContainer = pdpContainer?.querySelector('.pdp-info-container'); if (!product) { if (imageContainer) imageContainer.innerHTML = ''; if (infoContainer) infoContainer.innerHTML = '

Error: Product data is null. Cannot render UI.

'; return; } if (!imageContainer || !infoContainer) { console.error('PDP image or info container not found in the DOM.'); console.error('Debug info:', { componentId: componentId, pdpContainer: pdpContainer, imageContainer: imageContainer, infoContainer: infoContainer }); return; } try { renderProductImages(product, imageContainer); } catch (error) { console.error("renderProductUI: Error rendering product images:", error); if (product.featuredImage) { imageContainer.innerHTML = ` `; } } try { await renderProductInfo(product, infoContainer); } catch (error) { console.error("renderProductUI: Error rendering product info:", error); let basicInfo = `

${product.title}

`; const firstVariant = product.variants.edges[0]?.node; if (firstVariant) { basicInfo += `
${CURRENCY_SYMBOL}${parseFloat(firstVariant.price.amount).toFixed(2)}
`; basicInfo += `
`; } infoContainer.innerHTML = basicInfo; } try { initializeProductInteractions(product); } catch (error) { console.error("renderProductUI: Error initializing product interactions:", error); } if (pdpContainer) { pdpContainer.setAttribute('data-content-loaded', 'true'); } try { setupLazyLoading(); } catch (error) { console.error("renderProductUI: Error setting up lazy loading:", error); } } function renderProductImages(product, imageContainer) { cleanupImageContainer(imageContainer); let allGalleryHtml = ''; const imagesByAlt = {}; const commonImages = []; const allSpecificAlts = new Set(); const isSingleVariant = product.variants.edges.length === 1; let singleVariantOptionValues = []; if (isSingleVariant && product.variants.edges[0]?.node?.selectedOptions) { singleVariantOptionValues = product.variants.edges[0].node.selectedOptions.map(opt => opt.value); } if (product.images && product.images.edges.length > 0) { product.images.edges.forEach(edge => { const imageNode = edge.node; const alt = imageNode.altText; const isVariantOptionValue = isSingleVariant && singleVariantOptionValues.includes(alt); if (!alt || alt.trim() === '' || alt === product.title || alt === 'Default Title' || isVariantOptionValue) { commonImages.push(imageNode); } else { allSpecificAlts.add(alt); if (!imagesByAlt[alt]) { imagesByAlt[alt] = []; } imagesByAlt[alt].push(imageNode); } }); } else if (product.featuredImage) { commonImages.push(product.featuredImage); } const galleryKeys = [...allSpecificAlts]; const materialOptionForGalleries = product.options.find(option => option && option.name && (option.name.toLowerCase() === 'material' || option.name.toLowerCase() === 'color')); if (materialOptionForGalleries && !isSingleVariant) { for(let i = 0; i < materialOptionForGalleries.values.length; i++) { let value = materialOptionForGalleries.values[i]; if (!galleryKeys.includes(value)) { galleryKeys.push(value); if (!imagesByAlt[value]) { imagesByAlt[value] = []; } } for(let i = 0; i < product.variants.edges.length; i++) { let vEdge = product.variants.edges[i]; const variant = vEdge.node; const hasThisOptionValue = variant.selectedOptions.some(so => so.name === materialOptionForGalleries.name && so.value === value ); if (hasThisOptionValue && variant.image) { const variantImageAlt = variant.image.altText; if (variantImageAlt && variantImageAlt !== product.title && variantImageAlt === value) { } else if (!variantImageAlt || variantImageAlt === product.title) { } else { const imageAlreadyInGallery = imagesByAlt[value].some(img => img.url === variant.image.url); if (!imageAlreadyInGallery) { imagesByAlt[value].push(variant.image); } } } }; }; } if (galleryKeys.length === 0 && commonImages.length > 0) { galleryKeys.push(product.title); imagesByAlt[product.title] = []; } if (commonImages.length > 0 && !galleryKeys.includes(product.title)) { galleryKeys.push(product.title); if (!imagesByAlt[product.title]) { imagesByAlt[product.title] = []; } } if (isSingleVariant && commonImages.length > 0) { galleryKeys.length = 0; galleryKeys.push(product.title); if (!imagesByAlt[product.title]) { imagesByAlt[product.title] = []; } } galleryKeys.forEach(currentAltKey => { const specificImagesForThisKey = imagesByAlt[currentAltKey] || []; const allImagesForThisGallery = [...specificImagesForThisKey, ...commonImages].filter((img, index, self) => index === self.findIndex((t) => t.url === img.url) ); if (allImagesForThisGallery.length === 0) return; allGalleryHtml += `'; if (allImagesForThisGallery.length > 1) { allGalleryHtml += `'; } }); if (!allGalleryHtml && product.featuredImage) { const altKey = product.featuredImage.altText && product.featuredImage.altText !== product.title ? product.featuredImage.altText : product.title; allGalleryHtml += ``; if (!galleryKeys.includes(altKey)) galleryKeys.push(altKey); } imageContainer.innerHTML = allGalleryHtml; setupMainImageLoadHandling(imageContainer, product); initializeFlickityCarousels(product, galleryKeys); } function setupMainImageLoadHandling(imageContainer, product) { if (!imageContainer || !imageContainer.hasAttribute('data-height-locked')) return; const firstMainImage = imageContainer.querySelector('.carousel-main.product_gallery_pdp_v2 .main-gallery-cell img'); const releaseHeightLock = () => { imageContainer.style.minHeight = ''; imageContainer.removeAttribute('data-height-locked'); loadNavImages(imageContainer); }; if (firstMainImage) { if (firstMainImage.complete) { releaseHeightLock(); } else { firstMainImage.addEventListener('load', releaseHeightLock, { once: true }); firstMainImage.addEventListener('error', releaseHeightLock, { once: true }); } } else { releaseHeightLock(); } setTimeout(() => { if (imageContainer.hasAttribute('data-height-locked')) { console.warn('Height lock timeout reached, releasing lock'); releaseHeightLock(); } }, 5000); } function loadNavImages(imageContainer) { const navImages = imageContainer.querySelectorAll('.carousel-nav img[data-src]'); navImages.forEach(img => { if (img.dataset.src) { img.src = img.dataset.src; img.removeAttribute('data-src'); } }); } async function renderProductInfo(product, infoContainer) { let productInfoHtml = ''; let productArchetype = getMetafieldValue(product, 'product_archetype'); const firstVariant = product.variants.edges[0]?.node; const pdpFlareHtml = generatePdpFlareHtml(product) || ''; const flareHtml = generateFlareForVariant(firstVariant) || pdpFlareHtml; productInfoHtml += '
'; productInfoHtml += '
'; productInfoHtml += '5 stars'; productInfoHtml += '43776 REVIEWS'; productInfoHtml += '
'; productInfoHtml += '
' + flareHtml + '
'; productInfoHtml += '
'; productInfoHtml += '
'; const displayTitle = productArchetype || product.title || 'Product'; productInfoHtml += `

${displayTitle}

`; productInfoHtml += '
'; if (firstVariant) { productInfoHtml += `${CURRENCY_SYMBOL}${parseFloat(firstVariant.price.amount).toFixed(2)}`; if (firstVariant.compareAtPrice && parseFloat(firstVariant.compareAtPrice.amount) > parseFloat(firstVariant.price.amount)) { productInfoHtml += `${CURRENCY_SYMBOL}${parseFloat(firstVariant.compareAtPrice.amount).toFixed(2)}`; productInfoHtml += '' + flareHtml + ''; } } productInfoHtml += '
'; const materialOption = product.options.find(option => option && option.name && (option.name.toLowerCase() === 'material' || option.name.toLowerCase() === 'color')); if (currentActiveCollection) { try { const kitSelectorHTML = await buildKitSelectorHTML(product, currentActiveCollection); productInfoHtml += kitSelectorHTML; } catch (error) { console.error("renderProductInfo: Error generating kit selector HTML:", error); } } if (materialOption) { let selectedMaterialText = ''; if (firstVariant && firstVariant.selectedOptions) { selectedMaterialText = firstVariant.selectedOptions.find(o => o.name === materialOption.name)?.value || ''; } productInfoHtml += `

MATERIAL: ${selectedMaterialText}

`; productInfoHtml += '
'; if (currentActiveCollection && currentActiveCollection.products) { const currentProductHandle = document.querySelector('.pdp-container')?.getAttribute('data-current-product') || product.handle; currentActiveCollection.products.edges.forEach(edge => { const collectionProduct = edge.node; if (!collectionProduct.availableForSale) return; const selectedSwatchImage = getMetafieldValue(collectionProduct, 'shogun_swatch_image_selected'); const notSelectedSwatchImage = getMetafieldValue(collectionProduct, 'shogun_swatch_image_not_select'); if (!selectedSwatchImage || !notSelectedSwatchImage) return; const productColorway = getMetafieldValue(collectionProduct, 'colorway') || collectionProduct.title; const matchesMaterialValue = materialOption.values.some(value => value === productColorway || collectionProduct.title.includes(value) || collectionProduct.handle.includes(value.toLowerCase().replace(/\s+/g, '-')) ); if (!matchesMaterialValue) return; const isCurrentProduct = collectionProduct.handle === currentProductHandle; const swatchImage = isCurrentProduct ? selectedSwatchImage : notSelectedSwatchImage; const materialValue = materialOption.values.find(value => value === productColorway || collectionProduct.title.includes(value) || collectionProduct.handle.includes(value.toLowerCase().replace(/\s+/g, '-')) ) || productColorway; productInfoHtml += `
`; }); } else { materialOption.values.forEach(value => { const variantForSwatch = product.variants.edges.find(vEdge => vEdge.node.selectedOptions.some(so => so.name === materialOption.name && so.value === value) ); const swatchImage = variantForSwatch && variantForSwatch.node.image ? variantForSwatch.node.image.url : (product.featuredImage ? product.featuredImage.url : ''); const isSelected = selectedMaterialText === value; productInfoHtml += `
`; }); } productInfoHtml += '
'; productInfoHtml += `
`; } productInfoHtml += renderSilhouetteSelector(); const productType = getMetafieldValue(product, 'product_type') || ''; if (productType === 'Ring') { productInfoHtml += renderWhatsInTheKitComponent(); } if (productType === 'Ring') { const sizeOption = product.options.find(option => option && option.name && option.name.toLowerCase() === 'size'); if (sizeOption && sizeOption.values.length > 0) { const ringModalImage = getMetafieldValue(product, 'ring__i_dont_know_my_size_modal_image') || ''; let selectedSizeValue = ''; if (firstVariant && firstVariant.selectedOptions) { const selectedSizeOption = firstVariant.selectedOptions.find(o => o.name === sizeOption.name); selectedSizeValue = selectedSizeOption ? selectedSizeOption.value : ''; } productInfoHtml += `
Size: *
`; if (ringModalImage) { window.ringModalImageUrl = ringModalImage; } } } else { const styleOption = product.options.find(option => option && option.name && (option.name.toLowerCase() === 'style' || option.name.toLowerCase() === 'select a style')); if (styleOption && styleOption.values.length > 1) { productInfoHtml += `

STYLE:

`; productInfoHtml += '
'; styleOption.values.forEach(value => { const variantForStyle = product.variants.edges.find(vEdge => vEdge.node.selectedOptions.some(so => so.name === styleOption.name && so.value === value) ); const styleImage = variantForStyle && variantForStyle.node.image ? variantForStyle.node.image.url : (product.featuredImage ? product.featuredImage.url : ''); let isSelected = false; if (firstVariant && firstVariant.selectedOptions) { isSelected = firstVariant.selectedOptions.some(o => o.name === styleOption.name && o.value === value); } productInfoHtml += `
${value}
`; }); productInfoHtml += '
'; productInfoHtml += `
`; } } productInfoHtml += renderUpsellSlider(); const addToCartLabel = product.availableForSale ? "Add to Cart" : "Sold Out"; const ringSizeRequiredClass = productType === 'Ring' ? 'ring-size-required' : ''; productInfoHtml += `
`; productInfoHtml += buildFeaturesSection(); infoContainer.innerHTML = productInfoHtml; // Initialize silhouette container visibility for initial page load initializeSilhouetteContainerVisibility(); // Mark initial page load as complete initialPageLoadComplete = true; initializeRingSizeModal(); initializeWhatsInTheKitModal(); } function initializeRingSizeModal() { $(document).off('click', '.ring-size-modal'); $(document).on('click', '.ring-size-modal', function(e) { e.preventDefault(); let modalImgURL = window.ringModalImageUrl || ''; if (!modalImgURL) { modalImgURL = "../cdn/blog-images/files/POPUP_SIZE_CHART_2.png﹖v=1706119456"; } if (typeof $.confirm === 'function') { $.confirm({ backgroundDismiss: true, useBootstrap: false, title: false, cancelButton: false, closeIcon: true, content: '' + '', closeIcon: true, buttons: { ok: { isHidden: true, action: function () { } } } }); } else { console.warn('jQuery Confirm library not available'); } }); } function initializeWhatsInTheKitModal() { $(document).off('click', '.theridge-witk_v1__warranty-modal'); $(document).on('click', '.theridge-witk_v1__warranty-modal', function(e) { e.preventDefault(); let modalImgURL = $(this).closest('.theridge-witk_v1__container').data('modal-img') || ''; if (!modalImgURL) { modalImgURL = "../cdn/blog-images/files/Ring_Popup_1_390x572_28044854-f343-4cde-a62b-42a70e0ac069.png﹖v=1706052415"; } if (typeof $.confirm === 'function') { $.confirm({ backgroundDismiss: true, useBootstrap: false, fullScreen: true, title: false, cancelButton: false, closeIcon: true, content: '' + '', closeIcon: true, buttons: { ok: { isHidden: true, action: function () { } } } }); } else { console.warn('jQuery Confirm library not available'); } }); } function shouldShowPageDots() { return window.innerWidth < 768; } function handleMobileDotPositioning(mainCarouselEl, navCarouselEl) { if (!mainCarouselEl || !navCarouselEl) return; function repositionDots() { const isMobile = window.innerWidth <= 767; let dots = navCarouselEl.querySelector('.flickity-page-dots'); if (!dots) { dots = mainCarouselEl.querySelector('.flickity-page-dots'); } if (!dots) { const navFlickityInstance = navCarouselEl.flickityInstance || window.Flickity?.data(navCarouselEl); if (navFlickityInstance && navFlickityInstance.pageDotsInstance) { navFlickityInstance.pageDotsInstance.activate(); dots = navCarouselEl.querySelector('.flickity-page-dots'); } } if (dots) { if (isMobile) { if (dots.parentElement !== mainCarouselEl) { mainCarouselEl.appendChild(dots); } } else { if (dots.parentElement !== navCarouselEl) { navCarouselEl.appendChild(dots); } } dots.style.display = 'block'; } } setTimeout(() => { repositionDots(); }, 50); window.removeEventListener('resize', repositionDots); window.addEventListener('resize', repositionDots); } function cleanupImageContainer(imageContainer) { if (!imageContainer) return; const existingMainCarousels = imageContainer.querySelectorAll('.carousel-main.flickity-enabled'); const existingNavCarousels = imageContainer.querySelectorAll('.carousel-nav.flickity-enabled'); existingMainCarousels.forEach(carousel => { try { const flickityInstance = carousel.flickityInstance || window.Flickity?.data(carousel); if (flickityInstance) { flickityInstance.off(); flickityInstance.destroy(); } } catch (error) { console.warn('Error destroying existing main carousel:', error); } }); existingNavCarousels.forEach(carousel => { try { const flickityInstance = carousel.flickityInstance || window.Flickity?.data(carousel); if (flickityInstance) { flickityInstance.off(); flickityInstance.destroy(); } } catch (error) { console.warn('Error destroying existing nav carousel:', error); } }); const flickityElements = imageContainer.querySelectorAll('.flickity-prev-next-button, .flickity-page-dots, .flickity-viewport'); flickityElements.forEach(el => { try { el.remove(); } catch (error) { console.warn('Error removing Flickity element:', error); } }); const flickityEnabledElements = imageContainer.querySelectorAll('.flickity-enabled'); flickityEnabledElements.forEach(el => { el.classList.remove('flickity-enabled'); }); } function initializeFlickityCarousels(product, galleryKeys) { Object.values(flickityInstances).forEach(instances => { try { if (instances.main) { instances.main.off(); instances.main.destroy(); } } catch (error) { console.warn('Error destroying main Flickity instance:', error); } try { if (instances.nav) { instances.nav.off(); instances.nav.destroy(); } } catch (error) { console.warn('Error destroying nav Flickity instance:', error); } }); flickityInstances = {}; let imageContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .pdp-image-container`); if (!imageContainer) { console.warn(`Image container not found with component ID "${componentId}", trying fallback`); imageContainer = document.querySelector('.pdp-image-container'); } const containerSelector = imageContainer?.closest('.pdp-container')?.getAttribute('data-component-id') === componentId ? `.pdp-container[data-component-id="${componentId}"]` : ''; document.querySelectorAll(`${containerSelector} .carousel-main.product_gallery_pdp_v2`.trim()).forEach(mainCarouselEl => { const alt = mainCarouselEl.dataset.galleryAlt; if (!alt) return; if (mainCarouselEl.classList.contains('flickity-enabled')) { mainCarouselEl.classList.remove('flickity-enabled'); } const navCarouselEl = imageContainer.querySelector(`.carousel-nav.product_gallery_nav_pdp_v2[data-gallery-alt="${alt}"]`); let flktyMainInstance = null; let flktyNavInstance = null; const imagesInMain = mainCarouselEl.querySelectorAll('.carousel-cell').length; if (mainCarouselEl && typeof Flickity !== 'undefined' && imagesInMain > 0) { try { flktyMainInstance = new Flickity(mainCarouselEl, { pageDots: false, prevNextButtons: imagesInMain > 1, wrapAround: imagesInMain > 1, adaptiveHeight: false, arrowShape: {x0: 10, x1: 60, y1: 50, x2: 65, y2: 45, x3: 20}, }); flickityInstances[alt] = flickityInstances[alt] || {}; flickityInstances[alt].main = flktyMainInstance; if (navCarouselEl) { if (navCarouselEl.classList.contains('flickity-enabled')) { navCarouselEl.classList.remove('flickity-enabled'); } const imagesInNav = navCarouselEl.querySelectorAll('.carousel-cell').length; if (imagesInNav > 0) { try { flktyNavInstance = new Flickity(navCarouselEl, { draggable: true, freeScroll: false, dragThreshold: 3, setGallerySize: false, friction: 0.8, selectedAttraction: 0.2, wrapAround: true, resize: false, asNavFor: mainCarouselEl, contain: true, pageDots: shouldShowPageDots(), prevNextButtons: false, cellAlign: 'left', }); flickityInstances[alt].nav = flktyNavInstance; flktyMainInstance.on('select', function(index) { updateNavSelectedState(alt, index); }); updateNavSelectedState(alt, 0); handleMobileDotPositioning(mainCarouselEl, navCarouselEl); setTimeout(() => { try { if (flktyMainInstance && !flktyMainInstance.isDestroyed) { flktyMainInstance.resize(); } if (flktyNavInstance && !flktyNavInstance.isDestroyed) { flktyNavInstance.resize(); handleMobileDotPositioning(mainCarouselEl, navCarouselEl); } } catch (resizeError) { console.warn('Error during Flickity resize:', resizeError); } }, 100); } catch (navError) { console.warn('Error creating nav Flickity instance:', navError); if (navCarouselEl) navCarouselEl.remove(); } } else { navCarouselEl.remove(); } } } catch (mainError) { console.warn('Error creating main Flickity instance:', mainError); } } else if (imagesInMain === 0 && mainCarouselEl) { mainCarouselEl.remove(); if (navCarouselEl) navCarouselEl.remove(); } }); showInitialGallery(product); } function showInitialGallery(product) { let imageContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .pdp-image-container`); if (!imageContainer) { imageContainer = document.querySelector('.pdp-image-container'); } const firstVariant = product.variants.edges[0]?.node; let initialGalleryKeyToShow = null; if (firstVariant) { if (firstVariant.image && firstVariant.image.altText && firstVariant.image.altText !== product.title && firstVariant.image.altText !== 'Default Title' && flickityInstances[firstVariant.image.altText]) { initialGalleryKeyToShow = firstVariant.image.altText; } else { const materialOpt = product.options.find(opt => opt.name?.toLowerCase() === 'material' || opt.name?.toLowerCase() === 'color'); if (materialOpt) { const firstVariantMaterialValue = firstVariant.selectedOptions.find(so => so.name === materialOpt.name)?.value; if (firstVariantMaterialValue && flickityInstances[firstVariantMaterialValue]) { initialGalleryKeyToShow = firstVariantMaterialValue; } } } } if (!initialGalleryKeyToShow && flickityInstances[product.title]) { initialGalleryKeyToShow = product.title; } else if (!initialGalleryKeyToShow && Object.keys(flickityInstances).length > 0) { initialGalleryKeyToShow = Object.keys(flickityInstances).find(key => flickityInstances[key].main); } if (initialGalleryKeyToShow && flickityInstances[initialGalleryKeyToShow]?.main) { const mainToShowEl = imageContainer.querySelector(`.carousel-main[data-gallery-alt="${initialGalleryKeyToShow}"]`); const navToShowEl = imageContainer.querySelector(`.carousel-nav[data-gallery-alt="${initialGalleryKeyToShow}"]`); if (mainToShowEl) mainToShowEl.style.display = 'block'; if (navToShowEl) navToShowEl.style.display = 'block'; currentVisibleAlt = initialGalleryKeyToShow; flickityInstances[initialGalleryKeyToShow].main.resize(); if (flickityInstances[initialGalleryKeyToShow].nav) { flickityInstances[initialGalleryKeyToShow].nav.resize(); } if (firstVariant && flickityInstances[initialGalleryKeyToShow].main) { const activeMainFlkty = flickityInstances[initialGalleryKeyToShow].main; if (activeMainFlkty.cells.length > 0) { activeMainFlkty.select(0, false, true); } const currentIndex = activeMainFlkty.selectedIndex; updateNavSelectedState(initialGalleryKeyToShow, currentIndex); } // Hide navigation on page load for 3 seconds hideNavOnPageLoad(); const visibleMainImage = mainToShowEl.querySelector('.main-gallery-cell img'); if (visibleMainImage && imageContainer.hasAttribute('data-height-locked')) { const releaseHeightLock = () => { imageContainer.style.minHeight = ''; imageContainer.removeAttribute('data-height-locked'); loadNavImages(imageContainer); }; if (visibleMainImage.complete) { releaseHeightLock(); } else { visibleMainImage.addEventListener('load', releaseHeightLock, { once: true }); visibleMainImage.addEventListener('error', releaseHeightLock, { once: true }); } } } else if (product.featuredImage && !initialGalleryKeyToShow) { const singleImageGalleryKey = (product.featuredImage.altText && product.featuredImage.altText !== product.title) ? product.featuredImage.altText : product.title; const mainToShowEl = imageContainer.querySelector(`.carousel-main[data-gallery-alt="${singleImageGalleryKey}"]`); if (mainToShowEl) { mainToShowEl.style.display = 'block'; currentVisibleAlt = singleImageGalleryKey; if (flickityInstances[singleImageGalleryKey] && flickityInstances[singleImageGalleryKey].main) { flickityInstances[singleImageGalleryKey].main.resize(); } else if (mainToShowEl.classList.contains('flickity-enabled') === false && typeof Flickity !== 'undefined') { const tempFlkty = new Flickity(mainToShowEl, {adaptiveHeight: false, pageDots: false, prevNextButtons: false, wrapAround: false}); flickityInstances[singleImageGalleryKey] = {main: tempFlkty}; } const visibleMainImage = mainToShowEl.querySelector('.main-gallery-cell img'); if (visibleMainImage && imageContainer.hasAttribute('data-height-locked')) { const releaseHeightLock = () => { imageContainer.style.minHeight = ''; imageContainer.removeAttribute('data-height-locked'); loadNavImages(imageContainer); }; if (visibleMainImage.complete) { releaseHeightLock(); } else { visibleMainImage.addEventListener('load', releaseHeightLock, { once: true }); visibleMainImage.addEventListener('error', releaseHeightLock, { once: true }); } } } } } function initializeProductInteractions(product) { const firstVariant = product.variants.edges[0]?.node; currentSelectedOptions = {}; if (firstVariant && firstVariant.selectedOptions) { firstVariant.selectedOptions.forEach(opt => { currentSelectedOptions[opt.name] = opt.value; }); updateProductDetails(firstVariant, true); } else if (product.featuredImage && !firstVariant) { const dummyVariantForFeaturedImage = { price: product.price || {amount: '0'}, compareAtPrice: product.compareAtPrice || null, availableForSale: product.availableForSale, selectedOptions: [], image: product.featuredImage }; updateProductDetails(dummyVariantForFeaturedImage, true); } addEventListeners(); initializeAccordion(); addKitSelectorEventListeners(); addStandaloneProductSelectorEventListeners(); updateKitSelectorState(product); initializeUpsellSlider(); } function hideThumbnailNavTemporarily() { const imageContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .pdp-image-container`) || document.querySelector('.pdp-image-container'); if (!imageContainer) return; imageContainer.classList.add('nav-hidden'); if (imageContainer._navHiddenTimer) { clearTimeout(imageContainer._navHiddenTimer); } imageContainer._navHiddenTimer = setTimeout(() => { imageContainer.classList.remove('nav-hidden'); imageContainer._navHiddenTimer = null; }, 2200); } function hideNavOnPageLoad() { const imageContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .pdp-image-container`) || document.querySelector('.pdp-image-container'); if (!imageContainer) return; imageContainer.classList.add('nav-hidden'); if (imageContainer._pageLoadNavTimer) { clearTimeout(imageContainer._pageLoadNavTimer); } imageContainer._pageLoadNavTimer = setTimeout(() => { imageContainer.classList.remove('nav-hidden'); imageContainer._pageLoadNavTimer = null; }, 2000); } function updateNavSelectedState(galleryAlt, selectedIndex) { const navCarousel = document.querySelector(`.carousel-nav[data-gallery-alt="${galleryAlt}"]`); if (!navCarousel) return; navCarousel.querySelectorAll('.carousel-cell').forEach(cell => { cell.classList.remove('is-nav-selected'); }); const selectedCell = navCarousel.querySelector(`.carousel-cell[data-index="${selectedIndex}"]`); if (selectedCell) { selectedCell.classList.add('is-nav-selected'); } } function updateProductDetails(variant, isInitialLoad = false) { const currentPrice = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .current-price`) || document.querySelector('.current-price'); const compareAtPrice = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .compare-at-price`) || document.querySelector('.compare-at-price'); const addToCartButton = document.getElementById(`AddToCart-${componentId}`) || document.getElementById('AddToCart'); const addToCartText = addToCartButton?.querySelector('.text'); const selectedMaterialSpan = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .selected-material`) || document.querySelector('.selected-material'); let targetGalleryAlt = null; if (variant.image && variant.image.altText && variant.image.altText !== productDataGlobal.title && variant.image.altText !== 'Default Title' && flickityInstances[variant.image.altText]) { targetGalleryAlt = variant.image.altText; } else { const materialOption = productDataGlobal.options.find(opt => opt && opt.name && (opt.name.toLowerCase() === 'material' || opt.name.toLowerCase() === 'color')); if (materialOption) { const selectedOptValue = variant.selectedOptions.find(so => so.name === materialOption.name)?.value; if (selectedOptValue && flickityInstances[selectedOptValue]) { targetGalleryAlt = selectedOptValue; } } } if ((!targetGalleryAlt || !flickityInstances[targetGalleryAlt])) { if (flickityInstances[productDataGlobal.title]) { targetGalleryAlt = productDataGlobal.title; } else if (Object.keys(flickityInstances).length > 0) { targetGalleryAlt = Object.keys(flickityInstances).find(key => flickityInstances[key].main); } } if (targetGalleryAlt && targetGalleryAlt !== currentVisibleAlt && flickityInstances[targetGalleryAlt]?.main) { if (currentVisibleAlt && flickityInstances[currentVisibleAlt]) { const oldMainEl = document.querySelector(`.carousel-main.product_gallery_pdp_v2[data-gallery-alt="${currentVisibleAlt}"]`); const oldNavEl = document.querySelector(`.carousel-nav.product_gallery_nav_pdp_v2[data-gallery-alt="${currentVisibleAlt}"]`); if (oldMainEl) oldMainEl.style.display = 'none'; if (oldNavEl) oldNavEl.style.display = 'none'; } const newMainEl = document.querySelector(`.carousel-main.product_gallery_pdp_v2[data-gallery-alt="${targetGalleryAlt}"]`); const newNavEl = document.querySelector(`.carousel-nav.product_gallery_nav_pdp_v2[data-gallery-alt="${targetGalleryAlt}"]`); if (newMainEl) newMainEl.style.display = 'block'; if (newNavEl) newNavEl.style.display = 'block'; currentVisibleAlt = targetGalleryAlt; if (flickityInstances[targetGalleryAlt].main) flickityInstances[targetGalleryAlt].main.resize(); if (flickityInstances[targetGalleryAlt].nav) flickityInstances[targetGalleryAlt].nav.resize(); } if (!isInitialLoad && currentVisibleAlt && flickityInstances[currentVisibleAlt] && flickityInstances[currentVisibleAlt].main) { const activeMainFlkty = flickityInstances[currentVisibleAlt].main; let variantImageIndex = -1; if (variant.image && activeMainFlkty.cells) { const cells = activeMainFlkty.cells; for (let i = 0; i < cells.length; i++) { if (cells[i].element.dataset.imageUrl === variant.image.url) { variantImageIndex = i; break; } } } else if (productDataGlobal.featuredImage && activeMainFlkty.cells) { const cells = activeMainFlkty.cells; for (let i = 0; i < cells.length; i++) { if (cells[i].element.dataset.imageUrl === productDataGlobal.featuredImage.url) { variantImageIndex = i; break; } } } if (variantImageIndex !== -1) { activeMainFlkty.select(variantImageIndex, false, true); } else if (activeMainFlkty.cells && activeMainFlkty.cells.length > 0) { activeMainFlkty.select(0, false, true); } const currentIndex = activeMainFlkty.selectedIndex; updateNavSelectedState(currentVisibleAlt, currentIndex); } if (currentPrice) currentPrice.textContent = `${CURRENCY_SYMBOL}${parseFloat(variant.price.amount).toFixed(2)}`; if (compareAtPrice) { if (variant.compareAtPrice && parseFloat(variant.compareAtPrice.amount) > parseFloat(variant.price.amount)) { compareAtPrice.textContent = `${CURRENCY_SYMBOL}${parseFloat(variant.compareAtPrice.amount).toFixed(2)}`; compareAtPrice.style.display = ''; } else { compareAtPrice.style.display = 'none'; } } const newFlareHtml = generateFlareForVariant(variant); const mobileFlareContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .mobile-flare`) || document.querySelector('.mobile-flare'); const desktopFlareContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .desktop-flare`) || document.querySelector('.desktop-flare'); if (mobileFlareContainer) { mobileFlareContainer.innerHTML = newFlareHtml; } if (desktopFlareContainer) { desktopFlareContainer.innerHTML = newFlareHtml; } const materialOptionData = productDataGlobal.options.find(option => option && option.name && (option.name.toLowerCase() === 'material' || option.name.toLowerCase() === 'color')); if (materialOptionData && selectedMaterialSpan) { const selectedMatValue = variant.selectedOptions.find(so => so.name === materialOptionData.name)?.value; if (selectedMatValue) selectedMaterialSpan.textContent = selectedMatValue; document.querySelectorAll('.material-selector .swatch').forEach(el => { if (el.dataset.optionValue === selectedMatValue && el.dataset.optionName === materialOptionData.name) { el.classList.add('selected-swatch'); } else { el.classList.remove('selected-swatch'); } }); } if (addToCartButton && addToCartText) { if (variant.availableForSale) { addToCartButton.disabled = false; addToCartText.textContent = "Add to Cart"; addToCartButton.setAttribute('data-label', "Add to Cart"); } else { addToCartButton.disabled = true; addToCartText.textContent = "Sold Out"; addToCartButton.setAttribute('data-label', "Sold Out"); } } const styleOptionName = productDataGlobal.options.find(option => option && option.name && option.name.toLowerCase() === 'style')?.name; if (styleOptionName) { const selectedStyleValue = variant.selectedOptions.find(so => so.name === styleOptionName)?.value; document.querySelectorAll('.style-option').forEach(el => { el.classList.remove('selected'); if (el.dataset.optionValue === selectedStyleValue && el.dataset.optionName === styleOptionName) { el.classList.add('selected'); } }); } } function findVariantFromSelectedOptions(selectedOptions, productData = null) { const product = productData || productDataGlobal; if (!product || !product.variants) return null; return product.variants.edges.find(edge => { const variant = edge.node; return Object.entries(selectedOptions).every(([optionName, optionValue]) => { return variant.selectedOptions.some(variantOpt => variantOpt.name === optionName && variantOpt.value === optionValue); }); })?.node; } function handleOptionSelection(optionName, optionValue) { currentSelectedOptions[optionName] = optionValue; const matchedVariant = findVariantFromSelectedOptions(currentSelectedOptions); if (matchedVariant) { updateProductDetails(matchedVariant); } else { console.warn("No variant found for selection:", currentSelectedOptions); const addToCartButton = document.getElementById(`AddToCart-${componentId}`); if (addToCartButton) { const addToCartText = addToCartButton.querySelector('.text'); addToCartButton.disabled = true; if (addToCartText) { addToCartText.textContent = "Unavailable"; } } } } function addEventListeners() { addMaterialSelectorEventListeners(); const productType = getMetafieldValue(productDataGlobal, 'product_type') || ''; if (productType === 'Ring') { document.querySelectorAll(`.pdp-container[data-component-id="${componentId}"] .ridge-swatch-dropdown`).forEach(dropdown => { dropdown.addEventListener('change', function () { if (this.value !== 'placeholder') { handleOnVariantChange(this); const addToCartButton = document.getElementById(`AddToCart-${componentId}`); if (addToCartButton && addToCartButton.classList.contains('ring-size-required')) { addToCartButton.classList.remove('ring-size-required'); } } }); }); } document.querySelectorAll(`.pdp-container[data-component-id="${componentId}"] .style-selector .style-option`).forEach(optionElement => { optionElement.addEventListener('click', function () { const optionName = this.dataset.optionName; const optionValue = this.dataset.optionValue; handleOptionSelection(optionName, optionValue); }); }); document.querySelectorAll(`.pdp-container[data-component-id="${componentId}"] .silhouette-selector .silhouette-options`).forEach(silhouetteOption => { silhouetteOption.addEventListener('click', function () { const productHandle = this.dataset.productHandle; if (productHandle && productHandle !== productDataGlobal.handle) { animateSilhouetteOptionsTransition(); const upsellSlider = document.getElementById(`upsell-slider-${componentId}`); if (upsellSlider) { upsellSlider.style.display = 'none'; } hideThumbnailNavTemporarily(); switchToProduct(productHandle); } }); }); const silhouetteInfoIcon = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .silhouette-selector .silhouette-info-icon`); if (silhouetteInfoIcon) { silhouetteInfoIcon.addEventListener('click', function() { const infoIconImage = getMetafieldValue(productDataGlobal, 'info_icon_image'); if (infoIconImage && typeof $ !== 'undefined' && typeof $.confirm === 'function') { $.confirm({ backgroundDismiss: true, useBootstrap: false, title: false, cancelButton: false, closeIcon: true, content: ` `, buttons: { ok: { isHidden: true, action: function () {} } } }); } }); } } async function cacheDiscountProductData(discountProductHandle, currentProductHandle) { if (!discountProductHandle || !currentProductHandle) { console.warn('Missing handles:', { discountProductHandle, currentProductHandle }); return; } if (!sessionStorage.getItem(MINICART_DISCOUNT_PRODUCTS_SESSION_STORAGE_KEY)) { let newSessionStorageObj = {}; const discountProductObject = await getProductObject(discountProductHandle); if (discountProductObject) { newSessionStorageObj[discountProductHandle] = discountProductObject; sessionStorage.setItem(MINICART_DISCOUNT_PRODUCTS_SESSION_STORAGE_KEY, JSON.stringify(newSessionStorageObj)); } else { console.warn('Failed to fetch discount product object for:', discountProductHandle); } } else { let current = JSON.parse(sessionStorage.getItem(MINICART_DISCOUNT_PRODUCTS_SESSION_STORAGE_KEY)); if (!current[discountProductHandle]) { const discountProductObject = await getProductObject(discountProductHandle); if (discountProductObject) { current[discountProductHandle] = discountProductObject; sessionStorage.setItem(MINICART_DISCOUNT_PRODUCTS_SESSION_STORAGE_KEY, JSON.stringify(current)); } else { console.warn('Failed to fetch discount product object for:', discountProductHandle); } } else { console.log('Discount product already exists in session storage for:', discountProductHandle); } } if (!sessionStorage.getItem(PRODUCT_OBJECTS_WITH_DISCOUNT)) { let newObj = {}; newObj[currentProductHandle] = productDataGlobal; sessionStorage.setItem(PRODUCT_OBJECTS_WITH_DISCOUNT, JSON.stringify(newObj)); } else { let currentProductObjectsSessionStorage = JSON.parse(sessionStorage.getItem(PRODUCT_OBJECTS_WITH_DISCOUNT)); currentProductObjectsSessionStorage[currentProductHandle] = productDataGlobal; sessionStorage.setItem(PRODUCT_OBJECTS_WITH_DISCOUNT, JSON.stringify(currentProductObjectsSessionStorage)); } } async function getProductObject(productHandle) { if (!productHandle) return null; const DISCOUNT_PRODUCT_METAFIELD_QUERY = ` metafields(identifiers: [ {key: "product_archetype", namespace: "accentuate"}, {key: "colorway", namespace: "accentuate"}, {key: "minicart_discount_section_toggle", namespace: "accentuate"}, {key: "minicart_discount_section_toggle_ab_test", namespace: "accentuate"}, {key: "select_minicart_discount_product_ab_test", namespace: "accentuate"}, {key: "toggle_to_turn_on_adding_manual_discount_code", namespace: "accentuate"}, {key: "select_minicart_discount_product", namespace: "accentuate"}, {key: "select_discount_product_percent_off", namespace: "accentuate"}, {key: "dollar_amount_off", namespace: "accentuate"}, {key: "discount_section_main_header", namespace: "accentuate"}, {key: "manual_discount_code", namespace: "accentuate"} ]) { key value } `; const query = ` query { product(handle: "${productHandle}") { title availableForSale handle tags featuredImage { url } ${DISCOUNT_PRODUCT_METAFIELD_QUERY} variants(first: 200) { edges { node { availableForSale title id price { amount } compareAtPrice { amount } } } } } } `; try { return new Promise((resolve, reject) => { $.ajax({ type: "POST", url: GRAPHQL_URL_VERSION, headers: graphqlHeadersObj, data: query, success: function(res) { if (res.data && res.data.product) { resolve(res.data.product); } else { console.warn('No product data returned for:', productHandle); resolve(null); } }, error: function (status) { console.error("GraphQL error for product", productHandle, ":", status); reject(status); }, }); }); } catch (error) { console.warn('Error fetching product object for', productHandle, ':', error); return null; } } const pageAddToCartScoped = async function (e, targetComponentId = componentId) { if (e) e.preventDefault(); const clickedButton = e?.target?.closest('button'); const buttonComponentId = clickedButton?.dataset?.componentId || targetComponentId; const addToCartButton = document.getElementById(`AddToCart-${buttonComponentId}`); const addToCartText = addToCartButton?.querySelector('.text'); const checkmark = addToCartButton.querySelector('.checkmark'); const componentData = window.pdpComponentRegistry[buttonComponentId]; const productData = componentData?.productData || productDataGlobal; const selectedOptions = componentData?.selectedOptions || currentSelectedOptions; if (!productData) { console.error(`Product data not available for component ${buttonComponentId}`); return false; } const selectedVariant = findVariantFromSelectedOptions(selectedOptions, productData); if (!selectedVariant) { console.error('No variant selected'); return false; } if (!selectedVariant.availableForSale) { console.warn('Selected variant is not available for sale'); return false; } try { addToCartButton.disabled = true; addToCartButton.classList.add('disabled'); addToCartText.classList.remove('fadeInDown'); addToCartText.classList.add('animated', 'zoomOut'); const itemsToAdd = []; itemsToAdd.push({ id: selectedVariant.id.replace("gid://shopify/ProductVariant/", ""), quantity: 1 }); selectedUpsellProducts.forEach(upsellProduct => { itemsToAdd.push({ id: upsellProduct.variantId, quantity: 1 }); }); let response; if (itemsToAdd.length === 1) { response = await fetch('/cart/add.js', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(itemsToAdd[0]) }); } else { response = await fetch('/cart/add.js', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ items: itemsToAdd }) }); } if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const itemData = await response.json(); addToCartButton.classList.add('clicked'); if (checkmark) { checkmark.classList.add('checkmark-active'); } setTimeout(() => { addToCartButton.disabled = false; addToCartButton.classList.remove('disabled', 'clicked'); if (checkmark) { checkmark.classList.remove('checkmark-active'); } addToCartText.classList.remove('zoomOut'); addToCartText.classList.add('fadeInDown'); setTimeout(() => { addToCartText.classList.remove('animated', 'fadeInDown'); }, 1000); }, 1000); try { if (typeof adjustPdpDiscountHandleBasedOnTestingFlag === 'function' && document.querySelector('.theridge-pdp__background')) { adjustPdpDiscountHandleBasedOnTestingFlag(); } } catch (error) { console.warn('adjustPdpDiscountHandleBasedOnTestingFlag failed (expected for pdp-buy-box components):', error); } let discountProductHandle = null; const currentProductHandle = productData?.handle; const discountProductDefault = getMetafieldValue(productData, 'select_minicart_discount_product'); const discountProductAbTest = getMetafieldValue(productData, 'select_minicart_discount_product_ab_test'); const abTestToggle = getMetafieldValue(productData, 'minicart_discount_section_toggle_ab_test'); if (discountProductAbTest && abTestToggle === "true") { discountProductHandle = discountProductAbTest; } else if (discountProductDefault) { discountProductHandle = discountProductDefault; } if (discountProductHandle && currentProductHandle) { let newDiscountStackObj = {}; newDiscountStackObj[currentProductHandle] = discountProductHandle; if (!sessionStorage.getItem(DISCOUNT_STACK_SESSION_STORAGE_KEY)) { sessionStorage.setItem(DISCOUNT_STACK_SESSION_STORAGE_KEY, JSON.stringify([newDiscountStackObj])); } else { let newObj = {}; newObj[currentProductHandle] = discountProductHandle; let currentDiscountSessionStorage = JSON.parse(sessionStorage.getItem(DISCOUNT_STACK_SESSION_STORAGE_KEY)); if (!currentDiscountSessionStorage.some(obj => obj.hasOwnProperty(currentProductHandle))) { currentDiscountSessionStorage.push(newObj); sessionStorage.setItem(DISCOUNT_STACK_SESSION_STORAGE_KEY, JSON.stringify(currentDiscountSessionStorage)); } } try { await cacheDiscountProductData(discountProductHandle, currentProductHandle); } catch (error) { console.warn('Error caching minicart discount data:', error); } } const cartResponse = await fetch('/cart.js'); const cart = await cartResponse.json(); if (cart.items && cart.items.length > 0) { const lastItem = cart.items[0]; if (typeof fetchProductColorway === 'function') { try { const colorwayRes = await fetchProductColorway(lastItem.handle); sessionStorage.setItem('lastAddedTocartItemTitle', colorwayRes.metafields[0]?.value || lastItem.product_title || ''); } catch (error) { console.warn('Failed to fetch product colorway:', error); sessionStorage.setItem('lastAddedTocartItemTitle', lastItem.product_title || ''); } } else { sessionStorage.setItem('lastAddedTocartItemTitle', lastItem.product_title || ''); } if (typeof fetchProductArchetype === 'function') { try { const productArchetype = await fetchProductArchetype(lastItem.handle); sessionStorage.setItem('lastAddedTocartProductArchetype', productArchetype); } catch (error) { console.warn('Failed to fetch product archetype:', error); } } sessionStorage.setItem('lastAddedTocartProductHandle', lastItem.handle || ''); } if (typeof refreshMiniCart === 'function') { refreshMiniCart(cart, true, true); } const cartContainer = document.querySelector('#header .cart_container') || document.querySelector('.sticky_nav .cart_container') || document.querySelector('.top_bar .cart_container'); if (cartContainer) { cartContainer.classList.add('active_link'); } } catch (error) { console.error('Error adding to cart:', error); addToCartButton.disabled = false; addToCartButton.classList.remove('disabled', 'clicked'); let errorMessage = 'Unable to add item to cart. Please try again.'; if (error.message && error.message.includes('status: 422')) { errorMessage = 'This item is currently out of stock or unavailable.'; } const existingWarning = document.querySelector('.warning'); if (existingWarning) { existingWarning.remove(); } const warning = document.createElement('p'); warning.className = 'warning animated bounceIn'; warning.textContent = errorMessage; addToCartButton.parentNode.insertBefore(warning, addToCartButton.nextSibling); addToCartText.textContent = 'Add to Cart'; addToCartText.classList.remove('zoomOut'); addToCartText.classList.add('zoomIn'); } return false; }; function renderUpsellSlider() { if (!productDataGlobal) { console.warn('renderUpsellSlider: No product data available'); return ''; } const upsellSliderToggle = getMetafieldValue(productDataGlobal, 'upsell_slider_pdpmod16_master_toggle'); const upsellSliderCollectionId = getMetafieldValue(productDataGlobal, 'upsell_slider_collection_selection__page_version'); if (!upsellSliderToggle || upsellSliderToggle !== 'true') { console.log('renderUpsellSlider: Upsell slider not enabled for this product'); return ''; } if (!upsellSliderCollectionId) { console.warn('renderUpsellSlider: No collection specified for upsell slider'); return ''; } const numericCollectionId = upsellSliderCollectionId.replace('gid://shopify/Collection/', ''); const headerTitle = getMetafieldValue(productDataGlobal, 'upsell_slider_header_title') || 'POPULAR ADD ONS'; let upsellHtml = `

${headerTitle}:

`; if (typeof window !== 'undefined') { if (!window.pendingUpsellCollectionIds) { window.pendingUpsellCollectionIds = {}; } window.pendingUpsellCollectionIds[componentId] = numericCollectionId; window.pendingUpsellCollectionId = numericCollectionId; } return upsellHtml; } function renderWhatsInTheKitComponent() { if (!productDataGlobal) { return ''; } const witkToggle = getMetafieldValue(productDataGlobal, 'whats_in_the_kit_v2_toggle'); if (!witkToggle || witkToggle !== 'true') { return ''; } const witkWarrantyMessage = getMetafieldValue(productDataGlobal, 'whats_in_the_kit_v2_warranty_message') || 'LIFETIME WARRANTY'; const witkModalImage = getMetafieldValue(productDataGlobal, 'whats_in_the_kit_v2_modal_image') || '../cdn/blog-images/files/Lifetime_Warranty.v2png.png﹖v=1706554975'; const witkWarrantySectionToggle = getMetafieldValue(productDataGlobal, 'whats_in_the_kit_v2_warranty_section_toggle'); const witkWarrantyBadge = getMetafieldValue(productDataGlobal, 'whats_in_the_kit_v2_warranty_badge') || '../cdn/blog-images/files/Group_439.svg﹖v=1696969829'; const witkProductsNative = getMetafieldValue(productDataGlobal, 'whats_in_the_kit_v2_native'); let kitProducts = []; console.log('witkProductsNative', witkProductsNative); console.log('productCache', productCache); if (witkProductsNative) { try { const productIds = JSON.parse(witkProductsNative); kitProducts = productIds.map(gid => { return Object.values(productCache).find(p => p && p.id && p.id.toString() === gid); }).filter(Boolean); } catch (e) { console.error('Error parsing whats_in_the_kit_v2_native:', e); return ''; } } console.log('kitProducts', kitProducts); if (kitProducts.length === 0) { return ''; } let componentHtml = `
What's Included?
`; kitProducts.forEach(product => { if (product) { const colorway = getMetafieldValue(product, 'colorway') || product.title; const displayTitle = colorway.includes('Case') ? 'Ring Case' : colorway; const productImage = product.featuredImage ? product.featuredImage.url : ''; componentHtml += `
Included
${displayTitle}
${displayTitle}
`; } }); componentHtml += `
`; if (witkWarrantySectionToggle === 'true' || witkWarrantySectionToggle === true) { componentHtml += `
Lifetime Guarantee Badge
${witkWarrantyMessage}
INCLUDED
Learn More
`; } componentHtml += `
`; console.log('componentHtml', componentHtml); return componentHtml; } function renderSilhouetteSelector() { if (!productDataGlobal) { return ''; } const silhouetteToggle = getMetafieldValue(productDataGlobal, 'toggle_silhouette_selector'); const silhouetteProductsString = getMetafieldValue(productDataGlobal, 'products_for_silhouette_selector_page_version__4_max'); if (!silhouetteToggle || !silhouetteProductsString) { console.log("Silhouette selector not enabled or no products configured - this is normal"); return ''; } let productIds = []; try { productIds = JSON.parse(silhouetteProductsString); if (!Array.isArray(productIds) || productIds.length === 0) { console.log("No valid product IDs found for silhouette selector"); return ''; } } catch (error) { console.error('Error parsing silhouette products JSON:', error); return ''; } const mod14Title = getMetafieldValue(productDataGlobal, 'mod14_title') || 'RING TYPE:'; const infoIconToggle = getMetafieldValue(productDataGlobal, 'info_icon_toggle'); const infoIconImage = getMetafieldValue(productDataGlobal, 'info_icon_image'); const productType = getMetafieldValue(productDataGlobal, 'product_type') || ''; const pdpFlareStyle = getMetafieldValue(productDataGlobal, 'pdp_page_flare_style_selection') || ''; const titleOverrides = { 1: getMetafieldValue(productDataGlobal, 'product_1_title_override'), 2: getMetafieldValue(productDataGlobal, 'product_2_title_override'), 3: getMetafieldValue(productDataGlobal, 'product_3_title_override'), 4: getMetafieldValue(productDataGlobal, 'product_4_title_override') }; let silhouetteHtml = `
${mod14Title} ${infoIconToggle === 'true' && infoIconImage ? `information icon` : ''}
`; productIds.forEach((productId, index) => { let silhouetteProduct = null; for (const [handle, cachedProduct] of Object.entries(productCache)) { if (cachedProduct && cachedProduct.id === productId) { silhouetteProduct = cachedProduct; break; } } if (!silhouetteProduct) { console.warn(`Silhouette product not found in cache for ID: ${productId}`); fetchProductById(productId).then(productData => { if (productData && productData.handle) { productCache[productData.handle] = productData; } }).catch(error => { console.error(`Failed to fetch silhouette product ${productId}:`, error); }); return; } const positionIdx = index + 1; const productArchetype = getMetafieldValue(silhouetteProduct, 'product_archetype'); const productTypeField = getMetafieldValue(silhouetteProduct, 'product_type'); const isJtbCustomizable = getMetafieldValue(silhouetteProduct, 'is_jtb_customizable'); const swatchSelectorCollection = getMetafieldValue(silhouetteProduct, 'swatch_selector_collection'); let discountPercentage = 0; if (silhouetteProduct.variants && silhouetteProduct.variants.edges.length > 0) { const firstVariant = silhouetteProduct.variants.edges[0].node; if (firstVariant.compareAtPrice && firstVariant.price) { const comparePrice = parseFloat(firstVariant.compareAtPrice.amount); const currentPrice = parseFloat(firstVariant.price.amount); if (comparePrice > currentPrice) { discountPercentage = Math.round(((comparePrice - currentPrice) / comparePrice) * 100); } } } const flareOverride = getMetafieldValue(silhouetteProduct, 'mod14_this_products_flare_override'); let flareContent = ''; if (flareOverride) { flareContent = `
${flareOverride}
`; } else if (discountPercentage > 0) { flareContent = `
${discountPercentage}% OFF
`; } let productCopy = ''; if (titleOverrides[positionIdx]) { productCopy = titleOverrides[positionIdx]; } else { productCopy = getMetafieldValue(silhouetteProduct, "collection_page_subtext"); } const productImage = silhouetteProduct.featuredImage ? silhouetteProduct.featuredImage.url : ''; const isCurrentProduct = silhouetteProduct.handle === productDataGlobal.handle; let swatchHandles = ''; if (swatchSelectorCollection && currentActiveCollection && currentActiveCollection.products) { const swatchHandlesList = currentActiveCollection.products.edges .map(edge => edge.node.handle) .filter(h => h); swatchHandles = swatchHandlesList.join(','); } if (productArchetype) { silhouetteHtml += `
${flareContent}
${silhouetteProduct.title}
${productCopy}
${flareContent}
${productCopy}
`; } }); silhouetteHtml += `
`; return silhouetteHtml; } function buildFeaturesSection() { if (!productDataGlobal || !productDataGlobal.handle) { return `
Features

Wallet Features:

Holds 1-12 cards without stretching out

Blocks RFID to prevent wireless theft

Scratch resistant

Lifetime warranty

99-day risk free trial

Replaceable screws and elastic

6061-T6 aerospace-grade aluminum | Anodized

Weight: 2 oz | 86 x 54 x 6 mm

`; } const cachedDescriptions = productDescriptionsCache[productDataGlobal.handle]; if (cachedDescriptions && cachedDescriptions.fullHtml) { const isEmpty = cachedDescriptions.fullHtml.trim() === `
` || !cachedDescriptions.features && !cachedDescriptions.description && !cachedDescriptions.shipping; if (isEmpty) { const productType = getMetafieldValue(productDataGlobal, 'product_type') || ''; const isWallet = productType === 'Wallet'; if (isWallet) { return `
Features

Wallet Features:

Holds 1-12 cards without stretching out

Blocks RFID to prevent wireless theft

Scratch resistant

Lifetime warranty

99-day risk free trial

Replaceable screws and elastic

6061-T6 aerospace-grade aluminum | Anodized

Weight: 2 oz | 86 x 54 x 6 mm

Description

Premium wallet with advanced features and durable construction.

Shipping & Warranty

Free shipping on orders over $50. 30-day return policy. Lifetime warranty included.

`; } else { return `
Features

High-quality product with premium features and materials.

Description

Expertly crafted with attention to detail and quality.

Shipping & Warranty

Free shipping on orders over $50. 30-day return policy.

`; } } else { return cachedDescriptions.fullHtml; } } processProductDescriptions(productDataGlobal); const updatedCache = productDescriptionsCache[productDataGlobal.handle]; return updatedCache ? updatedCache.fullHtml : ''; } function initializeAccordion() { $(`.pdp-container[data-component-id="${componentId}"] .pdp-info-container .wh_heading`).off('click.pdpAccordion'); $(`.pdp-container[data-component-id="${componentId}"] .pdp-info-container .wh_heading`).on('click.pdpAccordion', function(e) { e.stopPropagation(); if ($(this).hasClass('active')) { $(`.pdp-container[data-component-id="${componentId}"] .pdp-info-container .wh_content`).hide('fast'); $(this).removeClass('active'); } else { $(`.pdp-container[data-component-id="${componentId}"] .pdp-info-container .wh_content`).hide('fast'); $(`.pdp-container[data-component-id="${componentId}"] .pdp-info-container .wh_heading`).removeClass('active'); $(this).next('.wh_content').show('fast'); $(this).addClass('active'); } }); } async function fetchCollectionData(collectionHandle) { const query = ` query { collection(handle: "${collectionHandle}") { products(first: 200) { edges { node { title handle id availableForSale options { values } featuredImage { url } variants(first: 200) { edges { node { title id price { amount } compareAtPrice { amount } } } } ${PRODUCT_GRAPHQL_METAFIELD_QUERY} } } } } } `; try { const response = await fetch(GRAPHQL_URL_VERSION, { method: 'POST', headers: graphqlHeadersObj, body: query }); const res = await response.json(); if (res.data && res.data.collection) { if (res.data.collection.products && res.data.collection.products.edges) { res.data.collection.products.edges.forEach(edge => { if (edge.node) { processProductDescriptions(edge.node); } }); } return res.data.collection; } else if (res.errors) { console.error('GraphQL Errors:', res.errors); return null; } else { console.warn('Collection data not found in GraphQL response', res); return null; } } catch (error) { console.error('AJAX error in collection query: ', error); return null; } } function getMetafieldValue(product, key) { if (!product.metafields) return null; const metafield = product.metafields.find(m => m && m.key === key); return metafield ? metafield.value : null; } function parseRichTextToHTML(richTextData) { if (!richTextData) return ''; try { const data = typeof richTextData === 'string' ? JSON.parse(richTextData) : richTextData; function processNode(node) { if (!node || !node.type) return ''; switch (node.type) { case 'root': return node.children ? node.children.map(processNode).join('') : ''; case 'paragraph': return `

${node.children ? node.children.map(processNode).join('') : ''}

`; case 'heading': const level = node.level || 1; return `${node.children ? node.children.map(processNode).join('') : ''}`; case 'list': const listTag = node.listType === 'ordered' ? 'ol' : 'ul'; return `<${listTag}>${node.children ? node.children.map(processNode).join('') : ''}`; case 'list-item': return `
  • ${node.children ? node.children.map(processNode).join('') : ''}
  • `; case 'text': let text = node.value || ''; if (node.bold) text = `${text}`; if (node.italic) text = `${text}`; if (node.underline) text = `${text}`; if (node.strikethrough) text = `${text}`; text = text.replace(/\n/g, '
    '); return text; case 'link': const url = node.url || '#'; const target = node.target ? ` target="${node.target}"` : ''; return `${node.children ? node.children.map(processNode).join('') : ''}`; default: return node.children ? node.children.map(processNode).join('') : ''; } } return processNode(data); } catch (error) { console.error('Error parsing rich text:', error); return richTextData; } } function extractProductId(gid) { if (!gid) return null; return gid.replace("gid://shopify/Product/", ""); } async function buildKitSelectorHTML(currentProduct, collectionData) { if (!collectionData || !collectionData.products) { console.log("buildKitSelectorHTML: No collection data available"); return ''; } const currentProductType = getMetafieldValue(currentProduct, 'product_type') || ''; const matchingProductId = getMetafieldValue(currentProduct, 'matching_kit_product'); const kitSelectorToggle = getMetafieldValue(currentProduct, 'kit_selector_toggle'); console.log("kitSelectorToggle: ", kitSelectorToggle); if (!kitSelectorToggle || kitSelectorToggle == 'false') { const currentProductHandle = currentProduct.handle; let singularSwatchesHTML = ''; try { singularSwatchesHTML = buildSwatchesHTML(currentProduct, collectionData, currentProductHandle); } catch (error) { console.error("buildKitSelectorHTML: Error building singular swatches HTML:", error); return ''; } return singularSwatchesHTML; } if (!matchingProductId) { console.log("buildKitSelectorHTML: No matching kit product found, skipping kit selector"); return ''; } const numericMatchingId = extractProductId(matchingProductId); let matchingProductEdge = collectionData.products.edges.find(edge => { const numericEdgeId = extractProductId(edge.node.id); return numericEdgeId === numericMatchingId; }); let matchingProduct; if (!matchingProductEdge) { try { matchingProduct = await fetchProductById(matchingProductId); if (!matchingProduct) { console.log("buildKitSelectorHTML: Could not fetch matching product, skipping kit selector"); return ''; } } catch (error) { console.error("buildKitSelectorHTML: Error fetching matching product:", error); return ''; } } else { matchingProduct = matchingProductEdge.node; } let singularProduct, kitProduct, singularChecked = '', kitChecked = ''; let discountPercent = 0; const currentProductIsKit = isKitProduct(currentProduct); const matchingProductIsKit = isKitProduct(matchingProduct); if (currentProductIsKit) { kitProduct = currentProduct; singularProduct = matchingProduct; kitChecked = 'checked'; } else { singularProduct = currentProduct; kitProduct = matchingProduct; singularChecked = 'checked'; } if (kitProduct && kitProduct.variants && kitProduct.variants.edges.length > 0) { const firstVariant = kitProduct.variants.edges[0].node; if (firstVariant.compareAtPrice && firstVariant.price) { discountPercent = Math.round( ((parseFloat(firstVariant.compareAtPrice.amount) - parseFloat(firstVariant.price.amount)) / parseFloat(firstVariant.compareAtPrice.amount)) * 100 ); } } const singularProductArchetype = getMetafieldValue(singularProduct, 'product_archetype') || ''; const overrideSingularTitle = getMetafieldValue(singularProduct, 'override_singular_tab_title'); let singularTabTitle = overrideSingularTitle || 'SINGLE ONLY'; if (!overrideSingularTitle) { if (singularProductArchetype.includes('Wallet')) { singularTabTitle = 'WALLET ONLY'; } else if (singularProductArchetype.includes('Check-In')) { singularTabTitle = 'CHECK-IN ONLY'; } else if (singularProductArchetype.includes('Carry-On')) { singularTabTitle = 'CARRY-ON ONLY'; } else if (singularProductArchetype.includes('KeyCase') || singularProductArchetype.includes('Keycase')) { singularTabTitle = 'KEYCASE ONLY'; } } const kitTabTitle = getMetafieldValue(kitProduct, 'kit_tab_title') || getMetafieldValue(singularProduct, 'kit_tab_title') || 'FULL KIT'; const currentProductHandle = currentProduct.handle; let singularSwatchesHTML = ''; let kitSwatchesHTML = ''; try { singularSwatchesHTML = buildSwatchesHTML(singularProduct, singularCollectionData, currentProductHandle); kitSwatchesHTML = buildSwatchesHTML(kitProduct, kitCollectionData, currentProductHandle); } catch (error) { console.error("buildKitSelectorHTML: Error building swatches HTML:", error); } return `
    ${singularSwatchesHTML}
    ${kitSwatchesHTML}
    `; } function buildSwatchesHTML(product, collectionData, currentHandle) { if (!product) { console.log("buildSwatchesHTML: No product provided"); return ''; } if (!collectionData || !collectionData.products) { const productMaterial = getMetafieldValue(product, 'pdp_swatch_selector_material') || 'colorway'; return `
    COLOR:
    ${productMaterial}
    `; } const actualCurrentHandle = document.querySelector('.pdp-container')?.getAttribute('data-current-product') || currentHandle; const productMaterial = getMetafieldValue(product, 'pdp_swatch_selector_material') || 'colorway'; let swatchesHTML = `
    COLOR:
    ${productMaterial}
    `; let swatchCount = 0; try { collectionData.products.edges.forEach((edge, index) => { const collectionProduct = edge.node; if (!collectionProduct.availableForSale) { return; } const selectedSwatchImage = getMetafieldValue(collectionProduct, 'shogun_swatch_image_selected'); const notSelectedSwatchImage = getMetafieldValue(collectionProduct, 'shogun_swatch_image_not_select'); if (!selectedSwatchImage && !notSelectedSwatchImage) { return; } let swatchImage = null; const isCurrentProduct = collectionProduct.handle === actualCurrentHandle; if (isCurrentProduct && selectedSwatchImage) { swatchImage = selectedSwatchImage; } else if (isCurrentProduct && !selectedSwatchImage && notSelectedSwatchImage) { swatchImage = notSelectedSwatchImage; } else { swatchImage = notSelectedSwatchImage; } if (!swatchImage) { return; } swatchCount++; swatchesHTML += `
    ${collectionProduct.handle} ${isCurrentProduct ? 'selected' : 'option'}
    `; }); } catch (error) { console.error("buildSwatchesHTML: Error processing collection products:", error); } if (swatchCount === 0) { swatchesHTML += `
    ${product.title}
    `; } swatchesHTML += `
    `; return swatchesHTML; } function updateKitSelectorState(currentProduct) { if (!currentProduct) { console.warn('updateKitSelectorState: No current product provided'); return; } const singularRadio = document.querySelector(`#tab-singular-${componentId}`); const kitRadio = document.querySelector(`#tab-kit-${componentId}`); if (!singularRadio || !kitRadio) { console.log('Kit selector radio buttons not found - this is normal for products without kit selector'); return; } const currentProductType = getMetafieldValue(currentProduct, 'product_type') || ''; const currentProductIsKit = isKitProduct(currentProduct); singularRadio.checked = false; kitRadio.checked = false; if (currentProductIsKit) { kitRadio.checked = true; } else { singularRadio.checked = true; } const pdpContainer = document.querySelector('.pdp-container'); if (pdpContainer) { pdpContainer.setAttribute('data-current-product', currentProduct.handle); } } function addKitSelectorEventListeners() { document.querySelectorAll(`.pdp-container[data-component-id="${componentId}"] .pdp-product-selector .tab-selectors`).forEach(tab => { tab.addEventListener('click', function(e) { e.preventDefault(); const productHandle = this.dataset.productUrl; if (productHandle && productHandle !== productDataGlobal.handle) { const upsellSlider = document.getElementById(`upsell-slider-${componentId}`); if (upsellSlider) { upsellSlider.style.display = 'none'; } const selectedTab = this.getAttribute('for'); if (selectedTab === 'tab-kit' && kitCollectionData) { currentActiveCollection = kitCollectionData; } else if (selectedTab === 'tab-singular' && singularCollectionData) { currentActiveCollection = singularCollectionData; } switchToProduct(productHandle); } }); }); document.querySelectorAll(`.pdp-container[data-component-id="${componentId}"] .pdp-product-selector .selector-swatch`).forEach(swatch => { swatch.addEventListener('click', function(e) { e.preventDefault(); const productHandle = this.dataset.productUrl; if (productHandle && productHandle !== productDataGlobal.handle) { // Trigger silhouette options animation animateSilhouetteOptionsTransition(); const upsellSlider = document.getElementById(`upsell-slider-${componentId}`); if (upsellSlider) { upsellSlider.style.display = 'none'; } hideThumbnailNavTemporarily(); switchToProduct(productHandle); } }); }); } function addMaterialSelectorEventListeners() { document.querySelectorAll(`.pdp-container[data-component-id="${componentId}"] .material-selector .swatch`).forEach(swatch => { swatch.addEventListener('click', function(e) { e.preventDefault(); const productHandle = this.dataset.productHandle; if (productHandle && productHandle !== productDataGlobal.handle) { const upsellSlider = document.getElementById(`upsell-slider-${componentId}`); if (upsellSlider) { upsellSlider.style.display = 'none'; } switchToProduct(productHandle); } else { const optionName = this.dataset.optionName; const optionValue = this.dataset.optionValue; handleOptionSelection(optionName, optionValue); } }); }); } function addStandaloneProductSelectorEventListeners() { document.querySelectorAll(`.pdp-container[data-component-id="${componentId}"] .product-selector-options .selector-swatch`).forEach(swatch => { swatch.addEventListener('click', function(e) { e.preventDefault(); const productHandle = this.dataset.productUrl; if (productHandle && productHandle !== productDataGlobal.handle) { // Trigger silhouette options animation animateSilhouetteOptionsTransition(); const upsellSlider = document.getElementById(`upsell-slider-${componentId}`); if (upsellSlider) { upsellSlider.style.display = 'none'; } hideThumbnailNavTemporarily(); switchToProduct(productHandle); } }); }); } async function fetchProductById(productId) { const query = ` query { product(id: "${productId}") { id title handle availableForSale tags descriptionHtml onlineStoreUrl featuredImage { url altText } images(first: 200) { edges { node { url altText } } } options { name values } variants(first: 200) { edges { node { id title availableForSale price { amount } compareAtPrice { amount } selectedOptions { name value } image { url altText } } } } ${PRODUCT_GRAPHQL_METAFIELD_QUERY} } } `; try { const response = await fetch(GRAPHQL_URL_VERSION, { method: 'POST', headers: graphqlHeadersObj, body: query }); const res = await response.json(); if (res.data && res.data.product) { processProductDescriptions(res.data.product); return res.data.product; } else { console.warn('Product not found by ID:', productId); return null; } } catch (error) { console.error('Error fetching product by ID:', error); return null; } } async function fetchUpsellProducts(collectionId) { if (!collectionId) { console.warn('fetchUpsellProducts: No collection ID provided'); return []; } const query = ` query { collection(id: "gid://shopify/Collection/${collectionId}") { id title products(first: 50) { edges { node { id title handle availableForSale featuredImage { url altText } variants(first: 1) { edges { node { id availableForSale price { amount } compareAtPrice { amount } } } } ${PRODUCT_GRAPHQL_METAFIELD_QUERY} } } } } }`; try { const response = await fetch(GRAPHQL_URL_VERSION, { method: 'POST', headers: graphqlHeadersObj, body: query }); const res = await response.json(); if (res.data && res.data.collection && res.data.collection.products) { return res.data.collection.products.edges .map(edge => edge.node) .filter(product => { // Check if product is available for sale if (!product.availableForSale) return false; // Check if the first variant (used for display) is available for sale if (!product.variants || !product.variants.edges.length) return false; const firstVariant = product.variants.edges[0].node; return firstVariant.availableForSale; }); } else { console.warn('fetchUpsellProducts: Collection not found or has no products'); return []; } } catch (error) { console.error('fetchUpsellProducts: Error fetching collection:', error); return []; } } // const defaultProductHandle = "royal-black-silicone-ring-8mm"; // const defaultProductHandle = "long-haul-kit-basecamp-orange"; const defaultProductHandle = "aluminum-gunmetal"; const productHandle = "basecamp-orange".length == 0 ? defaultProductHandle : "basecamp-orange"; async function initializeProduct() { try { const batchedInitialData = await fetchBatchedInitialData(productHandle); if (!batchedInitialData) { console.error('Failed to fetch initial data'); return; } const { product: initialProduct, shop: globalMetafields, matchingProduct } = batchedInitialData; if (globalMetafields && globalMetafields.metafields) { globalMetafields.metafields.forEach(metafield => { if (metafield && metafield.key && metafield.value) { globalMetafields[metafield.key] = metafield.value; } }); } if (initialProduct) { productCache[initialProduct.handle] = initialProduct; productDataGlobal = initialProduct; } if (matchingProduct) { productCache[matchingProduct.handle] = matchingProduct; } await fetchBothCollections(initialProduct, matchingProduct); await cacheCurrentProductSilhouettes(initialProduct); if (matchingProduct) { await cacheCurrentProductSilhouettes(matchingProduct); } await cacheWitkProducts(initialProduct); if (matchingProduct) { await cacheWitkProducts(matchingProduct); } setTimeout(() => { preloadRemainingDataInBackground(); }, 100); await setCurrentActiveCollectionForProduct(productDataGlobal); await renderProductUI(productDataGlobal); } catch (error) { console.error('Error during product initialization:', error); } } async function fetchBatchedInitialData(handle) { const query = ` query @inContext(country: ${COUNTRY_ISO_CODE}) { product(handle: "${handle}") { id title availableForSale handle tags descriptionHtml onlineStoreUrl featuredImage { url altText } images(first: 10) { edges { node { url altText } } } options { name values } ${PRODUCT_GRAPHQL_METAFIELD_QUERY} variants(first: 50) { edges { node { id title availableForSale price { amount } compareAtPrice { amount } selectedOptions { name value } image { url altText } } } } } shop { metafields(identifiers: [ {key: "shogun_product_default_feature", namespace: "globals"}, {key: "shogun_product_default_desc", namespace: "globals"}, {key: "shogun_product_def_shipping", namespace: "globals"}, {key: "generic_default_features", namespace: "globals"}, {key: "generic_default_description", namespace: "globals"}, {key: "generic_default_shipping", namespace: "globals"} ]){ key value } } } `; try { const response = await fetch(GRAPHQL_URL_VERSION, { method: 'POST', headers: graphqlHeadersObj, body: query }); const res = await response.json(); if (res.data) { let result = { product: res.data.product, shop: res.data.shop }; if (res.data.product) { const matchingProductId = getMetafieldValue(res.data.product, 'matching_kit_product'); if (matchingProductId) { const matchingProduct = await fetchProductById(matchingProductId); result.matchingProduct = matchingProduct; } } return result; } return null; } catch (error) { console.error('Error in fetchBatchedInitialData:', error); return null; } } async function preloadRemainingDataInBackground() { try { const preloadPromises = []; if (singularCollectionData) { preloadPromises.push(preloadCriticalProductsOnly(singularCollectionData)); } if (kitCollectionData) { preloadPromises.push(preloadCriticalProductsOnly(kitCollectionData)); } preloadPromises.push(cacheSilhouetteProductsOptimized()); await Promise.all(preloadPromises); } catch (error) { console.error('Error in background preloading:', error); } } async function cacheWitkProducts(product) { if (!product) return; const productType = getMetafieldValue(product, 'product_type') || ''; if (productType !== 'Ring') { return; } const witkToggle = getMetafieldValue(product, 'whats_in_the_kit_v2_toggle'); if (!witkToggle || witkToggle !== 'true') { return; } const witkProductsNative = getMetafieldValue(product, 'whats_in_the_kit_v2_native'); if (!witkProductsNative) { return; } try { const productIds = JSON.parse(witkProductsNative); console.log(`Caching WITK products for ${product.handle}:`, productIds); const fetchPromises = productIds.map(gid => { return fetchProductById(gid); }); const results = await Promise.all(fetchPromises); results.forEach(result => { if (result && result.handle) { productCache[result.handle] = result; console.log(`✅ Cached WITK product: ${result.handle}`); } }); } catch (error) { console.error(`Error caching WITK products for ${product.handle}:`, error); } } initializeProduct(); function isKitProduct(product) { if (!product) return false; const productType = getMetafieldValue(product, 'product_type') || ''; if (productType.includes('Kit')) { return true; } const handle = (product.handle || '').toLowerCase(); const title = (product.title || '').toLowerCase(); const isKitByHandle = handle.includes('kit') || handle.includes('-kit-') || handle.startsWith('kit-') || handle.endsWith('-kit'); const isKitByTitle = title.includes('kit') || title.includes(' kit ') || title.startsWith('kit ') || title.endsWith(' kit'); return isKitByHandle || isKitByTitle; } async function fetchBothCollections(currentProduct, matchingProduct) { const currentProductCollectionHandle = getMetafieldValue(currentProduct, 'swatch_selector_collection'); const matchingProductCollectionHandle = matchingProduct ? getMetafieldValue(matchingProduct, 'swatch_selector_collection') : null; const fetchPromises = []; if (currentProductCollectionHandle) { fetchPromises.push( fetchCollectionData(currentProductCollectionHandle).then(data => ({ type: 'current', handle: currentProductCollectionHandle, data })) ); } if (matchingProductCollectionHandle && matchingProductCollectionHandle !== currentProductCollectionHandle) { fetchPromises.push( fetchCollectionData(matchingProductCollectionHandle).then(data => ({ type: 'matching', handle: matchingProductCollectionHandle, data })) ); } try { const results = await Promise.all(fetchPromises); results.forEach(result => { if (result.data) { if (result.type === 'current') { if (isKitProduct(currentProduct)) { kitCollectionData = result.data; } else { singularCollectionData = result.data; } } else if (result.type === 'matching') { if (matchingProduct && isKitProduct(matchingProduct)) { kitCollectionData = result.data; } else { singularCollectionData = result.data; } } } }); if (isKitProduct(currentProduct)) { currentActiveCollection = kitCollectionData; } else { currentActiveCollection = singularCollectionData; } } catch (error) { console.error('Error fetching collections:', error); } } async function setCurrentActiveCollectionForProduct(product) { if (!product) return; const productCollectionHandle = getMetafieldValue(product, 'swatch_selector_collection'); if (!productCollectionHandle) { console.warn(`No swatch_selector_collection found for product: ${product.handle}`); return; } const needsNewCollections = await checkIfNeedsNewCollections(product); if (needsNewCollections) { await fetchCollectionsForProduct(product); } if (isKitProduct(product)) { currentActiveCollection = kitCollectionData; } else { currentActiveCollection = singularCollectionData; } } async function checkIfNeedsNewCollections(product) { const productCollectionHandle = getMetafieldValue(product, 'swatch_selector_collection'); if (!productCollectionHandle) return false; let productFoundInSingular = false; let productFoundInKit = false; if (singularCollectionData && singularCollectionData.products) { productFoundInSingular = singularCollectionData.products.edges.some(edge => edge.node.handle === product.handle ); } if (kitCollectionData && kitCollectionData.products) { productFoundInKit = kitCollectionData.products.edges.some(edge => edge.node.handle === product.handle ); } if (isKitProduct(product) && productFoundInKit) { console.log(`checkIfNeedsNewCollections: Kit product ${product.handle} found in existing kitCollectionData`); return false; } if (!isKitProduct(product) && productFoundInSingular) { console.log(`checkIfNeedsNewCollections: Singular product ${product.handle} found in existing singularCollectionData`); return false; } console.log(`checkIfNeedsNewCollections: Product ${product.handle} needs new collections`); return true; } async function fetchCollectionsForProduct(product) { const matchingProductId = getMetafieldValue(product, 'matching_kit_product'); let matchingProduct = null; if (matchingProductId) { matchingProduct = Object.values(productCache).find(cachedProduct => cachedProduct && cachedProduct.id === matchingProductId ); if (!matchingProduct) { try { matchingProduct = await fetchProductById(matchingProductId); if (matchingProduct && matchingProduct.handle) { productCache[matchingProduct.handle] = matchingProduct; } } catch (error) { console.error(`fetchCollectionsForProduct: Error fetching matching product:`, error); } } } const currentProductCollectionHandle = getMetafieldValue(product, 'swatch_selector_collection'); const matchingProductCollectionHandle = matchingProduct ? getMetafieldValue(matchingProduct, 'swatch_selector_collection') : null; const fetchPromises = []; if (currentProductCollectionHandle) { fetchPromises.push( fetchCollectionData(currentProductCollectionHandle).then(data => ({ type: 'current', handle: currentProductCollectionHandle, data, product })) ); } if (matchingProductCollectionHandle && matchingProductCollectionHandle !== currentProductCollectionHandle) { fetchPromises.push( fetchCollectionData(matchingProductCollectionHandle).then(data => ({ type: 'matching', handle: matchingProductCollectionHandle, data, product: matchingProduct })) ); } try { const results = await Promise.all(fetchPromises); results.forEach(result => { if (result.data) { if (result.type === 'current') { if (isKitProduct(product)) { kitCollectionData = result.data; } else { singularCollectionData = result.data; } } else if (result.type === 'matching' && matchingProduct) { if (isKitProduct(matchingProduct)) { kitCollectionData = result.data; } else { singularCollectionData = result.data; } } } }); const preloadPromises = []; results.forEach(result => { if (result.data) { preloadPromises.push(preloadAllProducts(result.data)); } }); if (preloadPromises.length > 0) { await Promise.all(preloadPromises); } } catch (error) { console.error('fetchCollectionsForProduct: Error fetching collections:', error); } } function initializeSilhouetteContainerVisibility() { try { const silhouetteContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .silhouette-options-container`); if (silhouetteContainer) { if (!initialPageLoadComplete) { // For initial page load only, show immediately without animation silhouetteContainer.classList.add('initial-load'); silhouetteContainer.classList.remove('fade-in'); } else { // For product switching, prepare for fade-in animation silhouetteContainer.classList.remove('initial-load'); // Don't add fade-in yet - let the timeout handle it } } } catch (error) { console.error(`initializeSilhouetteContainerVisibility (${componentId}): Error initializing silhouette container:`, error); } } function animateSilhouetteOptionsTransition() { try { const silhouetteContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .silhouette-options-container`); if (silhouetteContainer) { // Remove both classes immediately (disappears instantly) // The actual fade-in animation timing is now handled in refreshSilhouetteSelector // since the HTML gets replaced during product switching silhouetteContainer.classList.remove('fade-in', 'initial-load'); } } catch (error) { console.error(`animateSilhouetteOptionsTransition (${componentId}): Error animating silhouette options:`, error); } } async function switchToProduct(productHandle) { try { const upsellSlider = document.getElementById(`upsell-slider-${componentId}`); const upsellSkeleton = document.getElementById(`upsell-slider-skeleton-${componentId}`); if (upsellSlider) { upsellSlider.style.display = 'none'; if (upsellSkeleton) { upsellSkeleton.style.display = 'block'; } } const imageContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .pdp-image-container`) || document.querySelector('.pdp-image-container'); if (imageContainer) { const currentHeight = imageContainer.offsetHeight; if (currentHeight > 0) { imageContainer.style.minHeight = `${currentHeight}px`; imageContainer.setAttribute('data-height-locked', 'true'); } } const pdpContainer = document.querySelector('.pdp-container'); if (pdpContainer) { pdpContainer.removeAttribute('data-content-loaded'); // Remove any silhouette-loading flags and skeletons pdpContainer.removeAttribute('data-silhouette-loading'); try { pdpContainer.querySelectorAll('.skeleton-silhouette').forEach(el => el.remove()); } catch (e) {} } const skeletonElements = document.querySelectorAll('.skeleton-image-main, .skeleton-thumbnails, .skeleton-title, .skeleton-price, .skeleton-tabs, .skeleton-options, .skeleton-button, .skeleton-features'); for(let i = 0; i < skeletonElements.length; i++) { let el = skeletonElements[i]; if (el) el.style.display = 'block'; } const fetchResult = await fetchProductData(productHandle); if (productDataGlobal) { Promise.resolve().then(async () => { try { await cacheCurrentProductSilhouettes(productDataGlobal); const silhouetteToggle = getMetafieldValue(productDataGlobal, 'toggle_silhouette_selector'); const silhouetteProducts = getMetafieldValue(productDataGlobal, 'products_for_silhouette_selector_page_version__4_max'); if (silhouetteToggle && silhouetteProducts) { await refreshSilhouetteSelector(); } } catch (error) { console.warn('switchToProduct: Background silhouette operations failed:', error); } }); } } catch (error) { console.error(`switchToProduct: Error switching to product ${productHandle}:`, error); if (productDataGlobal && productDataGlobal.handle && productDataGlobal.handle !== productHandle) { try { await renderProductUI(productDataGlobal); } catch (renderError) { console.error('switchToProduct: Error reloading current product:', renderError); window.location.reload(); } } } } let upsellSliderInitializing = false; async function initializeUpsellSlider() { if (upsellSliderInitializing) { console.log('initializeUpsellSlider: Already initializing, skipping...'); return; } upsellSliderInitializing = true; try { const upsellSliderContainer = document.getElementById(`upsell-slider-${componentId}`) || document.getElementById('upsell-slider'); const upsellSkeleton = document.getElementById(`upsell-slider-skeleton-${componentId}`); if (!upsellSliderContainer) { console.log('initializeUpsellSlider: No upsell slider container found'); if (upsellSkeleton) { upsellSkeleton.style.display = 'none'; } return; } const collectionId = window.pendingUpsellCollectionIds?.[componentId] || window.pendingUpsellCollectionId; if (!collectionId) { console.log('initializeUpsellSlider: No pending collection ID found for component:', componentId); return; } const upsellProducts = await fetchUpsellProducts(collectionId); if (upsellProducts.length === 0) { upsellSliderContainer.style.display = 'none'; if (upsellSkeleton) { upsellSkeleton.style.display = 'none'; } return; } const carouselContainer = upsellSliderContainer.querySelector('.upsell-slider-carousel-container'); let productsHtml = ''; upsellProducts.forEach((product, index) => { const productCard = buildUpsellProductCard(product, index + 1); if (productCard) { productsHtml += productCard; } }); carouselContainer.innerHTML = productsHtml; upsellSliderContainer.style.visibility = 'hidden'; if (typeof Flickity !== 'undefined' && productsHtml) { if (upsellSliderFlickity) { try { upsellSliderFlickity.off(); upsellSliderFlickity.destroy(); } catch (error) { console.warn('initializeUpsellSlider: Error destroying existing Flickity instance:', error); } upsellSliderFlickity = null; } if (carouselContainer) { carouselContainer.classList.remove('flickity-enabled'); carouselContainer.removeAttribute('tabindex'); const flickityViewport = carouselContainer.querySelector('.flickity-viewport'); if (flickityViewport) { while (flickityViewport.firstChild) { carouselContainer.appendChild(flickityViewport.firstChild); } flickityViewport.remove(); } const flickityElements = carouselContainer.querySelectorAll('.flickity-prev-next-button, .flickity-page-dots'); flickityElements.forEach(el => el.remove()); } try { if (carouselContainer && carouselContainer.children.length > 0) { if (carouselContainer.classList.contains('flickity-enabled')) { console.warn('initializeUpsellSlider: Container already has Flickity enabled, skipping initialization'); return; } upsellSliderFlickity = new Flickity(carouselContainer, { dragThreshold: 3, friction: 0.8, selectedAttraction: 0.2, wrapAround: true, pageDots: true, cellAlign: "left", percentPosition: true, prevNextButtons: true, setGallerySize: false, }); if (upsellSliderContainer) { upsellSliderContainer.style.visibility = 'visible'; } } else { console.warn('initializeUpsellSlider: No valid carousel container or no products to display'); } } catch (error) { console.error('initializeUpsellSlider: Error creating new Flickity instance:', error); if (carouselContainer) { carouselContainer.style.display = 'flex'; carouselContainer.style.overflowX = 'auto'; carouselContainer.style.gap = '10px'; if (upsellSliderContainer) { upsellSliderContainer.style.visibility = 'visible'; } } } } else { console.warn('initializeUpsellSlider: Flickity not available or no products, showing slider with basic styling'); setTimeout(() => { if (upsellSliderContainer) { upsellSliderContainer.style.visibility = 'visible'; } if (upsellSkeleton) { upsellSkeleton.style.display = 'none'; } }, 100); } addUpsellSliderEventListeners(); applyUpsellSliderTextResize(); if (window.pendingUpsellCollectionIds) { delete window.pendingUpsellCollectionIds[componentId]; } if (window.pendingUpsellCollectionId === collectionId) { window.pendingUpsellCollectionId = null; } upsellSliderContainer.style.display = 'block'; upsellSliderContainer.style.visibility = 'visible'; if (upsellSkeleton) { upsellSkeleton.style.display = 'none'; } } catch (error) { console.error('initializeUpsellSlider: Error initializing upsell slider:', error); const upsellSliderContainer = document.getElementById(`upsell-slider-${componentId}`) || document.getElementById('upsell-slider'); if (upsellSliderContainer) { upsellSliderContainer.style.display = 'none'; } if (upsellSkeleton) { upsellSkeleton.style.display = 'none'; } } finally { upsellSliderInitializing = false; } } function buildUpsellProductCard(product, index) { if (!product || !product.variants || !product.variants.edges.length) { console.warn('buildUpsellProductCard: Invalid product data', product); return ''; } const variant = product.variants.edges[0].node; const variantId = variant.id.replace("gid://shopify/ProductVariant/", ""); const productImage = product.featuredImage ? product.featuredImage.url : ''; const upsellTitle = getMetafieldValue(product, 'upsell_slider_title') || getMetafieldValue(product, 'colorway') || product.title; const upsellBadgeTitle = getMetafieldValue(product, 'upsell_slider_badge_title') || 'POPULAR'; const upsellPopupImage = getMetafieldValue(product, 'upsell_slider_quick_view_click_behavior'); const upsellModalText = getMetafieldValue(product, 'upsell_slider_modal_text') || 'LEARN MORE'; let productPrice = parseFloat(variant.price.amount); let productCompareAtPrice = variant.compareAtPrice ? parseFloat(variant.compareAtPrice.amount) : null; const discountAmountOff = parseFloat(getMetafieldValue(product, 'dollar_amount_off') || '0'); const discountPercentOff = parseFloat(getMetafieldValue(product, 'select_discount_product_percent_off') || '0'); const discountToggle = getMetafieldValue(product, 'toggle_to_turn_on_adding_manual_discount_code') === 'true'; if (discountToggle) { if (discountAmountOff > 0) { productCompareAtPrice = productPrice; productPrice = productPrice - discountAmountOff; } else if (discountPercentOff > 0) { const discountAmount = productPrice * (discountPercentOff / 100); productCompareAtPrice = productPrice; productPrice = productPrice - discountAmount; } } return `
    ${getMetafieldValue(product, 'colorway') || product.title}
    ${upsellPopupImage ? `
    ${upsellModalText}
    ` : ''}
    ${upsellTitle}
    ${CURRENCY_SYMBOL}${productPrice.toFixed(0)}
    ${productCompareAtPrice ? `
    ${CURRENCY_SYMBOL}${productCompareAtPrice.toFixed(0)}
    ` : ''}
    ${upsellBadgeTitle}
    `; } function addUpsellSliderEventListeners() { const upsellSliderContainer = document.getElementById(`upsell-slider-${componentId}`) || document.getElementById('upsell-slider'); if (!upsellSliderContainer) return; upsellSliderContainer.querySelectorAll('.upsellSliderIOSToggleInput').forEach(input => { input.addEventListener('change', handleUpsellToggle); }); upsellSliderContainer.querySelectorAll('.upsell-slider-modal-text').forEach(modalText => { modalText.addEventListener('click', handleUpsellModal); }); } function handleUpsellToggle(event) { try { const input = event.target; const labelEl = document.querySelector(`label[for="${input.id}"]`); if (!labelEl) { console.error('handleUpsellToggle: Label element not found'); return; } const variantId = labelEl.dataset.variantId; const labelId = labelEl.dataset.labelId; const productHandle = labelEl.dataset.productHandle; const upsellSliderContainer = document.getElementById(`upsell-slider-${componentId}`); const togglingClass = "upsell-slider-toggled-on"; labelEl.classList.toggle(togglingClass); if (labelEl.classList.contains(togglingClass)) { selectedUpsellProducts.push({ variantId: variantId, labelId: labelId, productHandle: productHandle }); const inputQuantity = document.createElement('input'); inputQuantity.type = 'hidden'; inputQuantity.name = `items[${labelId}][quantity]`; inputQuantity.value = '1'; inputQuantity.setAttribute('data-upsell-input', labelId); upsellSliderContainer.appendChild(inputQuantity); const inputId = document.createElement('input'); inputId.type = 'hidden'; inputId.name = `items[${labelId}][id]`; inputId.value = variantId; inputId.setAttribute('data-upsell-input', labelId); upsellSliderContainer.appendChild(inputId); } else { const index = selectedUpsellProducts.findIndex(p => p.labelId === labelId); if (index > -1) { selectedUpsellProducts.splice(index, 1); } const inputsToRemove = upsellSliderContainer.querySelectorAll(`input[data-upsell-input="${labelId}"]`); inputsToRemove.forEach(input => input.remove()); } updateAddToCartButtonText(); } catch (error) { console.error('handleUpsellToggle: Error handling toggle:', error); } } function handleUpsellModal(event) { try { const modalImgUrl = event.target.dataset.modalImg; if (modalImgUrl && typeof $ !== 'undefined' && typeof $.confirm === 'function') { $.confirm({ backgroundDismiss: true, useBootstrap: false, title: false, cancelButton: false, closeIcon: true, content: ` `, buttons: { ok: { isHidden: true, action: function () {} } } }); } } catch (error) { console.error('handleUpsellModal: Error showing modal:', error); } } function applyUpsellSliderTextResize() { const upsellSliderContainer = document.getElementById(`upsell-slider-${componentId}`) || document.getElementById('upsell-slider'); if (!upsellSliderContainer) return; const upsellSliderTitles = upsellSliderContainer.querySelectorAll(".upsell-slider-product-cards .upsell-slider-title"); upsellSliderTitles.forEach(title => { if (title.innerText.length > 30) { title.classList.add("upsell-slider-title-resize"); } }); const badgeTitles = upsellSliderContainer.querySelectorAll('.upsell-slider-copy-container .upsell-slider-price-container .upsell-slider-sale-container'); badgeTitles.forEach(title => { if (title.innerText.length >= 10) { title.classList.add("upsell-slider-badge-resize"); } }); } function updateAddToCartButtonText() { try { const addToCartButton = document.getElementById(`AddToCart-${componentId}`); const addToCartText = addToCartButton ? addToCartButton.querySelector('.text') : null; if (!addToCartText) return; const totalProducts = 1 + selectedUpsellProducts.length; if (totalProducts === 1) { addToCartText.textContent = addToCartButton.getAttribute('data-label') || 'Add to Cart'; } else { const baseLabel = addToCartButton.getAttribute('data-label') || 'Add to Cart'; addToCartText.textContent = `${baseLabel} (${totalProducts})`; } } catch (error) { console.error('updateAddToCartButtonText: Error updating button text:', error); } } function clearUpsellSliderState() { try { const upsellContainer = document.getElementById(`upsell-slider-${componentId}`) || document.getElementById('upsell-slider'); if (upsellContainer) { upsellContainer.style.display = 'none'; } selectedUpsellProducts.length = 0; if (upsellSliderFlickity) { try { upsellSliderFlickity.off(); upsellSliderFlickity.destroy(); } catch (flickityError) { console.warn('clearUpsellSliderState: Error destroying Flickity instance:', flickityError); } upsellSliderFlickity = null; const upsellContainer = document.getElementById(`upsell-slider-${componentId}`) || document.getElementById('upsell-slider'); if (upsellContainer) { const carouselContainer = upsellContainer.querySelector('.upsell-slider-carousel-container'); if (carouselContainer) { carouselContainer.classList.remove('flickity-enabled'); carouselContainer.removeAttribute('tabindex'); const flickityElements = carouselContainer.querySelectorAll('.flickity-viewport, .flickity-prev-next-button, .flickity-page-dots'); flickityElements.forEach(el => el.remove()); } } } if (typeof window !== 'undefined') { if (window.pendingUpsellCollectionIds) { delete window.pendingUpsellCollectionIds[componentId]; } window.pendingUpsellCollectionId = null; } const upsellSliderContainer = document.getElementById(`upsell-slider-${componentId}`); if (upsellSliderContainer) { const existingUpsellInputs = upsellSliderContainer.querySelectorAll('input[data-upsell-input]'); existingUpsellInputs.forEach(input => input.remove()); } } catch (error) { console.error('clearUpsellSliderState: Error clearing state:', error); } } async function preloadCriticalProductsOnly(collectionData) { if (!collectionData || !collectionData.products) { console.warn('No collection data available for critical preloading'); return; } const criticalProductHandles = collectionData.products.edges .slice(0, 8) .map(edge => edge.node.handle) .filter(handle => handle && !productCache[handle]); if (criticalProductHandles.length === 0) { return; } const fetchPromises = criticalProductHandles.map(handle => fetchLightweightProductData(handle).then(productData => ({ handle, data: productData })) ); try { const results = await Promise.all(fetchPromises); results.forEach(result => { if (result.data) { productCache[result.handle] = result.data; } }); } catch (error) { console.error('Error preloading critical products:', error); } } async function fetchLightweightProductData(handle) { const query = ` query @inContext(country: ${COUNTRY_ISO_CODE}) { product(handle: "${handle}") { id title availableForSale handle tags featuredImage { url altText } images(first: 5) { edges { node { url altText } } } options { name values } ${PRODUCT_GRAPHQL_METAFIELD_QUERY} variants(first: 20) { edges { node { id title availableForSale price { amount } compareAtPrice { amount } selectedOptions { name value } image { url altText } } } } } }`; try { const response = await fetch(GRAPHQL_URL_VERSION, { method: 'POST', headers: graphqlHeadersObj, body: query }); const res = await response.json(); if (res.data && res.data.product) { processProductDescriptions(res.data.product); return res.data.product; } return null; } catch (error) { console.error(`Lightweight fetch error for product ${handle}:`, error); return null; } } async function cacheSilhouetteProductsOptimized() { const loadedProducts = Object.values(productCache); if (loadedProducts.length === 0) { return; } const criticalSilhouetteIds = new Set(); const additionalSilhouetteIds = new Set(); loadedProducts.forEach(product => { const silhouetteProductsString = getMetafieldValue(product, 'products_for_silhouette_selector_page_version__4_max'); if (silhouetteProductsString) { try { const productIds = JSON.parse(silhouetteProductsString); if (Array.isArray(productIds)) { productIds.slice(0, 2).forEach(id => criticalSilhouetteIds.add(id)); productIds.slice(2).forEach(id => additionalSilhouetteIds.add(id)); } } catch (error) { console.warn(`Error parsing silhouette products for ${product.handle}:`, error); } } }); if (criticalSilhouetteIds.size > 0) { const criticalFetchPromises = Array.from(criticalSilhouetteIds).map(productId => fetchProductById(productId).then(productData => ({ id: productId, data: productData })) ); try { const criticalResults = await Promise.all(criticalFetchPromises); criticalResults.forEach(result => { if (result.data && result.data.handle && !productCache[result.data.handle]) { productCache[result.data.handle] = result.data; } }); } catch (error) { console.error('Error caching critical silhouette products:', error); } } if (additionalSilhouetteIds.size > 0) { setTimeout(async () => { const additionalFetchPromises = Array.from(additionalSilhouetteIds).map(productId => fetchProductById(productId).then(productData => ({ id: productId, data: productData })) ); try { const additionalResults = await Promise.all(additionalFetchPromises); additionalResults.forEach(result => { if (result.data && result.data.handle && !productCache[result.data.handle]) { productCache[result.data.handle] = result.data; } }); } catch (error) { console.error('Error caching additional silhouette products:', error); } }, 500); } } async function cacheCurrentProductSilhouettes(product) { if (!product) return; const silhouetteProductsString = getMetafieldValue(product, 'products_for_silhouette_selector_page_version__4_max'); if (!silhouetteProductsString) { return; } try { const productIds = JSON.parse(silhouetteProductsString); if (!Array.isArray(productIds) || productIds.length === 0) { return; } const silhouetteFetchPromises = productIds.map(productId => deduplicatedFetch(`silhouette-${productId}`, async () => { return await fetchProductById(productId); }).then(productData => ({ id: productId, data: productData })) ); const silhouetteResults = await Promise.all(silhouetteFetchPromises); silhouetteResults.forEach(result => { if (result.data && result.data.handle && !productCache[result.data.handle]) { productCache[result.data.handle] = result.data; } }); } catch (error) { console.error('Error caching current product silhouettes:', error); } } async function refreshSilhouetteSelector() { if (!productDataGlobal) return; const pdpContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"]`) || document.querySelector('.pdp-container'); const silhouetteSelectorContainer = pdpContainer?.querySelector(`.silhouette-selector`); if (!silhouetteSelectorContainer) { console.log('refreshSilhouetteSelector: No silhouette selector container found'); return; } const newSilhouetteHtml = renderSilhouetteSelector(); if (newSilhouetteHtml) { // Replace markup directly without skeleton silhouetteSelectorContainer.outerHTML = newSilhouetteHtml; // Ensure container is visible immediately const refreshedContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .silhouette-selector`); if (refreshedContainer) { refreshedContainer.style.display = ''; } if (pdpContainer) { pdpContainer.removeAttribute('data-silhouette-loading'); } // Initialize silhouette container visibility initializeSilhouetteContainerVisibility(); // Schedule fade-in after the animation timeout (2 seconds as set by user) setTimeout(() => { const silhouetteContainer = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .silhouette-options-container`); if (silhouetteContainer) { silhouetteContainer.classList.add('fade-in'); } }, 500); const newSilhouetteOptions = document.querySelectorAll(`.pdp-container[data-component-id="${componentId}"] .silhouette-selector .silhouette-options`); newSilhouetteOptions.forEach(silhouetteOption => { silhouetteOption.addEventListener('click', function () { const productHandle = this.dataset.productHandle; if (productHandle && productHandle !== productDataGlobal.handle) { const upsellSlider = document.getElementById(`upsell-slider-${componentId}`); if (upsellSlider) { upsellSlider.style.display = 'none'; } switchToProduct(productHandle); } }); }); const newSilhouetteInfoIcon = document.querySelector(`.pdp-container[data-component-id="${componentId}"] .silhouette-selector .silhouette-info-icon`); if (newSilhouetteInfoIcon) { newSilhouetteInfoIcon.addEventListener('click', function() { const infoIconImage = getMetafieldValue(productDataGlobal, 'info_icon_image'); if (infoIconImage && typeof $ !== 'undefined' && typeof $.confirm === 'function') { $.confirm({ backgroundDismiss: true, useBootstrap: false, title: false, cancelButton: false, closeIcon: true, content: ` `, buttons: { ok: { isHidden: true, action: function () {} } } }); } }); } } else { silhouetteSelectorContainer.style.display = 'none'; } } function handleOnVariantChange(inputEl) { try { if (!inputEl) { console.error(`handleOnVariantChange (${componentId}): No input element provided`); return; } const componentContainer = document.querySelector(`[data-component-id="${componentId}"]`); if (!componentContainer) { console.error(`handleOnVariantChange (${componentId}): Component container not found`); return; } if (!productDataGlobal) { console.error(`handleOnVariantChange (${componentId}): No product data available`); return; } const optionName = inputEl.dataset.option; const selectedValue = inputEl.value; if (optionName && selectedValue) { if (optionName === 'option1') { const productType = getMetafieldValue(productDataGlobal, 'product_type') || ''; if (productType === 'Ring') { currentSelectedOptions['Size'] = selectedValue; } else { currentSelectedOptions[optionName] = selectedValue; } } else { currentSelectedOptions[optionName] = selectedValue; } } let matchingVariant = null; if (productDataGlobal.variants && productDataGlobal.variants.edges) { for (const variantEdge of productDataGlobal.variants.edges) { const variant = variantEdge.node; let isMatch = true; for (const selectedOption of variant.selectedOptions) { const optionName = selectedOption.name; const optionValue = selectedOption.value; if (currentSelectedOptions[optionName] && currentSelectedOptions[optionName] !== optionValue) { isMatch = false; break; } } if (isMatch) { matchingVariant = variant; break; } } } if (matchingVariant) { const priceElement = componentContainer.querySelector('.current-price'); const compareAtPriceElement = componentContainer.querySelector('.compare-at-price'); if (priceElement) { priceElement.textContent = `${CURRENCY_SYMBOL}${parseFloat(matchingVariant.price.amount).toFixed(2)}`; } if (compareAtPriceElement) { if (matchingVariant.compareAtPrice && parseFloat(matchingVariant.compareAtPrice.amount) > parseFloat(matchingVariant.price.amount)) { compareAtPriceElement.textContent = `${CURRENCY_SYMBOL}${parseFloat(matchingVariant.compareAtPrice.amount).toFixed(2)}`; compareAtPriceElement.style.display = 'inline'; } else { compareAtPriceElement.style.display = 'none'; } } const productForm = componentContainer.querySelector('form[action*="/cart/add"]'); if (productForm) { const variantIdInput = productForm.querySelector('input[name="id"]'); const variantId = matchingVariant.id.replace("gid://shopify/ProductVariant/", ""); if (variantIdInput) { variantIdInput.value = variantId; } } updateGalleryForVariant(matchingVariant); if (window.location.pathname.includes(productDataGlobal.handle)) { const variantId = matchingVariant.id.replace("gid://shopify/ProductVariant/", ""); const newUrl = `${window.location.origin}${window.location.pathname}?variant=${variantId}`; history.replaceState({id: window.location.pathname}, null, newUrl); } } updateVariantSelectorVisualState(inputEl); registerComponentData(); } catch (error) { console.error(`handleOnVariantChange (${componentId}): Error handling variant change:`, error); } } function updateVariantSelectorVisualState(inputEl) { try { const parentContainer = inputEl.closest('.ridge-product-swatch-v3'); if (parentContainer) { const allOptions = parentContainer.querySelectorAll('.swatch-option'); allOptions.forEach(option => option.classList.remove('selected')); const currentOption = inputEl.closest('.swatch-option'); if (currentOption) { currentOption.classList.add('selected'); } const headerTitle = parentContainer.querySelector('.swatch-option-header-title'); const selectedValue = inputEl.value; if (headerTitle && selectedValue) { headerTitle.textContent = selectedValue; } } } catch (error) { console.error(`updateVariantSelectorVisualState (${componentId}): Error updating visual state:`, error); } } function updateGalleryForVariant(variant) { try { if (variant.selectedOptions && variant.selectedOptions.length > 0) { const materialOption = variant.selectedOptions.find(opt => opt.name !== 'Size'); if (materialOption && materialOption.value) { switchGallery(materialOption.value); } } } catch (error) { console.error(`updateGalleryForVariant (${componentId}): Error updating gallery:`, error); } } function registerComponentData() { window.pdpComponentRegistry[componentId] = { productData: productDataGlobal, selectedOptions: currentSelectedOptions, componentId: componentId }; } window[`handleOnVariantChange_${componentId}`] = handleOnVariantChange; window[`pageAddToCart_${componentId}`] = pageAddToCartScoped; if (typeof window.handleOnVariantChange === 'undefined') { window.handleOnVariantChange = handleOnVariantChange; } if (typeof window.pageAddToCart === 'undefined') { window.pageAddToCart = pageAddToCartScoped; } registerComponentData(); return productDataGlobal; })();

    SAVE 10% SITEWIDE WITH CODE: RIDGE10

    SAVE 10% SITEWIDE WITH CODE: RIDGE10

    SAVE 10% SITEWIDE WITH CODE: RIDGE10

    100,000+ 5 Star Reviews

    5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

    The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

    BUY NOW
    Orange sports car and blue truck on a rocky terrain under a clear sky.

    100,000+ 5 Star Reviews

    5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

    The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

    BUY NOW
    Orange sports car and blue truck on a rocky terrain under a clear sky.

    100,000+ 5 Star Reviews

    5 REASONS TO CARRY A RIDGE WALLET (AND MAYBE WIN A LAMBORGHINI)

    The Wallet trusted by millions for a reason—and right now, it could win you a 610hp Lamborghini or 558hp Hennessey truck. Here's why it’s the smartest upgrade you’ll make all summer.

    BUY NOW
    Orange sports car and blue truck on a rocky terrain under a clear sky.

    1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

    Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


    Two winners. Ends soon. Don’t wait to make your move.

    1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

    Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


    Two winners. Ends soon. Don’t wait to make your move.

    1. FOR A LIMITED TIME, IT COULD WIN YOU A SUPERCAR

    Every Ridge Wallet purchase earns entries to win your choice: A 610hp Lamborghini Huracán Sterrato. A 558hp Hennessey VelociRaptor. Or $100,000 in cash.


    Two winners. Ends soon. Don’t wait to make your move.

    2. SLIM, BUT BUILT TO DO MORE

    Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


    No fraying seams. No folded leather. Just modern efficiency.

    2. SLIM, BUT BUILT TO DO MORE

    Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


    No fraying seams. No folded leather. Just modern efficiency.

    2. SLIM, BUT BUILT TO DO MORE

    Ridge Wallets carry 1–12 cards without stretching out. Keep your cards and cash secure with a slim, no-bulk design that slides easily into any pocket.


    No fraying seams. No folded leather. Just modern efficiency.

    3. ENGINEERED FROM MILITARY-GRADE MATERIALS

    Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


    It’s performance you’ll feel every day.

    3. ENGINEERED FROM MILITARY-GRADE MATERIALS

    Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


    It’s performance you’ll feel every day.

    3. ENGINEERED FROM MILITARY-GRADE MATERIALS

    Made with aluminum, carbon fiber, or forged composites—Ridge Wallets are built like the gear you trust most. Scratch-resistant. Weatherproof. Virtually indestructible.


    It’s performance you’ll feel every day.

    4. SECURITY THAT BLOCKS DIGITAL THEFT

    Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


    Form meets function, and security comes standard.

    4. SECURITY THAT BLOCKS DIGITAL THEFT

    Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


    Form meets function, and security comes standard.

    4. SECURITY THAT BLOCKS DIGITAL THEFT

    Every Ridge Wallet includes RFID-blocking plates to stop credit card skimmers. Your cards stay safe from contactless hacks—wherever you go.


    Form meets function, and security comes standard.

    5. 100,000+ 5-STAR REVIEWS BACK IT UP

    With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

     

    It’s a product people trust enough to gift, replace, and recommend.

    5. 100,000+ 5-STAR REVIEWS BACK IT UP

    With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

     

    It’s a product people trust enough to gift, replace, and recommend.

    5. 100,000+ 5-STAR REVIEWS BACK IT UP

    With over 5 million wallets sold, Ridge has become the go-to for everyday carry.

     

    It’s a product people trust enough to gift, replace, and recommend.

    EARN 4x ENTRIES

    UP TO 44% OFF

    EARN 4x ENTRIES

    UP TO 44% OFF

    EARN 4x ENTRIES

    UP TO 44% OFF

    EARN 4x ENTRIES

    UP TO 44% OFF

    EARN 4x ENTRIES

    UP TO 44% OFF

    EARN 4x ENTRIES

    EARN 4x ENTRIES

    UP TO 44% OFF

    EARN 4x ENTRIES

    UP TO 44% OFF

    EARN 4x ENTRIES

    UP TO 44% OFF

    EARN 4x ENTRIES

    UP TO 44% OFF

    EARN 4x ENTRIES

    HOW DOES IT WORK

    We’re going above and beyond this year with bigger, faster cars and TWO winners.

    Colorful car with speech bubble graphic and the word

    ENTER FOR FREE

    With Email & SMS

    Person holding a blue Ridge wallet in their hands.

    EARN MORE ENTRIES

    Buying gear you’ll love.

    Orange smartphone case, smartwatch, and cardholder on a black background.

    GET 2-4X ENTRIES

    On Exclusive Collections.

    Wooden crate with

    SPEND MORE

    For Mystery entries and gear.

    HOW DOES IT WORK

    We’re going above and beyond this year with bigger, faster cars and TWO winners.

    Icon of two speech bubbles with colorful background.

    ENTER FOR FREE

    With Email & SMS

    Person holding a blue card-like object with a smooth surface.

    EARN MORE ENTRIES

    Buying gear you’ll love.

    Orange phone case and accessories on a textured black background.

    GET 2-4X ENTRIES

    On Exclusive Collections.

    Wooden crate with

    SPEND MORE

    For Mystery entries and gear.

    GEAR BUILT BETTER

    HIGH-GRADE MATERIALS

    Custom designs with military-grade construction.

    LIFETIME
    WARRANTY

    Not just gear built to last — but guaranteed for life.

    99 DAY RISK-FREE TRIAL

    Don't love it after 99 days? Send it right back, no questions asked.