805 lines
35 KiB
JavaScript
805 lines
35 KiB
JavaScript
const SEED_VERSION = 7;
|
||
const PRICE_UPDATED_AT = '2026-05-01';
|
||
|
||
const CATEGORY_META = {
|
||
hotel: { emoji: '🏨', color: '#3b82f6' },
|
||
flight: { emoji: '✈️', color: '#38bdf8' },
|
||
golf: { emoji: '⛳', color: '#22c55e' },
|
||
nightlife: { emoji: '🎧', color: '#a855f7' },
|
||
excursion: { emoji: '🚤', color: '#06b6d4' },
|
||
itinerary: { emoji: '🗺️', color: '#fbbf24' },
|
||
budget: { emoji: '💸', color: '#f97316' },
|
||
results: { emoji: '🏆', color: '#facc15' },
|
||
};
|
||
|
||
const GUEST_ROSTER = [
|
||
{ name: 'Jon', last4: '7506', role: 'groom' },
|
||
{ name: 'Toph', last4: '8116', role: 'best-man' },
|
||
{ name: 'Hans', last4: '6681', role: 'guest' },
|
||
{ name: 'Janno', last4: '2809', role: 'guest' },
|
||
{ name: 'JT', last4: '3286', role: 'guest' },
|
||
{ name: 'Cordero', last4: '0379', role: 'guest' },
|
||
{ name: 'Lester', last4: '8014', role: 'guest' },
|
||
{ name: 'Nick', last4: '6044', role: 'guest' },
|
||
{ name: 'David', last4: '5993', role: 'guest' },
|
||
{ name: 'Poalo', last4: '9922', role: 'guest' },
|
||
{ name: 'Justin', last4: '2329', role: 'guest' },
|
||
{ name: 'Ben Stewart', last4: '1957', role: 'guest' },
|
||
{ name: 'Joseph', last4: '4976', role: 'guest' },
|
||
{ name: 'Francis', last4: '4934', role: 'guest' },
|
||
];
|
||
|
||
const BUDGET_SCENARIOS = [
|
||
{
|
||
id: 'budget-8',
|
||
tier: 'Budget',
|
||
groupSize: 8,
|
||
perPerson: 1405,
|
||
groupTotal: 11240,
|
||
summary: 'Corazon + Palmilla + one shared activity + one nightlife night',
|
||
notes: [
|
||
'Flight estimate: $350',
|
||
'Hotel estimate: $450',
|
||
'Golf: Palmilla from $130',
|
||
'Activity: public sail / whale watch about $95',
|
||
'Food + drinks buffer: $275',
|
||
'Private round-trip transfer share: about $33',
|
||
],
|
||
},
|
||
{
|
||
id: 'budget-10',
|
||
tier: 'Budget',
|
||
groupSize: 10,
|
||
perPerson: 1398,
|
||
groupTotal: 13980,
|
||
summary: 'Corazon + Palmilla + one shared activity + one nightlife night',
|
||
notes: [
|
||
'Flight estimate: $350',
|
||
'Hotel estimate: $450',
|
||
'Golf: Palmilla from $130',
|
||
'Activity: public sail / whale watch about $95',
|
||
'Food + drinks buffer: $275',
|
||
'Private round-trip transfer share: about $26',
|
||
],
|
||
},
|
||
{
|
||
id: 'budget-12',
|
||
tier: 'Budget',
|
||
groupSize: 12,
|
||
perPerson: 1392,
|
||
groupTotal: 16704,
|
||
summary: 'Corazon + Palmilla + one shared activity + one nightlife night',
|
||
notes: [
|
||
'Flight estimate: $350',
|
||
'Hotel estimate: $450',
|
||
'Golf: Palmilla from $130',
|
||
'Activity: public sail / whale watch about $95',
|
||
'Food + drinks buffer: $275',
|
||
'Private round-trip transfer share: about $22',
|
||
],
|
||
},
|
||
{
|
||
id: 'balanced-8',
|
||
tier: 'Balanced',
|
||
groupSize: 8,
|
||
perPerson: 1688,
|
||
groupTotal: 13504,
|
||
summary: 'Grand Fiesta Americana + golf + sunset sail + one nightlife night',
|
||
notes: [
|
||
'Flight estimate: $350',
|
||
'All-inclusive stay: $850',
|
||
'Golf: Cabo del Sol / similar from $180',
|
||
'Sunset sail: about $125',
|
||
'Nightlife + covers: $100',
|
||
'Transfer + resort buffer: about $83',
|
||
],
|
||
},
|
||
{
|
||
id: 'balanced-10',
|
||
tier: 'Balanced',
|
||
groupSize: 10,
|
||
perPerson: 1681,
|
||
groupTotal: 16810,
|
||
summary: 'Grand Fiesta Americana + golf + sunset sail + one nightlife night',
|
||
notes: [
|
||
'Flight estimate: $350',
|
||
'All-inclusive stay: $850',
|
||
'Golf: Cabo del Sol / similar from $180',
|
||
'Sunset sail: about $125',
|
||
'Nightlife + covers: $100',
|
||
'Transfer + resort buffer: about $76',
|
||
],
|
||
},
|
||
{
|
||
id: 'balanced-12',
|
||
tier: 'Balanced',
|
||
groupSize: 12,
|
||
perPerson: 1677,
|
||
groupTotal: 20124,
|
||
summary: 'Grand Fiesta Americana + golf + sunset sail + one nightlife night',
|
||
notes: [
|
||
'Flight estimate: $350',
|
||
'All-inclusive stay: $850',
|
||
'Golf: Cabo del Sol / similar from $180',
|
||
'Sunset sail: about $125',
|
||
'Nightlife + covers: $100',
|
||
'Transfer + resort buffer: about $72',
|
||
],
|
||
},
|
||
{
|
||
id: 'splurge-8',
|
||
tier: 'Splurge',
|
||
groupSize: 8,
|
||
perPerson: 2484,
|
||
groupTotal: 19872,
|
||
summary: 'Breathless or Secrets + premium golf + private charter + VIP table',
|
||
notes: [
|
||
'Flight estimate: $400',
|
||
'Upscale all-inclusive stay: $1250',
|
||
'Premium golf: Quivira / similar about $250',
|
||
'Private whale or charter share: about $188',
|
||
'VIP nightlife share: about $213',
|
||
'Transfers + premium dinner buffer: about $183',
|
||
],
|
||
},
|
||
{
|
||
id: 'splurge-10',
|
||
tier: 'Splurge',
|
||
groupSize: 10,
|
||
perPerson: 2346,
|
||
groupTotal: 23460,
|
||
summary: 'Breathless or Secrets + premium golf + private charter + VIP table',
|
||
notes: [
|
||
'Flight estimate: $400',
|
||
'Upscale all-inclusive stay: $1250',
|
||
'Premium golf: Quivira / similar about $250',
|
||
'Private whale or charter share: about $150',
|
||
'VIP nightlife share: about $170',
|
||
'Transfers + premium dinner buffer: about $126',
|
||
],
|
||
},
|
||
{
|
||
id: 'splurge-12',
|
||
tier: 'Splurge',
|
||
groupSize: 12,
|
||
perPerson: 2289,
|
||
groupTotal: 27468,
|
||
summary: 'Breathless or Secrets + premium golf + private charter + VIP table',
|
||
notes: [
|
||
'Flight estimate: $400',
|
||
'Upscale all-inclusive stay: $1250',
|
||
'Premium golf: Quivira / similar about $250',
|
||
'Private whale or charter share: about $125',
|
||
'VIP nightlife share: about $142',
|
||
'Transfers + premium dinner buffer: about $122',
|
||
],
|
||
},
|
||
];
|
||
|
||
function buildOptionImageUrl(option) {
|
||
if (option.imageUrl) return option.imageUrl;
|
||
const primaryUrl = option.links?.[0]?.url || option.url || option.bookingUrl || '';
|
||
return primaryUrl ? `/api/preview-image?url=${encodeURIComponent(primaryUrl)}` : null;
|
||
}
|
||
|
||
function createOption(option) {
|
||
const categoryColor = CATEGORY_META[option.categoryId]?.color || '#888';
|
||
const primaryUrl = option.links?.[0]?.url || option.url || null;
|
||
return {
|
||
approved: true,
|
||
addedBy: 'system',
|
||
votes: [],
|
||
details: [],
|
||
links: [],
|
||
categoryColor,
|
||
url: primaryUrl,
|
||
bookingUrl: option.bookingUrl || primaryUrl,
|
||
imageUrl: buildOptionImageUrl(option),
|
||
...option,
|
||
categoryColor,
|
||
url: primaryUrl,
|
||
bookingUrl: option.bookingUrl || primaryUrl,
|
||
imageUrl: buildOptionImageUrl(option),
|
||
};
|
||
}
|
||
|
||
function buildSeedData() {
|
||
return {
|
||
seedVersion: SEED_VERSION,
|
||
priceUpdatedAt: PRICE_UPDATED_AT,
|
||
categories: [
|
||
{ id: 'hotel', name: 'Hotels', emoji: '🏨' },
|
||
{ id: 'flight', name: 'Flights', emoji: '✈️' },
|
||
{ id: 'golf', name: 'Golf', emoji: '⛳' },
|
||
{ id: 'nightlife', name: 'Nightlife', emoji: '🎧' },
|
||
{ id: 'excursion', name: 'Excursions', emoji: '🚤' },
|
||
{ id: 'itinerary', name: 'Itineraries', emoji: '🗺️' },
|
||
{ id: 'budget', name: 'Budget', emoji: '💸' },
|
||
{ id: 'results', name: 'Results', emoji: '🏆' },
|
||
],
|
||
guestRoster: GUEST_ROSTER,
|
||
budgetScenarios: BUDGET_SCENARIOS,
|
||
options: [
|
||
createOption({
|
||
id: 'hotel-corazon',
|
||
seedKey: 'hotel-corazon',
|
||
categoryId: 'hotel',
|
||
name: 'Corazon Cabo Resort & Spa',
|
||
desc: 'Best party-first base on Medano Beach. Walkable to downtown and Costco package pages currently show transfer-inclusive offers plus 4th or 5th night promos.',
|
||
lat: 23.0639,
|
||
lng: -109.6991,
|
||
details: ['Costco package availability only', 'KAYAK no fresh rates', 'Walk to marina nightlife'],
|
||
links: [
|
||
{ label: 'Official', url: 'https://www.corazoncabo.com/' },
|
||
{ label: 'Costco Travel', url: 'https://www.costcotravel.com/Vacation-Packages/Offers/MEXLOSCABOSCORAZON20230510' },
|
||
{ label: 'KAYAK', url: 'https://www.kayak.com/Cabo-San-Lucas-Hotels-Cabo-Villas-Beach-Resort-Spa.58565.ksp' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-breathless',
|
||
seedKey: 'hotel-breathless',
|
||
categoryId: 'hotel',
|
||
name: 'Breathless Cabo San Lucas',
|
||
desc: 'Adults-only, marina-facing, and the easiest all-inclusive pick for a true bachelor-party vibe.',
|
||
lat: 23.0628,
|
||
lng: -109.6981,
|
||
details: ['Apple exact-date quote: $2,016 pp', 'Costco package: $1,678.99 pp', 'Adults-only'],
|
||
links: [
|
||
{ label: 'Official', url: 'https://www.hyattinclusivecollection.com/en/resorts-hotels/breathless/mexico/cabo-san-lucas-resort-spa/' },
|
||
{ label: 'Hyatt', url: 'https://www.hyatt.com/en-US/hotel/mexico/breathless-cabo-san-lucas/brcsl' },
|
||
{ label: 'Costco Travel', url: 'https://www.costcotravel.com/Vacation-Packages/Offers/MEXLOSCABOSBREATHE20230330' },
|
||
{ label: 'Apple Vacations', url: 'https://www.applevacations.com/hotels/breathless-cabo-san-lucas-resort-spa-all-inclusive-adults-only?cachefaretype=&destinationcode=SJD&dynamicpackageid=H01&los=4&mode=0&onsaleid=1398047&traveldate=2027-02-02' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-grand-fiesta',
|
||
seedKey: 'hotel-grand-fiesta',
|
||
categoryId: 'hotel',
|
||
name: 'Grand Fiesta Americana Los Cabos',
|
||
desc: 'Best overall balance for golf + all-inclusive + quality. Strong fit if the group wants one easy answer without going full splurge.',
|
||
lat: 23.0949,
|
||
lng: -109.7067,
|
||
details: ['Apple exact-date quote: $2,111 pp', 'KAYAK from $212/night', 'Golf-friendly'],
|
||
links: [
|
||
{ label: 'Official', url: 'https://www.fiestamericanatravelty.com/en/grand-fiesta-americana/hotels/grand-fiesta-americana-los-cabos-all-inclusive-golf-and-spa' },
|
||
{ label: 'Costco Travel', url: 'https://www.costcotravel.com/Vacation-Packages/Offers/MEXLOSCABOSGRANDFIESTA20171011' },
|
||
{ label: 'Apple Vacations', url: 'https://www.applevacations.com/HotelById?cachefaretype=&destinationcode=SJD&dynamicpackageid=H01&hotelcode=43000&los=4&mode=0&onsaleid=1614780&redirect=false&remotesourcecode=HBSHotel&traveldate=2027-02-02&vendorcode=APV' },
|
||
{ label: 'KAYAK', url: 'https://www.kayak.com/Cabo-San-Lucas-Hotels-Grand-Fiesta-Americana-Los-Cabos-Golf-Spa.331383.ksp' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-secrets',
|
||
seedKey: 'hotel-secrets',
|
||
categoryId: 'hotel',
|
||
name: 'Secrets Puerto Los Cabos',
|
||
desc: 'Upscale adults-only pick with strong group-trip polish. Better for a luxe weekend than a chaos-first party hotel.',
|
||
lat: 23.0227,
|
||
lng: -109.7062,
|
||
details: ['KAYAK exact-date room rate: $335/night', 'Costco package: $2,005.80 pp', 'Adults-only'],
|
||
links: [
|
||
{ label: 'Official', url: 'https://www.hyattinclusivecollection.com/en/resorts-hotels/secrets/mexico/puerto-los-cabos-golf-spa-resort/' },
|
||
{ label: 'Costco Travel', url: 'https://www.costcotravel.com/Vacation-Packages/Offers/MEXLOSCABOSSECRETSPUERT20230330' },
|
||
{ label: 'CheapCaribbean', url: 'https://www.cheapcaribbean.com/HotelById/?cachefaretype=&destinationcode=SJD&dynamicpackageid=H01&hotelcode=SJDSCRT&los=4&mode=0&onsaleid=2173329&redirect=false&remotesourcecode=LtmsHotel&traveldate=2027-02-02&vendorcode=CCV' },
|
||
{ label: 'KAYAK', url: 'https://www.kayak.com/San-Jose-del-Cabo-Hotels-Secrets-Puerto-Los-Cabos-Adults-Only.551846.ksp' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-pacifica',
|
||
seedKey: 'hotel-pacifica',
|
||
categoryId: 'hotel',
|
||
name: 'Pueblo Bonito Pacifica',
|
||
desc: 'Luxury adults-only option with Quivira access. Best if the trip is really a premium golf weekend with nightlife as a side quest.',
|
||
lat: 23.0474,
|
||
lng: -109.7053,
|
||
details: ['Adults-only', 'Quivira access', 'Luxury retreat'],
|
||
links: [
|
||
{ label: 'Official', url: 'https://www.pueblobonito.com/resorts/pacifica?resort=4' },
|
||
{ label: 'Quivira FAQ', url: 'https://www.pueblobonito.com/resorts/pacifica/faq' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-dreams-los-cabos',
|
||
seedKey: 'hotel-dreams-los-cabos',
|
||
categoryId: 'hotel',
|
||
name: 'Dreams Los Cabos Suites Golf Resort & Spa',
|
||
desc: 'Balanced all-inclusive option with the cleanest Apple and Costco pricing signal from today.',
|
||
details: ['Apple exact-date quote: $1,757 pp', 'Costco package: $1,447.80 pp', 'All-inclusive'],
|
||
links: [
|
||
{ label: 'Hyatt Inclusive', url: 'https://www.hyattinclusivecollection.com/en/resorts-hotels/dreams/mexico/los-cabos-suites-golf-resort-spa/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-zoetry-casa-del-mar',
|
||
seedKey: 'hotel-zoetry-casa-del-mar',
|
||
categoryId: 'hotel',
|
||
name: 'Zoetry Casa del Mar',
|
||
desc: 'Higher-end adults-only pick that sits in the luxe tier without going fully maxed out.',
|
||
details: ['Apple exact-date quote: $1,944 pp', 'Costco package: $1,717.42 pp', 'Adults-only'],
|
||
links: [
|
||
{ label: 'Hyatt', url: 'https://www.hyatt.com/en-US/hotel/mexico/zoetry-casa-del-mar/zocdm' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-hyatt-ziva-los-cabos',
|
||
seedKey: 'hotel-hyatt-ziva-los-cabos',
|
||
categoryId: 'hotel',
|
||
name: 'Hyatt Ziva Los Cabos',
|
||
desc: 'Family-friendly luxury option that still works for a big group if the trip tilts more polished than rowdy.',
|
||
details: ['Apple exact-date quote: $2,178 pp', 'Beachfront', 'All-inclusive'],
|
||
links: [
|
||
{ label: 'Hyatt', url: 'https://www.hyatt.com/en-US/hotel/mexico/hyatt-ziva-los-cabos/sjdif' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-riu-palace-cabo-san-lucas',
|
||
seedKey: 'hotel-riu-palace-cabo-san-lucas',
|
||
categoryId: 'hotel',
|
||
name: 'Riu Palace Cabo San Lucas',
|
||
desc: 'Value-forward all-inclusive with a more party-friendly profile than the luxury adults-only resorts.',
|
||
details: ['Apple exact-date quote: $1,529 pp', 'Party-friendly all-inclusive', 'Value pick'],
|
||
links: [
|
||
{ label: 'RIU', url: 'https://www.riu.com/en/hotel/mexico/los-cabos/hotel-riu-palace-cabo-san-lucas/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-riu-palace-baja-california',
|
||
seedKey: 'hotel-riu-palace-baja-california',
|
||
categoryId: 'hotel',
|
||
name: 'Riu Palace Baja California',
|
||
desc: 'Adults-only RIU choice with a cleaner energy than Cabo San Lucas while staying in the value band.',
|
||
details: ['Apple exact-date quote: $1,597 pp', 'Adults-only', 'RIU all-inclusive'],
|
||
links: [
|
||
{ label: 'RIU', url: 'https://www.riu.com/en/hotel/mexico/los-cabos/hotel-riu-palace-baja-california/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-me-cabo-by-melia',
|
||
seedKey: 'hotel-me-cabo-by-melia',
|
||
categoryId: 'hotel',
|
||
name: 'ME Cabo by Meliá',
|
||
desc: 'Beach-club leaning stay for the group that wants energy and location over quiet luxury.',
|
||
details: ['Apple exact-date quote: $1,533 pp', 'Beach club energy', 'Medano Beach'],
|
||
links: [
|
||
{ label: 'ME Cabo', url: 'https://www.hotelmecabo.com/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-paradisus-los-cabos',
|
||
seedKey: 'hotel-paradisus-los-cabos',
|
||
categoryId: 'hotel',
|
||
name: 'Paradisus Los Cabos',
|
||
desc: 'Upscale all-inclusive with strong amenities and a better balance than the ultra-luxe splurge properties.',
|
||
details: ['Apple exact-date quote: $1,722 pp', 'Spa-forward', 'Adults-friendly luxury'],
|
||
links: [
|
||
{ label: 'Paradisus', url: 'https://www.paradisusloscabosresort.com/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-hard-rock-los-cabos',
|
||
seedKey: 'hotel-hard-rock-los-cabos',
|
||
categoryId: 'hotel',
|
||
name: 'Hard Rock Hotel Los Cabos',
|
||
desc: 'The loudest splurge option from today’s Apple search, with the highest quoted price on the list.',
|
||
details: ['Apple exact-date quote: $3,343 pp', 'Premium splurge', 'High-energy all-inclusive'],
|
||
links: [
|
||
{ label: 'Hard Rock', url: 'https://hotel.hardrock.com/los-cabos' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-solmar-resort',
|
||
seedKey: 'hotel-solmar-resort',
|
||
categoryId: 'hotel',
|
||
name: 'Solmar Resort',
|
||
desc: 'Low-cost KAYAK option if the group wants to keep the room line item very lean.',
|
||
details: ['KAYAK exact-date quote: $185/night', 'Budget-friendly', 'Downtown-adjacent'],
|
||
links: [
|
||
{ label: 'Solmar', url: 'https://www.solmar.com/en/hotels/cabo-san-lucas/solmar-resort/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-tesoro-los-cabos',
|
||
seedKey: 'hotel-tesoro-los-cabos',
|
||
categoryId: 'hotel',
|
||
name: 'Tesoro Los Cabos',
|
||
desc: 'Marina-side value stay that landed in the middle of the KAYAK result set today.',
|
||
details: ['KAYAK exact-date quote: $250/night', 'Marina access', 'Low-mid budget'],
|
||
links: [
|
||
{ label: 'Tesoro', url: 'https://tesoroloscabos.com/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-grand-solmar-lands-end',
|
||
seedKey: 'hotel-grand-solmar-lands-end',
|
||
categoryId: 'hotel',
|
||
name: "Grand Solmar Land's End Resort & Spa",
|
||
desc: 'Luxury Pacific-side resort with a stronger price tag than the value stays but below the ultra-splurge properties.',
|
||
details: ['KAYAK exact-date quote: $712/night', 'Luxury', 'Pacific-side'],
|
||
links: [
|
||
{ label: 'Grand Solmar', url: 'https://grandsolmarresort.solmar.com/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-comfort-inn-suites-los-cabos',
|
||
seedKey: 'hotel-comfort-inn-suites-los-cabos',
|
||
categoryId: 'hotel',
|
||
name: 'Comfort Inn & Suites Los Cabos',
|
||
desc: 'Bare-bones KAYAK option if the group wants a practical bed-and-shower stay.',
|
||
details: ['KAYAK exact-date quote: $129/night', 'Budget stay', 'Practical'],
|
||
links: [
|
||
{ label: 'KAYAK', url: 'https://www.kayak.com/Cabo-San-Lucas-Hotels-Comfort-Inn-Suites-Los-Cabos.1071781145.ksp' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-capital-o-hotel-dos-mares',
|
||
seedKey: 'hotel-capital-o-hotel-dos-mares',
|
||
categoryId: 'hotel',
|
||
name: 'Capital O Hotel Dos Mares, Cabo San Lucas',
|
||
desc: 'Lowest visible KAYAK price of the day, useful only if the group is aggressively minimizing room cost.',
|
||
details: ['KAYAK exact-date quote: $48/night', 'Lowest visible price', 'Budget'],
|
||
links: [
|
||
{ label: 'OYO', url: 'https://www.oyorooms.com/mx/92226/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-villa-del-palmar-beach-resort-cabo-san-lucas',
|
||
seedKey: 'hotel-villa-del-palmar-beach-resort-cabo-san-lucas',
|
||
categoryId: 'hotel',
|
||
name: 'Villa del Palmar Beach Resort Cabo San Lucas',
|
||
desc: 'Broad-appeal beach resort with a middle-of-the-road KAYAK room price today.',
|
||
details: ['KAYAK exact-date quote: $460/night', 'Beach resort', 'Family-friendly'],
|
||
links: [
|
||
{ label: 'Villa del Palmar', url: 'https://cabo.villadelpalmar.com/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'hotel-esperanza-auberge-collection',
|
||
seedKey: 'hotel-esperanza-auberge-collection',
|
||
categoryId: 'hotel',
|
||
name: 'Esperanza, Auberge Collection',
|
||
desc: 'Top-end KAYAK splurge result from today, priced well above the other options in the set.',
|
||
details: ['KAYAK exact-date quote: $3,243/night', 'Luxury splurge', 'Auberge Collection'],
|
||
links: [
|
||
{ label: 'Auberge', url: 'https://aubergeresorts.com/esperanza/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'flight-ont-sjd-kayak-cheapest',
|
||
seedKey: 'flight-ont-sjd-kayak-cheapest',
|
||
categoryId: 'flight',
|
||
name: 'ONT to SJD on KAYAK - Cheapest',
|
||
desc: 'Lowest exact-date round-trip flight quote from Ontario to San Jose del Cabo for the target trip window.',
|
||
details: ['$402 RT pp', 'Volaris, 1 stop', 'Best budget-flight anchor'],
|
||
links: [
|
||
{ label: 'KAYAK Flight Search', url: 'https://www.kayak.com/flights/ONT-SJD/2027-02-02/2027-02-06?sort=bestflight_a' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'flight-ont-sjd-kayak-best',
|
||
seedKey: 'flight-ont-sjd-kayak-best',
|
||
categoryId: 'flight',
|
||
name: 'ONT to SJD on KAYAK - Best',
|
||
desc: 'Higher-comfort exact-date round-trip flight quote for the target trip window.',
|
||
details: ['$605 RT pp', 'American, 1 stop', 'Best-value comfort anchor'],
|
||
links: [
|
||
{ label: 'KAYAK Flight Search', url: 'https://www.kayak.com/flights/ONT-SJD/2027-02-02/2027-02-06?sort=bestflight_a' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'golf-palmilla',
|
||
seedKey: 'golf-palmilla',
|
||
categoryId: 'golf',
|
||
name: 'Palmilla Golf Club',
|
||
desc: 'Best public price signal I found with transparent inclusions: green fee, shared cart, practice facilities, and bottled water.',
|
||
lat: 23.0519,
|
||
lng: -109.7058,
|
||
details: ['From $130 pp', 'Shared cart included', 'Strong budget-track pick'],
|
||
links: [
|
||
{ label: 'Cabo Villas Golf', url: 'https://www.cabovillas.com/golf/palmilla' },
|
||
{ label: 'Visit Los Cabos Golf Guide', url: 'https://www.visitloscabos.travel/golf/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'golf-cabo-del-sol',
|
||
seedKey: 'golf-cabo-del-sol',
|
||
categoryId: 'golf',
|
||
name: 'Cabo del Sol',
|
||
desc: 'The most natural golf pairing for Grand Fiesta Americana and the balanced-track itinerary.',
|
||
lat: 23.0569,
|
||
lng: -109.6962,
|
||
details: ['Use about $180 as current planning number', 'Best balanced-track fit', 'Ocean-desert layout'],
|
||
links: [
|
||
{ label: 'Official', url: 'https://cabodelsol.com/' },
|
||
{ label: 'Visit Los Cabos Golf Guide', url: 'https://www.visitloscabos.travel/golf/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'golf-quivira',
|
||
seedKey: 'golf-quivira',
|
||
categoryId: 'golf',
|
||
name: 'Quivira Golf Club',
|
||
desc: 'Premium golf move for the splurge weekend. Access is easiest through the Pueblo Bonito / Pacifica side of the destination.',
|
||
lat: 23.0403,
|
||
lng: -109.7221,
|
||
details: ['Use about $250 for planning', 'Pairs with Pacifica', 'Signature ocean holes'],
|
||
links: [
|
||
{ label: 'Official', url: 'https://www.quiviraloscabos.com/golf/' },
|
||
{ label: 'Pacifica FAQ', url: 'https://www.pueblobonito.com/resorts/pacifica/faq' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'golf-puerto-los-cabos',
|
||
seedKey: 'golf-puerto-los-cabos',
|
||
categoryId: 'golf',
|
||
name: 'Puerto Los Cabos Golf',
|
||
desc: 'Most natural pairing with Secrets Puerto Los Cabos if the group picks the upscale San Jose side.',
|
||
lat: 23.0308,
|
||
lng: -109.6964,
|
||
details: ['Convenient from Secrets', 'Upscale east-cape feel', 'Good alternative to Quivira'],
|
||
links: [
|
||
{ label: 'Visit Los Cabos Golf Guide', url: 'https://www.visitloscabos.travel/golf/' },
|
||
{ label: 'Secrets Official', url: 'https://www.hyattinclusivecollection.com/en/resorts-hotels/secrets/mexico/puerto-los-cabos-golf-spa-resort/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'nightlife-cabo-bash',
|
||
seedKey: 'nightlife-cabo-bash',
|
||
categoryId: 'nightlife',
|
||
name: 'Cabo Bash VIP Nightlife',
|
||
desc: 'Most turnkey option if you want the weekend hosted instead of DIY. They also coordinate yachts, villas, and day clubs.',
|
||
lat: 23.0627,
|
||
lng: -109.6989,
|
||
details: ['Gold package for 16 guests: $1,700', 'Concierge coordination', 'Strongest bachelor specialist'],
|
||
links: [
|
||
{ label: 'Bachelor Parties', url: 'https://www.cabobash.com/bachelor.html' },
|
||
{ label: 'Nightlife', url: 'https://www.cabobash.com/nightlife.html' },
|
||
{ label: 'Day Clubs', url: 'https://www.cabobash.com/day-clubs.html' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'nightlife-cabo-agency',
|
||
seedKey: 'nightlife-cabo-agency',
|
||
categoryId: 'nightlife',
|
||
name: 'The Cabo Agency VIP Tables',
|
||
desc: 'Best if you want to book specific tables instead of a full concierge weekend.',
|
||
lat: 23.0692,
|
||
lng: -109.6993,
|
||
details: ['Cabo Wabo VIP table $155 with $100 credit', 'Booth $400 with $300 credit', 'A la carte nightlife'],
|
||
links: [
|
||
{ label: 'VIP Tables', url: 'https://www.thecaboagency.com/cabo_vip_tables.php' },
|
||
{ label: 'Entertainment Packages', url: 'https://www.thecaboagency.com/cabo_entertainment_packages.php' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'nightlife-taboo',
|
||
seedKey: 'nightlife-taboo',
|
||
categoryId: 'nightlife',
|
||
name: 'Taboo Beach Club',
|
||
desc: 'High-spend daytime flex. Better for a splashy afternoon than an all-weekend base.',
|
||
lat: 23.0637,
|
||
lng: -109.7001,
|
||
details: ['Pool island for 4: $884', 'Cabana for 8: $2,060', 'Use for splurge tier'],
|
||
links: [
|
||
{ label: 'Cabo Bash Day Clubs', url: 'https://www.cabobash.com/day-clubs.html' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'nightlife-mango-deck',
|
||
seedKey: 'nightlife-mango-deck',
|
||
categoryId: 'nightlife',
|
||
name: 'Mango Deck / Office Zone',
|
||
desc: 'Best lower-spend party zone if you want daytime chaos close to Medano Beach without burning the whole budget.',
|
||
lat: 23.0631,
|
||
lng: -109.6995,
|
||
details: ['Mango Deck deposit from $40 pp', 'Easy with Corazon', 'Budget-track friendly'],
|
||
links: [
|
||
{ label: 'Cabo Bash Day Clubs', url: 'https://www.cabobash.com/day-clubs.html' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'excursion-whale-public',
|
||
seedKey: 'excursion-whale-public',
|
||
categoryId: 'excursion',
|
||
name: 'Cabo Adventures Whale Watching',
|
||
desc: 'February is prime whale season, and this is the cleanest official public-tour price signal I found.',
|
||
lat: 23.0626,
|
||
lng: -109.7004,
|
||
details: ['From $76', 'Prime season in February', 'Dock fee and transport extras may apply'],
|
||
links: [
|
||
{ label: 'Official', url: 'https://www.cabo-adventures.com/en/' },
|
||
{ label: 'Whale Season Guide', url: 'https://www.visitloscabos.travel/blog/post/whale-watching-in-los-cabos-2025-the-ultimate-guide-to-an-unforgettable-season/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'excursion-whale-private',
|
||
seedKey: 'excursion-whale-private',
|
||
categoryId: 'excursion',
|
||
name: 'Private Whale Watching Charter',
|
||
desc: 'Best splurge-group activity because the per-person hit gets much better as the group size rises.',
|
||
lat: 23.0626,
|
||
lng: -109.7004,
|
||
details: ['From $1,504 total', 'About $188 pp at 8', 'About $125 pp at 12'],
|
||
links: [
|
||
{ label: 'Cabo Adventures Private Tours', url: 'https://www.cabo-adventures.com/en/tours/private-cabo/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'excursion-atv',
|
||
seedKey: 'excursion-atv',
|
||
categoryId: 'excursion',
|
||
name: 'ATV Desert Adventure',
|
||
desc: 'Classic bachelor-party activity with a real extra-fee caveat worth budgeting up front.',
|
||
lat: 23.0289,
|
||
lng: -109.6689,
|
||
details: ['About $78-$91', '$35 damage waiver per vehicle', 'Entrance fee noted at check-in'],
|
||
links: [
|
||
{ label: 'Tour Landing Page', url: 'https://www.cabo-adventures.com/en/tours/land-adventures/' },
|
||
{ label: 'ATV Details', url: 'https://www.cabo-adventures.com/en/tour/atv-desert-adventure/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'excursion-sail',
|
||
seedKey: 'excursion-sail',
|
||
categoryId: 'excursion',
|
||
name: 'Sunset Sail / Public Yacht Day',
|
||
desc: 'Best balanced activity if the group wants a solid Cabo moment without chartering the entire day.',
|
||
lat: 23.0634,
|
||
lng: -109.6978,
|
||
details: ['Public sail from $109', 'Sunset sail $124.50', 'Private 38 foot sailboat from $855.94'],
|
||
links: [
|
||
{ label: 'Cabo Sailing', url: 'https://www.cabovillas.com/water-tours/cabo-sailing' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'itinerary-budget',
|
||
seedKey: 'itinerary-budget',
|
||
categoryId: 'itinerary',
|
||
name: 'Budget Track: Corazon + Palmilla + Public Activity',
|
||
desc: 'Best option if the group wants a real Cabo bachelor trip while keeping the all-in number close to the low-$1.4k range before extra bar tabs.',
|
||
lat: 23.0639,
|
||
lng: -109.6991,
|
||
details: ['8 guys: about $1,405 pp', '10 guys: about $1,398 pp', '12 guys: about $1,392 pp'],
|
||
links: [
|
||
{ label: 'Corazon', url: 'https://www.corazoncabo.com/' },
|
||
{ label: 'Palmilla', url: 'https://www.cabovillas.com/golf/palmilla' },
|
||
{ label: 'Transfers', url: 'https://www.cabovillas.com/transportation' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'itinerary-balanced',
|
||
seedKey: 'itinerary-balanced',
|
||
categoryId: 'itinerary',
|
||
name: 'Balanced Track: Grand Fiesta + Golf + Sail',
|
||
desc: 'Best all-around answer for a group that wants fewer logistics, a nice resort, and one clean golf day.',
|
||
lat: 23.0949,
|
||
lng: -109.7067,
|
||
details: ['8 guys: about $1,688 pp', '10 guys: about $1,681 pp', '12 guys: about $1,677 pp'],
|
||
links: [
|
||
{ label: 'Grand Fiesta', url: 'https://www.fiestamericanatravelty.com/en/grand-fiesta-americana/hotels/grand-fiesta-americana-los-cabos-all-inclusive-golf-and-spa' },
|
||
{ label: 'Costco Package', url: 'https://www.costcotravel.com/Vacation-Packages/Offers/MEXLOSCABOSGRANDFIESTA20171011' },
|
||
{ label: 'Sailing', url: 'https://www.cabovillas.com/water-tours/cabo-sailing' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'itinerary-splurge',
|
||
seedKey: 'itinerary-splurge',
|
||
categoryId: 'itinerary',
|
||
name: 'Splurge Track: Breathless or Secrets + Premium Golf + VIP Night',
|
||
desc: 'Best if the weekend is really about going big once, with the budget climbing above $2.2k per person depending on group size.',
|
||
lat: 23.0628,
|
||
lng: -109.6981,
|
||
details: ['8 guys: about $2,484 pp', '10 guys: about $2,346 pp', '12 guys: about $2,289 pp'],
|
||
links: [
|
||
{ label: 'Breathless', url: 'https://www.hyattinclusivecollection.com/en/resorts-hotels/breathless/mexico/cabo-san-lucas-resort-spa/' },
|
||
{ label: 'Secrets', url: 'https://www.hyattinclusivecollection.com/en/resorts-hotels/secrets/mexico/puerto-los-cabos-golf-spa-resort/' },
|
||
{ label: 'VIP Tables', url: 'https://www.thecaboagency.com/cabo_vip_tables.php' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'itinerary-concierge',
|
||
seedKey: 'itinerary-concierge',
|
||
categoryId: 'itinerary',
|
||
name: 'Concierge Route: Cabo Bash / Cabo Agency',
|
||
desc: 'Best if the group wants to stop spreadsheeting and hand flights, villas, yachts, transfers, and nightlife to a specialist.',
|
||
lat: 23.0633,
|
||
lng: -109.6992,
|
||
details: ['Most turnkey', 'Great for split budgets', 'Request quote for final pricing'],
|
||
links: [
|
||
{ label: 'Cabo Bash', url: 'https://www.cabobash.com/bachelor.html' },
|
||
{ label: 'The Cabo Agency', url: 'https://www.thecaboagency.com/cabo_bachelor_party.php' },
|
||
{ label: 'Blue Desert Package', url: 'https://www.bluedesertcabo.com/activities/packages/bachelor-party-vacation-package/' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'budget-option-budget',
|
||
seedKey: 'budget-option-budget',
|
||
categoryId: 'budget',
|
||
name: 'Budget Track',
|
||
desc: 'Corazon + one golf round + one public activity + one nightlife night. Best value if you want the trip fun but not financially reckless.',
|
||
details: ['8: $1,405 pp', '10: $1,398 pp', '12: $1,392 pp'],
|
||
links: [
|
||
{ label: 'Corazon', url: 'https://www.corazoncabo.com/' },
|
||
{ label: 'Palmilla', url: 'https://www.cabovillas.com/golf/palmilla' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'budget-option-balanced',
|
||
seedKey: 'budget-option-balanced',
|
||
categoryId: 'budget',
|
||
name: 'Balanced Track',
|
||
desc: 'Grand Fiesta all-inclusive + better golf + sunset sail + one nightlife push. Strongest overall bachelor-weekend value.',
|
||
details: ['8: $1,688 pp', '10: $1,681 pp', '12: $1,677 pp'],
|
||
links: [
|
||
{ label: 'Grand Fiesta', url: 'https://www.fiestamericanatravelty.com/en/grand-fiesta-americana/hotels/grand-fiesta-americana-los-cabos-all-inclusive-golf-and-spa' },
|
||
{ label: 'Costco Travel', url: 'https://www.costcotravel.com/Vacation-Packages/Offers/MEXLOSCABOSGRANDFIESTA20171011' },
|
||
],
|
||
}),
|
||
createOption({
|
||
id: 'budget-option-splurge',
|
||
seedKey: 'budget-option-splurge',
|
||
categoryId: 'budget',
|
||
name: 'Splurge Track',
|
||
desc: 'Adults-only resort, premium golf, private charter, and VIP nightlife. This is the blowout version.',
|
||
details: ['8: $2,484 pp', '10: $2,346 pp', '12: $2,289 pp'],
|
||
links: [
|
||
{ label: 'Breathless', url: 'https://www.hyattinclusivecollection.com/en/resorts-hotels/breathless/mexico/cabo-san-lucas-resort-spa/' },
|
||
{ label: 'Private Tour', url: 'https://www.cabo-adventures.com/en/tours/private-cabo/' },
|
||
],
|
||
}),
|
||
],
|
||
voters: [],
|
||
pollsOpen: true,
|
||
};
|
||
}
|
||
|
||
function mergeSeedData(existing = {}) {
|
||
const seed = buildSeedData();
|
||
const existingOptions = Array.isArray(existing.options) ? existing.options : [];
|
||
const mergedSeedOptions = seed.options.map((seedOption) => {
|
||
const match = existingOptions.find((option) => (
|
||
option.seedKey === seedOption.seedKey
|
||
|| (option.addedBy === 'system' && option.categoryId === seedOption.categoryId && option.name === seedOption.name)
|
||
));
|
||
|
||
return {
|
||
...seedOption,
|
||
votes: Array.isArray(match?.votes) ? match.votes : [],
|
||
approved: typeof match?.approved === 'boolean' ? match.approved : seedOption.approved,
|
||
addedBy: match?.addedBy || seedOption.addedBy,
|
||
};
|
||
});
|
||
|
||
const preservedCustomOptions = existingOptions.filter((option) => {
|
||
if (option.addedBy === 'system') return false;
|
||
|
||
return !mergedSeedOptions.some((seedOption) => (
|
||
(seedOption.seedKey && option.seedKey === seedOption.seedKey)
|
||
|| (seedOption.categoryId === option.categoryId && seedOption.name === option.name)
|
||
));
|
||
});
|
||
|
||
const existingCategories = Array.isArray(existing.categories) ? existing.categories : [];
|
||
const preservedCustomCategories = existingCategories.filter(
|
||
(category) => !seed.categories.some((seedCategory) => seedCategory.id === category.id),
|
||
);
|
||
|
||
return {
|
||
...existing,
|
||
seedVersion: seed.seedVersion,
|
||
priceUpdatedAt: seed.priceUpdatedAt,
|
||
categories: [...seed.categories, ...preservedCustomCategories],
|
||
budgetScenarios: seed.budgetScenarios,
|
||
guestRoster: seed.guestRoster,
|
||
options: [...mergedSeedOptions, ...preservedCustomOptions],
|
||
voters: Array.isArray(existing.voters) ? existing.voters : [],
|
||
pollsOpen: typeof existing.pollsOpen === 'boolean' ? existing.pollsOpen : true,
|
||
};
|
||
}
|
||
|
||
module.exports = {
|
||
SEED_VERSION,
|
||
PRICE_UPDATED_AT,
|
||
CATEGORY_META,
|
||
buildSeedData,
|
||
mergeSeedData,
|
||
};
|