export function tailorAlterationsCalculator(form: FormTs) {
// Base prices for garment types
const defaultPrices = { 'hem': 15, 'waist': 25, 'taper': 30, 'take-in': 25, 'sleeves': 20, 'shoulders': 50, 'bustle': 85, 'straps': 15, 'full-rebuild': 65 };
const garmentPrices: Record<string, Record<string, number>> = {
'pants': { 'hem': 15, 'waist': 25, 'taper': 30, 'take-in': 25, 'full-rebuild': 65 },
'dress-shirt': { 'hem': 12, 'sleeves': 18, 'take-in': 25, 'full-rebuild': 45 },
'dress': { 'hem': 20, 'take-in': 35, 'straps': 15, 'sleeves': 20, 'full-rebuild': 85 },
'suit-jacket': { 'sleeves': 35, 'take-in': 55, 'shoulders': 75, 'full-rebuild': 150 },
'wedding-dress': { 'hem': 75, 'bustle': 85, 'take-in': 125, 'straps': 25, 'full-rebuild': 350 },
'jeans': { 'hem': 12, 'waist': 30, 'taper': 35, 'take-in': 30, 'full-rebuild': 55 },
'skirt': { 'hem': 15, 'waist': 20, 'take-in': 25, 'full-rebuild': 45 },
'coat': { 'hem': 35, 'sleeves': 40, 'take-in': 65, 'full-rebuild': 125 }
};
// Rush fee multiplier
const rushFees: Record<string, number> = {
'standard': 1,
'rush-3day': 1.5,
'rush-24hr': 2
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Tailoring & Alterations Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Garment Details Section
const garmentSection = form.addSubform('garmentDetails', { title: '๐ Garment Details' });
garmentSection.addRow(row => {
row.addDropdown('garmentType', {
label: 'Garment Type',
options: [
{ id: 'pants', name: 'Pants/Trousers' },
{ id: 'jeans', name: 'Jeans' },
{ id: 'dress-shirt', name: 'Dress Shirt/Blouse' },
{ id: 'dress', name: 'Dress' },
{ id: 'skirt', name: 'Skirt' },
{ id: 'suit-jacket', name: 'Suit Jacket/Blazer' },
{ id: 'coat', name: 'Coat/Outerwear' },
{ id: 'wedding-dress', name: 'Wedding Dress' }
],
defaultValue: 'pants',
isRequired: true
}, '1fr');
row.addInteger('quantity', {
label: 'Quantity',
min: 1,
max: 20,
defaultValue: 1,
isRequired: true
}, '1fr');
});
garmentSection.addRow(row => {
row.addDropdown('fabricType', {
label: 'Fabric Type',
options: [
{ id: 'standard', name: 'Standard (cotton, polyester)' },
{ id: 'delicate', name: 'Delicate (silk, satin) +25%' },
{ id: 'heavy', name: 'Heavy (denim, leather) +35%' },
{ id: 'specialty', name: 'Specialty (beaded, lace) +50%' }
],
defaultValue: 'standard',
tooltip: 'Delicate and specialty fabrics require extra care'
}, '1fr');
row.addDropdown('garmentCondition', {
label: 'Garment Condition',
options: [
{ id: 'good', name: 'Good condition' },
{ id: 'worn', name: 'Worn (minor repairs needed) +$10' },
{ id: 'damaged', name: 'Damaged (significant repairs) +$25' }
],
defaultValue: 'good'
}, '1fr');
});
// Alteration Services Section
const alterationsSection = form.addSubform('alterations', { title: 'โ๏ธ Alteration Services' });
alterationsSection.addRow(row => {
row.addCheckbox('hemming', {
label: 'Hemming/Shortening',
defaultValue: true,
tooltip: 'Adjust length of pants, sleeves, or dresses'
}, '1fr');
row.addCheckbox('takeIn', {
label: 'Take In/Let Out',
defaultValue: false,
tooltip: 'Adjust width for better fit'
}, '1fr');
});
alterationsSection.addRow(row => {
row.addCheckbox('waistAdjust', {
label: 'Waist Adjustment',
defaultValue: false,
tooltip: 'Resize waistband on pants or skirts',
isVisible: () => {
const type = garmentSection.dropdown('garmentType')?.value();
return type === 'pants' || type === 'jeans' || type === 'skirt';
}
}, '1fr');
row.addCheckbox('sleeves', {
label: 'Sleeve Adjustment',
defaultValue: false,
tooltip: 'Shorten or reshape sleeves',
isVisible: () => {
const type = garmentSection.dropdown('garmentType')?.value();
return type === 'dress-shirt' || type === 'suit-jacket' || type === 'coat' || type === 'dress';
}
}, '1fr');
});
alterationsSection.addRow(row => {
row.addCheckbox('tapering', {
label: 'Tapering/Slimming',
defaultValue: false,
tooltip: 'Slim down legs or body for modern fit',
isVisible: () => {
const type = garmentSection.dropdown('garmentType')?.value();
return type === 'pants' || type === 'jeans' || type === 'dress-shirt';
}
}, '1fr');
row.addCheckbox('shoulders', {
label: 'Shoulder Adjustment',
defaultValue: false,
tooltip: 'Complex alteration requiring restructuring',
isVisible: () => {
const type = garmentSection.dropdown('garmentType')?.value();
return type === 'suit-jacket' || type === 'coat';
}
}, '1fr');
});
alterationsSection.addRow(row => {
row.addCheckbox('bustle', {
label: 'Add Bustle',
defaultValue: false,
tooltip: 'Add bustle points for train',
isVisible: () => garmentSection.dropdown('garmentType')?.value() === 'wedding-dress'
}, '1fr');
row.addCheckbox('straps', {
label: 'Strap Adjustment',
defaultValue: false,
tooltip: 'Adjust or replace straps',
isVisible: () => {
const type = garmentSection.dropdown('garmentType')?.value();
return type === 'dress' || type === 'wedding-dress';
}
}, '1fr');
});
// Additional Services Section
const extrasSection = form.addSubform('extras', { title: 'โจ Additional Services' });
extrasSection.addRow(row => {
row.addCheckbox('buttonReplacement', {
label: 'Button Replacement (+$3/button)',
defaultValue: false
}, '1fr');
row.addCheckbox('zipperReplacement', {
label: 'Zipper Replacement (+$15-35)',
defaultValue: false
}, '1fr');
});
extrasSection.addRow(row => {
row.addCheckbox('liningRepair', {
label: 'Lining Repair (+$25)',
defaultValue: false,
tooltip: 'Repair or replace torn lining'
}, '1fr');
row.addCheckbox('pressing', {
label: 'Professional Pressing (+$8)',
defaultValue: false,
tooltip: 'Steam press after alterations'
}, '1fr');
});
extrasSection.addRow(row => {
row.addInteger('buttonCount', {
label: 'Number of Buttons',
min: 1,
max: 20,
defaultValue: 1,
isVisible: () => extrasSection.checkbox('buttonReplacement')?.value() === true
}, '1fr');
});
// Timing Section
const timingSection = form.addSubform('timing', { title: '๐
Turnaround Time' });
timingSection.addRow(row => {
row.addRadioButton('rushOption', {
label: 'When do you need it?',
options: [
{ id: 'standard', name: 'Standard (5-7 business days)' },
{ id: 'rush-3day', name: 'Rush - 3 Days (+50%)' },
{ id: 'rush-24hr', name: 'Same Day/24 Hours (+100%)' }
],
defaultValue: 'standard',
orientation: 'vertical'
});
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Price Summary Section
const summarySection = form.addSubform('summary', { title: '๐ฐ Price Breakdown', isCollapsible: false });
summarySection.addRow(row => {
row.addPriceDisplay('baseAlterations', {
label: 'Alterations',
computedValue: () => {
const garmentType = garmentSection.dropdown('garmentType')?.value() || 'pants';
const prices = garmentPrices[garmentType] || defaultPrices;
let total = 0;
if (alterationsSection.checkbox('hemming')?.value()) {
total += prices['hem'] || 15;
}
if (alterationsSection.checkbox('takeIn')?.value()) {
total += prices['take-in'] || 25;
}
if (alterationsSection.checkbox('waistAdjust')?.value()) {
total += prices['waist'] || 25;
}
if (alterationsSection.checkbox('sleeves')?.value()) {
total += prices['sleeves'] || 20;
}
if (alterationsSection.checkbox('tapering')?.value()) {
total += prices['taper'] || 30;
}
if (alterationsSection.checkbox('shoulders')?.value()) {
total += prices['shoulders'] || 75;
}
if (alterationsSection.checkbox('bustle')?.value()) {
total += prices['bustle'] || 85;
}
if (alterationsSection.checkbox('straps')?.value()) {
total += prices['straps'] || 15;
}
return total;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('fabricAdjustment', {
label: 'Fabric Adjustment',
computedValue: () => {
const fabricType = garmentSection.dropdown('fabricType')?.value() || 'standard';
const garmentType = garmentSection.dropdown('garmentType')?.value() || 'pants';
const prices = garmentPrices[garmentType] || defaultPrices;
let baseTotal = 0;
if (alterationsSection.checkbox('hemming')?.value()) baseTotal += prices['hem'] || 15;
if (alterationsSection.checkbox('takeIn')?.value()) baseTotal += prices['take-in'] || 25;
if (alterationsSection.checkbox('waistAdjust')?.value()) baseTotal += prices['waist'] || 25;
if (alterationsSection.checkbox('sleeves')?.value()) baseTotal += prices['sleeves'] || 20;
if (alterationsSection.checkbox('tapering')?.value()) baseTotal += prices['taper'] || 30;
if (alterationsSection.checkbox('shoulders')?.value()) baseTotal += prices['shoulders'] || 75;
if (alterationsSection.checkbox('bustle')?.value()) baseTotal += prices['bustle'] || 85;
if (alterationsSection.checkbox('straps')?.value()) baseTotal += prices['straps'] || 15;
let multiplier = 0;
if (fabricType === 'delicate') multiplier = 0.25;
if (fabricType === 'heavy') multiplier = 0.35;
if (fabricType === 'specialty') multiplier = 0.50;
return Math.round(baseTotal * multiplier);
},
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('extras', {
label: 'Additional Services',
computedValue: () => {
let total = 0;
const condition = garmentSection.dropdown('garmentCondition')?.value();
if (condition === 'worn') total += 10;
if (condition === 'damaged') total += 25;
if (extrasSection.checkbox('buttonReplacement')?.value()) {
const buttonCount = extrasSection.integer('buttonCount')?.value() || 1;
total += buttonCount * 3;
}
if (extrasSection.checkbox('zipperReplacement')?.value()) {
const garmentType = garmentSection.dropdown('garmentType')?.value();
total += (garmentType === 'coat' || garmentType === 'suit-jacket') ? 35 : 15;
}
if (extrasSection.checkbox('liningRepair')?.value()) total += 25;
if (extrasSection.checkbox('pressing')?.value()) total += 8;
return total;
},
variant: 'default',
prefix: '+'
}, '1fr');
row.addPriceDisplay('rushFee', {
label: 'Rush Fee',
computedValue: () => {
const rushOption = timingSection.radioButton('rushOption')?.value() || 'standard';
if (rushOption === 'standard') return 0;
// Calculate base total
const garmentType = garmentSection.dropdown('garmentType')?.value() || 'pants';
const fabricType = garmentSection.dropdown('fabricType')?.value() || 'standard';
const prices = garmentPrices[garmentType] || defaultPrices;
let baseTotal = 0;
if (alterationsSection.checkbox('hemming')?.value()) baseTotal += prices['hem'] || 15;
if (alterationsSection.checkbox('takeIn')?.value()) baseTotal += prices['take-in'] || 25;
if (alterationsSection.checkbox('waistAdjust')?.value()) baseTotal += prices['waist'] || 25;
if (alterationsSection.checkbox('sleeves')?.value()) baseTotal += prices['sleeves'] || 20;
if (alterationsSection.checkbox('tapering')?.value()) baseTotal += prices['taper'] || 30;
if (alterationsSection.checkbox('shoulders')?.value()) baseTotal += prices['shoulders'] || 75;
if (alterationsSection.checkbox('bustle')?.value()) baseTotal += prices['bustle'] || 85;
if (alterationsSection.checkbox('straps')?.value()) baseTotal += prices['straps'] || 15;
let fabricMultiplier = 1;
if (fabricType === 'delicate') fabricMultiplier = 1.25;
if (fabricType === 'heavy') fabricMultiplier = 1.35;
if (fabricType === 'specialty') fabricMultiplier = 1.50;
baseTotal *= fabricMultiplier;
const rushMultiplier = (rushFees[rushOption] || 1) - 1;
return Math.round(baseTotal * rushMultiplier);
},
variant: 'default',
prefix: '+'
}, '1fr');
});
const finalSection = form.addSubform('final', {
title: '๐งพ Summary',
isCollapsible: false,
sticky: 'bottom'
});
finalSection.addRow(row => {
row.addPriceDisplay('perItemPrice', {
label: 'Per Item',
computedValue: () => {
const garmentType = garmentSection.dropdown('garmentType')?.value() || 'pants';
const fabricType = garmentSection.dropdown('fabricType')?.value() || 'standard';
const rushOption = timingSection.radioButton('rushOption')?.value() || 'standard';
const prices = garmentPrices[garmentType] || defaultPrices;
let alterationTotal = 0;
if (alterationsSection.checkbox('hemming')?.value()) alterationTotal += prices['hem'] || 15;
if (alterationsSection.checkbox('takeIn')?.value()) alterationTotal += prices['take-in'] || 25;
if (alterationsSection.checkbox('waistAdjust')?.value()) alterationTotal += prices['waist'] || 25;
if (alterationsSection.checkbox('sleeves')?.value()) alterationTotal += prices['sleeves'] || 20;
if (alterationsSection.checkbox('tapering')?.value()) alterationTotal += prices['taper'] || 30;
if (alterationsSection.checkbox('shoulders')?.value()) alterationTotal += prices['shoulders'] || 75;
if (alterationsSection.checkbox('bustle')?.value()) alterationTotal += prices['bustle'] || 85;
if (alterationsSection.checkbox('straps')?.value()) alterationTotal += prices['straps'] || 15;
// Fabric multiplier
let fabricMultiplier = 1;
if (fabricType === 'delicate') fabricMultiplier = 1.25;
if (fabricType === 'heavy') fabricMultiplier = 1.35;
if (fabricType === 'specialty') fabricMultiplier = 1.50;
alterationTotal *= fabricMultiplier;
// Rush multiplier
alterationTotal *= rushFees[rushOption] || 1;
// Condition
const condition = garmentSection.dropdown('garmentCondition')?.value();
if (condition === 'worn') alterationTotal += 10;
if (condition === 'damaged') alterationTotal += 25;
// Extras (per item)
if (extrasSection.checkbox('pressing')?.value()) alterationTotal += 8;
return Math.round(alterationTotal);
},
variant: 'default',
suffix: '/item'
}, '1fr');
row.addPriceDisplay('totalPrice', {
label: 'Total',
computedValue: () => {
const garmentType = garmentSection.dropdown('garmentType')?.value() || 'pants';
const fabricType = garmentSection.dropdown('fabricType')?.value() || 'standard';
const rushOption = timingSection.radioButton('rushOption')?.value() || 'standard';
const quantity = garmentSection.integer('quantity')?.value() || 1;
const prices = garmentPrices[garmentType] || defaultPrices;
let alterationTotal = 0;
if (alterationsSection.checkbox('hemming')?.value()) alterationTotal += prices['hem'] || 15;
if (alterationsSection.checkbox('takeIn')?.value()) alterationTotal += prices['take-in'] || 25;
if (alterationsSection.checkbox('waistAdjust')?.value()) alterationTotal += prices['waist'] || 25;
if (alterationsSection.checkbox('sleeves')?.value()) alterationTotal += prices['sleeves'] || 20;
if (alterationsSection.checkbox('tapering')?.value()) alterationTotal += prices['taper'] || 30;
if (alterationsSection.checkbox('shoulders')?.value()) alterationTotal += prices['shoulders'] || 75;
if (alterationsSection.checkbox('bustle')?.value()) alterationTotal += prices['bustle'] || 85;
if (alterationsSection.checkbox('straps')?.value()) alterationTotal += prices['straps'] || 15;
let fabricMultiplier = 1;
if (fabricType === 'delicate') fabricMultiplier = 1.25;
if (fabricType === 'heavy') fabricMultiplier = 1.35;
if (fabricType === 'specialty') fabricMultiplier = 1.50;
alterationTotal *= fabricMultiplier;
alterationTotal *= rushFees[rushOption] || 1;
const condition = garmentSection.dropdown('garmentCondition')?.value();
if (condition === 'worn') alterationTotal += 10;
if (condition === 'damaged') alterationTotal += 25;
if (extrasSection.checkbox('pressing')?.value()) alterationTotal += 8;
let total = alterationTotal * quantity;
// One-time extras
if (extrasSection.checkbox('buttonReplacement')?.value()) {
const buttonCount = extrasSection.integer('buttonCount')?.value() || 1;
total += buttonCount * 3;
}
if (extrasSection.checkbox('zipperReplacement')?.value()) {
total += (garmentType === 'coat' || garmentType === 'suit-jacket') ? 35 : 15;
}
if (extrasSection.checkbox('liningRepair')?.value()) total += 25;
return Math.round(total);
},
variant: 'large'
}, '1fr');
});
finalSection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Final price confirmed after in-person fitting. Complex alterations may require additional consultation.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'font-style': 'italic' }
});
});
form.configureSubmitButton({
label: 'Book Fitting'
});
}