import React, { useState, useMemo } from ‘react’;
import {
Plane,
Bus,
Car,
MapPin,
Briefcase,
Train,
Clock,
ChevronRight,
ChevronLeft,
RotateCw,
Info,
CheckCircle2,
BookOpen,
MessageSquare,
Dumbbell,
Check,
X,
HelpCircle,
RefreshCw,
Layers
} from ‘lucide-react’;
const COLLOCATIONS = {
A2: [
{ id: ‘a2-1’, phrase: “Go by bus / train / plane”, translation: “Jechać autobusem / pociągiem / lecieć samotelom”, tip: “Używamy ‘by’ dla środka transportu.” },
{ id: ‘a2-2’, phrase: “Go on foot”, translation: “Iść pieszo”, tip: “Wyjątek! Nie mówimy ‘by foot’.” },
{ id: ‘a2-3’, phrase: “Get on / Get off”, translation: “Wsiadać / Wysiadać (duże pojazdy)”, tip: “Autobus, pociąg, samolot, statek.” },
{ id: ‘a2-4’, phrase: “Get in / Get out of”, translation: “Wsiadać / Wysiadać (samochód/taksówka)”, tip: “Tylko dla małych pojazdów.” },
{ id: ‘a2-5’, phrase: “Book a flight”, translation: “Zarezerwować lot”, tip: “Można też zarezerwować pokój (book a room).” },
{ id: ‘a2-6’, phrase: “Pack a suitcase”, translation: “Pakować walizkę”, tip: “Przeciwieństwo: unpack.” },
{ id: ‘a2-7’, phrase: “Miss a flight”, translation: “Spóźnić się na lot”, tip: “Kiedy samolot odleci bez Ciebie.” },
{ id: ‘a2-8’, phrase: “Catch a bus”, translation: “Złapać autobus”, tip: “Kiedy zdążysz na czas.” },
],
B1: [
{ id: ‘b1-1’, phrase: “Set off / Set out”, translation: “Wyruszyć w drogę”, tip: “Zacząć podróż.” },
{ id: ‘b1-2’, phrase: “Pick someone up”, translation: “Odebrać kogoś”, tip: “Np. samochodem z lotniska.” },
{ id: ‘b1-3’, phrase: “Drop someone off”, translation: “Podrzucić kogoś”, tip: “Zostawić kogoś w konkretnym miejscu.” },
{ id: ‘b1-4’, phrase: “Give someone a lift”, translation: “Podwieźć kogoś”, tip: “Zabrać kogoś swoim samochodem.” },
{ id: ‘b1-5’, phrase: “Take off”, translation: “Startować (o samolocie)”, tip: “Kiedy samolot wzbija się w powietrze.” },
{ id: ‘b1-6’, phrase: “Off the beaten track”, translation: “Poza utartym szlakiem”, tip: “Miejsca rzadko odwiedzane przez turystów.” },
{ id: ‘b1-7’, phrase: “Travel light”, translation: “Podróżować z małym bagażem”, tip: “Bez dużych walizek.” },
{ id: ‘b1-8’, phrase: “Check into a hotel”, translation: “Zameldować się w hotelu”, tip: “Proces rejestracji w recepcji.” },
]
};
const ROME_STORY = [
{ text: “My best friend and I finally went on that “, highlight: “package holiday”, trans: “wakacje zorganizowane” },
{ text: ” to Rome we’ve been talking about. We “, highlight: “booked our flight”, trans: “zarezerwowaliśmy lot” },
{ text: ” months ago to save some cash. On the day we had to “, highlight: “set off”, trans: “wyruszyć” },
{ text: “, everything went wrong! My brother was supposed to “, highlight: “pick us up”, trans: “odebrać nas” },
{ text: ” and “, highlight: “give us a lift”, trans: “podwieźć nas” },
{ text: ” to the airport, but he was 30 minutes late! Then, we got stuck in the biggest “, highlight: “traffic jam”, trans: “korek” },
{ text: ” I’ve ever seen. It was the middle of the “, highlight: “rush hour”, trans: “godziny szczytu” },
{ text: ” and cars weren’t moving at all. We were so scared we would “, highlight: “miss our flight”, trans: “spóźnić się na lot” },
{ text: “. When we finally arrived, he “, highlight: “dropped us off”, trans: “wysadził nas” },
{ text: ” and we sprinted to the gate. We “, highlight: “checked in”, trans: “odprawiliśmy się” },
{ text: ” just in time and “, highlight: “got on”, trans: “wsiedliśmy” },
{ text: ” the plane exactly two minutes before it “, highlight: “took off”, trans: “wystartował” },
{ text: “. Talk about stress! Once we “, highlight: “landed”, trans: “wylądowaliśmy” },
{ text: ” in sunny Italy, it was much better. We used “, highlight: “public transport”, trans: “transport publiczny” },
{ text: ” to get to our hotel. We “, highlight: “checked into”, trans: “zameldowaliśmy się w” },
{ text: ” our room, left our bags, and went to “, highlight: “look around”, trans: “rozejrzeć się” },
{ text: “. We even joined a cool “, highlight: “guided tour”, trans: “wycieczka z przewodnikiem” },
{ text: ” of the Vatican. We “, highlight: “got lost”, trans: “zgubiliśmy się” },
{ text: ” once in those narrow streets, but we “, highlight: “asked for directions”, trans: “zapytaliśmy o drogę” },
{ text: ” and a local guy was super helpful. It was a “, highlight: “safe journey”, trans: “bezpieczna podróż” },
{ text: ” in the end, but man, what a start!” }
];
const GAP_FILL_DIALOGUES = [
{
id: 1,
title: “Checking in at the Hotel”,
lines: [
{ speaker: “Receptionist”, text: “Welcome to Rome! Do you have a reservation?” },
{ speaker: “You”, text: “Yes, I’d like to ________ in, please. The name is Smith.”, answer: “check” },
{ speaker: “Receptionist”, text: “Perfect. Can I see your ID?” }
]
},
{
id: 2,
title: “In the Taxi”,
lines: [
{ speaker: “You”, text: “Could you ________ me off near the Colosseum?”, answer: “drop” },
{ speaker: “Driver”, text: “Sure, but there is a lot of traffic today.” },
{ speaker: “You”, text: “No problem, I’m not in a hurry.” }
]
},
{
id: 3,
title: “Asking for Help”,
lines: [
{ speaker: “You”, text: “Excuse me, I’m ________. Can you help me?”, answer: “lost” },
{ speaker: “Local”, text: “Of course! Where are you trying to go?” },
{ speaker: “You”, text: “I’m looking for the Trevi Fountain.” }
]
},
{
id: 4,
title: “At the Airport”,
lines: [
{ speaker: “Friend”, text: “We need to hurry! The plane ________ off in 40 minutes.”, answer: “takes” },
{ speaker: “You”, text: “Don’t worry, we already checked in online.” }
]
},
{
id: 5,
title: “Meeting a Friend”,
lines: [
{ speaker: “Friend”, text: “I can ________ you up from the station at 6 PM.”, answer: “pick” },
{ speaker: “You”, text: “That would be great! I’ll wait near the exit.” }
]
}
];
const COMPREHENSION_QUIZ = [
{
q: “Why did they book the flight months ago?”,
options: [“To save money”, “Because it was a gift”, “To choose seats”],
a: 0
},
{
q: “The brother was 30 minutes late.”,
options: [“True”, “False”],
a: 0
},
{
q: “They were stuck in a traffic jam during the rush hour.”,
options: [“True”, “False”],
a: 0
},
{
q: “They missed their flight.”,
options: [“True”, “False”],
a: 1
},
{
q: “In Rome, they used a taxi to get to the hotel.”,
options: [“True”, “False (Public transport)”],
a: 1
}
];
const App = () => {
const [view, setView] = useState(‘list’);
const [level, setLevel] = useState(‘A2’);
const [dialogueAnswers, setDialogueAnswers] = useState({});
const [quizAnswers, setQuizAnswers] = useState({});
const [showDialogueResults, setShowDialogueResults] = useState(false);
const [showQuizResults, setShowQuizResults] = useState(false);
// Flashcards state
const [flashcardIndex, setFlashcardIndex] = useState(0);
const [isFlipped, setIsFlipped] = useState(false);
const currentFlashcards = COLLOCATIONS[level];
const handleDialogueChange = (id, val) => {
setDialogueAnswers(prev => ({ …prev, [id]: val.toLowerCase().trim() }));
};
const handleQuizSelect = (idx, optIdx) => {
if (showQuizResults) return;
setQuizAnswers(prev => ({ …prev, [idx]: optIdx }));
};
const resetDialogues = () => {
setDialogueAnswers({});
setShowDialogueResults(false);
};
const resetQuiz = () => {
setQuizAnswers({});
setShowQuizResults(false);
};
const nextFlashcard = () => {
setIsFlipped(false);
setTimeout(() => {
setFlashcardIndex((prev) => (prev + 1) % currentFlashcards.length);
}, 150);
};
const prevFlashcard = () => {
setIsFlipped(false);
setTimeout(() => {
setFlashcardIndex((prev) => (prev – 1 + currentFlashcards.length) % currentFlashcards.length);
}, 150);
};
return (
{/* Header */}
setView(‘list’)}>
TravelMaster
{/* VIEW: VOCABULARY LIST */}
{view === ‘list’ && (