Fiktivní webový projekt semestrálního kurzu React 1 JARO 2024, na kterém si procvičíme, co vše jsme se v Reactu naučili.
V praxi často začnete pracovat na projektu, na kterém už pracoval někdo před vámi. V tomto cvičení tomu nebude jinak a také začneme s projektem, který již obsahuje nějaký kód.
-
Nejprve si prohlédněte dopředu připravený design webu LeviExpress, ze kterého budeme vycházet. V připraveném designu najdete kromě úvodní stránky taky stránku s detailem jízdenky. Jde o statické stránky, které nemají žádnou funkčnost. Obsahují pouze HTML a CSS. Zdrojové kódy najdete v leviexpress-design (tento repositář si klonovat nemusíte, slouží hlavně pro inspiraci). Odsud můžete vzít všechny potřebné styly, HTML a obrázky pro váš projekt.
-
Vytvořte si repozitář ze šablony leviexpress-starter. V tomto repozitáři najdete již rozpracovaný základ aplikace.
-
Svůj repozitář si naklonujte do počítače a otevřete ve VS Code.
-
Nainstalujte všechny závislosti pomocí
npm install
a spusťte projekt pomocínpm run dev
. -
Prohlédněte si strukturu projektu a projděte si kód připravených komponent.
Hned na začátku rozběháme routování, abychom ho pak nemuseli složitě roubovat do již rozpracovaného projektu. Knihovna react-router
už je v naklonovaném projektu nainstalovaná, můžete ji rovnou začít používat.
Naše aplikace bude mít dvě hlavní stránky: Home a Reservation. Obě obsahují stejnou hlavičku i patičku. Stránka Home bude pod routou /
, stránka s detaily rezervace bude mít adresu /reservation
.
- Uvnitř komponenty
App
již máte připravenou strukturu s hlavičkou a patičkou stránky. Dále máte již hotovou kostru komponentyHome
. Sestavte router tak, aby komponentyHeader
aFooter
byly na stránce zobrazeny vždy. Mezi ně vložte prvekRouterProvider
z React Routeru a předejte do něho konfigurační objekt, ve kterém budete mít vytvořené dvě routy:/
a/reservation
. V první routě zobrazte komponentuHome
, ve druhé zatím necháme jen nadpish2
s textem "Detail jízdenky". Vyzkoušejte, že vaše stránka správně zobrazuje obě stránky. Odkazy (Link
) na stránku nedávejte – uživatel přijde vždy na hlavní stránku/
. Na stránku/reservation
se dostane až po kliknutí na tlačítko pro objednání, které zprovozníte až později. - Vytvořte komponentu
Reservation
. Tuto komponentu zobrazte na adrese/reservation
. Zatím může vracet pouze nadpish2
, abychom viděli, že se na stránce něco děje. Obsah komponenty vytvoříme později. - Vyzkoušejte, že vaše stránka správně funguje (adresu
/reservation
vyzkoušejte tak, že ji napíšete do adresního řádku prohlížeče). - Proveďte commit změn se smysluplnou commit zprávou.
Ve svém projektu již máte vytvořen základy komponenty s názvem JourneyPicker
. Ta je součástí komponenty Home
a zatím vrací pouze statické JSX
- V komponentě
JourneyPicker
si připravte funkcihandleSubmit(event)
, která se bude volat při odeslání formuláře. Ošetřete, aby prohlížeč sám neodesílal formulář a zatím si ve funkci jen vypište do konzole text'Odesílám formulář s cestou'
. - Napojte funkci
handleSubmit
na událost submit ve formuláři. Ověřte v prohlížeči, že po kliknutí na Vyhledat spoj se v konzoli objeví výše uvedený text. - Pomocí
useState
si v komponentě připravte tři stavy:fromCity
,toCity
adate
. Výchozí hodnotou bude ve všech třech případech prázdný řetězec''
; - Napojte každý ze stavů na správý
<select>
tak, abyselect
zobrazoval vybraný stav a změna vselect
u se promítla do stavu. Vytvoříte tedy dvoucestný databinding, kdy se např. stavfromCity
bude promítat dovalue
příslušnéhoselect
u, a při událostionChange
naselect
u se nová hodnota zapíše do stavufromCity
. Obdobně i pro další dvaselect
y a stavytoCity
adate
. - Upravte funkci
handleSubmit
tak, aby do konzole vypsala všechny tři stavy. Vyzkoušejte, že výběrem stavu vselect
u se změní stav – po kliknutí na tlačítko se do konzole vypíše změněný stav. Tím, že si dočasně změníte výchozí hodnotu vuseState('')
na některou z hodnot (atributvalue
) v<option>
můžete ověřit, že funguje správně nastavení výchozího stavuselect
u. - Commitněte změny.
Na konci tohoto cvičení si uživatel bude schopen vybrat startovní a cílové město ze seznamu měst stažených z API. Vytvoříte komponentu CityOptions
, která dostane na vstupu pole se seznamem destinací a vytvoří z něj elementy <option>
do select
ů pro výběr výchozího a cílového města. Seznam měst se bude stahovat v komponentě JourneyPicker
z API endpointu /api/cities. Prohlédněte si strukturu dat, která endpoint vrací.
-
Přímo v souboru
index.jsx
komponentyJourneyPicker
si vytvořte novou komponentuCityOptions
. Přesuňte do ní všechny<option>
zeselect
u pro výběr výchozího města. KomponentuCityOptions
použijte v obouselect
ech pro výběr města. Zkontrolujte, že v prohlížeči vše funguje stejně. -
V komponentě
JourneyPicker
si vytvořte pomocíuseState
další stavcities
. V tomto stavu bude seznam měst, mezi kterými lze cestovat. Pro otestování nastavte do seznamu dvě města:[ { name: 'Praha', code: 'CZ-PRG' }, { name: 'Brno', code: 'CZ-BRQ' }, ];
-
Komponenta
CityOptions
bude vprops
přijímatcities
. V něm bude pole – seznam měst, které může uživatel vybrat. Upravte tedy příslušným způsobem hlavičku komponentyCityOptions
a získanou propertycities
si vypište do konzole. -
Na obou místech, kde máte komponentu
CityOptions
použitou, nastavte property/atributcities
na hodnotu stavucities
. V prohlížeči se teď při zobrazení stránky vypíše dvakrát do konzole seznam měst – Praha a Brno. -
Upravte komponentu
CityOptions
tak, aby se na základě seznamu měst v propertycities
vypsaly jednotlivé<option>
. Pro textoption
se použije název destinace, jako hodnota (atributvalue
) a také jako klíč pro React (key
) se použije kód destinace. -
Nechceme, aby při zobrazení stránky byla rovnou vybraná první města ze seznamu. Proto před elementy
option
vytvořené z pole ještě ručně vložíme jedenoption
s textem „Vyberte“. Atributvalue
tohotooption
bude prázdný. -
Odstraňte z komponenty
CityOptions
výpis do konzole a zkontrolujte v prohlížeči, že se v seznamu výchozích i cílových měst zobrazuje Praha a Brno a že stále správně funguje výběr měst. -
Do hlavní komponenty
JourneyPicker
přidejteuseEffect
, který se bude volat při prvním zobrazení komponenty. Přesuňte do něj nastavení stavucities
– naše dvě testovací města. Výchozí stav procities
tedy bude prázdné pole, teprveuseEffect
nastaví seznam měst na Prahu a Brno. Ověřte v prohlížeči, že se vselect
ech stále zobrazují obě města. Dejte pozor na to, aby se efekt volal opravdu jen při prvním zobrazení komponenty – můžete si to ověřit pomocným výpisem do konzole prohlížeče, který se musí objevit jen jednou – když budete překlikávat na jiná města, výpis už se nebude opakovat. -
Upravte useEffect tak, že bude seznam měst získávat z API. Endpoint je na adrese
https://apps.kodim.cz/daweb/leviexpress/api/cities
a vrací seznam měst jako JSON ve formátu, který jsme použili výše. Získaná data použijte místo Prahy a Brna ve stavu
cities
. Ověřte v prohlížeči, že se v seznamu měst objeví i další města. -
Commitněte změny.
Na konci tohoto cvičení bude uživatel schopen vybrat datum cesty podle dat stažených z API. Budeme postupovat obdobně jako s komponentou CityOptions
. Tentokrát však vytvoříme komponentu DatesOptions
, která vygeneruje elementy option
do výběru termínů cesty. Termíny cest se budou získávat z API endpointu /api/dates. Prohlédněte si strukturu dat, která tento endpoint vrací.
-
Komponentu
DatesOptions
vytvořte opět přímo v souboru s komponentamiJourneyPicker
aCityOptions
. -
HTML kód s elementy
<option>
pro výběr termínu přesuňte zeselect
u pro výběr data do komponentyDatesOptions
. Vselect
u použijte vytvořenou komponentuDatesOptions
. Zkontrolujte v prohlížeči, že se výběr termínů zobrazuje stále stejně. -
Podobně jako
CityOptions
získává seznam měst v propertycities
, bude iDatesOptions
získávat seznam termínů v propertydates
. V elementech<option>
(s výjimkou prvního ručně vloženého s textem „Vyberte“) použijte jakovalue
akey
hodnotudateBasic
a jako hodnotudateCs
použijte jako obsah. -
Připravte si pomocí
useState
další stavdates
. Pro otestování si do něj vložte tato data:[ { "dateBasic": "28.05.2021", "dateCs": "pá 28. květen 2021" }, { "dateBasic": "29.05.2021", "dateCs": "so 29. květen 2021" } ]
-
Použijte stav
dates
pro naplnění hodnot propertydates
tam, kde je použita komponentaDatesOptions
. Ověřte v prohlížeči, že se ve výběru termínů zobrazují dvě uvedená data. -
Upravte
useEffect
volaný při prvním zobrazení komponenty. Vedle seznamu měst bude z API získávat také seznam termínů. Endpoint je na adresehttps://apps.kodim.cz/daweb/leviexpress/api/dates
a vrací seznam termínů ve formátu, který máme připraven. Změňte výchozí stav
dates
na prázdné pole a poté do něj nastavte výsledek volání uvedeného endpointu. -
Ověřte v prohlížeči, že se do
select
ů načítají data (města a termíny) a že po kliknutí na tlačítko „Vyhledat spoj“ se uživatelem zvolené údaje vypíší do konzole prohlížeče. -
Commitněte změny.
V tomto cvičení dokončíte komponentu pro vyhledání spojení. V komponentě už funguje výběr výchozího a cílového města a také data cesty. Nyní napojíte komponentu na API pro vyhledávání spojení.
-
Pokračujte v komponentě
JourneyPicker
. Do tlačítka „Vyhledat spoj“ přidejte atributdisabled
tak, aby tlačítko bylo povolené pouze v případě, že jsou vybrána obě města i datum. -
Při kliknutí na tlačítko „Vyhledat spoj“ se volá funkce
handleSubmit
, která vypíše údaje zadané uživatelem. Nyní výpis do konzole nahradíte voláním API. Bude se volat následující API endpointhttps://apps.kodim.cz/daweb/leviexpress/api/journey?fromCity=…&toCity=…&date=…
Vytečkovaná místa se nahradí hodnotami vybranými uživatelem, které jsou uložené ve stavech
fromCity
,toCity
adate
. -
Volání tohoto API vrací JSON s nalezenými spoji. Vypište si výstup do konzole prohlížeče.
-
Nalezená spojení budeme potřebovat zobrazit v další komponentě na stránce. Potřebujeme je tedy poslat z komponenty
JourneyPicker
jejímu rodiči – to uděláme v následujících krocích. -
V komponentě
Home
si připravte funkcihandleJourneyChange
. FunkcehandleJourneyChange
bude očekávat jeden parametr – objekt s údaji o nalezeném spojení. Nazvěte jej třebajourney
. Ve funkci zatím vypište tento parametr do konzole. Funkce se zatím nebude nikde volat – volání zajistíme v následujících krocích, kde bude funkcehandleJourneyChange
sloužit jako callback předaný do komponentyJourneyPicker
. -
V komponentě
Home
používáte komponentuJourneyPicker
. Této komponentě předejte property jménemonJourneyChange
, jako hodnotu jí předejte funkci (callback)handleJourneyChange
. -
V komponentě
JourneyPicker
bude propertyonJourneyChange
, do které rodič (Home
) vkládá funkci, která se zavolá s údaji nalezeném spoji. Všimněte si, že v hlavičce komponentyJourneyPicker
už je propertyonJourneyChange
připravená. -
Ve funkci
handleSubmit
v komponentěJourneyPicker
máte nyní výpis nalezených spojení do konzole prohlížeče. Tento výpis nahraďte voláním funkce uložené v propertyonJourneyChange
, které jako paramter předáte data získaná z volání API pod klíčemresults
. -
Vraťte se do komponenty
Home
, ze které se volá komponentaJourneyPicker
. V komponentěHome
vytvořte pomocíuseState
nový stavjourney
, výchozí hodnota budenull
. -
Propojte komponentu
JourneyPicker
se stavemjourney
– když je volán callbackhandleJourneyChange
s údaji o nalezeném spoji, nastaví se toto spojení do stavujourney
. -
Upravte komponentu
Home
tak, aby v případě, kdy ve stavujourney
je nějaké spojení, vypsala pod vyhledávací formulář text „Nalezeno spojení s id …“. Místo tří teček budejourneyId
z dat o nalezeném spojení. -
Ověřte, že funguje výběr měst a data, že po zadání všech třech údajů můžete kliknout na „Vyhledat spoj“ a že se po kliknutí vyhledá nějaké spojení a vypíše se do stránky jeho id.
-
Commitněte změny.
V tomto cvičení vytvoříte komponentu pro zobrazení detailu cesty a komponentu pro zobrazení zastávky. Využijí se informace, které vrátilo API pro vyhledání spoje.
- Ve svém projektu vytvořte komponentu s názvem JourneyDetail. Do komponenty
JourneyDetail
zatím zkopírujte HTML kód ze zadání – celý elementdiv
s třídamijourney-detail
acontainer
i s jeho obsahem. Vytvořte v komponentě také souborstyle.css
, do kterého zkopírujte ze zadání styly pro třídystops
ajourney-detail
. Naimportujte soubor se styly do komponenty. - Použijete komponentu
JourneyDetail
v komponentěHome
na místě, kde se nyní vypisuje id nalezeného spoje. Komponenta se bude zobrazovat jenom tehdy, když ve stavujourney
v komponentěHome
je něco jiného, nežnull
. Ověřte, že po vyhledání spojení se na stránce zobrazí podrobnosti cesty s městy 1 až 4. - V samostatné složce vytvořte komponentu s názvem
BusStop
. V komponentě vytvořte také soubor se styly, do kterého ze zadání zkopírujete všechny styly pro třídy začínajícíbus-stop
. - Do komponenty
BusStop
vložte ze zadání celý elementdiv
, který má třídubus-stop
. Je to jeden prvek ze seznamu zastávek. - V komponentě
JourneyDetail
smažte HTML kód se seznamem zastávek. Zůstane tam jen kontejner, v němh2
s textem „Podrobnosti cesty“ a pod nímdiv
s třídoustops
. Do tohoto divu vložte komponentuBusStop
. Zkontrolujte v prohlížeči, že se zobrazí jedna zastávka. - Komponenta
BusStop
bude očekávat tři props –name
,station
atime
. Tam, kde používáte komponentuBusStop
, přidejte komponentě odpovídající atributy a nastavte jim hodnoty „Praha“, „ÚAN Florenc“ a „15:55“. KomponentuBusStop
upravte tak, aby se tyto hodnoty propsaly na správná místa v HTML. Zkontrolujte, že se v prohlížeči zobrazují správné údaje pro jednu zastávku. - Komponenta
JourneyDetail
bude vprops
očekávat propertyjourney
s údaji o cestě. V propertyjourney
bude objekt, který má v sobě v propertystops
seznam zastávek. Propertyjourney
si můžete vypsat do konzole prohlížeče. - Místo jedné komponenty
BusStop
použité v komponentě napište kód, který projde všechny zastávky vjourney.stops
a pro každou zastávku vloží jednu komponentuBusStop
, které předá správné údaje. Můžete si pomoci tak, že nejprve upravíte vloženou komponentuBusStop
, ve které máte „Praha“, „ÚAN Florenc“ a „15:55“ tak, aby se místo těchto údajů vložily údaje z první zastávky vjourney.stops[0]
a následně kód upravíte tak, aby pomocí funkcemap
prošel všechny zastávky vjourney.stops
. Jako klíč (key
) pro React můžete použít propertycode
, která je uvedená vjourney.stops
u každé zastávky. - Nyní už zbývá jen poslat z komponenty
Home
do komponentyJourneyDetail
údaje o cestě. Vraťte se do komponentyHome
. Ve stavujourney
tam jsou uloženy údaje o cestě. Nyní už jen stačí tento stav předat do propjourney
komponentyJourneyDetail
. - Ověřte v prohlížeči, že funguje vyhledání spojení a že se pod vyhledávacím formulářem zobrazí „jízdní řád“ spoje – seznam zastávek s časy. Zastávek je u spoje víc a když vyhledáte jiné spojení, změní se i seznam zastávek.
- Commitněte změny.
V první fázi projektu bude sedadlo pro cestujícího přidělovat automaticky backend. Jistě jste si všimli, že API endpoint /journey
vrací JSON s vlastností autoSeat
. Tato vlastnost obsahuje automaticky vybrané volné sedadlo. V tomto cvičení jej zobrazíme uživateli na stránce.
- Na vzorové stránce vidíte sekci s nadpisem „Vaše sedadlo“. Vytvořte pro tuto sekci React komponentu s názvem
SelectedSeat
. Její obsah vyplňte dle vzorové stránky. Všimněte si, že obrázek sedadla je vytvořen pomocí SVG. - Najděte, kde se ve struktuře SVG nastavuje číslo sedadlo. Zařiďte, aby šlo komponentě
SelectedSeat
nastavit číslo sedadla skrze propnumber
. - Zkontrolujte v prohlížeči, že se správně zobrazuje sekce se sedadlem a že je možné pomocí prop
number
měnit číslo sedadla. - V komponentě
Home
máme ve stavujourney
uložen výsledek vyhledané cesty. Stačí tedy vlastnostautoSeat
předat komponentěSelectedSeat
. Dejte však pozor na to, že při načtení stránky je ve stavujourney
hodnotanull
. V takovém případě komponentuSelectedSeat
vůbec nezobrazujte.
Nyní již máme ve stavu journey
uložené všechny potřebné informace k tomu, abychom mohli provést rezervaci jízdenky. V tomto cvičení potvrdíme rezervaci kliknutím na tlačíko, zpracujeme odpověď ze serveru a přesměrujeme uživatele na detail rezervované jízdenky.
-
Vložte do komponenty
Home
oddíl s tlačítkem „Rezervovat". Stále v komponentěHome
vytvořte funkcihandleBuy
a zařiďte, aby byla tato funkce volána při kliknutí na tlačítko „Rezervovat". Ve funkci si zatím můžete vypsat nějakou zprávu do konzole('Funguju!')
. -
Podle dokumentace React Routeru se podívejte, jak lze pomocí hooku
useNavigate
přímo v kódu změnit stránku, na které se uživatel nachází. Tedy jak uživatele přesměrovat. -
Na začátku komponenty
Home
vytvořte proměnnounavigate
s použitím hookuuseNavigate()
, nezapomeňte hook naimportovat zreact-router-dom
. Za moment tuto proměnnou použijeme. -
Nákup jízdenky se ve funkci
handleBuy
provede tak, že metodou POST zavoláte API endpointhttps://apps.kodim.cz/daweb/leviexpress/api/reservation
Tělo požadavku bude obsahovat akcicreate
, vlastnostseat
– číslo sedadla vybrané uživatelem, a vlastnostjourneyId
– hodnotajourneyId
ze stavu. Příklad:fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ action: 'create', seat: journey.autoSeat, journeyId: journey.journeyId, }), });
-
Volání tohoto API vrací JSON s daty, ze kterých nás bude zajímat hodnota
reservationId
. Vypište si ji do konzole. -
Pomocí funkce
navigate
a hodnotyreservationId
přesměrujte uživatele na stránku detailu rezervace. Takové volání bude vypadat následovně:navigate(`/reservation/${reservationId}`);
-
Zkontrolujte, že po kliknutí na tlačítko „Rezervovat" se stránka přesměruje například na adresu
http://localhost:8080/reservation/HAQBAQASf7M
kde záhy vytvoříme detail jízdenky!
- Commitněte změny.
V předešlé lekci jsme dospěli k vytvoření rezervace a získání reservationId
. K dokončení základní verze projektu tak stačí vytvořit detail pro jednu jízdenku a zobrazit její data.
- V komponentě
App
připravte již existující komponentu na správné zpracování detailu jízdenky. Upravtepath
v routeru tak, aby dynamicky zpracovávala:id
parametr. Výsledná path bude vypadat takto:path="/reservation/:id"
. - Do komponenty
Reservation
zkopírujte HTML kód ze zadání. Ze souborureservation.html
převezměte elementdiv
s třídoureservation
i s jeho obsahem. - Vytvořte v komponentě soubor
style.css
, do kterého zkopírujte ze zadání styly pro třídy začínajícíreservation
. Naimportujte soubor se styly do komponenty. - Komponenta musí zjistit, na detailu které jízdenky se nachází. Naimportujte si
useParams
hook zreact-router-dom
. Uvnitř komponenty tento hook zavolejte a získejte z něj parametrid
. Příklad použití. - Pomocí
useState
vytvořte nový stavreservation
, výchozí hodnota budenull
. - Přidejte
useEffect
volaný při prvním zobrazení komponenty. Bude z API získávat podrobné informace o jedné jízdence. Endpoint je na adrese https://apps.kodim.cz/daweb/leviexpress/api/reservation?id=… kde tečky nahradíid
konkrétní jízdenky. Totoid
vezměte z vytvořené proměnnéid
zuseParams
hooku. - Endpoint vrací údaje o jízdence, pomocí funkce
setReservation
zuseState
hooku nastavte do proměnnéreservation
výsledek volání uvedeného endpointu. - Data z endpointu si také můžete vypsat do konzole. Podívejte se na jejich formát a porovnejte strukturu dat s daty, která jsou natvrdo v JSX (vykopírované z
reservation.html
). - Nahraďte data jízdenky vepsaná natvrdo za ta, která jsou nyní uložená v proměnné
reservation
. Nezapomeňte zobrazení dat podmínit tím, že stavreservation
nemá hodnotunull
, jinak bude prohlížeč hlásit chybu, že nelze číst zundefined
. - Zkontrolujte, že stránka vzhledově odpovídá zadání.
- Commitněte a pushněte změny. Nyní máte zcela hotovou první část projektu. Pokochejte se hotovou aplikací a pochvalte se za pořádný kus dobře odvedené práce. Po malé oslavě svých úspěchů se můžete vrhnout na druhou část.
V druhé fázi projektu zprovozníme výběr sedadla uživatelem.
V tomto cvičení vytvoříme komponentu zobrazující plánek autobusu se sedadly. Obsazená sedadla budou zobrazena šedě a nepůjde na ně kliknout. API vrací seznam sedadel po řadách – nemusíte tedy řešit rozmístění sedadel. Zobrazíte jednoduše každou řadu zvlášť a v ní sedadla zleva doprava.
- Smažte z projektu komponentu
SelectedSeat
. V této verzi projektu už ji nebudeme potřebovat. Sedadlo vybereme z plánku. - Vytvořte komponentu
SeatPicker
a přidejte styly pro třídyseat-picker
aseats
ze zadání projektu. Do komponentySeatPicker
zkopírujte ze zadání celýdiv
s třídamiseat-picker
acontainer
. Obsahdiv
useats
nechte však prázdný. - Přidejte komponentu
SeatPicker
do komponentyHome
tam, kde před tím byla komponentaSelectedSeat
. Bude tak umístěna podJourneyDetail
. Komponentu budeme chtít zobrazit jen v případě, kdy stavjourney
neobsahujenull
. Pro vývoj komponenty ale nyní bude rychlejší, když se prozatím bude zobrazovat stále. - Dále v projektu vytvořte komponentu
Seat
představující jedno sedadlo v autobusu. Sedadlo je vytvořeno pomocí SVG, které najdete v zadání projektu. Do komponentySeat
přidejte všechny styly týkající se jednoho sedadla. - Komponenta
Seat
bude mít zatím jednu prop s názvemnumber
, ve které bude číslo sedadla. - Zkusmo vložte do komponenty
SeatPicker
pár sedadel s různými čísly, například 1, 17 a 33. Zatím jen tak pod sebe, abychom si vyzkoušeli, že je vůbec dokážeme správně zobrazit. - Zkontrolujte v prohlížeči, že se zobrazuje nadpis „Vyberte sedadlo“ a pod ním tři modrá sedadla 1, 17 a 33.
Nyní zařídíme zobrazování sedadel v řadách. Plánek sedadel bude vypadat tak, že v HTML bude pro každou řadu sedadel jedna komponenta SeatRow
a teprve uvnitř této komponenty budou jednotlivá sedadla – komponenty Seat
.
-
V projektu vytvořte komponentu
SeatRow
, která představuje jednu řadu sedadel. Bude vracetdiv
s třídouseat-row
, který v dalších krocích naplníme sedadly tak, jak nám přijdou z API. Zatím do komponenty natvrdo vložte pár sedadel jen pro testovací účely. KomponentuSeatRow
pak vložte dodiv
useats
v komponentěSeatPicker
. -
Komponenta
SeatRow
bode očekávat prop s názvemrow
, ve které budou data pro jednu řadu sedadel. Pro testovací účely si vytvořte proměnnoutestRow
, která bude obsahovat takovýto objekt.const testRow = [ { number: 33, isOccupied: false, }, { number: 29, isOccupied: true, }, { number: 25, isOccupied: false, }, ];
-
Předejte tuto proměnou komponentě
SeatRow
a uvnitř ní pomocí funkcemap
zobrazte jednotlivá sedadla. Jakokey
prop u jednotlivých sedadel můžete použít samotné číslo sedadla. -
Nyní máme vše připraveno pro zobrazení správného plánku sedadel podle dat z API. Pracovat budeme v komponentě
SeatPicker
– tam, kde máme testovací řadu sedadel. Když se podíváte do konzole na výpis objektu uloženého ve stavujourney
komponentyHome
, uvidíte, že máte velké štěstí. Ve vlastnostiseats
je pole, které představuje přímo jednotlivé řady v autobusu. -
Nyní je tedy potřeba údaje o sedadlech předat z komponenty
Home
do komponentySeatPicker
. Zároveň se bude později hodit i identifikátor spoje. Do komponentySeatPicker
tedy přidejte dvě props –seats
(vloží se do níjourney.seats
) ajourneyId
(sem přijdejourney.journeyId
). -
Ještě je potřeba upravit komponentu
Home
tak, aby komponentaSeatPicker
byla vidět jedině v případě, že je stavjourney
jiný nežnull
– tedy stejně, jako se zobrazuje komponentaJourneyDetail
. Ověřte v prohlížeči, že po vyhledání spoje se zobrazí podrobnosti cesty a také komponenta pro výběr sedadel – zatím s vašimi testovacími sedadly. -
Uvnitř komponenty
SeatPicker
projděte poleseats
pomocí funkcemap
, a pro každý řádek pole vytvořte jednu komponentuSeatRow
. I komponentySeatRow
potřebují propkey
. Zde bohužel nemáme žádnou rozumnou datovou položku, kterou bychom jako klíč mohli použít. Vzpomeňme si však, že funkce vložená do funkcemap
může mít dva parametry, druhý parametr je pořadové číslo (takzvaný index) aktuálního prvku. V tomto případě jej výjimečně můžeme použít jakokey
proSeatRow
. -
Pokud jste všechno zařídili správně, měli byste po vyhledání cesty vidět sedadla rozmístěná stejně jako ve vzorovém designu stránky. V tuto chvíli už nám stačí pouze správně zobrazit zabraná sedadla. Zda je sedadlo zabrané udává vlastnost
isOccupied
v datech z API. Stačí tedy komponentěSeat
přidat propisOccupied
a poslat do ní hodnotu obdrženou z API. -
Uvnitř komponenty
Seat
zařiďte, aby se na elementsvg
přidala CSS třídaseat--occupied
ve chvíli, kdy je sedadlo zabrené. -
Pokochejte se krásným plánkem sedadel a commitněte změny.
Když už dokážeme zobrazit plánek autobusu, je na čase zobrazit vybrané sedadlo. Zde bude potřeba hodně komunikace směrem od rodiče k dítěti.
- Nejprve musíme upravit komponentu
Seat
tak, aby správně zobrazovala vybrané sedadlo. Přidáme jí tedy novou propisSelected
. Pokud je sedadlo vybrané (propisSelected
je nastavena natrue
), bude mít sedadlo nastavenu vedleseat
také tříduseat--selected
. - V komponentě
SeatRow
budeme nyní potřebovat proprowSelectedSeat
, do které vložíme číslo vybraného sedadla. Na komponentáchSeat
uvnitřSeatRow
pak změníme atributisSelected
. Místo statické hodnotytrue
nebofalse
nastavujte jeho hodnotu v závislosti na tom, zda číslo sedadla je shodné s číslem v proprowSelectedSeat
. - Odkud však má komponenta
SeatRow
vzít číslo vybraného sedadla? Získá jej od rodičeSeatPicker
. Do komponentySeatPicker
tedy přidejte prop s názvemselectedSeat
. Hodnotu v této proppak předejte komponentám
SeatRowjako
rowSelectedSeat`. - Nyní si v prohlížeči vyzkoušejte, že pomocí prop
selectedSeat
komponentySeatPicker
můžete nastavit libovolné sedadlo jako vybrané. - Zkuste nyní jako vybrané nastavit sedadlo, které přišlo v hodnotě
autoSeat
z backendu. - Commitněte změny.
Nyní jsme ve stavu, kdy uživatel vidí automaticky vybrané sedadlo přímo na plánku autobusu.
V předchozí verzi projektu jsme sedadlo pro rezervaci získali z hodnoty autoSeat
stavu journey v komponentě Home
. Nyní však sedadlo bude vybírat uživatel. Potřebujeme tedy nový stav v komponentě Home
. Zde si užijeme hodně komunikace od potomka k předkovi.
- V komponentě
Home
vytvořte nový stav s názvemuserSeat
. Jeho hodnota bude na začátkunull
. - Na začátku budeme chtít, aby se uživateli nabídlo sedadlo, které server vybral automaticky. Ve funkci
handleJourneyChange
tak nastavte stavuserSeat
na hodnotuautoSeat
, která přišla ze serveru při výběru cesty. - Hodnotu ze stavu
userSeat
pošlete do propselectedSeat
komponentySeatPicker
. - Do komponenty
Seat
přidejte proponSelect
. V této prop bude funkce, kterouSeat
zavolá, když uživatel vybere sedadlo. Jako parametr této funkci předejte číslo sedadla. - Nyní chceme být schopní změnit stav
userSeat
při kliknutí na komponentuSeat
, která je ovšem zanořena v hlubinách komponentySeatPicker
. Mezi komponentamiSeat
aHome
je vztah potomek - pra-prarodič. Komunikace mezi nimi tedy musí probíhat skrze komponentySeatRow
aSeatPicker
. - Obě komponenty
SeatPicker
iSeatRow
musí mít proto proponSeatSelected
. KomponentaSeatRow
tuto funkci předá všem svýmSeat
jako proponSelect
. KomponentaSeatPicker
funkcionSeatSelected
předá dolů komponentěSeatRow
skrze stejnojmennou prop. Takto můžeme z prarodičeSeatPicker
propašovat funkci do vnukaSeat
. - Nyní stačí komponentě
SeatPicker
skrze proponSeatSelected
předat funkcisetUserSeat
, která nastaví stav v komponentěHome
. Pokud se povedlo vše správně propojit, při kliknutí na sedadlo se změní stavuserSeat
v komponentěHome
a plánek zobrazí vybrané sedadlo. Vyzkoušejte v prohlížeči, že vše správně funguje. - Pokud jste došli až sem, váš projekt je téměř hotový. Stačí už je v obsluze tlačítka pro rezervaci místo
autoSeat
použít stavuuserSeat
. - Pokud se vše povedlo, váš projekt LeviExpress je hotový. Umožní uživateli vybrat, odkud kam chce jet, datum cesty i sedadlo, a rezervovat si jízdenku. Commitněte změny a kochejte se fungující aplikací.