export function internationalShippingCalculator(form: FormTs) {
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'International Shipping Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Route Section
const routeSection = form.addSubform('route', { title: '🌍 Shipping Route' });
routeSection.addRow(row => {
row.addAddress('originAddress', {
label: 'Ship From',
placeholder: 'Enter origin address...',
distanceUnit: 'km',
isRequired: true
});
});
routeSection.addRow(row => {
row.addAddress('destAddress', {
label: 'Ship To',
placeholder: 'Enter destination address...',
showMap: true,
showDistance: true,
referenceAddress: () => routeSection.address('originAddress')?.value() ?? null,
distanceUnit: 'km',
isRequired: true
});
});
routeSection.addRow(row => {
row.addTextPanel('routeInfo', {
computedValue: () => {
const originAddr = routeSection.address('originAddress')?.value();
const destAddr = routeSection.address('destAddress')?.value();
const destField = routeSection.address('destAddress');
const km = destField?.distance();
if (!originAddr || !destAddr) return 'Enter both addresses to calculate shipping';
const originCountry = originAddr.countryCode || '';
const destCountry = destAddr.countryCode || '';
if (originCountry && destCountry && originCountry === destCountry) {
return '⚠️ Same country detected. For domestic shipping, use our Shipping Cost Calculator';
}
if (km != null) {
return `📍 Distance: ${Math.round(km).toLocaleString()} km (${Math.round(km * 0.621371).toLocaleString()} miles)`;
}
return '';
},
customStyles: () => {
const originAddr = routeSection.address('originAddress')?.value();
const destAddr = routeSection.address('destAddress')?.value();
const originCountry = originAddr?.countryCode || '';
const destCountry = destAddr?.countryCode || '';
const isSame = originCountry && destCountry && originCountry === destCountry;
return isSame
? { 'font-size': '0.9rem', 'color': '#dc2626', 'background': '#fef2f2', 'padding': '10px', 'border-radius': '6px' }
: { 'font-size': '0.9rem', 'color': '#0369a1', 'background': '#e0f2fe', 'padding': '10px', 'border-radius': '6px' };
}
});
});
// Package Details Section
const packageSection = form.addSubform('package', { title: '📦 Package Details' });
packageSection.addRow(row => {
row.addDecimal('weight', {
label: 'Weight',
min: 0.1,
max: 150,
defaultValue: 2,
isRequired: true
}, '1fr');
row.addDropdown('weightUnit', {
label: 'Weight Unit',
options: [
{ id: 'lb', name: 'Pounds (lb)' },
{ id: 'kg', name: 'Kilograms (kg)' }
],
defaultValue: 'lb'
}, '1fr');
});
packageSection.addRow(row => {
row.addDecimal('length', {
label: 'Length',
min: 1,
max: 120,
defaultValue: 12,
isRequired: true
}, '1fr');
row.addDecimal('width', {
label: 'Width',
min: 1,
max: 120,
defaultValue: 8,
isRequired: true
}, '1fr');
row.addDecimal('height', {
label: 'Height',
min: 1,
max: 120,
defaultValue: 6,
isRequired: true
}, '1fr');
});
packageSection.addRow(row => {
row.addDropdown('dimUnit', {
label: 'Dimension Unit',
options: [
{ id: 'in', name: 'Inches (in)' },
{ id: 'cm', name: 'Centimeters (cm)' }
],
defaultValue: 'in'
}, '1fr');
row.addTextPanel('dimWeight', {
label: 'Dimensional Weight',
computedValue: () => {
const length = packageSection.decimal('length')?.value() || 12;
const width = packageSection.decimal('width')?.value() || 8;
const height = packageSection.decimal('height')?.value() || 6;
const dimUnit = packageSection.dropdown('dimUnit')?.value() || 'in';
const weightUnit = packageSection.dropdown('weightUnit')?.value() || 'lb';
// Convert to inches if cm
const l = dimUnit === 'cm' ? length / 2.54 : length;
const w = dimUnit === 'cm' ? width / 2.54 : width;
const h = dimUnit === 'cm' ? height / 2.54 : height;
// International DIM factor is typically 139 for lb
const dimWeight = (l * w * h) / 139;
const displayWeight = weightUnit === 'kg' ? dimWeight * 0.453592 : dimWeight;
return `${(Number(displayWeight) || 0).toFixed(1)} ${weightUnit}`;
},
customStyles: { 'font-size': '1rem', 'color': '#2563eb' }
}, '1fr');
});
// Customs Information Section
const customsSection = form.addSubform('customs', { title: '📋 Customs Information' });
customsSection.addRow(row => {
row.addMoney('declaredValue', {
label: 'Declared Value',
min: 1,
max: 100000,
defaultValue: 100,
currency: '$',
isRequired: true,
tooltip: 'Value of goods for customs declaration'
}, '1fr');
row.addDropdown('contentType', {
label: 'Content Type',
options: [
{ id: 'merchandise', name: 'Merchandise/Goods' },
{ id: 'gift', name: 'Gift' },
{ id: 'documents', name: 'Documents' },
{ id: 'sample', name: 'Commercial Sample' },
{ id: 'returned', name: 'Returned Goods' }
],
defaultValue: 'merchandise'
}, '1fr');
});
customsSection.addRow(row => {
row.addDropdown('productCategory', {
label: 'Product Category',
options: [
{ id: 'electronics', name: 'Electronics' },
{ id: 'clothing', name: 'Clothing & Apparel' },
{ id: 'accessories', name: 'Accessories & Jewelry' },
{ id: 'home', name: 'Home & Garden' },
{ id: 'sports', name: 'Sports & Outdoor' },
{ id: 'toys', name: 'Toys & Games' },
{ id: 'beauty', name: 'Beauty & Health' },
{ id: 'books', name: 'Books & Media' },
{ id: 'food', name: 'Food & Beverages' },
{ id: 'other', name: 'Other' }
],
defaultValue: 'electronics',
tooltip: 'Category affects duty rates'
}, '1fr');
row.addCheckbox('commercial', {
label: 'Commercial Shipment',
defaultValue: true,
tooltip: 'Business/commercial vs personal shipment'
}, '1fr');
});
// Shipping Options Section
const shippingSection = form.addSubform('shipping', { title: '🚚 Shipping Options' });
shippingSection.addRow(row => {
row.addRadioButton('serviceLevel', {
label: 'Service Level',
options: [
{ id: 'express', name: 'Express (1-5 days)' },
{ id: 'expedited', name: 'Expedited (5-10 days)' },
{ id: 'standard', name: 'Standard (10-20 days)' },
{ id: 'economy', name: 'Economy (2-6 weeks)' }
],
defaultValue: 'standard',
isRequired: true
});
});
shippingSection.addRow(row => {
row.addDropdown('incoterms', {
label: 'Incoterms (Duty Payment)',
options: [
{ id: 'ddp', name: 'DDP - Delivered Duty Paid (sender pays all)' },
{ id: 'dap', name: 'DAP - Delivered at Place (recipient pays duties)' }
],
defaultValue: 'dap',
tooltip: 'Who pays customs duties and taxes'
});
});
// Additional Services Section
const servicesSection = form.addSubform('services', { title: '✨ Additional Services' });
servicesSection.addRow(row => {
row.addCheckbox('insurance', {
label: 'Shipping Insurance',
defaultValue: false,
tooltip: 'Coverage for lost or damaged packages'
}, '1fr');
row.addCheckbox('signature', {
label: 'Signature Required',
defaultValue: true
}, '1fr');
});
servicesSection.addRow(row => {
row.addCheckbox('tracking', {
label: 'Full Tracking',
defaultValue: true
}, '1fr');
row.addCheckbox('saturdayDelivery', {
label: 'Saturday Delivery',
defaultValue: false,
tooltip: 'May not be available in all areas'
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Results Section
const resultsSection = form.addSubform('results', { title: '📊 Cost Breakdown', isCollapsible: false });
const calculateShipping = () => {
const originAddr = routeSection.address('originAddress')?.value();
const destAddr = routeSection.address('destAddress')?.value();
const destField = routeSection.address('destAddress');
const distanceKm = destField?.distance() ?? 5000; // default to transatlantic
const origin = originAddr?.countryCode || 'US';
const destination = destAddr?.countryCode || 'UK';
// Get actual and dimensional weight
const actualWeight = packageSection.decimal('weight')?.value() || 2;
const weightUnit = packageSection.dropdown('weightUnit')?.value() || 'lb';
const weightInLb = weightUnit === 'kg' ? actualWeight * 2.20462 : actualWeight;
const length = packageSection.decimal('length')?.value() || 12;
const width = packageSection.decimal('width')?.value() || 8;
const height = packageSection.decimal('height')?.value() || 6;
const dimUnit = packageSection.dropdown('dimUnit')?.value() || 'in';
const l = dimUnit === 'cm' ? length / 2.54 : length;
const w = dimUnit === 'cm' ? width / 2.54 : width;
const h = dimUnit === 'cm' ? height / 2.54 : height;
const dimWeight = (l * w * h) / 139;
const billableWeight = Math.max(weightInLb, dimWeight);
// Base rates by zone - now based on actual distance
const getZone = (distKm: number, orig: string, dest: string) => {
// Neighbors (NA to NA, EU to EU)
if (['CA', 'MX'].includes(dest) && orig === 'US') return 'zone1';
if (['CA', 'MX'].includes(orig) && dest === 'US') return 'zone1';
// Distance-based zones
if (distKm < 2000) return 'zone1'; // Short international
if (distKm < 6000) return 'zone2'; // Medium (transatlantic)
if (distKm < 12000) return 'zone3'; // Long (US to Asia/Australia)
return 'zone4'; // Very long (intercontinental)
};
const zone = getZone(distanceKm, origin, destination);
const serviceLevel = shippingSection.radioButton('serviceLevel')?.value() || 'standard';
// Base rates per lb by zone and service
const baseRates = {
'express': { 'zone1': 8, 'zone2': 12, 'zone3': 16, 'zone4': 20 },
'expedited': { 'zone1': 5, 'zone2': 8, 'zone3': 11, 'zone4': 14 },
'standard': { 'zone1': 3, 'zone2': 5, 'zone3': 7, 'zone4': 9 },
'economy': { 'zone1': 2, 'zone2': 3.5, 'zone3': 5, 'zone4': 6.5 }
};
const ratePerLb = baseRates[serviceLevel][zone];
let shippingCost = Math.max(20, billableWeight * ratePerLb);
// Fuel surcharge (typical ~15%)
const fuelSurcharge = shippingCost * 0.15;
// Declared value and customs
const declaredValue = customsSection.money('declaredValue')?.value() || 100;
const productCategory = customsSection.dropdown('productCategory')?.value() || 'electronics';
const contentType = customsSection.dropdown('contentType')?.value() || 'merchandise';
// Duty rates by category (simplified estimates)
const dutyRates = {
'electronics': 0.03,
'clothing': 0.12,
'accessories': 0.08,
'home': 0.05,
'sports': 0.06,
'toys': 0.04,
'beauty': 0.07,
'books': 0,
'food': 0.10,
'other': 0.05
};
// De minimis thresholds (simplified)
const deMinimis = {
'US': 800,
'CA': 20,
'UK': 135,
'DE': 22,
'FR': 22,
'AU': 1000,
'CN': 50,
'JP': 100,
'MX': 50,
'default': 50
};
const threshold = deMinimis[destination] || deMinimis['default'];
const isGift = contentType === 'gift';
const giftMultiplier = isGift ? 0.5 : 1;
// Calculate duties
let estimatedDuty = 0;
if (declaredValue > threshold) {
estimatedDuty = declaredValue * dutyRates[productCategory] * giftMultiplier;
}
// VAT/GST rates by country
const vatRates = {
'UK': 0.20,
'DE': 0.19,
'FR': 0.20,
'AU': 0.10,
'CA': 0.13,
'JP': 0.10,
'CN': 0.13,
'BR': 0.17,
'IN': 0.18,
'MX': 0.16,
'default': 0.15
};
const vatRate = vatRates[destination] || vatRates['default'];
let importTax = 0;
if (declaredValue > threshold) {
importTax = (declaredValue + shippingCost + estimatedDuty) * vatRate;
}
// Brokerage/customs clearance fee
const brokerageFee = estimatedDuty + importTax > 0 ? 15 : 0;
// Additional services
let additionalCosts = 0;
if (servicesSection.checkbox('insurance')?.value()) {
additionalCosts += Math.max(3, declaredValue * 0.02);
}
if (servicesSection.checkbox('signature')?.value()) {
additionalCosts += 5;
}
if (servicesSection.checkbox('saturdayDelivery')?.value()) {
additionalCosts += 15;
}
// Total shipping (carrier costs)
const totalShipping = shippingCost + fuelSurcharge + additionalCosts;
// Duties and taxes
const totalDutiesTaxes = estimatedDuty + importTax + brokerageFee;
// Who pays duties?
const incoterms = shippingSection.dropdown('incoterms')?.value() || 'dap';
const senderTotal = incoterms === 'ddp' ? totalShipping + totalDutiesTaxes : totalShipping;
const recipientPays = incoterms === 'dap' ? totalDutiesTaxes : 0;
return {
billableWeight: Math.round(billableWeight * 10) / 10,
shippingCost: Math.round(shippingCost),
fuelSurcharge: Math.round(fuelSurcharge),
additionalServices: Math.round(additionalCosts),
totalShipping: Math.round(totalShipping),
estimatedDuty: Math.round(estimatedDuty),
importTax: Math.round(importTax),
brokerageFee: Math.round(brokerageFee),
totalDutiesTaxes: Math.round(totalDutiesTaxes),
senderTotal: Math.round(senderTotal),
recipientPays: Math.round(recipientPays),
grandTotal: Math.round(totalShipping + totalDutiesTaxes)
};
};
resultsSection.addRow(row => {
row.addTextPanel('billableWeight', {
label: 'Billable Weight',
computedValue: () => `${calculateShipping().billableWeight} lb`,
customStyles: { 'font-size': '1rem', 'font-weight': '500' }
}, '1fr');
row.addPriceDisplay('baseShipping', {
label: 'Base Shipping',
computedValue: () => calculateShipping().shippingCost,
variant: 'default'
}, '1fr');
});
resultsSection.addRow(row => {
row.addPriceDisplay('fuelSurcharge', {
label: 'Fuel Surcharge',
computedValue: () => calculateShipping().fuelSurcharge,
variant: 'default'
}, '1fr');
row.addPriceDisplay('additionalServices', {
label: 'Additional Services',
computedValue: () => calculateShipping().additionalServices,
variant: 'default',
isVisible: () => calculateShipping().additionalServices > 0
}, '1fr');
});
resultsSection.addRow(row => {
row.addPriceDisplay('totalShipping', {
label: 'Total Shipping Cost',
computedValue: () => calculateShipping().totalShipping,
variant: 'success'
});
});
// Duties Section
const dutiesSection = form.addSubform('duties', { title: '🏛️ Estimated Duties & Taxes', isCollapsible: false });
dutiesSection.addRow(row => {
row.addPriceDisplay('duty', {
label: 'Import Duty',
computedValue: () => calculateShipping().estimatedDuty,
variant: 'default'
}, '1fr');
row.addPriceDisplay('importTax', {
label: 'Import Tax (VAT/GST)',
computedValue: () => calculateShipping().importTax,
variant: 'default'
}, '1fr');
});
dutiesSection.addRow(row => {
row.addPriceDisplay('brokerage', {
label: 'Brokerage Fee',
computedValue: () => calculateShipping().brokerageFee,
variant: 'default',
isVisible: () => calculateShipping().brokerageFee > 0
}, '1fr');
row.addPriceDisplay('totalDuties', {
label: 'Total Duties & Taxes',
computedValue: () => calculateShipping().totalDutiesTaxes,
variant: 'default'
}, '1fr');
});
// Summary Section
const summarySection = form.addSubform('summary', {
title: '💰 Total Cost',
isCollapsible: false,
sticky: 'bottom'
});
summarySection.addRow(row => {
row.addPriceDisplay('senderPays', {
label: 'You Pay (Sender)',
computedValue: () => calculateShipping().senderTotal,
variant: 'large'
}, '1fr');
row.addPriceDisplay('recipientPays', {
label: 'Recipient Pays',
computedValue: () => calculateShipping().recipientPays,
variant: 'default',
isVisible: () => calculateShipping().recipientPays > 0
}, '1fr');
});
summarySection.addRow(row => {
row.addTextPanel('grandTotal', {
computedValue: () => `Total Landed Cost: $${calculateShipping().grandTotal}`,
customStyles: { 'font-size': '1.1rem', 'font-weight': '600', 'text-align': 'center', 'color': '#059669' }
});
});
summarySection.addRow(row => {
row.addTextPanel('note', {
computedValue: () => 'Duties and taxes are estimates. Actual amounts determined by customs. Contact carrier for exact rates.',
customStyles: { 'font-size': '0.8rem', 'color': '#64748b', 'text-align': 'center' }
});
});
form.configureSubmitButton({
label: 'Get Shipping Quote'
});
}