[INF.03] PEŁNY ARKUSZ EGZAMINACYJNY

Serwis Rezerwacji Biletów Lotniczych „AirFinder”

1. ✈️ Zadanie – Serwis Biletów Lotniczych „AirFinder”

1.1 Wymagania SQL i Baza Danych

Zbuduj bazę danych zawierającą tabele kierunki i loty, połączone kluczem obcym. Wypełnij minimum 5 rekordami.

Wykonaj następujące kwerendy:

1.2 Wymagania CSS (styl_loty.css)

Utwórz arkusz stylów. Zadbaj o poniższe wymagania:

1.3 Wymagania HTML i JavaScript

Zrealizuj dwa pliki HTML i skrypt JS.

2. 💾 Gotowe kody źródłowe – AirFinder

2.1 Kod SQL i kwerendy (baza_loty.sql)

/* Plik: baza_loty.sql - Tworzenie struktury, danych i kwerendy */

CREATE DATABASE `airfinder` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8_general_ci;
USE `airfinder`;

CREATE TABLE `kierunki` (
  `id_kierunku` int(3) NOT NULL PRIMARY KEY,
  `miasto` varchar(50) NOT NULL,
  `kod_lotniska` char(3) NOT NULL
);
INSERT INTO `kierunki` (`id_kierunku`, `miasto`, `kod_lotniska`) VALUES
(101, 'Londyn', 'LHR'), (102, 'Paryż', 'CDG'), (103, 'Rzym', 'FCO'), (104, 'Madryt', 'MAD');

CREATE TABLE `loty` (
  `id_lotu` int(6) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `numer_lotu` varchar(10) NOT NULL,
  `cena_bazowa` float(10,2) NOT NULL,
  `data_wylotu` date NOT NULL,
  `wolne_miejsca` int(3) NOT NULL,
  `id_kierunku` int(3) NOT NULL,
  CONSTRAINT `fk_kierunek` FOREIGN KEY (`id_kierunku`) REFERENCES `kierunki` (`id_kierunku`)
);
INSERT INTO `loty` (`numer_lotu`, `cena_bazowa`, `data_wylotu`, `wolne_miejsca`, `id_kierunku`) VALUES
('AF1234', 750.00, '2026-03-10', 50, 102),
('BA5678', 650.00, '2026-03-15', 30, 101),
('LH9012', 920.00, '2026-04-01', 80, 103),
('IB3456', 500.00, '2026-03-05', 100, 104),
('AF7890', 799.99, '2026-03-20', 45, 102);

SELECT l.numer_lotu, l.cena_bazowa, k.miasto
FROM loty l JOIN kierunki k ON l.id_kierunku = k.id_kierunku
WHERE l.cena_bazowa < 800;

SELECT numer_lotu, data_wylotu, cena_bazowa
FROM loty
ORDER BY data_wylotu DESC;

CREATE USER 'Pilot'@'localhost' IDENTIFIED BY 'Samolot_2026';
GRANT SELECT, DELETE ON airfinder.loty TO 'Pilot'@'localhost';
    

2.2 Kod CSS (styl_loty.css)

/* Plik: styl_loty.css */
:root {
    --color-primary: #3498db;
    --color-accent: #e74c3c;
    --color-light-bg: #f4f4f9;
    --color-dark: #2c3e50;
    --color-header-bg: #2980b9;
    --color-white: #ffffff;
}
* { font-family: 'Verdana', sans-serif; box-sizing: border-box; }
body { background-color: var(--color-light-bg); color: var(--color-dark); margin:0; line-height: 1.5; text-align: center;}
header, footer { background-color: var(--color-primary); color: var(--color-white); text-align: center; padding: 15px 0; }
nav { background-color: var(--color-primary); padding: 5px 0; margin-bottom: 20px; }
nav a { color: var(--color-white); padding: 8px 12px; text-decoration: none; font-weight: bold; }
nav a:hover { background-color: var(--color-accent); }
table { border: 1px solid var(--color-primary); width: 90%; margin: 20px auto; text-align: left; border-collapse: collapse;}
th { background: var(--color-header-bg); color: var(--color-white); padding: 10px; border: 1px solid #ccc;}
td { border: 1px solid #ccc; padding: 10px;}
.input-pole {
    width: 80%; padding: 8px; margin: 5px auto 15px auto;
    border: 1px solid var(--color-primary); display: block; box-sizing: border-box;
}
.form-box { background: #ffffff; padding: 20px; border-radius: 8px; max-width: 500px; margin: 20px auto; text-align: left;}
#wynik { margin-top: 20px; padding: 12px; border: 2px solid var(--color-accent); background: #ffe6e6; border-radius: 4px; text-align: center;}
    

2.3 Kod oferta.html

<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <title>AirFinder - Oferty Lotów</title>
    <link rel="stylesheet" href="styl_loty.css">
</head>
<body>
    <header><h1>✈️ Aktualne Oferty Lotów</h1></header>
    <nav>
        <a href="oferta.html">Aktualne Loty</a>
        <a href="rezerwacja.html">Zarezerwuj / Kalkulator</a>
    </nav>
    <div class="container">
        <h2>Dostępne Połączenia Lotnicze</h2>
        <table>
            <tr>
                <th>Numer Lotu</th><th>Miasto Docelowe</th><th>Data Wylotu</th><th>Cena Bazowa (PLN)</th><th>Wolne Miejsca</th>
            </tr>
            <tr><td>AF1234</td><td>Paryż</td><td>2026-03-10</td><td>750.00</td><td>50</td></tr>
            <tr><td>BA5678</td><td>Londyn</td><td>2026-03-15</td><td>650.00</td><td>30</td></tr>
            <tr><td>LH9012</td><td>Rzym</td><td>2026-04-01</td><td>920.00</td><td>80</td></tr>
            <tr><td>IB3456</td><td>Madryt</td><td>2026-03-05</td><td>500.00</td><td>100</td></tr>
            <tr><td>AF7890</td><td>Paryż</td><td>2026-03-20</td><td>799.99</td><td>45</td></tr>
        </table>

        <h3>Dane Kontaktowe</h3>
        <ul>
            <li>Nazwa: AirFinder Sp. z o.o.</li>
            <li>Adres: ul. Lotnicza 1, 02-143 Warszawa</li>
            <li>Telefon: +48 111 222 333</li>
            <li>Email: <a href="mailto:rezerwacja@airfinder.pl">rezerwacja@airfinder.pl</a></li>
        </ul>
    </div>
    <footer><p>Przygotował: [NUMER ZDAJĄCEGO] | INF.03</p></footer>
</body>
</html>
    

2.4 Kod rezerwacja.html (wersja podstawowa)

<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <title>AirFinder - Kalkulator Rezerwacji</title>
    <link rel="stylesheet" href="styl_loty.css">
</head>
<body>
    <header><h1>🧮 Kalkulator Ceny Biletu</h1></header>
    <nav>
        <a href="oferta.html">Aktualne Loty</a>
        <a href="rezerwacja.html">Zarezerwuj / Kalkulator</a>
    </nav>
    <div class="container">
        <div class="form-box" style="margin: 20px auto; max-width: 500px;">
            <h2 style="text-align: center;">Formularz Rezerwacji</h2>

            <label for="imie_nazwisko"><strong>Imię i Nazwisko:</strong></label>
            <input type="text" id="imie_nazwisko" class="input-pole" required>

            <label for="lot_id"><strong>Wybierz Kierunek:</strong></label>
            <select id="lot_id" class="input-pole">
                <option value="750" data-kierunek="Paryż">AF1234 - Paryż (750 PLN)</option>
                <option value="650" data-kierunek="Londyn">BA5678 - Londyn (650 PLN)</option>
                <option value="920" data-kierunek="Rzym">LH9012 - Rzym (920 PLN)</option>
                <option value="500" data-kierunek="Madryt">IB3456 - Madryt (500 PLN)</option>
                <option value="799.99" data-kierunek="Paryż">AF7890 - Paryż (799.99 PLN)</option>
            </select>

            <label>
                <input type="checkbox" id="bagaz">
                <strong>Dodaj bagaż rejestrowany (+50 PLN)</strong>
            </label>

            <button onclick="obliczCene()" style="margin-top: 15px; padding: 10px 20px; background: #3498db; color: white; border: none; cursor: pointer; border-radius: 4px; display: block; width: 100%;">
                Oblicz Cenę Biletu
            </button>

            <p id="wynik">Wynik kalkulacji pojawi się tutaj...</p>
        </div>
    </div>
    <footer><p>Przygotował: [NUMER ZDAJĄCEGO] | INF.03</p></footer>

    <script>
        function obliczCene() {
            const imieNazwisko = document.getElementById('imie_nazwisko').value.trim();
            const selectLot = document.getElementById('lot_id');
            const cenaBazowa = parseFloat(selectLot.value);
            const kierunek = selectLot.options[selectLot.selectedIndex].getAttribute('data-kierunek');
            const czyBagaz = document.getElementById('bagaz').checked;
            const paragrafWynik = document.getElementById('wynik');

            if (imieNazwisko === "") {
                paragrafWynik.innerHTML = "❌ BŁĄD: Proszę podać Imię i Nazwisko.";
                paragrafWynik.style.backgroundColor = '#ffc0c0';
                paragrafWynik.style.borderColor = 'red';
                return;
            }

            let cenaKoncowa = cenaBazowa;
            let rabat = 0;

            if (czyBagaz) {
                cenaKoncowa += 50;
            }

            if (kierunek === "Paryż") {
                rabat = cenaBazowa * 0.20;
                cenaKoncowa -= rabat;
            }

            const statusBagaz = czyBagaz ? "TAK (+50 PLN)" : "NIE";
            const statusRabat = rabat > 0 ? `TAK (-${rabat.toFixed(2)} PLN)` : "NIE";

            const komunikat = `
                ✅ Rezerwacja dla <strong>${imieNazwisko}</strong> (Kierunek: ${kierunek})
                <br>Cena Bazowa: ${cenaBazowa.toFixed(2)} PLN
                <br>Bagaż Rejestrowany: <strong>${statusBagaz}</strong>
                <br>Zniżka (Paryż): <strong>${statusRabat}</strong>
                <br>***
                <br>Cena Końcowa: <strong>${cenaKoncowa.toFixed(2)} PLN</strong>
            `;

            paragrafWynik.innerHTML = komunikat;
            paragrafWynik.style.backgroundColor = '#d4edda';
            paragrafWynik.style.borderColor = '#155724';
        }
    </script>
</body>
</html>
    

3. ✈️ Wymagania – AirFinder na 100%

3.1 Dodatkowe wymagania

Rozszerz serwis AirFinder o dodatkowe pola oraz obliczenia, pozostając w tym samym projekcie.

Nowy wzór:

3.2 Przykładowy rozszerzony formularz (rezerwacja.html)

<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <title>AirFinder - Rozszerzony kalkulator</title>
    <link rel="stylesheet" href="styl_loty.css">
</head>
<body>
    <header><h1>🧮 Kalkulator Ceny Biletu (Rozszerzony)</h1></header>
    <nav>
        <a href="oferta.html">Aktualne Loty</a>
        <a href="rezerwacja.html">Zarezerwuj / Kalkulator</a>
    </nav>
    <div class="container">
        <div class="form-box">
            <h2 style="text-align: center;">Formularz Rezerwacji</h2>

            <label for="imie_nazwisko"><strong>Imię i Nazwisko:</strong></label>
            <input type="text" id="imie_nazwisko" class="input-pole" required>

            <label for="lot_id"><strong>Wybierz Kierunek:</strong></label>
            <select id="lot_id" class="input-pole">
                <option value="750" data-kierunek="Paryż">AF1234 - Paryż (750 PLN)</option>
                <option value="650" data-kierunek="Londyn">BA5678 - Londyn (650 PLN)</option>
                <option value="920" data-kierunek="Rzym">LH9012 - Rzym (920 PLN)</option>
                <option value="500" data-kierunek="Madryt">IB3456 - Madryt (500 PLN)</option>
                <option value="799.99" data-kierunek="Paryż">AF7890 - Paryż (799.99 PLN)</option>
            </select>

            <label>
                <input type="checkbox" id="bagaz">
                <strong>Dodaj bagaż rejestrowany (+50 PLN)</strong>
            </label>

            <label for="pasazerowie"><strong>Liczba pasażerów:</strong></label>
            <input type="number" id="pasazerowie" class="input-pole" value="1" min="1">

            <label>
                <input type="checkbox" id="ubezpieczenie">
                <strong>Ubezpieczenie podróżne (+30 PLN za osobę)</strong>
            </label>

            <button onclick="obliczCeneRozszerzona()" style="margin-top: 15px; padding: 10px 20px; background: #3498db; color: white; border: none; cursor: pointer; border-radius: 4px; display: block; width: 100%;">
                Oblicz Cenę Rezerwacji
            </button>

            <p id="wynik">Wynik kalkulacji pojawi się tutaj...</p>
        </div>
    </div>
    <footer><p>Przygotował: [NUMER ZDAJĄCEGO] | INF.03</p></footer>

    <script>
        function obliczCeneRozszerzona() {
            const imieNazwisko = document.getElementById('imie_nazwisko').value.trim();
            const selectLot = document.getElementById('lot_id');
            const cenaBazowa = parseFloat(selectLot.value);
            const kierunek = selectLot.options[selectLot.selectedIndex].getAttribute('data-kierunek');
            const czyBagaz = document.getElementById('bagaz').checked;
            const liczbaPasazerow = parseInt(document.getElementById('pasazerowie').value, 10);
            const czyUbezpieczenie = document.getElementById('ubezpieczenie').checked;
            const paragrafWynik = document.getElementById('wynik');

            if (imieNazwisko === "" || isNaN(liczbaPasazerow) || liczbaPasazerow < 1) {
                paragrafWynik.innerHTML = "❌ BŁĄD: Podaj imię i nazwisko oraz poprawną liczbę pasażerów (min. 1).";
                paragrafWynik.style.backgroundColor = "#ffc0c0";
                paragrafWynik.style.borderColor = "red";
                return;
            }

            let cenaJednego = cenaBazowa;
            let rabat = 0;

            if (czyBagaz) {
                cenaJednego += 50;
            }

            if (kierunek === "Paryż") {
                rabat = cenaBazowa * 0.20;
                cenaJednego -= rabat;
            }

            let suma = cenaJednego * liczbaPasazerow;

            if (czyUbezpieczenie) {
                suma += 30 * liczbaPasazerow;
            }

            const infoBagaz = czyBagaz ? "TAK (+50 PLN/os.)" : "NIE";
            const infoUbezp = czyUbezpieczenie ? "TAK (+30 PLN/os.)" : "NIE";
            const infoRabat = rabat > 0 ? `TAK (-${rabat.toFixed(2)} PLN/os.)` : "NIE";

            paragrafWynik.innerHTML = `
                ✅ Rezerwacja dla <strong>${imieNazwisko}</strong> (Kierunek: ${kierunek})
                <br>Liczba pasażerów: <strong>${liczbaPasazerow}</strong>
                <br>Cena bazowa za 1 osobę: ${cenaBazowa.toFixed(2)} PLN
                <br>Bagaż rejestrowany: <strong>${infoBagaz}</strong>
                <br>Zniżka (Paryż): <strong>${infoRabat}</strong>
                <br>Ubezpieczenie: <strong>${infoUbezp}</strong>
                <br>***
                <br>Cena za 1 osobę po uwzględnieniu opcji: <strong>${cenaJednego.toFixed(2)} PLN</strong>
                <br>Łączna kwota do zapłaty: <strong>${suma.toFixed(2)} PLN</strong>
            `;
            paragrafWynik.style.backgroundColor = "#d4edda";
            paragrafWynik.style.borderColor = "#155724";
        }
    </script>
</body>
</html>
        

4. 👀 Podgląd gotowych stron AirFinder

Poniżej znajdują się podglądy docelowego wyglądu stron oferta.html i rezerwacja.html. Pliki muszą być w tym samym folderze co ten arkusz.

4.1 Podgląd strony ofert (oferta.html)

4.2 Podgląd strony rezerwacji (rezerwacja.html)