export function photographyPricingForm(form: FormTs) {
form.setTitle(() => '๐ธ Build Your Photo Session Package');
form.configureCompletionScreen({
type: 'text',
title: () => '๐ Quote Ready!',
message: () => 'Your custom photography quote has been generated. Download your PDF to save the details.'
});
// Pricing data
const sessionRates: Record<string, number> = {
'mini': 150,
'standard': 300,
'extended': 450,
'full-day': 800
};
const locationFees: Record<string, number> = {
'studio': 0,
'outdoor-local': 50,
'client-home': 75,
'travel': 150
};
const addonPrices: Record<string, number> = {
'extraOutfits': 50,
'hairMakeup': 150,
'rushDelivery': 100,
'printRelease': 75,
'extraDigitals': 100,
'slideshow': 125
};
const printPackages: Record<string, number> = {
'none': 0,
'basic': 150,
'standard': 300,
'premium': 500
};
// Session Details
const session = form.addSubform('session', {
title: () => '๐ท Session Details',
mobileBreakpoint: 0
});
session.addRow(row => {
row.addDropdown('type', {
label: 'Session Type',
defaultValue: 'standard',
isRequired: true,
options: [
{ id: 'mini', name: 'โก Mini Session (20 min, 10 photos)' },
{ id: 'standard', name: '๐ธ Standard Session (1 hr, 25 photos)' },
{ id: 'extended', name: '๐ Extended Session (2 hrs, 50 photos)' },
{ id: 'full-day', name: '๐ Full Day (4+ hrs, 100+ photos)' }
]
}, '1fr');
row.addDropdown('occasion', {
label: 'Occasion',
defaultValue: 'portrait',
isRequired: true,
options: [
{ id: 'portrait', name: '๐ค Individual Portrait' },
{ id: 'couple', name: '๐ Couple Session' },
{ id: 'family', name: '๐จโ๐ฉโ๐งโ๐ฆ Family Portrait' },
{ id: 'headshot', name: '๐ผ Professional Headshot' },
{ id: 'maternity', name: '๐คฐ Maternity' },
{ id: 'newborn', name: '๐ถ Newborn' }
]
}, '1fr');
});
session.addRow(row => {
row.addDropdown('location', {
label: 'Location',
defaultValue: 'studio',
isRequired: true,
options: [
{ id: 'studio', name: '๐ Studio (no fee)' },
{ id: 'outdoor-local', name: '๐ณ Outdoor - Local (+$50)' },
{ id: 'client-home', name: '๐ก Your Home (+$75)' },
{ id: 'travel', name: 'โ๏ธ Travel Location (+$150)' }
]
}, '1fr');
row.addInteger('people', {
label: 'Number of People',
defaultValue: 1,
min: 1,
max: 15,
isRequired: true
}, '1fr');
});
// Extras
const extras = form.addSubform('extras', {
title: () => 'โจ Customize Your Package',
mobileBreakpoint: 500
});
extras.addRow(row => {
row.addCheckboxList('sessionExtras', {
label: 'Session Add-ons',
orientation: 'vertical',
options: [
{ id: 'extraOutfits', name: '๐ Extra Outfit Changes (+$50)' },
{ id: 'hairMakeup', name: '๐ Hair & Makeup (+$150)' },
{ id: 'rushDelivery', name: 'โก Rush Delivery 48hrs (+$100)' }
]
}, '1fr');
row.addCheckboxList('digitalExtras', {
label: 'Digital Extras',
orientation: 'vertical',
options: [
{ id: 'printRelease', name: '๐ Print Release (+$75)' },
{ id: 'extraDigitals', name: '๐ 20 Extra Digitals (+$100)' },
{ id: 'slideshow', name: '๐ฌ Animated Slideshow (+$125)' }
]
}, '1fr');
});
// Print Package
const prints = form.addSubform('prints', {
title: () => '๐ผ๏ธ Print Package',
mobileBreakpoint: 0
});
prints.addRow(row => {
row.addRadioButton('printPackage', {
label: 'Select Print Package',
defaultValue: 'none',
isRequired: true,
orientation: 'vertical',
options: [
{ id: 'none', name: 'โ No Prints (digital only)' },
{ id: 'basic', name: '๐ท Basic - 5 prints up to 8x10 (+$150)' },
{ id: 'standard', name: '๐ผ๏ธ Standard - 10 prints + 1 canvas (+$300)' },
{ id: 'premium', name: '๐ Premium - 20 prints + album (+$500)' }
]
});
});
// Calculate functions
const getBasePrice = () => {
const sessionType = session.dropdown('type')?.value() || 'standard';
const people = session.integer('people')?.value() || 1;
let baseRate = sessionRates[sessionType] || 300;
// Additional person fee (after first 2 people)
if (people > 2) {
baseRate += (people - 2) * 25;
}
return baseRate;
};
const getLocationFee = () => {
const location = session.dropdown('location')?.value() || 'studio';
return locationFees[location] || 0;
};
const getAddonsTotal = () => {
let total = 0;
const sessionExtras = extras.checkboxList('sessionExtras')?.value() || [];
const digitalExtras = extras.checkboxList('digitalExtras')?.value() || [];
const allSelected = [...sessionExtras, ...digitalExtras];
for (const addonId of allSelected) {
total += addonPrices[addonId] || 0;
}
return total;
};
const getPrintPackagePrice = () => {
const printPkg = prints.radioButton('printPackage')?.value() || 'none';
return printPackages[printPkg] || 0;
};
const getTotalPrice = () => {
return getBasePrice() + getLocationFee() + getAddonsTotal() + getPrintPackagePrice();
};
const getSelectedAddons = () => {
const sessionExtras = extras.checkboxList('sessionExtras')?.value() || [];
const digitalExtras = extras.checkboxList('digitalExtras')?.value() || [];
return [...sessionExtras, ...digitalExtras];
};
// Quote Summary
const summary = form.addSubform('summary', {
title: () => '๐ฐ Your Custom Quote',
isCollapsible: false,
});
summary.addRow(row => {
row.addPriceDisplay('totalPrice', {
label: 'Total Investment',
computedValue: () => getTotalPrice(),
alignment: 'center',
variant: 'large'
});
});
summary.addRow(row => {
row.addTextPanel('includes', {
computedValue: () => {
const sessionType = session.dropdown('type')?.value() || 'standard';
const photoCounts: Record<string, string> = {
'mini': '10 edited photos',
'standard': '25 edited photos',
'extended': '50 edited photos',
'full-day': '100+ edited photos'
};
return `๐ธ Includes: ${photoCounts[sessionType] || '25 edited photos'} in online gallery`;
},
customStyles: {
fontSize: '0.9rem',
color: '#6b7280',
textAlign: 'center'
}
});
});
form.configureSubmitButton({
label: () => 'Request This Package'
});
// Configure PDF
form.configurePdf('quoteDocument', (pdf) => {
pdf.configure({
filename: 'photography-quote.pdf',
pageSize: 'A4',
allowUserDownload: true,
downloadButtonLabel: 'Download Your Quote',
header: {
title: 'Photography Session Quote',
subtitle: 'Custom Package Details'
},
footer: {
text: 'Thank you for choosing us for your photography needs!',
showPageNumbers: true
}
});
pdf.addSection('Session Details', (section) => {
section.addRow((row) => {
const typeMap: Record<string, string> = {
'mini': 'Mini Session (20 min)',
'standard': 'Standard Session (1 hr)',
'extended': 'Extended Session (2 hrs)',
'full-day': 'Full Day (4+ hrs)'
};
const type = session.dropdown('type')?.value() || 'standard';
row.addField('Session Type', typeMap[type] || type);
});
section.addRow((row) => {
const occasionMap: Record<string, string> = {
'portrait': 'Individual Portrait',
'couple': 'Couple Session',
'family': 'Family Portrait',
'headshot': 'Professional Headshot',
'maternity': 'Maternity',
'newborn': 'Newborn'
};
const occasion = session.dropdown('occasion')?.value() || 'portrait';
row.addField('Occasion', occasionMap[occasion] || occasion);
});
section.addRow((row) => {
const locationMap: Record<string, string> = {
'studio': 'Studio',
'outdoor-local': 'Outdoor - Local',
'client-home': 'Client Home',
'travel': 'Travel Location'
};
const location = session.dropdown('location')?.value() || 'studio';
row.addField('Location', locationMap[location] || location);
const people = session.integer('people')?.value() || 1;
row.addField('Number of People', people.toString());
});
});
const selectedAddons = getSelectedAddons();
if (selectedAddons.length > 0) {
pdf.addSection('Add-On Services', (section) => {
const addonLabels: Record<string, string> = {
'extraOutfits': 'Extra Outfit Changes',
'hairMakeup': 'Hair & Makeup',
'rushDelivery': 'Rush Delivery (48hrs)',
'printRelease': 'Print Release',
'extraDigitals': '20 Extra Digitals',
'slideshow': 'Animated Slideshow'
};
const tableRows = selectedAddons.map(addonId => [
addonLabels[addonId] || addonId,
`$${addonPrices[addonId] || 0}`
]);
section.addTable(['Service', 'Price'], tableRows);
});
}
const printPkg = prints.radioButton('printPackage')?.value() || 'none';
if (printPkg !== 'none') {
pdf.addSection('Print Package', (section) => {
const printLabels: Record<string, string> = {
'basic': 'Basic - 5 prints up to 8x10',
'standard': 'Standard - 10 prints + 1 canvas',
'premium': 'Premium - 20 prints + album'
};
section.addRow((row) => {
row.addField('Package', printLabels[printPkg] || printPkg);
row.addField('Price', `$${getPrintPackagePrice()}`);
});
});
}
pdf.addSection('Quote Summary', (section) => {
section.addRow((row) => {
row.addField('Base Session', `$${getBasePrice()}`);
});
const locationFee = getLocationFee();
if (locationFee > 0) {
section.addRow((row) => {
row.addField('Location Fee', `$${locationFee}`);
});
}
if (selectedAddons.length > 0) {
section.addRow((row) => {
row.addField('Add-ons', `$${getAddonsTotal()}`);
});
}
if (printPkg !== 'none') {
section.addRow((row) => {
row.addField('Print Package', `$${getPrintPackagePrice()}`);
});
}
section.addDivider();
section.addSpacer(10);
section.addRow((row) => {
row.addField('TOTAL', `$${getTotalPrice()}`);
});
});
pdf.addSection('What\'s Included', (section) => {
const sessionType = session.dropdown('type')?.value() || 'standard';
const includes: Record<string, string[]> = {
'mini': ['20-minute session', '10 professionally edited photos', 'Online gallery for 30 days'],
'standard': ['1-hour session', '25 professionally edited photos', 'Online gallery for 60 days', '1 outfit change'],
'extended': ['2-hour session', '50 professionally edited photos', 'Online gallery for 90 days', '2 outfit changes'],
'full-day': ['4+ hour session', '100+ professionally edited photos', 'Online gallery for 1 year', 'Unlimited outfit changes']
};
const items = includes[sessionType] ?? includes['standard'] ?? [];
items.forEach(item => {
section.addText(`โข ${item}`);
});
});
pdf.addSection('Terms & Conditions', (section) => {
section.addText('โข This quote is valid for 14 days from the date of generation.');
section.addText('โข 50% retainer required to book your session date.');
section.addText('โข Rescheduling requires 48-hour notice.');
section.addText('โข Photos delivered within 2-3 weeks (rush delivery available).');
section.addSpacer(10);
section.addText('Questions? Contact us at hello@photographer.com');
});
});
}