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 */}
Coogee Wine Room
�� Ask Sommelier Tom For a Great Wine to Drink
{/* Progress dots */} {step >= 1 && step <= 5 && (
{[1,2,3,4,5].map(n => (
{n < step ? "✓" : n}
))}
)}
{/* WELCOME */} {step === 0 && (
��
Good Evening
Answer 5 quick questions and he'll recommend the perfect bottle for your table tonight.
)} {/* QUESTIONS */} {currentQ && (
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 && ( )}
)} {/* LOADING */} {step === 6 && (
��
Consulting the cellar…
Finding the perfect bottles for your table
{[0,1,2].map(i => (
))}
)} {/* RESULTS */} {step === 7 && (
Tonight's Recommendations
Your Perfect Bottles
{error ? (
{error}
) : (
{renderResult(result)}
)}
)}
); }
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 */}
Coogee Wine Room
�� Ask Sommelier Tom For a Great Wine to Drink
{/* Progress dots */} {step >= 1 && step <= 5 && (
{[1,2,3,4,5].map(n => (
{n < step ? "✓" : n}
))}
)}
{/* WELCOME */} {step === 0 && (
��
Good Evening
Answer 5 quick questions and he'll recommend the perfect bottle for your table tonight.
)} {/* QUESTIONS */} {currentQ && (
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 && ( )}
)} {/* LOADING */} {step === 6 && (
��
Consulting the cellar…
Finding the perfect bottles for your table
{[0,1,2].map(i => (
))}
)} {/* RESULTS */} {step === 7 && (
Tonight's Recommendations
Your Perfect Bottles
{error ? (
{error}
) : (
{renderResult(result)}
)}
)}
); }