export function legalServicesCalculator(form: FormTs) {
// Hourly rates by attorney level
const hourlyRates: Record<string, number> = {
'paralegal': 95,
'associate': 250,
'senior-associate': 350,
'partner': 500,
'senior-partner': 650
};
// Service type base fees (flat fee or estimated hours)
const serviceFees: Record<string, { type: 'flat' | 'hourly', amount: number, minHours?: number, maxHours?: number }> = {
'consultation': { type: 'flat', amount: 150 },
'contract-review-simple': { type: 'flat', amount: 350 },
'contract-review-complex': { type: 'hourly', amount: 0, minHours: 3, maxHours: 8 },
'contract-drafting': { type: 'hourly', amount: 0, minHours: 4, maxHours: 12 },
'llc-formation': { type: 'flat', amount: 750 },
'corporation-formation': { type: 'flat', amount: 1200 },
'trademark-search': { type: 'flat', amount: 400 },
'trademark-filing': { type: 'flat', amount: 1500 },
'nda-drafting': { type: 'flat', amount: 450 },
'employment-agreement': { type: 'flat', amount: 850 },
'lease-review': { type: 'flat', amount: 500 },
'will-simple': { type: 'flat', amount: 500 },
'will-complex': { type: 'flat', amount: 1200 },
'trust-creation': { type: 'flat', amount: 2500 },
'power-of-attorney': { type: 'flat', amount: 250 },
'demand-letter': { type: 'flat', amount: 500 },
'cease-desist': { type: 'flat', amount: 600 },
'negotiation': { type: 'hourly', amount: 0, minHours: 2, maxHours: 10 },
'mediation-prep': { type: 'hourly', amount: 0, minHours: 5, maxHours: 15 },
'general-counsel': { type: 'hourly', amount: 0, minHours: 10, maxHours: 40 }
};
// Complexity multipliers
const complexityMultipliers: Record<string, number> = {
'simple': 0.8,
'standard': 1.0,
'complex': 1.5,
'highly-complex': 2.0
};
// Urgency multipliers
const urgencyMultipliers: Record<string, number> = {
'standard': 1.0,
'expedited': 1.25,
'rush': 1.5,
'emergency': 2.0
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Legal Services Fee Estimate',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Service Selection Section
const serviceSection = form.addSubform('serviceDetails', { title: 'โ๏ธ Service Selection' });
serviceSection.addRow(row => {
row.addDropdown('practiceArea', {
label: 'Practice Area',
options: [
{ id: 'business', name: 'Business & Corporate' },
{ id: 'contracts', name: 'Contracts & Agreements' },
{ id: 'ip', name: 'Intellectual Property' },
{ id: 'estate', name: 'Estate Planning' },
{ id: 'employment', name: 'Employment Law' },
{ id: 'real-estate', name: 'Real Estate' },
{ id: 'litigation', name: 'Litigation Support' },
{ id: 'general', name: 'General Counsel' }
],
defaultValue: 'contracts',
isRequired: true
}, '1fr');
row.addDropdown('serviceType', {
label: 'Service Type',
options: () => {
const area = serviceSection.dropdown('practiceArea')?.value() || 'contracts';
if (area === 'business') {
return [
{ id: 'consultation', name: 'Initial Consultation' },
{ id: 'llc-formation', name: 'LLC Formation' },
{ id: 'corporation-formation', name: 'Corporation Formation' },
{ id: 'general-counsel', name: 'General Counsel (Monthly)' }
];
} else if (area === 'contracts') {
return [
{ id: 'consultation', name: 'Initial Consultation' },
{ id: 'contract-review-simple', name: 'Simple Contract Review' },
{ id: 'contract-review-complex', name: 'Complex Contract Review' },
{ id: 'contract-drafting', name: 'Contract Drafting' },
{ id: 'nda-drafting', name: 'NDA Drafting' }
];
} else if (area === 'ip') {
return [
{ id: 'consultation', name: 'Initial Consultation' },
{ id: 'trademark-search', name: 'Trademark Search' },
{ id: 'trademark-filing', name: 'Trademark Filing' },
{ id: 'cease-desist', name: 'Cease & Desist Letter' }
];
} else if (area === 'estate') {
return [
{ id: 'consultation', name: 'Initial Consultation' },
{ id: 'will-simple', name: 'Simple Will' },
{ id: 'will-complex', name: 'Complex Will' },
{ id: 'trust-creation', name: 'Trust Creation' },
{ id: 'power-of-attorney', name: 'Power of Attorney' }
];
} else if (area === 'employment') {
return [
{ id: 'consultation', name: 'Initial Consultation' },
{ id: 'employment-agreement', name: 'Employment Agreement' },
{ id: 'contract-review-simple', name: 'Contract Review' },
{ id: 'demand-letter', name: 'Demand Letter' }
];
} else if (area === 'real-estate') {
return [
{ id: 'consultation', name: 'Initial Consultation' },
{ id: 'lease-review', name: 'Lease Review' },
{ id: 'contract-review-complex', name: 'Purchase Agreement Review' },
{ id: 'negotiation', name: 'Negotiation Support' }
];
} else if (area === 'litigation') {
return [
{ id: 'consultation', name: 'Case Evaluation' },
{ id: 'demand-letter', name: 'Demand Letter' },
{ id: 'negotiation', name: 'Settlement Negotiation' },
{ id: 'mediation-prep', name: 'Mediation Preparation' }
];
} else {
return [
{ id: 'consultation', name: 'Initial Consultation' },
{ id: 'general-counsel', name: 'General Counsel Services' }
];
}
},
defaultValue: 'consultation',
isRequired: true
}, '1fr');
});
serviceSection.addRow(row => {
row.addDropdown('attorneyLevel', {
label: 'Attorney Level',
options: [
{ id: 'paralegal', name: 'Paralegal ($95/hr)' },
{ id: 'associate', name: 'Associate Attorney ($250/hr)' },
{ id: 'senior-associate', name: 'Senior Associate ($350/hr)' },
{ id: 'partner', name: 'Partner ($500/hr)' },
{ id: 'senior-partner', name: 'Senior Partner ($650/hr)' }
],
defaultValue: 'associate',
isRequired: true
}, '1fr');
row.addDropdown('complexity', {
label: 'Matter Complexity',
options: [
{ id: 'simple', name: 'Simple (-20%)' },
{ id: 'standard', name: 'Standard' },
{ id: 'complex', name: 'Complex (+50%)' },
{ id: 'highly-complex', name: 'Highly Complex (+100%)' }
],
defaultValue: 'standard',
isRequired: true
}, '1fr');
});
// Details Section
const detailsSection = form.addSubform('matterDetails', { title: '๐ Matter Details' });
detailsSection.addRow(row => {
row.addDropdown('urgency', {
label: 'Timeline / Urgency',
options: [
{ id: 'standard', name: 'Standard (2-4 weeks)' },
{ id: 'expedited', name: 'Expedited (1-2 weeks) (+25%)' },
{ id: 'rush', name: 'Rush (3-5 days) (+50%)' },
{ id: 'emergency', name: 'Emergency (24-48 hrs) (+100%)' }
],
defaultValue: 'standard',
isRequired: true
}, '1fr');
row.addInteger('estimatedHours', {
label: 'Estimated Hours',
min: 1,
max: 100,
defaultValue: 5,
isVisible: () => {
const service = serviceSection.dropdown('serviceType')?.value() || 'consultation';
const serviceInfo = serviceFees[service];
return serviceInfo?.type === 'hourly';
}
}, '1fr');
});
detailsSection.addRow(row => {
row.addCheckbox('includeFilingFees', {
label: 'Include Filing Fees (Estimated)',
defaultValue: true,
isVisible: () => {
const service = serviceSection.dropdown('serviceType')?.value();
return ['llc-formation', 'corporation-formation', 'trademark-filing'].includes(service || '');
}
}, '1fr');
row.addCheckbox('retainerAgreement', {
label: 'Monthly Retainer Arrangement',
defaultValue: false,
isVisible: () => {
const service = serviceSection.dropdown('serviceType')?.value();
return service === 'general-counsel';
}
}, '1fr');
});
detailsSection.addRow(row => {
row.addInteger('retainerHours', {
label: 'Monthly Retainer Hours',
min: 5,
max: 40,
defaultValue: 10,
isVisible: () => {
const service = serviceSection.dropdown('serviceType')?.value();
return service === 'general-counsel' && detailsSection.checkbox('retainerAgreement')?.value() === true;
}
});
});
// Additional Services Section
const addonsSection = form.addSubform('additionalServices', { title: 'โจ Additional Services' });
addonsSection.addRow(row => {
row.addCheckbox('prioritySupport', {
label: 'Priority Phone/Email Support (+$150/mo)',
defaultValue: false
}, '1fr');
row.addCheckbox('documentStorage', {
label: 'Secure Document Storage (+$50/mo)',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('quarterlyReview', {
label: 'Quarterly Compliance Review (+$500/qtr)',
defaultValue: false
}, '1fr');
row.addCheckbox('legalAudit', {
label: 'Initial Legal Audit (+$750)',
defaultValue: false
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Price Summary Section
const summarySection = form.addSubform('summary', { title: '๐ฐ Fee Estimate', isCollapsible: false });
summarySection.addRow(row => {
row.addPriceDisplay('baseFee', {
label: 'Base Legal Fee',
computedValue: () => {
const service = serviceSection.dropdown('serviceType')?.value() || 'consultation';
const attorneyLevel = serviceSection.dropdown('attorneyLevel')?.value() || 'associate';
const complexity = serviceSection.dropdown('complexity')?.value() || 'standard';
const estimatedHours = detailsSection.integer('estimatedHours')?.value() || 5;
const retainerAgreement = detailsSection.checkbox('retainerAgreement')?.value();
const retainerHours = detailsSection.integer('retainerHours')?.value() || 10;
const serviceInfo = serviceFees[service];
const hourlyRate = hourlyRates?.[attorneyLevel] ?? 250;
const complexityMult = complexityMultipliers?.[complexity] ?? 1.0;
let fee = 0;
if (serviceInfo?.type === 'flat') {
fee = serviceInfo.amount * complexityMult;
} else {
if (service === 'general-counsel' && retainerAgreement) {
fee = hourlyRate * retainerHours * 0.85; // 15% retainer discount
} else {
fee = hourlyRate * estimatedHours * complexityMult;
}
}
return fee;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('urgencyFee', {
label: 'Urgency Adjustment',
computedValue: () => {
const service = serviceSection.dropdown('serviceType')?.value() || 'consultation';
const attorneyLevel = serviceSection.dropdown('attorneyLevel')?.value() || 'associate';
const complexity = serviceSection.dropdown('complexity')?.value() || 'standard';
const urgency = detailsSection.dropdown('urgency')?.value() || 'standard';
const estimatedHours = detailsSection.integer('estimatedHours')?.value() || 5;
const serviceInfo = serviceFees[service];
const hourlyRate = hourlyRates?.[attorneyLevel] ?? 250;
const complexityMult = complexityMultipliers?.[complexity] ?? 1.0;
const urgencyMult = urgencyMultipliers?.[urgency] ?? 1.0;
let baseFee = 0;
if (serviceInfo?.type === 'flat') {
baseFee = serviceInfo.amount * complexityMult;
} else {
baseFee = hourlyRate * estimatedHours * complexityMult;
}
return baseFee * (urgencyMult - 1);
},
variant: 'default',
prefix: '+'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('filingFees', {
label: 'Filing Fees (Est.)',
computedValue: () => {
const service = serviceSection.dropdown('serviceType')?.value();
const includeFilingFees = detailsSection.checkbox('includeFilingFees')?.value();
if (!includeFilingFees) return 0;
const filingFeeEstimates: Record<string, number> = {
'llc-formation': 150,
'corporation-formation': 300,
'trademark-filing': 350
};
return filingFeeEstimates?.[service || ''] ?? 0;
},
variant: 'default',
prefix: '+'
}, '1fr');
row.addPriceDisplay('addonsTotal', {
label: 'Additional Services',
computedValue: () => {
let total = 0;
if (addonsSection.checkbox('prioritySupport')?.value()) total += 150;
if (addonsSection.checkbox('documentStorage')?.value()) total += 50;
if (addonsSection.checkbox('quarterlyReview')?.value()) total += 500;
if (addonsSection.checkbox('legalAudit')?.value()) total += 750;
return total;
},
variant: 'default',
prefix: '+'
}, '1fr');
});
const finalSection = form.addSubform('final', {
title: '๐งพ Total Estimate',
isCollapsible: false,
sticky: 'bottom'
});
finalSection.addRow(row => {
row.addPriceDisplay('totalFee', {
label: 'Estimated Total Fee',
computedValue: () => {
const service = serviceSection.dropdown('serviceType')?.value() || 'consultation';
const attorneyLevel = serviceSection.dropdown('attorneyLevel')?.value() || 'associate';
const complexity = serviceSection.dropdown('complexity')?.value() || 'standard';
const urgency = detailsSection.dropdown('urgency')?.value() || 'standard';
const estimatedHours = detailsSection.integer('estimatedHours')?.value() || 5;
const includeFilingFees = detailsSection.checkbox('includeFilingFees')?.value();
const retainerAgreement = detailsSection.checkbox('retainerAgreement')?.value();
const retainerHours = detailsSection.integer('retainerHours')?.value() || 10;
const serviceInfo = serviceFees[service];
const hourlyRate = hourlyRates?.[attorneyLevel] ?? 250;
const complexityMult = complexityMultipliers?.[complexity] ?? 1.0;
const urgencyMult = urgencyMultipliers?.[urgency] ?? 1.0;
// Base fee
let baseFee = 0;
if (serviceInfo?.type === 'flat') {
baseFee = serviceInfo.amount * complexityMult;
} else {
if (service === 'general-counsel' && retainerAgreement) {
baseFee = hourlyRate * retainerHours * 0.85;
} else {
baseFee = hourlyRate * estimatedHours * complexityMult;
}
}
// Apply urgency
let total = baseFee * urgencyMult;
// Filing fees
if (includeFilingFees) {
const filingFees: Record<string, number> = {
'llc-formation': 150,
'corporation-formation': 300,
'trademark-filing': 350
};
total += filingFees?.[service] ?? 0;
}
// Add-ons
if (addonsSection.checkbox('prioritySupport')?.value()) total += 150;
if (addonsSection.checkbox('documentStorage')?.value()) total += 50;
if (addonsSection.checkbox('quarterlyReview')?.value()) total += 500;
if (addonsSection.checkbox('legalAudit')?.value()) total += 750;
return Math.round(total);
},
variant: 'large',
suffix: () => {
const service = serviceSection.dropdown('serviceType')?.value();
const retainer = detailsSection.checkbox('retainerAgreement')?.value();
if (service === 'general-counsel' && retainer) return '/month';
return '';
}
});
});
finalSection.addRow(row => {
row.addTextPanel('hourlyNote', {
computedValue: () => {
const attorneyLevel = serviceSection.dropdown('attorneyLevel')?.value() || 'associate';
const rate = hourlyRates?.[attorneyLevel] ?? 250;
return `Hourly rate: $${rate}/hour`;
},
customStyles: { 'font-size': '0.9rem', 'color': '#64748b', 'text-align': 'center' }
});
});
finalSection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'This is an estimate only. Actual fees depend on matter complexity and are confirmed after consultation. No attorney-client relationship is formed by using this calculator.',
customStyles: { 'font-size': '0.8rem', 'color': '#64748b', 'font-style': 'italic' }
});
});
form.configureSubmitButton({
label: 'Schedule Consultation'
});
}