// Guided Recommender component const QUESTIONS = [ { id: 'goal', text: 'What is the primary research goal?', options: [ { label: 'Understand trade-offs between product attributes', value: 'tradeoff' }, { label: 'Rank or prioritise a list of items/messages', value: 'rank' }, { label: 'Select the best combination of items for reach', value: 'coverage' }, { label: 'Set or validate a price range', value: 'pricing' }, { label: 'Identify what drives satisfaction, loyalty, or behaviour', value: 'drivers' }, { label: 'Discover distinct audience segments', value: 'segments' }, { label: 'Predict a binary outcome (yes/no)', value: 'predict' }, { label: 'Visualise decision pathways and interaction effects', value: 'decision' }, ] }, { id: 'data', text: 'What kind of data do you have or plan to collect?', options: [ { label: 'New primary survey (we will design and field it)', value: 'survey' }, { label: 'Existing survey / tracker data', value: 'existing_survey' }, { label: 'CRM, claims, or administrative data', value: 'admin' }, { label: 'Registry or real-world evidence data', value: 'rwe' }, ] }, { id: 'audience', text: 'Who is the primary study audience?', options: [ { label: 'Healthcare professionals (HCPs)', value: 'hcp' }, { label: 'Patients / caregivers', value: 'patient' }, { label: 'Payers / market access stakeholders', value: 'payer' }, { label: 'Mixed audience', value: 'mixed' }, ] }, { id: 'stage', text: 'What stage of the product lifecycle is this for?', options: [ { label: 'Early development / concept stage', value: 'early' }, { label: 'Pre-launch (12–18 months before launch)', value: 'prelaunch' }, { label: 'Launch / first year on market', value: 'launch' }, { label: 'Post-launch / ongoing tracking', value: 'post' }, ] }, { id: 'budget', text: 'What is the approximate research budget?', options: [ { label: 'Lean (quick, low-cost)', value: 'low' }, { label: 'Moderate (standard study)', value: 'medium' }, { label: 'Significant (complex study)', value: 'high' }, ] }, ]; const RECOMMENDATION_LOGIC = (answers) => { const recs = {}; const add = (id, score, reason) => { recs[id] = { score: (recs[id]?.score || 0) + score, reasons: [...(recs[id]?.reasons || []), reason] }; }; const { goal, data, audience, stage, budget } = answers; // Goal-based scoring if (goal === 'tradeoff') { add('conjoint', 5, 'Conjoint is the gold standard for multi-attribute trade-off measurement'); } if (goal === 'rank') { add('maxdiff', 5, 'MaxDiff is the most robust method for item prioritisation and ranking'); } if (goal === 'coverage') { add('turf', 5, 'TURF directly optimises reach from a set of candidate items'); add('maxdiff', 2, 'MaxDiff provides complementary importance ranking for the same item list'); } if (goal === 'pricing') { add('vanwestendorp', 5, 'Van Westendorp PSM is designed specifically for price range and optimal price point research'); } if (goal === 'drivers') { add('keydriver', 5, 'Key Driver Analysis statistically identifies which factors predict the outcome'); add('logistic', 2, 'Logistic Regression is useful if the outcome is binary'); } if (goal === 'segments') { add('cluster', 5, 'Cluster Analysis is the standard method for empirical audience segmentation'); add('chaid', 2, 'CHAID can profile known segments with transparent decision rules'); } if (goal === 'predict') { add('logistic', 5, 'Logistic Regression is the interpretable standard for binary outcome prediction'); add('chaid', 3, 'CHAID provides an alternative visualisable prediction structure'); } if (goal === 'decision') { add('chaid', 5, 'CHAID produces the visual decision tree structure you need'); add('logistic', 2, 'Logistic Regression provides complementary probability estimates'); } // Data modifiers if (data === 'admin' || data === 'rwe') { add('logistic', 2, 'Logistic regression works well with claims and EHR data'); add('chaid', 2, 'CHAID handles categorical administrative data effectively'); add('keydriver', 1, 'KDA can use CRM rating data'); } if (data === 'existing_survey') { add('keydriver', 2, 'Existing tracker data often supports driver analysis directly'); add('cluster', 1, 'Attitudinal battery data can be used for segmentation'); } if (data === 'survey') { add('conjoint', 1, 'Conjoint requires new primary survey design'); add('maxdiff', 1, 'MaxDiff is survey-native'); add('turf', 1, 'TURF uses rating data from a new survey'); } // Stage modifiers if (stage === 'early') { add('maxdiff', 1, 'MaxDiff is well-suited to early-stage prioritisation'); add('conjoint', 1, 'Conjoint can help define TPP early'); } if (stage === 'prelaunch') { add('conjoint', 2, 'Conjoint is ideal for pre-launch TPP refinement'); add('vanwestendorp', 1, 'Pre-launch pricing research fits Van Westendorp'); } if (stage === 'launch') { add('cluster', 2, 'Segmentation and targeting are critical at launch'); add('chaid', 2, 'CHAID helps build HCP targeting profiles at launch'); add('logistic', 2, 'Propensity modelling supports launch targeting'); } if (stage === 'post') { add('keydriver', 2, 'Brand tracking KDA is most relevant post-launch'); add('cluster', 1, 'Post-launch segmentation tracking'); } // Budget modifiers if (budget === 'low') { add('maxdiff', 1, 'MaxDiff is cost-effective'); add('vanwestendorp', 1, 'Van Westendorp is one of the lowest-cost primary methods'); add('keydriver', 1, 'KDA from existing data is very cost-effective'); } if (budget === 'high') { add('conjoint', 1, 'Sufficient budget for conjoint design and HB modelling'); add('cluster', 1, 'Sufficient budget for large-sample segmentation study'); } if (budget === 'medium') { add('maxdiff', 1, 'Good fit for medium budgets'); add('turf', 1, 'TURF is achievable on a medium budget'); } // Audience modifiers if (audience === 'payer') { add('conjoint', 1, 'Conjoint/DCE is widely used in HTA and payer research'); add('vanwestendorp', 1, 'Pricing research for payer context'); } if (audience === 'patient') { add('conjoint', 1, 'Patient preference evidence (DCE) is HTA-aligned'); add('maxdiff', 1, 'MaxDiff is accessible to patient audiences'); } // Sort and return top 3 return Object.entries(recs) .sort((a, b) => b[1].score - a[1].score) .slice(0, 3) .map(([id, data]) => ({ id, score: data.score, reasons: data.reasons })); }; function Recommender({ techniques, onSelect, onClose }) { const [step, setStep] = React.useState(0); const [answers, setAnswers] = React.useState({}); const [results, setResults] = React.useState(null); const question = QUESTIONS[step]; const totalSteps = QUESTIONS.length; const progress = (step / totalSteps) * 100; const answer = (qid, val) => { const newAnswers = { ...answers, [qid]: val }; setAnswers(newAnswers); if (step < totalSteps - 1) { setStep(s => s + 1); } else { setResults(RECOMMENDATION_LOGIC(newAnswers)); } }; const reset = () => { setStep(0); setAnswers({}); setResults(null); }; if (results) { return (
Based on your answers, here are the best-fit methods