export function carRentalCalculator(form: FormTs) {
// Daily rates by vehicle type
const dailyRates: Record<string, number> = {
'economy': 35,
'compact': 42,
'midsize': 50,
'fullsize': 58,
'suv-small': 65,
'suv-midsize': 78,
'suv-fullsize': 95,
'luxury': 120,
'sports': 150,
'minivan': 85,
'pickup': 75,
'convertible': 110
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Car Rental Cost Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Rental Details Section
const rentalSection = form.addSubform('rental', { title: '📅 Rental Details' });
rentalSection.addRow(row => {
row.addInteger('rentalDays', {
label: 'Rental Duration (days)',
min: 1,
max: 365,
defaultValue: 5,
isRequired: true
}, '1fr');
row.addDropdown('vehicleType', {
label: 'Vehicle Type',
options: [
{ id: 'economy', name: 'Economy ($35/day)' },
{ id: 'compact', name: 'Compact ($42/day)' },
{ id: 'midsize', name: 'Midsize Sedan ($50/day)' },
{ id: 'fullsize', name: 'Full-size Sedan ($58/day)' },
{ id: 'suv-small', name: 'Small SUV ($65/day)' },
{ id: 'suv-midsize', name: 'Midsize SUV ($78/day)' },
{ id: 'suv-fullsize', name: 'Full-size SUV ($95/day)' },
{ id: 'luxury', name: 'Luxury ($120/day)' },
{ id: 'sports', name: 'Sports Car ($150/day)' },
{ id: 'minivan', name: 'Minivan ($85/day)' },
{ id: 'pickup', name: 'Pickup Truck ($75/day)' },
{ id: 'convertible', name: 'Convertible ($110/day)' }
],
defaultValue: 'midsize',
isRequired: true
}, '1fr');
});
rentalSection.addRow(row => {
row.addAddress('pickupAddress', {
label: 'Pickup Location',
placeholder: 'Enter pickup address...',
distanceUnit: 'miles',
isRequired: true
});
});
rentalSection.addRow(row => {
row.addCheckbox('differentDropoff', {
label: 'Return at different location',
defaultValue: false,
tooltip: 'One-way rental fees may apply'
});
});
rentalSection.addRow(row => {
row.addAddress('dropoffAddress', {
label: 'Drop-off Location',
placeholder: 'Enter drop-off address...',
showMap: true,
showDistance: true,
referenceAddress: () => rentalSection.address('pickupAddress')?.value() ?? null,
distanceUnit: 'miles',
isVisible: () => rentalSection.checkbox('differentDropoff')?.value() === true,
isRequired: () => rentalSection.checkbox('differentDropoff')?.value() === true
});
});
rentalSection.addRow(row => {
row.addTextPanel('oneWayInfo', {
computedValue: () => {
if (rentalSection.checkbox('differentDropoff')?.value() !== true) return '';
const dropoffField = rentalSection.address('dropoffAddress');
const miles = dropoffField?.distance();
if (miles == null) return 'Enter drop-off address to calculate one-way fee';
// Calculate one-way fee based on distance
let fee = 0;
let feeType = '';
if (miles < 50) {
fee = 50;
feeType = 'Local one-way';
} else if (miles < 200) {
fee = 150;
feeType = 'Regional one-way';
} else if (miles < 500) {
fee = 200;
feeType = 'Different city';
} else {
fee = 300;
feeType = 'Long distance';
}
return `📍 ${feeType}: ${Math.round(miles)} miles (+$${fee} one-way fee)`;
},
customStyles: { 'font-size': '0.9rem', 'color': '#0369a1', 'background': '#e0f2fe', 'padding': '10px', 'border-radius': '6px' },
isVisible: () => rentalSection.checkbox('differentDropoff')?.value() === true
});
});
rentalSection.addRow(row => {
row.addDropdown('pickupLocationType', {
label: 'Pickup Location Type',
options: [
{ id: 'airport', name: 'Airport' },
{ id: 'downtown', name: 'Downtown' },
{ id: 'suburban', name: 'Suburban Location' },
{ id: 'hotel', name: 'Hotel Delivery (+$25)' }
],
defaultValue: 'airport'
}, '1fr');
});
// Helper to calculate one-way fee from distance
const getOneWayFee = () => {
if (rentalSection.checkbox('differentDropoff')?.value() !== true) return 0;
const dropoffField = rentalSection.address('dropoffAddress');
const miles = dropoffField?.distance();
if (miles == null) return 0;
if (miles < 50) return 50;
if (miles < 200) return 150;
if (miles < 500) return 200;
return 300;
};
// Insurance Section
const insuranceSection = form.addSubform('insurance', { title: '🛡️ Insurance & Protection' });
insuranceSection.addRow(row => {
row.addDropdown('insurancePackage', {
label: 'Insurance Package',
options: [
{ id: 'none', name: 'Decline All Coverage' },
{ id: 'basic', name: 'Basic - Liability Only ($12/day)' },
{ id: 'standard', name: 'Standard - LDW + Liability ($22/day)' },
{ id: 'premium', name: 'Premium - Full Coverage ($35/day)' }
],
defaultValue: 'standard',
tooltip: 'LDW = Loss Damage Waiver'
}, '1fr');
row.addCheckbox('personalAccident', {
label: 'Personal Accident Insurance',
defaultValue: false,
tooltip: '+$5/day - Covers medical costs for driver and passengers'
}, '1fr');
});
insuranceSection.addRow(row => {
row.addCheckbox('roadside', {
label: 'Roadside Assistance',
defaultValue: true,
tooltip: '+$7/day - 24/7 towing, flat tire, lockout service'
}, '1fr');
row.addCheckbox('personalEffects', {
label: 'Personal Effects Coverage',
defaultValue: false,
tooltip: '+$4/day - Covers stolen personal items'
}, '1fr');
});
// Add-ons Section
const addonsSection = form.addSubform('addons', { title: '✨ Add-ons & Extras' });
addonsSection.addRow(row => {
row.addCheckbox('gps', {
label: 'GPS Navigation',
defaultValue: false,
tooltip: '+$10/day'
}, '1fr');
row.addCheckbox('childSeat', {
label: 'Child Safety Seat',
defaultValue: false,
tooltip: '+$12/day'
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('wifi', {
label: 'Mobile WiFi Hotspot',
defaultValue: false,
tooltip: '+$15/day'
}, '1fr');
row.addCheckbox('skiRack', {
label: 'Ski/Bike Rack',
defaultValue: false,
tooltip: '+$8/day'
}, '1fr');
});
addonsSection.addRow(row => {
row.addInteger('additionalDrivers', {
label: 'Additional Drivers',
min: 0,
max: 5,
defaultValue: 0,
tooltip: '$10/day per additional driver'
}, '1fr');
row.addDropdown('fuelOption', {
label: 'Fuel Option',
options: [
{ id: 'return-full', name: 'Return Full (No Charge)' },
{ id: 'prepay', name: 'Prepay Fuel ($65)' },
{ id: 'purchase', name: 'Fuel Purchase Option (+$85)' }
],
defaultValue: 'return-full'
}, '1fr');
});
// Driver Info Section
const driverSection = form.addSubform('driver', { title: '👤 Driver Information' });
driverSection.addRow(row => {
row.addDropdown('driverAge', {
label: 'Driver Age',
options: [
{ id: 'under21', name: 'Under 21 (+$30/day surcharge)' },
{ id: '21-24', name: '21-24 (+$20/day surcharge)' },
{ id: '25-69', name: '25-69 (Standard Rate)' },
{ id: '70plus', name: '70+ (+$10/day surcharge)' }
],
defaultValue: '25-69'
}, '1fr');
row.addDropdown('loyalty', {
label: 'Loyalty Program',
options: [
{ id: 'none', name: 'No Membership' },
{ id: 'basic', name: 'Basic Member (5% off)' },
{ id: 'silver', name: 'Silver Member (10% off)' },
{ id: 'gold', name: 'Gold Member (15% off)' },
{ id: 'platinum', name: 'Platinum Member (20% off)' }
],
defaultValue: 'none'
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Cost Breakdown Section
const breakdownSection = form.addSubform('breakdown', { title: '📊 Cost Breakdown', isCollapsible: false });
breakdownSection.addRow(row => {
row.addPriceDisplay('baseCost', {
label: 'Vehicle Rental',
computedValue: () => {
const days = rentalSection.integer('rentalDays')?.value() || 5;
const vehicle = rentalSection.dropdown('vehicleType')?.value() || 'midsize';
return (dailyRates[vehicle] || 50) * days;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('insuranceCost', {
label: 'Insurance & Protection',
computedValue: () => {
const days = rentalSection.integer('rentalDays')?.value() || 5;
const insurance = insuranceSection.dropdown('insurancePackage')?.value() || 'standard';
const insuranceRates: Record<string, number> = {
'none': 0,
'basic': 12,
'standard': 22,
'premium': 35
};
let cost = (insuranceRates[insurance] || 22) * days;
if (insuranceSection.checkbox('personalAccident')?.value()) cost += 5 * days;
if (insuranceSection.checkbox('roadside')?.value()) cost += 7 * days;
if (insuranceSection.checkbox('personalEffects')?.value()) cost += 4 * days;
return cost;
},
variant: 'default'
}, '1fr');
});
breakdownSection.addRow(row => {
row.addPriceDisplay('addonsCost', {
label: 'Add-ons & Extras',
computedValue: () => {
const days = rentalSection.integer('rentalDays')?.value() || 5;
const fuel = addonsSection.dropdown('fuelOption')?.value() || 'return-full';
const additionalDrivers = addonsSection.integer('additionalDrivers')?.value() || 0;
let cost = 0;
if (addonsSection.checkbox('gps')?.value()) cost += 10 * days;
if (addonsSection.checkbox('childSeat')?.value()) cost += 12 * days;
if (addonsSection.checkbox('wifi')?.value()) cost += 15 * days;
if (addonsSection.checkbox('skiRack')?.value()) cost += 8 * days;
cost += additionalDrivers * 10 * days;
if (fuel === 'prepay') cost += 65;
if (fuel === 'purchase') cost += 85;
return cost;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('feesCost', {
label: 'Fees & Surcharges',
computedValue: () => {
const days = rentalSection.integer('rentalDays')?.value() || 5;
const pickup = rentalSection.dropdown('pickupLocationType')?.value() || 'airport';
const age = driverSection.dropdown('driverAge')?.value() || '25-69';
let cost = 0;
// Location fees
if (pickup === 'hotel') cost += 25;
// One-way fee based on distance
cost += getOneWayFee();
// Age surcharges
const ageSurcharges: Record<string, number> = {
'under21': 30,
'21-24': 20,
'25-69': 0,
'70plus': 10
};
cost += (ageSurcharges[age] || 0) * days;
// Airport fees (typically 10-15% of base rate)
if (pickup === 'airport') {
const vehicle = rentalSection.dropdown('vehicleType')?.value() || 'midsize';
const baseRate = dailyRates[vehicle] || 50;
cost += Math.round(baseRate * days * 0.12); // 12% airport fee
}
return cost;
},
variant: 'default'
}, '1fr');
});
breakdownSection.addRow(row => {
row.addPriceDisplay('discount', {
label: 'Loyalty Discount',
computedValue: () => {
const days = rentalSection.integer('rentalDays')?.value() || 5;
const vehicle = rentalSection.dropdown('vehicleType')?.value() || 'midsize';
const loyalty = driverSection.dropdown('loyalty')?.value() || 'none';
const baseRate = (dailyRates[vehicle] || 50) * days;
const discountRates: Record<string, number> = {
'none': 0,
'basic': 0.05,
'silver': 0.10,
'gold': 0.15,
'platinum': 0.20
};
const discount = baseRate * (discountRates[loyalty] || 0);
return discount > 0 ? -Math.round(discount) : 0;
},
variant: 'success',
prefix: ''
}, '1fr');
row.addPriceDisplay('taxesFees', {
label: 'Taxes (Est. 15%)',
computedValue: () => {
const days = rentalSection.integer('rentalDays')?.value() || 5;
const vehicle = rentalSection.dropdown('vehicleType')?.value() || 'midsize';
const insurance = insuranceSection.dropdown('insurancePackage')?.value() || 'standard';
const pickup = rentalSection.dropdown('pickupLocationType')?.value() || 'airport';
const age = driverSection.dropdown('driverAge')?.value() || '25-69';
const fuel = addonsSection.dropdown('fuelOption')?.value() || 'return-full';
const additionalDrivers = addonsSection.integer('additionalDrivers')?.value() || 0;
const loyalty = driverSection.dropdown('loyalty')?.value() || 'none';
// Calculate subtotal
let subtotal = (dailyRates[vehicle] || 50) * days;
// Insurance
const insuranceRates: Record<string, number> = {
'none': 0, 'basic': 12, 'standard': 22, 'premium': 35
};
subtotal += (insuranceRates[insurance] || 22) * days;
if (insuranceSection.checkbox('personalAccident')?.value()) subtotal += 5 * days;
if (insuranceSection.checkbox('roadside')?.value()) subtotal += 7 * days;
if (insuranceSection.checkbox('personalEffects')?.value()) subtotal += 4 * days;
// Add-ons
if (addonsSection.checkbox('gps')?.value()) subtotal += 10 * days;
if (addonsSection.checkbox('childSeat')?.value()) subtotal += 12 * days;
if (addonsSection.checkbox('wifi')?.value()) subtotal += 15 * days;
if (addonsSection.checkbox('skiRack')?.value()) subtotal += 8 * days;
subtotal += additionalDrivers * 10 * days;
if (fuel === 'prepay') subtotal += 65;
if (fuel === 'purchase') subtotal += 85;
// Fees
if (pickup === 'hotel') subtotal += 25;
subtotal += getOneWayFee();
const ageSurcharges: Record<string, number> = {
'under21': 30, '21-24': 20, '25-69': 0, '70plus': 10
};
subtotal += (ageSurcharges[age] || 0) * days;
if (pickup === 'airport') {
subtotal += Math.round((dailyRates[vehicle] || 50) * days * 0.12);
}
// Discount
const discountRates: Record<string, number> = {
'none': 0, 'basic': 0.05, 'silver': 0.10, 'gold': 0.15, 'platinum': 0.20
};
subtotal -= (dailyRates[vehicle] || 50) * days * (discountRates[loyalty] || 0);
return Math.round(subtotal * 0.15);
},
variant: 'default'
}, '1fr');
});
// Summary Section
const summarySection = form.addSubform('summary', {
title: '💰 Total Rental Cost',
isCollapsible: false,
sticky: 'bottom'
});
summarySection.addRow(row => {
row.addPriceDisplay('totalCost', {
label: 'Total Estimated Cost',
computedValue: () => {
const days = rentalSection.integer('rentalDays')?.value() || 5;
const vehicle = rentalSection.dropdown('vehicleType')?.value() || 'midsize';
const insurance = insuranceSection.dropdown('insurancePackage')?.value() || 'standard';
const pickup = rentalSection.dropdown('pickupLocationType')?.value() || 'airport';
const age = driverSection.dropdown('driverAge')?.value() || '25-69';
const fuel = addonsSection.dropdown('fuelOption')?.value() || 'return-full';
const additionalDrivers = addonsSection.integer('additionalDrivers')?.value() || 0;
const loyalty = driverSection.dropdown('loyalty')?.value() || 'none';
// Base
let total = (dailyRates[vehicle] || 50) * days;
// Insurance
const insuranceRates: Record<string, number> = {
'none': 0, 'basic': 12, 'standard': 22, 'premium': 35
};
total += (insuranceRates[insurance] || 22) * days;
if (insuranceSection.checkbox('personalAccident')?.value()) total += 5 * days;
if (insuranceSection.checkbox('roadside')?.value()) total += 7 * days;
if (insuranceSection.checkbox('personalEffects')?.value()) total += 4 * days;
// Add-ons
if (addonsSection.checkbox('gps')?.value()) total += 10 * days;
if (addonsSection.checkbox('childSeat')?.value()) total += 12 * days;
if (addonsSection.checkbox('wifi')?.value()) total += 15 * days;
if (addonsSection.checkbox('skiRack')?.value()) total += 8 * days;
total += additionalDrivers * 10 * days;
if (fuel === 'prepay') total += 65;
if (fuel === 'purchase') total += 85;
// Fees
if (pickup === 'hotel') total += 25;
total += getOneWayFee();
const ageSurcharges: Record<string, number> = {
'under21': 30, '21-24': 20, '25-69': 0, '70plus': 10
};
total += (ageSurcharges[age] || 0) * days;
if (pickup === 'airport') {
total += Math.round((dailyRates[vehicle] || 50) * days * 0.12);
}
// Discount
const discountRates: Record<string, number> = {
'none': 0, 'basic': 0.05, 'silver': 0.10, 'gold': 0.15, 'platinum': 0.20
};
total -= (dailyRates[vehicle] || 50) * days * (discountRates[loyalty] || 0);
// Taxes
total *= 1.15;
return Math.round(total);
},
variant: 'large'
});
});
summarySection.addRow(row => {
row.addTextPanel('perDay', {
computedValue: () => {
const days = rentalSection.integer('rentalDays')?.value() || 5;
const vehicle = rentalSection.dropdown('vehicleType')?.value() || 'midsize';
const insurance = insuranceSection.dropdown('insurancePackage')?.value() || 'standard';
const pickup = rentalSection.dropdown('pickupLocationType')?.value() || 'airport';
const age = driverSection.dropdown('driverAge')?.value() || '25-69';
const fuel = addonsSection.dropdown('fuelOption')?.value() || 'return-full';
const additionalDrivers = addonsSection.integer('additionalDrivers')?.value() || 0;
const loyalty = driverSection.dropdown('loyalty')?.value() || 'none';
let total = (dailyRates[vehicle] || 50) * days;
const insuranceRates: Record<string, number> = {
'none': 0, 'basic': 12, 'standard': 22, 'premium': 35
};
total += (insuranceRates[insurance] || 22) * days;
if (insuranceSection.checkbox('personalAccident')?.value()) total += 5 * days;
if (insuranceSection.checkbox('roadside')?.value()) total += 7 * days;
if (insuranceSection.checkbox('personalEffects')?.value()) total += 4 * days;
if (addonsSection.checkbox('gps')?.value()) total += 10 * days;
if (addonsSection.checkbox('childSeat')?.value()) total += 12 * days;
if (addonsSection.checkbox('wifi')?.value()) total += 15 * days;
if (addonsSection.checkbox('skiRack')?.value()) total += 8 * days;
total += additionalDrivers * 10 * days;
if (fuel === 'prepay') total += 65;
if (fuel === 'purchase') total += 85;
if (pickup === 'hotel') total += 25;
total += getOneWayFee();
const ageSurcharges: Record<string, number> = {
'under21': 30, '21-24': 20, '25-69': 0, '70plus': 10
};
total += (ageSurcharges[age] || 0) * days;
if (pickup === 'airport') {
total += Math.round((dailyRates[vehicle] || 50) * days * 0.12);
}
const discountRates: Record<string, number> = {
'none': 0, 'basic': 0.05, 'silver': 0.10, 'gold': 0.15, 'platinum': 0.20
};
total -= (dailyRates[vehicle] || 50) * days * (discountRates[loyalty] || 0);
total *= 1.15;
// Add route info if addresses are used
const pickupAddr = rentalSection.address('pickupAddress')?.value();
const pickupCity = pickupAddr?.formattedAddress?.split(',')[0] || '';
const perDay = Math.round(total / days);
const locationInfo = pickupCity ? `${pickupCity} | ` : '';
return `${locationInfo}$${perDay}/day average for ${days} days`;
},
customStyles: { 'font-size': '0.95rem', 'color': '#475569', 'text-align': 'center', 'font-weight': '500' }
});
});
summarySection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Prices are estimates. Actual costs may vary by location, season, and availability. Fuel costs not included unless prepaid.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'text-align': 'center' }
});
});
form.configureSubmitButton({
label: 'Reserve Now'
});
}