diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..0fc20b3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,25 @@ +# Auto-detect text files and normalize line endings to LF on checkin +* text=auto eol=lf + +# Explicitly declare text files you want to always be normalized and converted to LF on checkout +*.php text eol=lf +*.js text eol=lf +*.css text eol=lf +*.json text eol=lf +*.md text eol=lf +*.yml text eol=lf +*.yaml text eol=lf +*.xml text eol=lf +*.sh text eol=lf +*.sql text eol=lf + +# Denote all files that are truly binary and should not be modified +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.pdf binary +*.zip binary +*.tar binary +*.gz binary diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 54c3700..ee2db69 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -145,7 +145,7 @@ jobs: run: npm install -g newman - name: Run Postman tests - run: newman run "./postman/collections/F1 Management API.json" --env-var baseUrl=http://127.0.0.1:8080 + run: newman run "./postman/collections/F1 Management API.json" --env-var baseUrl=http://127.0.0.1:8080/api - name: Display PHP server logs if: always() diff --git a/.idea/.gitignore b/.idea/.gitignore index 13566b8..cb0232c 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -6,3 +6,9 @@ # Datasource local storage ignored files /dataSources/ /dataSources.local.xml + +*.iml +laravel-idea-personal.xml +laravel-idea.xml +deployment.xml +/codeStyles diff --git a/.idea/I425-Team-Project.iml b/.idea/I425-Team-Project.iml index af6d931..b71c3a8 100644 --- a/.idea/I425-Team-Project.iml +++ b/.idea/I425-Team-Project.iml @@ -4,6 +4,8 @@ + + diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 3bddc34..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 79ee123..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/config/routes.php b/config/routes.php index 3614ac7..08b1fed 100644 --- a/config/routes.php +++ b/config/routes.php @@ -2,9 +2,9 @@ declare(strict_types=1); -use App\Middleware\AuthMiddleware; use App\Controllers\{AuthController, CarController, DriverController, EventController, TeamController, TrackController}; use Psr\Http\Message\ResponseInterface as Response; +use Psr\Http\Message\ServerRequestInterface as Request; use Slim\App; use Slim\Routing\RouteCollectorProxy; @@ -22,8 +22,66 @@ return $response; }); - // Team routes - $app->group('/teams', function (RouteCollectorProxy $group) { + // ============================================ + // SPA PAGE ROUTES (Serve HTML) + // ============================================ + // These routes render PHP pages with embedded JavaScript that call the API endpoints below + + $app->get('/', function (Request $request, Response $response) { + ob_start(); + require __DIR__ . '/../public/mainPage.php'; + $html = ob_get_clean(); + $response->getBody()->write($html); + return $response->withHeader('Content-Type', 'text/html'); + }); + + $app->get('/teamsPage', function (Request $request, Response $response) { + ob_start(); + require __DIR__ . '/../public/teamsPage.php'; + $html = ob_get_clean(); + $response->getBody()->write($html); + return $response->withHeader('Content-Type', 'text/html'); + }); + + $app->get('/driversPage', function (Request $request, Response $response) { + ob_start(); + require __DIR__ . '/../public/driversPage.php'; + $html = ob_get_clean(); + $response->getBody()->write($html); + return $response->withHeader('Content-Type', 'text/html'); + }); + + $app->get('/tracksPage', function (Request $request, Response $response) { + ob_start(); + require __DIR__ . '/../public/tracksPage.php'; + $html = ob_get_clean(); + $response->getBody()->write($html); + return $response->withHeader('Content-Type', 'text/html'); + }); + + $app->get('/eventsPage', function (Request $request, Response $response) { + ob_start(); + require __DIR__ . '/../public/eventsPage.php'; + $html = ob_get_clean(); + $response->getBody()->write($html); + return $response->withHeader('Content-Type', 'text/html'); + }); + + $app->get('/carsPage', function (Request $request, Response $response) { + ob_start(); + require __DIR__ . '/../public/carsPage.php'; + $html = ob_get_clean(); + $response->getBody()->write($html); + return $response->withHeader('Content-Type', 'text/html'); + }); + + // ============================================ + // API ROUTES (Return JSON) + // ============================================ + // All API endpoints are namespaced under /api to prevent collision with SPA page routes + + // Team API routes + $app->group('/api/teams', function (RouteCollectorProxy $group) { $group->get('', TeamController::class . ':getAll'); $group->get('/{id:\d+}', TeamController::class . ':getById'); $group->post('', TeamController::class . ':create'); @@ -31,8 +89,8 @@ $group->delete('/{id:\d+}', TeamController::class . ':delete'); }); - // Event routes - $app->group('/events', function (RouteCollectorProxy $group) { + // Event API routes + $app->group('/api/events', function (RouteCollectorProxy $group) { $group->get('', EventController::class . ':getAll'); $group->get('/{id:\d+}', EventController::class . ':getById'); $group->post('', EventController::class . ':create'); @@ -40,8 +98,8 @@ $group->delete('/{id:\d+}', EventController::class . ':delete'); }); - // Track routes - $app->group('/tracks', function (RouteCollectorProxy $group) { + // Track API routes + $app->group('/api/tracks', function (RouteCollectorProxy $group) { $group->get('', TrackController::class . ':getAllWithParams'); $group->get('/{id:\d+}', TrackController::class . ':getById'); $group->post('', TrackController::class . ':create'); @@ -49,8 +107,8 @@ $group->delete('/{id:\d+}', TrackController::class . ':delete'); }); - // Driver routes - $app->group('/drivers', function (RouteCollectorProxy $group) { + // Driver API routes + $app->group('/api/drivers', function (RouteCollectorProxy $group) { $group->get('', DriverController::class . ':getAll'); $group->get('/{id:\d+}', DriverController::class . ':getById'); $group->post('', DriverController::class . ':create'); @@ -59,8 +117,8 @@ $group->get('/search', DriverController::class . ':search'); }); - // Car routes - $app->group('/cars', function (RouteCollectorProxy $group) { + // Car API routes + $app->group('/api/cars', function (RouteCollectorProxy $group) { $group->get('', CarController::class . ':getAll'); $group->get('/{id:\d+}', CarController::class . ':getById'); $group->post('', CarController::class . ':create'); @@ -68,8 +126,8 @@ $group->delete('/{id:\d+}', CarController::class . ':delete'); }); - // Auth routes TODO need documentation - $app->group('/auth', function (RouteCollectorProxy $group) { + // Auth API routes + $app->group('/api/auth', function (RouteCollectorProxy $group) { $group->post('/login', AuthController::class . ':login'); $group->post('/register', AuthController::class . ':register'); $group->post('/revoke', AuthController::class . ':revoke'); diff --git a/public/carsPage.php b/public/carsPage.php new file mode 100644 index 0000000..360bf13 --- /dev/null +++ b/public/carsPage.php @@ -0,0 +1,115 @@ + + + + + + Formula 1 Cars + + + + +
+
+

Formula 1 Cars

+ +
+
+
+
+

Formula 1 Cars

+

Explore the cars used by the top teams in Formula 1.

+ +
+ +
+
+
+
+

© 2024 Formula 1 Center. All Rights Reserved.

+
+
+ + diff --git a/public/css/f1.css b/public/css/f1.css new file mode 100644 index 0000000..e11c5eb --- /dev/null +++ b/public/css/f1.css @@ -0,0 +1,179 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + line-height: 1.6; + background-color: #fff; + color: #121f45; + overflow-x: hidden; +} + +.container { + width: 90%; + max-width: 1200px; + margin: 0 auto; +} + +header { + background-color: #223971; + color: white; + padding: 15px 0; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); +} + +header h1 { + font-size: 2rem; + font-weight: bold; +} + +nav { + display: flex; + justify-content: space-between; + width: 100%; +} + +nav ul { + list-style: none; + display: flex; +} + +nav ul li { + margin-right: 20px; +} + +nav ul li a { + text-decoration: none; + color: #ffc906; + font-weight: 600; + font-size: 1.1rem; +} + +nav ul li a:hover { + color: white; +} + +.signin-btn { + background-color: #ffc906; + color: #121f45; + padding: 10px 20px; + font-size: 1rem; + border: none; + border-radius: 5px; + text-decoration: none; + transition: background-color 0.3s ease; +} + +#hero { + position: relative; + width: 100%; + height: 50vh; + overflow: hidden; +} + +.hero-container { + display: flex; + transition: transform 1s ease-in-out; + height: 100%; + width: 100%; +} + +.slide { + min-width: 100%; + display: flex; + justify-content: center; +} + +.hero-image { + width: 100%; + height: 100%; + object-fit: cover; + object-position: bottom; +} + +.section { + padding: 60px 0; + text-align: center; + background-color: #f9f9f9; +} + +.section h2 { + font-size: 2.8rem; + margin-bottom: 20px; + font-weight: bold; +} + +.section p { + font-size: 1.2rem; + margin-bottom: 30px; +} + +.track-list, .driver-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 30px; + margin-top: 30px; +} + +.track-item, .driver-item { + background-color: #fff; + padding: 20px; + border-radius: 10px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + text-align: center; +} + +.track-item img, .driver-item img { + width: 100%; + height: auto; + object-fit: contain; + max-height: 200px; + border-radius: 10px; + margin-bottom: 15px; +} + +.track-item h3, .driver-item h3 { + font-size: 1.8rem; + margin-bottom: 10px; + color: #223971; +} + +.track-item p, .driver-item p { + font-size: 1.1rem; + margin: 5px 0; + color: #121f45; +} + +.track-item strong { + font-weight: bold; +} + +footer { + background-color: #121f45; + color: white; + padding: 20px 0; + text-align: center; + margin-top: 40px; +} + +footer p { + font-size: 1rem; +} + +@media (max-width: 768px) { + .track-list, .driver-list { + grid-template-columns: 1fr 1fr; + } +} + +@media (max-width: 480px) { + .track-list, .driver-list { + grid-template-columns: 1fr; + } +} diff --git a/public/css/global.css b/public/css/global.css new file mode 100644 index 0000000..ceb1395 --- /dev/null +++ b/public/css/global.css @@ -0,0 +1,196 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + line-height: 1.6; + background-color: #fff; + color: #121f45; + overflow-x: hidden; +} + +.container { + width: 90%; + max-width: 1200px; + margin: 0 auto; +} + +header { + background-color: #223971; + color: white; + padding: 15px 0; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); +} + +header h1 { + font-size: 2rem; + font-weight: bold; +} + +nav { + display: flex; + justify-content: space-between; + width: 100%; +} + +nav ul { + list-style: none; + display: flex; +} + +nav ul li { + margin-right: 20px; +} + +nav ul li a { + text-decoration: none; + color: #ffc906; + font-weight: 600; + font-size: 1.1rem; + transition: color 0.3s ease; +} + +nav ul li a:hover { + color: white; +} + +.signin-btn { + background-color: #ffc906; + color: #121f45; + padding: 10px 20px; + font-size: 1rem; + border: none; + border-radius: 5px; + text-decoration: none; + transition: background-color 0.3s ease; +} + +.section { + padding: 60px 0; + text-align: center; + background-color: #f9f9f9; +} + +.section h2 { + font-size: 2.8rem; + margin-bottom: 20px; + font-weight: bold; + color: #223971; +} + +.section p { + font-size: 1.2rem; + margin-bottom: 30px; +} + +.team-list, .event-list, .driver-list, .car-list, .track-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 30px; + margin-top: 30px; +} + +.team-item, .event-item, .driver-item, .car-item, .track-item { + background-color: #fff; + padding: 20px; + border-radius: 10px; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.team-item:hover, .event-item:hover, .driver-item:hover, .car-item:hover, .track-item:hover { + transform: translateY(-5px); + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15); +} + +.team-item h3, .event-item h3, .driver-item h3, .car-item h3, .track-item h3 { + font-size: 1.8rem; + margin-bottom: 10px; + color: #223971; +} + +.team-item p, .event-item p, .driver-item p, .car-item p, .track-item p { + font-size: 1.1rem; + margin: 5px 0; + color: #121f45; +} + +.team-item strong, .event-item strong, .driver-item strong, .car-item strong, .track-item strong { + font-weight: bold; +} + +.team-item .team-headquarters, .team-item .team-principal, +.event-item .event-status, .event-item .event-date, +.driver-item .driver-stats, .driver-item .driver-info, +.track-item .track-length, .track-item .track-continent { + margin-top: 10px; + font-size: 1.2rem; + font-weight: bold; + color: #223971; +} + +.search-box { + width: 100%; + padding: 10px; + margin-bottom: 20px; + font-size: 1rem; + border: 1px solid #ccc; + border-radius: 5px; + box-sizing: border-box; +} + +.search-box:focus { + outline: none; + border-color: #223971; +} + +.pagination { + display: flex; + justify-content: center; + margin-top: 20px; +} + +.page-btn { + padding: 10px 15px; + margin: 0 5px; + background-color: #223971; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.page-btn:hover { + background-color: #3a5a80; +} + +@media (max-width: 768px) { + .team-list, .event-list, .driver-list, .car-list, .track-list { + grid-template-columns: 1fr 1fr; + } +} + +@media (max-width: 480px) { + .team-list, .event-list, .driver-list, .car-list, .track-list { + grid-template-columns: 1fr; + } +} + +footer { + background-color: #121f45; + color: white; + padding: 20px 0; + text-align: center; + margin-top: 40px; +} + +footer p { + font-size: 1rem; +} diff --git a/public/driversPage.php b/public/driversPage.php new file mode 100644 index 0000000..ae1003d --- /dev/null +++ b/public/driversPage.php @@ -0,0 +1,135 @@ + + + + + + Formula 1 Drivers + + + + +
+
+

Formula 1 Drivers

+ +
+
+
+
+

Formula 1 Drivers

+

Meet the drivers of Formula 1 and learn more about their careers and achievements.

+ +
+ +
+
+
+
+

© 2024 Formula 1 Center. All Rights Reserved.

+
+
+ + diff --git a/public/eventsPage.php b/public/eventsPage.php new file mode 100644 index 0000000..6377dd4 --- /dev/null +++ b/public/eventsPage.php @@ -0,0 +1,116 @@ + + + + + + Formula 1 Events + + + + +
+
+

Formula 1 Events

+ +
+
+
+
+

Formula 1 Events

+

Stay up to date with the latest Formula 1 events around the world.

+ +
+ +
+
+
+
+

© 2024 Formula 1 Center. All Rights Reserved.

+
+
+ + diff --git a/public/images/betterracing.jpg b/public/images/betterracing.jpg new file mode 100644 index 0000000..0f4fea0 Binary files /dev/null and b/public/images/betterracing.jpg differ diff --git a/public/images/charles-leclerc.jpg b/public/images/charles-leclerc.jpg new file mode 100644 index 0000000..182f499 Binary files /dev/null and b/public/images/charles-leclerc.jpg differ diff --git a/public/images/cooltrack.jpg b/public/images/cooltrack.jpg new file mode 100644 index 0000000..7d62eba Binary files /dev/null and b/public/images/cooltrack.jpg differ diff --git a/public/images/f1car.jpg b/public/images/f1car.jpg new file mode 100644 index 0000000..935a656 Binary files /dev/null and b/public/images/f1car.jpg differ diff --git a/public/images/lewis-hamilton.jpg b/public/images/lewis-hamilton.jpg new file mode 100644 index 0000000..9a27975 Binary files /dev/null and b/public/images/lewis-hamilton.jpg differ diff --git a/public/images/max-verstappen.jpg b/public/images/max-verstappen.jpg new file mode 100644 index 0000000..74381f9 Binary files /dev/null and b/public/images/max-verstappen.jpg differ diff --git a/public/images/monaco.jpg b/public/images/monaco.jpg new file mode 100644 index 0000000..3a25fc1 Binary files /dev/null and b/public/images/monaco.jpg differ diff --git a/public/images/racing.jpg b/public/images/racing.jpg new file mode 100644 index 0000000..84738dc Binary files /dev/null and b/public/images/racing.jpg differ diff --git a/public/images/silverstone.jpg b/public/images/silverstone.jpg new file mode 100644 index 0000000..db29153 Binary files /dev/null and b/public/images/silverstone.jpg differ diff --git a/public/images/suzuka.jpg b/public/images/suzuka.jpg new file mode 100644 index 0000000..f34d56e Binary files /dev/null and b/public/images/suzuka.jpg differ diff --git a/public/mainPage.php b/public/mainPage.php new file mode 100644 index 0000000..f441b41 --- /dev/null +++ b/public/mainPage.php @@ -0,0 +1,120 @@ + + + + + + F1 Center + + + +
+
+

F1 Center

+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+

F1 Tracks

+

Discover iconic F1 race tracks around the world.

+
+
+ Silverstone Circuit +

Silverstone Circuit

+

Location: Northamptonshire, UK

+

The iconic British Grand Prix is a must-watch!

+
+
+ Monaco Grand Prix +

Monaco Grand Prix

+

Location: Monte Carlo, Monaco

+

One of the most prestigious and historic F1 races.

+
+
+ Suzuka Circuit +

Suzuka Circuit

+

Location: Suzuka, Japan

+

Famous for its challenging and fast layout.

+
+
+ See All Tracks +
+
+
+
+

Meet the F1 Drivers

+

Get to know the stars of Formula 1!

+
+
+ Lewis Hamilton +

Lewis Hamilton

+

Team: Mercedes

+

Nationality: British

+

World Championships: 7

+
+
+ Max Verstappen +

Max Verstappen

+

Team: Red Bull Racing

+

Nationality: Dutch

+

World Championships: 2

+
+
+ Charles Leclerc +

Charles Leclerc

+

Team: Ferrari

+

Nationality: Monegasque

+

World Championships: 0

+
+
+ See All Drivers +
+
+
+
+

© 2024 F1 Center. All Rights Reserved.

+
+
+ + + diff --git a/public/teamsPage.php b/public/teamsPage.php new file mode 100644 index 0000000..28da0b9 --- /dev/null +++ b/public/teamsPage.php @@ -0,0 +1,119 @@ + + + + + + Formula 1 Teams + + + + +
+
+

Formula 1 Teams

+ +
+
+
+
+

Formula 1 Teams

+

Discover the top teams competing in Formula 1.

+ +
+ +
+
+
+
+

© 2024 Formula 1 Center. All Rights Reserved.

+
+
+ + diff --git a/public/tracksPage.php b/public/tracksPage.php new file mode 100644 index 0000000..31939ef --- /dev/null +++ b/public/tracksPage.php @@ -0,0 +1,118 @@ + + + + + + Formula 1 Tracks + + + + +
+
+

Formula 1 Tracks

+ +
+
+
+
+

F1 Tracks

+

Explore the iconic Formula 1 tracks from around the world.

+ +
+ +
+
+ + +