import { useState, useRef, useEffect } from "react";
const BG = "#445548";
const BG2 = "#3a4a3d";
const BG3 = "#334038";
const BORDER = "#5a6e5d";
const GOLD = "#d4a843";
const GOLD2 = "#c9982a";
const TEXT1 = "#f0ebe0";
const TEXT2 = "#c8d4c0";
const TEXT3 = "#9aaa94";
const TEXT4 = "#7a8a74";
const BTN_ACTIVE_BG = "#3a4a3d";
const WINES = [
{id:1,name:"DAOSA 'Natural Reserve'",vintage:"NV",region:"Adelaide Hills, SA",category:"Sparkling",price:115},
{id:2,name:"Voyager Estate Sparkling Chenin",vintage:"2023",region:"Margaret River, WA",category:"Sparkling",price:80},
{id:3,name:"Hentley Farm Blanc de Noir",vintage:"NV",region:"Barossa Valley, SA",category:"Sparkling",price:80},
{id:4,name:"Henskens Rankin Brut Vintage",vintage:"2014",region:"Tasmania",category:"Sparkling",price:150},
{id:5,name:"André Clouet Grande Reserve Brut",vintage:"NV",region:"Bouzy, Champagne, France",category:"Champagne",price:170},
{id:6,name:"Ayala 'Brut Majeur'",vintage:"NV",region:"Aÿ, Champagne, France",category:"Champagne",price:160},
{id:7,name:"Gosset Grande Réserve Brut",vintage:"NV",region:"Aÿ, Champagne, France",category:"Champagne",price:235},
{id:8,name:"Charles Heidsieck Brut Réserve",vintage:"NV",region:"Reims, Champagne, France",category:"Champagne",price:208},
{id:9,name:"Ruinart Blanc de Blancs",vintage:"NV",region:"Champagne, France",category:"Champagne",price:270},
{id:10,name:"Dom Pérignon",vintage:"2015",region:"Champagne, France",category:"Champagne",price:540},
{id:11,name:"De Chanceny Crémant de Loire",vintage:"NV",region:"Loire Valley, France",category:"Sparkling",price:87},
{id:12,name:"Astoria 'Butterfly' Prosecco DOC",vintage:"2023",region:"Treviso, Italy",category:"Sparkling",price:80},
{id:13,name:"Stonehorse by Kaesler Riesling",vintage:"2023",region:"Clare Valley, SA",category:"Riesling",price:75},
{id:14,name:"Jim Barry 'The Florita' Riesling",vintage:"2024",region:"Clare Valley, SA",category:"Riesling",price:129},
{id:15,name:"Grosset 'Polish Hill' Riesling",vintage:"2022",region:"Clare Valley, SA",category:"Riesling",price:167},
{id:16,name:"Henschke 'Peggy's Hill' Riesling",vintage:"2024",region:"Eden Valley, SA",category:"Riesling",price:70},
{id:17,name:"Trimbach 'Cuvée Frédéric Emile' Riesling",vintage:"2008",region:"Alsace, France",category:"Riesling",price:208},
{id:18,name:"Markus Molitor 'Alte Reben' Kabinett Riesling",vintage:"2022",region:"Mosel, Germany",category:"Riesling",price:142},
{id:19,name:"Bründlmayer Grüner Veltliner",vintage:"2023",region:"Niederösterreich, Austria",category:"Grüner Veltliner",price:75},
{id:20,name:"Hiedler 'Thal' Grüner Veltliner",vintage:"2021",region:"Kamptal, Austria",category:"Grüner Veltliner",price:115},
{id:21,name:"Cloudy Bay Sauvignon Blanc",vintage:"2023",region:"Marlborough, NZ",category:"Sauvignon Blanc",price:115},
{id:22,name:"Shaw + Smith Sauvignon Blanc",vintage:"2024",region:"Adelaide Hills, SA",category:"Sauvignon Blanc",price:87},
{id:23,name:"Murdoch Hill Sauvignon Blanc",vintage:"2025",region:"Adelaide Hills, SA",category:"Sauvignon Blanc",price:77},
{id:24,name:"Leeuwin Estate 'Art Series' Sauvignon Blanc",vintage:"2025",region:"Margaret River, WA",category:"Sauvignon Blanc",price:87},
{id:25,name:"Tyrrell's Vat 1 Semillon",vintage:"2018",region:"Hunter Valley, NSW",category:"Semillon",price:187},
{id:26,name:"Tyrrell's Vat 1 Semillon",vintage:"2007",region:"Hunter Valley, NSW",category:"Semillon",price:200},
{id:27,name:"Tyrrell's Vat 1 Semillon",vintage:"1998",region:"Hunter Valley, NSW",category:"Semillon",price:275},
{id:28,name:"Mercer Pinot Grigio",vintage:"2025",region:"Orange, NSW",category:"Pinot Grigio",price:72},
{id:29,name:"Tiefenbrunner 'Merus' Pinot Grigio",vintage:"2023",region:"Alto Adige, Italy",category:"Pinot Grigio",price:85},
{id:30,name:"Schiopetto Pinot Grigio",vintage:"2020",region:"Friuli, Italy",category:"Pinot Grigio",price:140},
{id:31,name:"Ocean Eight Pinot Gris",vintage:"2024",region:"Mornington Peninsula, VIC",category:"Pinot Gris",price:86},
{id:32,name:"Mount Difficulty 'Bannockburn' Pinot Gris",vintage:"2025",region:"Central Otago, NZ",category:"Pinot Gris",price:85},
{id:33,name:"L&C Poitout Chablis",vintage:"2023",region:"Chablis, France",category:"Chardonnay",price:148},
{id:34,name:"Daniel Dampt 'Bougros' Chablis Grand Cru",vintage:"2021",region:"Chablis, France",category:"Chardonnay",price:310},
{id:35,name:"By Farr Chardonnay",vintage:"2024",region:"Bannockburn, VIC",category:"Chardonnay",price:209},
{id:36,name:"Giant Steps Chardonnay",vintage:"2023",region:"Yarra Valley, VIC",category:"Chardonnay",price:108},
{id:37,name:"Shaw + Smith M3 Chardonnay",vintage:"2023",region:"Adelaide Hills, SA",category:"Chardonnay",price:121},
{id:38,name:"Tolpuddle Chardonnay",vintage:"2024",region:"Coal River Valley, TAS",category:"Chardonnay",price:177},
{id:39,name:"Leeuwin Estate 'Art Series' Chardonnay",vintage:"2021",region:"Margaret River, WA",category:"Chardonnay",price:260},
{id:40,name:"Giaconda Estate Chardonnay",vintage:"2022",region:"Beechworth, VIC",category:"Chardonnay",price:595},
{id:41,name:"Domaine Talmard Mâcon",vintage:"2021",region:"Bourgogne, France",category:"Chardonnay",price:85},
{id:42,name:"Cloudburst Chardonnay",vintage:"2020",region:"Margaret River, WA",category:"Chardonnay",price:325},
{id:43,name:"Papagiannakos 'Old Vines' Savatiano",vintage:"2023",region:"Attica, Greece",category:"Mediterranean White",price:78},
{id:44,name:"Abellio Albariño",vintage:"2022",region:"Rias Baixas, Spain",category:"Mediterranean White",price:85},
{id:45,name:"Maugeri 'Contrada Volpare' Etna Bianco Superiore",vintage:"2023",region:"Sicily, Italy",category:"Mediterranean White",price:175},
{id:46,name:"Domaine Georges Vernay 'Le Pied de Samson' Viognier",vintage:"2017",region:"Condrieu, France",category:"Mediterranean White",price:164},
{id:47,name:"By Farr Viognier",vintage:"2018",region:"Geelong, VIC",category:"Mediterranean White",price:157},
{id:48,name:"Athletes of Wine 'Amber' Trebbiano",vintage:"2022",region:"Mildura, VIC",category:"Skin Contact",price:80},
{id:49,name:"Swinging Bridge Amber Pinot Gris Riesling Gewürztraminer",vintage:"2024",region:"Orange, NSW",category:"Skin Contact",price:80},
{id:50,name:"M de Minuty Rosé",vintage:"2024",region:"Provence, France",category:"Rosé",price:76},
{id:51,name:"Domaines Ott 'Clos Mireille' Rosé",vintage:"2022",region:"Provence, France",category:"Rosé",price:173},
{id:52,name:"Domaine Tempier Bandol Rosé",vintage:"2020",region:"Provence, France",category:"Rosé",price:149},
{id:53,name:"Spinifex Rosé",vintage:"2022",region:"Barossa Valley, SA",category:"Rosé",price:77},
{id:54,name:"Rob Hall Pinot Noir",vintage:"2024",region:"Yarra Valley, VIC",category:"Pinot Noir",price:79},
{id:55,name:"By Farr 'Sangreal' Pinot Noir",vintage:"2023",region:"Geelong, VIC",category:"Pinot Noir",price:228},
{id:56,name:"Giant Steps Pinot Noir",vintage:"2024",region:"Yarra Valley, VIC",category:"Pinot Noir",price:108},
{id:57,name:"Tolpuddle Pinot Noir",vintage:"2023",region:"Coal River Valley, TAS",category:"Pinot Noir",price:199},
{id:58,name:"Bindi Original Vineyard Pinot Noir",vintage:"2022",region:"Macedon Ranges, VIC",category:"Pinot Noir",price:210},
{id:59,name:"Ata Rangi Pinot Noir",vintage:"2020",region:"Martinborough, NZ",category:"Pinot Noir",price:200},
{id:60,name:"Rippon 'Mature Vine' Pinot Noir",vintage:"2020",region:"Central Otago, NZ",category:"Pinot Noir",price:205},
{id:61,name:"Domaine Trapet Gevrey-Chambertin 'Ostrea'",vintage:"2020",region:"Bourgogne, France",category:"Pinot Noir",price:425},
{id:62,name:"David Duband Echezeaux Grand Cru",vintage:"2020",region:"Bourgogne, France",category:"Pinot Noir",price:960},
{id:63,name:"Domaine Metrat 'Fleurie La Roilette' Gamay",vintage:"2022",region:"Beaujolais, France",category:"Gamay",price:92},
{id:64,name:"Anduma Langhe Nebbiolo DOC",vintage:"2023",region:"Piedmont, Italy",category:"Nebbiolo",price:89},
{id:65,name:"Cascina Chicco Langhe Nebbiolo DOC",vintage:"2022",region:"Piedmont, Italy",category:"Nebbiolo",price:105},
{id:66,name:"Brezza Barolo 'Cannubi' DOCG",vintage:"2018",region:"Piedmont, Italy",category:"Barolo",price:223},
{id:67,name:"Poderi Aldo Conterno 'Colonnello' Barolo DOCG",vintage:"2013",region:"Piedmont, Italy",category:"Barolo",price:479},
{id:68,name:"Massolino Barbaresco 'Albesani' DOCG",vintage:"2019",region:"Piedmont, Italy",category:"Barbaresco",price:287},
{id:69,name:"Cascina Luisin Barbaresco 'Paolin' DOCG",vintage:"2021",region:"Piedmont, Italy",category:"Barbaresco",price:208},
{id:70,name:"Camporsino Chianti DOCG",vintage:"2023",region:"Tuscany, Italy",category:"Sangiovese",price:74},
{id:71,name:"Fontodi Chianti Classico DOCG",vintage:"2019",region:"Tuscany, Italy",category:"Sangiovese",price:168},
{id:72,name:"Fuligni Brunello di Montalcino",vintage:"2019",region:"Tuscany, Italy",category:"Sangiovese",price:355},
{id:73,name:"Tenuta Dell'Ornellaia 'Ornellaia'",vintage:"2019",region:"Bolgheri, Italy",category:"Super Tuscan",price:650},
{id:74,name:"Graci Etna Rosso",vintage:"2022",region:"Sicily, Italy",category:"Other Red",price:118},
{id:75,name:"Tommasi Amarone Classico",vintage:"2019",region:"Veneto, Italy",category:"Other Red",price:241},
{id:76,name:"Emiliana 'Adobe' Carmenere",vintage:"2023",region:"Colchagua Valley, Chile",category:"Other Red",price:72},
{id:77,name:"Mullineux Kloof Street Rouge",vintage:"2020",region:"Swartland, South Africa",category:"Other Red",price:86},
{id:78,name:"Tyrrell's Vat 9 Shiraz",vintage:"2021",region:"Hunter Valley, NSW",category:"Shiraz",price:185},
{id:79,name:"Yarra Yering Dry Red No. 2 Shiraz",vintage:"2021",region:"Yarra Valley, VIC",category:"Shiraz",price:215},
{id:80,name:"Hentley Farm Shiraz",vintage:"2023",region:"Barossa Valley, SA",category:"Shiraz",price:87},
{id:81,name:"Elderton 'Command' Shiraz",vintage:"2017",region:"Barossa Valley, SA",category:"Shiraz",price:228},
{id:82,name:"Penfolds 'Grange'",vintage:"2019",region:"Multi-Regional, SA",category:"Shiraz",price:1635},
{id:83,name:"Henschke 'Hill of Grace' Shiraz",vintage:"2021",region:"Eden Valley, SA",category:"Shiraz",price:1485},
{id:84,name:"Rockford Basket Press Shiraz",vintage:"2021",region:"Barossa Valley, SA",category:"Shiraz",price:310},
{id:85,name:"Mullineux 'Iron' Syrah",vintage:"2021",region:"Swartland, South Africa",category:"Shiraz",price:315},
{id:86,name:"Domaine Billon Côte-Rôtie 'La Brocarde'",vintage:"2020",region:"Rhône Valley, France",category:"Shiraz",price:286},
{id:87,name:"Domaine de Marcoux Châteauneuf-du-Pape",vintage:"2007",region:"Rhône Valley, France",category:"Grenache",price:254},
{id:88,name:"Alvaro Palacios 'Les Terrasses'",vintage:"2018",region:"Priorat, Spain",category:"Grenache",price:189},
{id:89,name:"MMAD Old Vine Grenache",vintage:"2022",region:"McLaren Vale, SA",category:"Grenache",price:155},
{id:90,name:"Sons of Eden 'Kennedy' GSM",vintage:"2021",region:"Barossa Valley, SA",category:"Grenache",price:75},
{id:91,name:"Cullen 'Diana Madeline' Cabernet Blend",vintage:"2020",region:"Margaret River, WA",category:"Cabernet",price:246},
{id:92,name:"Moss Wood Cabernet",vintage:"2020",region:"Margaret River, WA",category:"Cabernet",price:228},
{id:93,name:"Mount Mary 'Quintet' Cabernet",vintage:"2019",region:"Yarra Valley, VIC",category:"Cabernet",price:271},
{id:94,name:"Wynns Black Label Cabernet Sauvignon",vintage:"2021",region:"Coonawarra, SA",category:"Cabernet",price:98},
{id:95,name:"Wynns Black Label Cabernet Sauvignon",vintage:"2012",region:"Coonawarra, SA",category:"Cabernet",price:135},
{id:96,name:"Château Meyney St. Estèphe",vintage:"2018",region:"Bordeaux, France",category:"Bordeaux",price:201},
{id:97,name:"Château Potensac Haut-Médoc",vintage:"2005",region:"Bordeaux, France",category:"Bordeaux",price:315},
{id:98,name:"Relais de la Dominique St. Emilion Grand Cru",vintage:"2016",region:"Bordeaux, France",category:"Bordeaux",price:169},
{id:99,name:"Frogmore Creek Iced Riesling (375ml)",vintage:"2022",region:"Coal River Valley, TAS",category:"Dessert",price:75},
{id:100,name:"Klein Constantia 'Vin de Constance' (500ml)",vintage:"2014",region:"Constantia, South Africa",category:"Dessert",price:250},
{id:101,name:"Pfeiffer 'Classic' Muscat (500ml)",vintage:"NV",region:"Rutherglen, VIC",category:"Dessert",price:90},
{id:102,name:"Valdespino 'El Candado' Pedro Ximenez (750ml)",vintage:"NV",region:"Jerez, Spain",category:"Dessert",price:125},
];
const WINE_LIST_TEXT = WINES.map(w => `${w.vintage} ${w.name} | ${w.region} | ${w.category} | $${w.price}`).join("\n");
const MENU_ITEMS = [
"Sydney Rock Oysters","Guinness Braised Beef Shin Doughnut","Smoked Hummus & Flat Bread",
"Cacio E Pepe Arancini","Wagyu Bresaola & Crumpet","Tuna Crudo",
"Pumpkin Tart","Heirloom Tomatoes & Stracciatella","Farro & Barley Risotto (veg)",
"Alaskan King Crab Casarecce Pasta","Fish Of The Day","Lamb Rump",
"MBS 5+ Wagyu Scotch Fillet","Seasonal Greens","Slow Roast Cauliflower",
"Cheese Selection","Cheese & Charcuterie","Orange Bavarois",
"Dark Chocolate & Hazelnut Torta","Chocolate Truffles"
];
const QUESTIONS = [
{ id:"dishes", q:"What are you eating tonight?", sub:"Select everything your table is ordering", type:"multi", options:MENU_ITEMS },
{ id:"colour", q:"Any preference on wine style or varietal?", sub:null, type:"single_with_input",
options:["White","Red","Rosé","Sparkling / Champagne","Open to anything","I have a specific varietal in mind…"],
inputPlaceholder:"e.g. Shiraz, Riesling, Pinot Noir, Chardonnay, Barolo…",
inputHint:"We have: Sparkling & Champagne · Riesling · Grüner Veltliner · Sauvignon Blanc · Semillon · Pinot Grigio/Gris · Chardonnay · Mediterranean Whites · Skin Contact · Rosé · Pinot Noir · Gamay · Nebbiolo · Barolo · Barbaresco · Sangiovese · Shiraz & Syrah · Grenache · Cabernet Sauvignon · Bordeaux · Dessert Wines",
},
{ id:"style", q:"How do you like your wine to taste?", sub:null, type:"single",
options:["Light & delicate","Fresh & crisp","Rich & full-bodied","Earthy & savoury","I'm not sure — surprise me"] },
{ id:"experience", q:"How adventurous are you feeling tonight?", sub:null, type:"single",
options:["Stick to my favourites","Open to something new","Take me somewhere unexpected"] },
{ id:"budget", q:"What's your bottle budget?", sub:null, type:"single",
options:["Under $90","$90 – $150","$150 – $250","The sky's the limit"] },
];
const SYSTEM_PROMPT = `You are the virtual sommelier at Coogee Wine Room, a celebrated Mediterranean coastal wine bar in Coogee, Sydney. You are warm, knowledgeable, and speak with quiet confidence.
A guest has answered 5 quick questions. Based on their answers, recommend EXACTLY 3 bottles from our wine list.
FORMAT YOUR RESPONSE EXACTLY LIKE THIS:
Start with one single sentence of warm acknowledgement (max 15 words).
Then list 3 wines using this exact structure:
**[NUMBER]. [EMOJI] [VINTAGE] [WINE NAME]**
[REGION] · $[PRICE]
[2-3 sentences explaining why this wine is perfect for their specific dishes and preferences.]
CRITICAL RULES:
- ONLY recommend wines from the list below. Use exact names, vintages and prices.
- Bottles only — no wines by the glass.
- Match one wine to the LOWER end of their budget, one to the MIDPOINT, and one to the TOP end. Use these bands strictly:
- "Under $90": lower = under $80, mid = $80–$85, top = $85–$90
- "$90 – $150": lower = $90–$100, mid = $110–$130, top = $140–$150
- "$150 – $250": lower = $150–$170, mid = $180–$210, top = $220–$250
- "The sky's the limit": lower = $150–$250, mid = $250–$450, top = $450+
- Label each: �� Great Value, �� Our Pick, ✨ The Splurge respectively.
- Tailor every explanation to their actual food and stated preferences.
- Keep the whole response under 300 words.
OUR WINE LIST:
${WINE_LIST_TEXT}`;
export default function App() {
const [step, setStep] = useState(0);
const [answers, setAnswers] = useState({ dishes:[], colour:"", style:"", experience:"", budget:"" });
const [selected, setSelected] = useState([]);
const [varietalInput, setVarietalInput] = useState("");
const [result, setResult] = useState("");
const [error, setError] = useState("");
const topRef = useRef(null);
useEffect(() => { topRef.current?.scrollIntoView({ behavior:"smooth" }); }, [step]);
const currentQ = step >= 1 && step <= 5 ? QUESTIONS[step - 1] : null;
const toggleMulti = (opt) => setSelected(prev => prev.includes(opt) ? prev.filter(o => o !== opt) : [...prev, opt]);
const handleSingle = (opt) => { setSelected([opt]); if (opt !== "I have a specific varietal in mind…") setVarietalInput(""); };
const canContinue = selected.length > 0 &&
(selected[0] !== "I have a specific varietal in mind…" || varietalInput.trim().length > 0);
const next = async () => {
const q = currentQ;
const rawVal = q.type === "multi" ? selected : selected[0];
const val = rawVal === "I have a specific varietal in mind…" && varietalInput.trim()
? `Specific varietal: ${varietalInput.trim()}` : rawVal;
const newAnswers = { ...answers, [q.id]: val };
setAnswers(newAnswers);
setSelected([]);
if (step < 5) { setStep(s => s + 1); }
else { setStep(6); await getRecommendation(newAnswers); }
};
const getRecommendation = async (ans) => {
const prompt = `Guest's answers:
1. Dishes: ${Array.isArray(ans.dishes) && ans.dishes.length ? ans.dishes.join(", ") : "Not specified"}
2. Wine preference: ${ans.colour}
3. Taste style: ${ans.style}
4. Adventurousness: ${ans.experience}
5. Budget: ${ans.budget}
Please recommend 3 bottles.`;
try {
const res = await fetch("https://api.anthropic.com/v1/messages", {
method:"POST", headers:{"Content-Type":"application/json"},
body: JSON.stringify({ model:"claude-sonnet-4-20250514", max_tokens:800, system:SYSTEM_PROMPT, messages:[{role:"user",content:prompt}] })
});
const data = await res.json();
setResult(data.content?.[0]?.text || "");
setStep(7);
} catch {
setError("Something went wrong. Please ask your server for a recommendation.");
setStep(7);
}
};
const restart = () => { setStep(0); setAnswers({dishes:[],colour:"",style:"",experience:"",budget:""}); setSelected([]); setVarietalInput(""); setResult(""); setError(""); };
const renderResult = (text) => text.split("\n").map((line, i) => {
if (/^\*\*.*\*\*$/.test(line.trim()))
return
{line.replace(/\*\*/g,"")}
;
if (line.includes(" · $"))
return {line.split(" · ")[0]} · {line.split(" · ")[1]}
;
if (line.trim()==="") return ;
return
{line}
;
});
const s = { // shared styles
optBtn: (active) => ({
padding:"12px 15px", borderRadius:4, cursor:"pointer", fontSize:13, textAlign:"left",
fontFamily:"Georgia,serif", transition:"all 0.15s",
border:`1px solid ${active ? GOLD : BORDER}`,
background: active ? BG3 : "transparent",
color: active ? GOLD : TEXT2,
}),
chipBtn: (active) => ({
padding:"7px 12px", borderRadius:4, cursor:"pointer", fontSize:12, textAlign:"left",
fontFamily:"Georgia,serif", transition:"all 0.15s",
border:`1px solid ${active ? GOLD : BORDER}`,
background: active ? BG3 : "transparent",
color: active ? GOLD : TEXT2,
}),
};
return (
{/* Header */}
{/* Progress dots */}
{step >= 1 && step <= 5 && (
)}
);
}
Coogee Wine Room
�� Ask Sommelier Tom For a Great Wine to Drink
{[1,2,3,4,5].map(n => (
{n < step ? "✓" : n}
))}
{/* WELCOME */}
{step === 0 && (
)}
{/* QUESTIONS */}
{currentQ && (
)}
{/* LOADING */}
{step === 6 && (
)}
{/* RESULTS */}
{step === 7 && (
{error ? (
)}
��
Good Evening
Answer 5 quick questions and he'll recommend the perfect bottle for your table tonight.
Question {step} of 5
{currentQ.q}
{currentQ.sub && {currentQ.sub}
}
{currentQ.options.map(opt => {
const active = selected.includes(opt);
return (
);
})}
{selected[0]==="I have a specific varietal in mind…" && (
setVarietalInput(e.target.value)}
onKeyDown={e => e.key==="Enter" && canContinue && next()}
placeholder={currentQ.inputPlaceholder}
style={{width:"100%",padding:"12px 14px",background:BG3,border:`1px solid ${GOLD}`,borderRadius:4,color:TEXT1,fontSize:14,fontFamily:"Georgia,serif",outline:"none",boxSizing:"border-box",marginBottom:10}}
/>
)}
Available varietals: {currentQ.inputHint}
{step > 1 && (
)}
��
Consulting the cellar…
Finding the perfect bottles for your table
{[0,1,2].map(i => (
))}
Tonight's Recommendations
Your Perfect Bottles
{error}
) : (
{renderResult(result)}
)}