export function dataProcessingAgreementCalculator(form: FormTs) {
// DPA type base costs
const dpaTypeCosts: Record<string, number> = {
'template': 350,
'standard': 750,
'custom': 1500,
'complex': 3000,
'enterprise': 5000
};
// Processing risk multipliers
const riskMultipliers: Record<string, number> = {
'low': 0.8,
'moderate': 1.0,
'high': 1.3,
'very-high': 1.6
};
// Jurisdiction complexity
const jurisdictionMultipliers: Record<string, number> = {
'single-eu': 1.0,
'single-other': 1.1,
'multi-eu': 1.3,
'global': 1.6
};
// Negotiation complexity
const negotiationCosts: Record<string, number> = {
'none': 0,
'light': 500,
'moderate': 1200,
'extensive': 2500
};
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Data Processing Agreement Cost Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Service Type Section
const serviceSection = form.addSubform('serviceType', { title: '📄 Service Type' });
serviceSection.addRow(row => {
row.addDropdown('dpaService', {
label: 'DPA Service Needed',
options: [
{ id: 'draft', name: 'Draft new DPA (you as controller)' },
{ id: 'review', name: 'Review vendor DPA' },
{ id: 'negotiate', name: 'Review & negotiate vendor DPA' },
{ id: 'both', name: 'Draft own + review vendor DPAs' },
{ id: 'program', name: 'DPA management program' }
],
defaultValue: 'review',
isRequired: true
}, '1fr');
row.addDropdown('dpaType', {
label: 'DPA Complexity',
options: [
{ id: 'template', name: 'Template-based (standard clauses)' },
{ id: 'standard', name: 'Standard (some customization)' },
{ id: 'custom', name: 'Custom (significant tailoring)' },
{ id: 'complex', name: 'Complex (multi-party, special data)' },
{ id: 'enterprise', name: 'Enterprise (comprehensive program)' }
],
defaultValue: 'standard',
isRequired: true
}, '1fr');
});
serviceSection.addRow(row => {
row.addInteger('dpaCount', {
label: 'Number of DPAs',
min: 1,
max: 100,
defaultValue: 1
}, '1fr');
row.addDropdown('urgency', {
label: 'Timeline',
options: [
{ id: 'standard', name: 'Standard (2-4 weeks)' },
{ id: 'expedited', name: 'Expedited (1-2 weeks) (+25%)' },
{ id: 'urgent', name: 'Urgent (under 1 week) (+50%)' }
],
defaultValue: 'standard'
}, '1fr');
});
// Data Processing Details Section
const dataSection = form.addSubform('dataDetails', { title: '🔒 Data Processing Details' });
dataSection.addRow(row => {
row.addDropdown('dataRisk', {
label: 'Data Sensitivity Level',
options: [
{ id: 'low', name: 'Low (basic contact info, non-sensitive)' },
{ id: 'moderate', name: 'Moderate (financial, employment)' },
{ id: 'high', name: 'High (health, biometric, children)' },
{ id: 'very-high', name: 'Very High (special categories + high volume)' }
],
defaultValue: 'moderate',
isRequired: true
}, '1fr');
row.addDropdown('jurisdiction', {
label: 'Jurisdictional Scope',
options: [
{ id: 'single-eu', name: 'Single EU country' },
{ id: 'single-other', name: 'Single non-EU jurisdiction' },
{ id: 'multi-eu', name: 'Multiple EU countries' },
{ id: 'global', name: 'Global (multiple regions)' }
],
defaultValue: 'single-eu',
isRequired: true
}, '1fr');
});
dataSection.addRow(row => {
row.addCheckbox('crossBorderTransfer', {
label: 'International data transfers',
defaultValue: false
}, '1fr');
row.addCheckbox('subProcessors', {
label: 'Sub-processor provisions needed',
defaultValue: true
}, '1fr');
});
dataSection.addRow(row => {
row.addCheckbox('sccs', {
label: 'Standard Contractual Clauses (SCCs)',
defaultValue: false,
isVisible: () => dataSection.checkbox('crossBorderTransfer')?.value() === true
}, '1fr');
row.addCheckbox('tia', {
label: 'Transfer Impact Assessment',
defaultValue: false,
isVisible: () => dataSection.checkbox('crossBorderTransfer')?.value() === true
}, '1fr');
});
// Additional Services Section
const addonsSection = form.addSubform('addons', { title: '✨ Additional Services' });
addonsSection.addRow(row => {
row.addCheckbox('vendorAssessment', {
label: 'Vendor security assessment',
defaultValue: false
}, '1fr');
row.addCheckbox('dpia', {
label: 'Data Protection Impact Assessment',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addCheckbox('ropa', {
label: 'Record of Processing Activities update',
defaultValue: false
}, '1fr');
row.addCheckbox('dataMapping', {
label: 'Data flow mapping',
defaultValue: false
}, '1fr');
});
addonsSection.addRow(row => {
row.addDropdown('negotiation', {
label: 'Negotiation Support',
options: [
{ id: 'none', name: 'No negotiation needed' },
{ id: 'light', name: 'Light (1-2 rounds)' },
{ id: 'moderate', name: 'Moderate (3-5 rounds)' },
{ id: 'extensive', name: 'Extensive (complex negotiations)' }
],
defaultValue: 'none',
isVisible: () => {
const service = serviceSection.dropdown('dpaService')?.value();
return service === 'negotiate' || service === 'both' || service === 'program';
}
}, '1fr');
});
// Ongoing Services Section
const ongoingSection = form.addSubform('ongoing', { title: '🔄 Ongoing Services' });
ongoingSection.addRow(row => {
row.addCheckbox('annualReview', {
label: 'Annual DPA review',
defaultValue: false
}, '1fr');
row.addCheckbox('vendorMonitoring', {
label: 'Vendor compliance monitoring',
defaultValue: false
}, '1fr');
});
ongoingSection.addRow(row => {
row.addCheckbox('updateService', {
label: 'Regulatory update service',
defaultValue: false
}, '1fr');
row.addCheckbox('dpaRepository', {
label: 'DPA repository management',
defaultValue: false
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Cost Summary Section
const summarySection = form.addSubform('summary', { title: '📊 Cost Breakdown', isCollapsible: false });
summarySection.addRow(row => {
row.addPriceDisplay('baseDpaCost', {
label: 'DPA Drafting/Review',
computedValue: () => {
const dpaType = serviceSection.dropdown('dpaType')?.value() || 'standard';
const dpaCount = serviceSection.integer('dpaCount')?.value() || 1;
const dpaService = serviceSection.dropdown('dpaService')?.value() || 'review';
const dataRisk = dataSection.dropdown('dataRisk')?.value() || 'moderate';
const jurisdiction = dataSection.dropdown('jurisdiction')?.value() || 'single-eu';
const urgency = serviceSection.dropdown('urgency')?.value() || 'standard';
let baseCost = dpaTypeCosts[dpaType] || 750;
baseCost *= riskMultipliers[dataRisk] || 1;
baseCost *= jurisdictionMultipliers[jurisdiction] || 1;
// Service type adjustments
if (dpaService === 'draft') baseCost *= 1.2;
if (dpaService === 'both') baseCost *= 1.8;
if (dpaService === 'program') baseCost *= 2.5;
// Volume discount
let totalCost = baseCost * dpaCount;
if (dpaCount >= 5) totalCost *= 0.9;
if (dpaCount >= 10) totalCost *= 0.85;
// Urgency
if (urgency === 'expedited') totalCost *= 1.25;
if (urgency === 'urgent') totalCost *= 1.5;
return Math.round(totalCost);
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('transferCost', {
label: 'International Transfer Provisions',
computedValue: () => {
let cost = 0;
if (dataSection.checkbox('crossBorderTransfer')?.value()) {
cost += 500;
if (dataSection.checkbox('sccs')?.value()) cost += 750;
if (dataSection.checkbox('tia')?.value()) cost += 1000;
}
return cost;
},
variant: 'default'
}, '1fr');
});
summarySection.addRow(row => {
row.addPriceDisplay('addonsCost', {
label: 'Additional Services',
computedValue: () => {
let cost = 0;
if (addonsSection.checkbox('vendorAssessment')?.value()) cost += 800;
if (addonsSection.checkbox('dpia')?.value()) cost += 2000;
if (addonsSection.checkbox('ropa')?.value()) cost += 500;
if (addonsSection.checkbox('dataMapping')?.value()) cost += 1000;
const negotiation = addonsSection.dropdown('negotiation')?.value() || 'none';
cost += negotiationCosts[negotiation] || 0;
return cost;
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('ongoingCost', {
label: 'Ongoing Services',
computedValue: () => {
const dpaCount = serviceSection.integer('dpaCount')?.value() || 1;
let monthlyCost = 0;
if (ongoingSection.checkbox('annualReview')?.value()) {
monthlyCost += (dpaCount * 200) / 12; // Annual cost spread monthly
}
if (ongoingSection.checkbox('vendorMonitoring')?.value()) monthlyCost += 300;
if (ongoingSection.checkbox('updateService')?.value()) monthlyCost += 150;
if (ongoingSection.checkbox('dpaRepository')?.value()) monthlyCost += 100;
return Math.round(monthlyCost);
},
variant: 'default',
suffix: '/month'
}, '1fr');
});
const finalSection = form.addSubform('final', {
title: '💰 Total Cost Estimate',
isCollapsible: false,
sticky: 'bottom'
});
finalSection.addRow(row => {
row.addPriceDisplay('initialCost', {
label: 'Initial Project Cost',
computedValue: () => {
const dpaType = serviceSection.dropdown('dpaType')?.value() || 'standard';
const dpaCount = serviceSection.integer('dpaCount')?.value() || 1;
const dpaService = serviceSection.dropdown('dpaService')?.value() || 'review';
const dataRisk = dataSection.dropdown('dataRisk')?.value() || 'moderate';
const jurisdiction = dataSection.dropdown('jurisdiction')?.value() || 'single-eu';
const urgency = serviceSection.dropdown('urgency')?.value() || 'standard';
// Base DPA cost
let baseCost = dpaTypeCosts[dpaType] || 750;
baseCost *= riskMultipliers[dataRisk] || 1;
baseCost *= jurisdictionMultipliers[jurisdiction] || 1;
if (dpaService === 'draft') baseCost *= 1.2;
if (dpaService === 'both') baseCost *= 1.8;
if (dpaService === 'program') baseCost *= 2.5;
let totalCost = baseCost * dpaCount;
if (dpaCount >= 5) totalCost *= 0.9;
if (dpaCount >= 10) totalCost *= 0.85;
if (urgency === 'expedited') totalCost *= 1.25;
if (urgency === 'urgent') totalCost *= 1.5;
// Transfer provisions
if (dataSection.checkbox('crossBorderTransfer')?.value()) {
totalCost += 500;
if (dataSection.checkbox('sccs')?.value()) totalCost += 750;
if (dataSection.checkbox('tia')?.value()) totalCost += 1000;
}
// Add-ons
if (addonsSection.checkbox('vendorAssessment')?.value()) totalCost += 800;
if (addonsSection.checkbox('dpia')?.value()) totalCost += 2000;
if (addonsSection.checkbox('ropa')?.value()) totalCost += 500;
if (addonsSection.checkbox('dataMapping')?.value()) totalCost += 1000;
const negotiation = addonsSection.dropdown('negotiation')?.value() || 'none';
totalCost += negotiationCosts[negotiation] || 0;
return Math.round(totalCost);
},
variant: 'large'
}, '1fr');
row.addPriceDisplay('annualOngoing', {
label: 'Annual Ongoing Cost',
computedValue: () => {
const dpaCount = serviceSection.integer('dpaCount')?.value() || 1;
let annualCost = 0;
if (ongoingSection.checkbox('annualReview')?.value()) {
annualCost += dpaCount * 200;
}
if (ongoingSection.checkbox('vendorMonitoring')?.value()) annualCost += 3600;
if (ongoingSection.checkbox('updateService')?.value()) annualCost += 1800;
if (ongoingSection.checkbox('dpaRepository')?.value()) annualCost += 1200;
return Math.round(annualCost);
},
variant: 'large',
suffix: '/year'
}, '1fr');
});
finalSection.addRow(row => {
row.addTextPanel('volumeNote', {
computedValue: () => {
const dpaCount = serviceSection.integer('dpaCount')?.value() || 1;
if (dpaCount >= 10) return 'Volume discount applied: 15% off base DPA costs';
if (dpaCount >= 5) return 'Volume discount applied: 10% off base DPA costs';
return '';
},
customStyles: { 'font-size': '0.85rem', 'color': '#10b981', 'text-align': 'center' }
});
});
finalSection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'This calculator provides estimates only. Actual costs depend on specific requirements, vendor cooperation, and negotiation complexity. Consult with a privacy professional for accurate project scoping.',
customStyles: { 'font-size': '0.8rem', 'color': '#64748b', 'font-style': 'italic' }
});
});
form.configureSubmitButton({
label: 'Request DPA Services Quote'
});
}