- Add Leaflet map tab in public/index.html with CARTO dark tiles, category toggles, vote-count markers, and external venue search - Extract seed data to seed-data.js with CATEGORY_META, buildSeedData(), mergeSeedData() helpers - Refactor server.js: approvedOptionsWithVoteSummary(), buildRealtimeSnapshot(), createUserOption() helpers; Yelp API proxy at /api/yelp; /api/budgets endpoint - Extract inline seed data from server.js to seed-data.js module - Add budgetScenarios and priceUpdatedAt to realtime snapshot
587 lines
25 KiB
JavaScript
587 lines
25 KiB
JavaScript
const SEED_VERSION = 2;
|
|
const PRICE_UPDATED_AT = '2026-04-29';
|
|
|
|
const CATEGORY_META = {
|
|
hotel: { emoji: '🏨', color: '#3b82f6' },
|
|
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 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 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,
|
|
...option,
|
|
categoryColor,
|
|
url: primaryUrl,
|
|
};
|
|
}
|
|
|
|
function buildSeedData() {
|
|
return {
|
|
seedVersion: SEED_VERSION,
|
|
priceUpdatedAt: PRICE_UPDATED_AT,
|
|
categories: [
|
|
{ id: 'hotel', name: 'Hotels', 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: '🏆' },
|
|
],
|
|
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: ['KAYAK recent rooms $173-$551/night', 'Costco package', '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 Vacations from $942 pp / 3 nights', 'KAYAK from $393/night', '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=3&mode=0&onsaleid=1398047&traveldate=2026-05-10' },
|
|
],
|
|
}),
|
|
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 Vacations from $859 pp / 3 nights', 'KAYAK from $209/night', 'Golf-friendly'],
|
|
links: [
|
|
{ label: 'Official', url: 'https://www.fiestamericana.com/en/hotels/grand-fiesta-americana-los-cabos' },
|
|
{ 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=3&mode=0&onsaleid=1614780&redirect=false&remotesourcecode=HBSHotel&traveldate=&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: ['CheapCaribbean from $885 pp / 3 nights', '4-night examples from $1,108 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=3&mode=0&onsaleid=2173329&redirect=false&remotesourcecode=LtmsHotel&traveldate=&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: '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.fiestamericana.com/en/hotels/grand-fiesta-americana-los-cabos' },
|
|
{ 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.fiestamericana.com/en/hotels/grand-fiesta-americana-los-cabos' },
|
|
{ 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,
|
|
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,
|
|
};
|