diff --git a/ProjectSourceCode/src/index.js b/ProjectSourceCode/src/index.js
index c54a6c7..4bc8a8f 100644
--- a/ProjectSourceCode/src/index.js
+++ b/ProjectSourceCode/src/index.js
@@ -78,19 +78,51 @@ app.use(
app.use(express.static(path.join(__dirname, 'resources')));
// *****************************************************
-//
+//
// *****************************************************
-/************************
- Header Scoreboard Routes
-*************************/
-
-const fetchMatchesData = require('./resources/routes/navigation-bar/current-match-information');
+// Middleware to automatically update live scoreboard
+const fetchMatchesData = require('./resources/middleware/navigation-bar/current-match-information');
app.use(fetchMatchesData);
-const convert_time = require('./resources/js/navigation-bar/scoreboard-header/convert-time');
+//Middleware to automatically update in-game time abbreviations
+
+const convert_time = require('./resources/middleware/navigation-bar/convert-time');
app.use(convert_time);
+
+// Leagues Page Middleware
+
+const fetchLeaguesData = require('./resources/middleware/leagues-page/get-current-league-information');
+const fetchLeagueScorerData = require('./resources/middleware/leagues-page/get-current-league-top-scorers');
+
+app.get('/league/:leagueID', [fetchLeaguesData, fetchLeagueScorerData], (req, res) => {
+ // Render the Handlebars view with league data
+ res.render('pages/leagues-page', {
+ leagueID: req.params.leagueID,
+ leagues: res.locals.leagues,
+ scorers: res.locals.topScorers // Assuming fetchLeagueScorerData sets the data in res.locals.scorers
+ });
+});
+
+// Clubs Page Middleware
+
+const fetchClubsData = require('./resources/middleware/clubs-page/get-current-club-information');
+
+app.get('/club/:clubID', [fetchClubsData], (req, res) => {
+ // Render the Handlebars view with league data
+ res.render('pages/clubs-page', {
+ clubID: req.params.clubID,
+ clubs: res.locals.club
+ });
+});
+
+
+
+// *****************************************************
+//
+// *****************************************************
+
/************************
Login Page Routes
*************************/
@@ -98,91 +130,99 @@ app.use(convert_time);
// Redirect to the /login endpoint
app.get('/', (req, res) => {
res.redirect('/home');
- });
+});
- // Render login page for /login route
- app.get('/login', (req, res) => {
+// Render login page for /login route
+app.get('/login', (req, res) => {
res.render('pages/home');
- });
+});
- // Trigger login form to check database for matching username and password
- app.post('/login', async (req, res) => {
+// Trigger login form to check database for matching username and password
+app.post('/login', async (req, res) => {
try {
+ // Check if username exists in DB
+ const user = await db.oneOrNone('SELECT * FROM users WHERE username = $1', req.body.username);
- // Check if username exists in DB
- const user = await db.oneOrNone('SELECT * FROM users WHERE username = $1', req.body.username);
+ if (!user) {
+ // Redirect user to login screen if no user is found with the provided username
+ return res.redirect('/register');
+ }
- if (!user) {
- // Redirect user to login screen if no user is found with the provided username
- return res.redirect('/register');
- }
+ // Check if password from request matches with password in DB
+ const match = await bcrypt.compare(req.body.password, user.password);
- // Check if password from request matches with password in DB
- const match = await bcrypt.compare(req.body.password, user.password);
+ // Check if match returns no data
+ if (!match) {
+ // Render the login page with the message parameter
+ return res.render('pages/home', { message: 'Password does not match' });
+ }
- // Check if mathc returns no data
- if (!match) {
- // Render the login page with the message parameter
- return res.render('pages/home', { message: 'Password does not match' });
- }
+ // Save user information in the session variable
+ req.session.user = user;
+ req.session.save();
- // Save user information in the session variable
- req.session.user = user;
- req.session.save();
-
- // Redirect user to the home page
- res.redirect('/home');
-
+ // Redirect user to the home page
+ res.redirect('/home');
} catch (error) {
- // Direct user to login screen if no user is found with matching password
- res.redirect('/register');
+ // Direct user to login screen if no user is found with matching password
+ res.redirect('/register');
}
- });
+});
- /************************
- Registration Page Routes
- *************************/
+/************************
+ Registration Page Routes
+*************************/
- // Render registration page for /register route
- app.get('/register', (req, res) => {
+// Render registration page for /register route
+app.get('/register', (req, res) => {
res.render('pages/register');
- });
-
+});
// Trigger Registration Form to Post
app.post('/register', async (req, res) => {
- try {
- if (!req.body.username || !req.body.password) {
- // If username or password is missing, respond with status 400 and an error message
- return res.status(400).json({ status: 'error', message: 'Invalid input' });
+ try {
+ if (!req.body.username || !req.body.password) {
+ // If username or password is missing, respond with status 400 and an error message
+ return res.status(400).json({ status: 'error', message: 'Invalid input' });
+ }
+ // Hash the password using bcrypt library
+ const hash = await bcrypt.hash(req.body.password, 10);
+
+ // Insert username and hashed password into the 'users' table
+ await db.none('INSERT INTO users (username, password) VALUES ($1, $2)', [req.body.username, hash]);
+
+ // Redirect user to the login page after successful registration
+ res.status(200).json({ status: 'success', message: 'Registration successful' });
+ } catch (error) {
+ // If an error occurs during registration, respond with status 500 and an error message
+ res.status(500).json({ status: 'error', message: 'An error occurred during registration' });
}
- // Hash the password using bcrypt library
- const hash = await bcrypt.hash(req.body.password, 10);
-
- // Insert username and hashed password into the 'users' table
- await db.none('INSERT INTO users (username, password) VALUES ($1, $2)', [req.body.username, hash]);
-
- // Redirect user to the login page after successful registration
- res.status(200).json({ status: 'success', message: 'Registration successful' });
- } catch (error) {
- // If an error occurs during registration, respond with status 500 and an error message
- res.status(500).json({ status: 'error', message: 'An error occurred during registration' });
- }
});
-
/************************
Home Page Routes
*************************/
app.get('/home', (req, res) => {
- res.render('pages/home');
+ res.render('pages/home');
});
+/************************
+ League Page Routes
+*************************/
+
// Import and call generateLeagueRoutes function
const generateLeagueRoutes = require('./resources/routes/league-pages/generate-league-routes');
generateLeagueRoutes(app);
+/************************
+ Club Page Routes
+*************************/
+
+// Import and call generateLeagueRoutes function
+const generateClubRoutes = require('./resources/routes/club-pages/generate-club-routes');
+generateClubRoutes(app);
+
// *****************************************************
//
// *****************************************************
diff --git a/ProjectSourceCode/src/resources/css/all-pages-style.css b/ProjectSourceCode/src/resources/css/all-pages-style.css
new file mode 100644
index 0000000..ac4d128
--- /dev/null
+++ b/ProjectSourceCode/src/resources/css/all-pages-style.css
@@ -0,0 +1,5 @@
+body {
+ /* background-image: url('./../img/grass-background.png'); Specify the path to your background image */
+ /* background-repeat: repeat; Set the background image to repeat both horizontally and vertically */
+ /* background-size: 1000px; Set the size of the background image for each repeat */
+}
\ No newline at end of file
diff --git a/ProjectSourceCode/src/resources/css/club-pages/club-page.css b/ProjectSourceCode/src/resources/css/club-pages/club-page.css
new file mode 100644
index 0000000..61433d8
--- /dev/null
+++ b/ProjectSourceCode/src/resources/css/club-pages/club-page.css
@@ -0,0 +1,66 @@
+#club-page-body {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+}
+
+#club-information-container {
+ height: 100px;
+ width: fit-content;
+ margin: 20px;
+ background: linear-gradient(to right, white, rgb(245, 245, 245), rgb(227, 227, 227)); /* Gradient from white to gray */
+ padding: 10px 20px; /* Adjust padding as needed */
+ transform: skewX(-20deg); /* Skew the banner to create a triangular side */
+ cursor: pointer; /* Change cursor to pointer on hover */
+ box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.4);
+
+ display: flex; /* Use flexbox for layout */
+ align-items: center; /* Center content vertically */
+
+ /* Add any other styling you need for the club information container */
+}
+
+#club-information-container::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: 8px; /* Width of the red strip */
+ background-color: red; /* Red color */
+ }
+
+#club-logo {
+ margin: 0px 30px;
+ transform: skewX(20deg); /* Skew the banner to create a triangular side */
+}
+
+#club-title {
+ transform: skewX(20deg); /* Skew the banner to create a triangular side */
+ margin-right: 20px;
+}
+
+#club-flag {
+
+ transform: skewX(20deg); /* Skew the banner to create a triangular side */
+ height: 20px;
+ margin-right: 200px;
+}
+
+#club-stats-container {
+ width: 100%;
+ display: flex;
+ flex: 1;
+}
+
+#club-stats-container .container {
+ margin: 0 10px;
+
+ background-color: #eaeaea; /* Example background color */
+
+ border: 1px solid gray;
+ border-radius: 8px;
+
+ box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.4);
+ /* Add any other styling you need for the club table container */
+}
diff --git a/ProjectSourceCode/src/resources/css/club-pages/club-top-scorers.css b/ProjectSourceCode/src/resources/css/club-pages/club-top-scorers.css
new file mode 100644
index 0000000..2d62b21
--- /dev/null
+++ b/ProjectSourceCode/src/resources/css/club-pages/club-top-scorers.css
@@ -0,0 +1,6 @@
+#club-top-scorers-container {
+ flex: 1;
+ background-color: #dcdcdc; /* Example background color */
+ width: 40%;
+ /* Add any other styling you need for the top scorers container */
+}
diff --git a/ProjectSourceCode/src/resources/routes/league-pages/get-current-league-information.js b/ProjectSourceCode/src/resources/css/club-pages/players-table.css
similarity index 100%
rename from ProjectSourceCode/src/resources/routes/league-pages/get-current-league-information.js
rename to ProjectSourceCode/src/resources/css/club-pages/players-table.css
diff --git a/ProjectSourceCode/src/resources/css/league-page/league-page.css b/ProjectSourceCode/src/resources/css/league-page/league-page.css
deleted file mode 100644
index 38a1182..0000000
--- a/ProjectSourceCode/src/resources/css/league-page/league-page.css
+++ /dev/null
@@ -1,28 +0,0 @@
-#league-page-body {
- display: flex;
- flex-direction: column;
- height: 100vh;
-}
-
-#league-information-container {
- height: 100px;
- background-color: #f0f0f0; /* Example background color */
- /* Add any other styling you need for the league information container */
-}
-
-#league-stats-container {
- display: flex;
- flex: 1;
-}
-
-#league-table-container {
- flex: 1;
- background-color: #eaeaea; /* Example background color */
- /* Add any other styling you need for the league table container */
-}
-
-#top-scorers-container {
- flex: 1;
- background-color: #dcdcdc; /* Example background color */
- /* Add any other styling you need for the top scorers container */
-}
diff --git a/ProjectSourceCode/src/resources/css/league-pages/league-page.css b/ProjectSourceCode/src/resources/css/league-pages/league-page.css
new file mode 100644
index 0000000..37a9204
--- /dev/null
+++ b/ProjectSourceCode/src/resources/css/league-pages/league-page.css
@@ -0,0 +1,142 @@
+/*
+==============================================================
+ OVERALL PAGE STYLES
+==============================================================
+*/
+
+#league-page-body
+{
+ /* --- SIZE CONTAINER --- */
+ width: 100%; /* Set the width to the full width of screen */
+ padding: 10px 100px; /* Create some distance between page boundries and elements */
+
+ /* --- FORMAT CHILD ITEMS (Table and Leading Scorers Cards) --- */
+ display: flex; /* Enable flexbox layout */
+ flex-direction: column; /* Arrange child elements vertically */
+}
+
+/*
+=================================
+ LEAGUE INFORMATION HEADER
+=================================
+*/
+
+/* Stylization for League Information Header Card */
+#league-information-container
+{
+ /* --- POSITION CONTAINER --- */
+ align-items: center; /* Center content vertically */
+ margin: 20px;
+
+ /* --- SIZE CONTAINER --- */
+ height: 100px;
+ width: fit-content;
+ padding: 10px 20px; /* Adjust padding as needed */
+
+ /* --- STYLE CONTAINER --- */
+ background: linear-gradient(to right, white, rgb(245, 245, 245), rgb(227, 227, 227)); /* Gradient from white to gray */
+ transform: skewX(-20deg); /* Skew the banner to create a triangular side */
+ box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.4);
+
+ /* --- FORMAT CHILD ITEMS (logo, league name, flag) --- */
+ display: flex; /* Enable flexbox layout */
+ flex-direction: row; /* Arrange child elements horizontally */
+}
+
+ /*
+ ===========================
+ LEAGUE INFORMATION CHILD ITEMS
+ ===========================
+ */
+
+ /* Adds Red Diagonal Strip at the end of the #league-information-container */
+ #league-information-container::after
+ {
+ content: '';
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: 8px; /* Width of the red strip */
+ background-color: red; /* Red color */
+ }
+
+ /* Styling for League Logo in League Information Header */
+ #league-logo
+ {
+ margin: 0px 30px;
+ transform: skewX(20deg); /* Skew the banner to create a triangular side */
+ height: 80%;
+ }
+
+ /* Styling for League Title in League Information Header */
+ #league-title
+ {
+ transform: skewX(20deg); /* Skew the banner to create a triangular side */
+ margin-right: 20px;
+ }
+
+ /* Styling for FLag in League Information Header */
+ #league-flag
+ {
+ transform: skewX(20deg); /* Skew the banner to create a triangular side */
+ height: 20px;
+ margin-right: 200px;
+ }
+
+/*
+=============================================
+ CARDS IN PAGE BODY
+=============================================
+*/
+
+#table-and-top-scorers-containers {
+ display: flex;
+ flex-direction: row;
+}
+
+/* Styling for Standings and Top Scorers Cards */
+#table-stats-container, #top-scorers-stats-container
+{
+ /* --- POSITION CONTAINER --- */
+ margin: 0 10px;
+ margin-bottom: 20px;
+
+ /* --- SIZE CONTAINER --- */
+ padding: 15px;
+
+ /* --- STYLE CONTAINER --- */
+ background: linear-gradient(to top, rgb(216, 216, 216), rgb(236, 236, 236), rgb(241, 240, 240));
+ border: 1px solid gray;
+ box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.5);
+}
+
+/*
+==============================================================
+ HOVER STYLES
+==============================================================
+*/
+
+ /* Hover Styling for Standings and Top Scorers Cards */
+ #table-stats-container:hover, #top-scorers-stats-container:hover
+ {
+ transform: scale(1.01); /* Scale the row by 1.1 on hover */
+ box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.3);
+ }
+
+/*
+==============================================================
+ DYNAMIC PAGE WIDTH STYLES
+==============================================================
+*/
+
+/* Width of Screen is Less Than 950px */
+@media (max-width: 1230px)
+{
+ #table-and-top-scorers-containers {
+ display: flex;
+ flex-direction: column;
+ }
+}
+
+
\ No newline at end of file
diff --git a/ProjectSourceCode/src/resources/css/league-pages/league-table.css b/ProjectSourceCode/src/resources/css/league-pages/league-table.css
new file mode 100644
index 0000000..60f6ea2
--- /dev/null
+++ b/ProjectSourceCode/src/resources/css/league-pages/league-table.css
@@ -0,0 +1,130 @@
+/*
+=================================
+ TABLE ADN HEADER CONTAINER
+=================================
+*/
+
+/* Container for table and header */
+#league-table-container
+{
+ width: 60%;
+ justify-content: center;
+ align-items: center;
+
+ margin-right: 30px;
+
+ transition: transform 0.3s ease; /* Add smooth transition effect */
+}
+
+/*
+=================================
+ TABLE CONTAINER
+=================================
+*/
+
+/* Container for Table */
+#table-stats-container
+{
+ width: 100%;
+}
+
+/* Table that holds all the standing information */
+#standings-table
+{
+ width: 100%;
+ padding: 15px;
+
+ /* Table Header Styling */
+ th
+ {
+ border-bottom: 3px solid red; /* Add red bottom border */
+ }
+
+ /* Data in Row Style */
+ td
+ {
+ padding: 5px;
+ }
+
+ /* Every Odd Row in Table Style */
+ tbody tr:nth-child(odd)
+ {
+ background-color: #d2d2d2; /* Light gray for odd rows */
+ }
+}
+
+ /*
+ ===========================
+ TABLE COLUMNS STYLE
+ ===========================
+ */
+
+ /* Club Logo Column in Table Style */
+ #club-logo-column {
+ width: 25px;
+
+ /* Club Logo Style */
+ #table-club-logo
+ {
+ width: 25px;
+ margin-right: 5px;
+ cursor: pointer;
+ }
+
+ }
+
+ /* Club Name Column in Table Style */
+ #club-name-column
+ {
+ font-weight: 500;
+ cursor: pointer;
+ }
+
+ /* Points Column in Table Style */
+ #points-column
+ {
+ font-weight: bolder;
+ }
+
+/*
+==============================================================
+ HOVER STYLES
+==============================================================
+*/
+
+/* Add hover effect to table rows */
+#standings-table tbody tr:hover
+{
+ /* Create border around row on hover */
+ border: 1px solid lightgray;
+ border-radius: 10px;
+
+ /* Make club logo larger on hover */
+ #table-club-logo
+ {
+ width: 32px;
+ }
+
+ /* Undeline club name on hover */
+ #club-name-column
+ {
+ text-decoration: underline; /* Add underline effect */
+ }
+}
+
+/*
+==============================================================
+ DYNAMIC PAGE WIDTH STYLES
+==============================================================
+*/
+
+/* Stlye for Screens Smaller than 1230px */
+@media (max-width: 1230px)
+{
+ #league-table-container
+ {
+ align-items: center;
+ width: 75%;
+ min-width: 580px;
+ }
+}
\ No newline at end of file
diff --git a/ProjectSourceCode/src/resources/css/league-pages/top-scorers.css b/ProjectSourceCode/src/resources/css/league-pages/top-scorers.css
new file mode 100644
index 0000000..03eacea
--- /dev/null
+++ b/ProjectSourceCode/src/resources/css/league-pages/top-scorers.css
@@ -0,0 +1,96 @@
+/*
+=================================
+ TABLE ADN HEADER CONTAINER
+=================================
+*/
+
+#top-scorers-container
+{
+ width: 40%;
+}
+
+#top-scorers-stats-container {
+
+ /* Table Header Styling */
+ th
+ {
+ border-bottom: 3px solid red; /* Add red bottom border */
+ }
+
+ tr
+ {
+ padding: 3px;
+ }
+
+ /* Data in Row Style */
+ td
+ {
+ padding: 5px;
+ }
+}
+
+ /*
+ ===========================
+ TABLE COLUMNS STYLE
+ ===========================
+ */
+
+ #goals-column
+ {
+ text-align: center;
+ font-size: 20px;
+ font-weight: bolder;
+ }
+
+ #top-scorers-logo
+ {
+ width: 25px;
+ margin: 0 15px;
+ cursor: pointer;
+ }
+
+ #player-name-column
+ {
+
+ font-size: 14px;
+ font-weight: bold;
+ padding-right: 15px;
+ }
+
+ #club-name-column
+ {
+ padding-right: 15px;
+ }
+
+/*
+==============================================================
+ HOVER STYLES
+==============================================================
+*/
+
+#top-scorers-stats-container tbody tr:hover
+{
+
+ border: 1px solid lightgray;
+
+ #top-scorers-logo {
+ width: 32px;
+ }
+
+ #club-name-column {
+ text-decoration: underline;
+ }
+}
+
+/*
+==============================================================
+ DYNAMIC PAGE WIDTH STYLES
+==============================================================
+*/
+
+@media (max-width: 1230px) {
+ #top-scorers-container {
+ align-items: center;
+ width: 75%;
+ }
+}
\ No newline at end of file
diff --git a/ProjectSourceCode/src/resources/img/grass-background.jpeg b/ProjectSourceCode/src/resources/img/grass-background.jpeg
new file mode 100644
index 0000000..620ec2c
Binary files /dev/null and b/ProjectSourceCode/src/resources/img/grass-background.jpeg differ
diff --git a/ProjectSourceCode/src/resources/img/grass-background.png b/ProjectSourceCode/src/resources/img/grass-background.png
new file mode 100644
index 0000000..32ced85
Binary files /dev/null and b/ProjectSourceCode/src/resources/img/grass-background.png differ
diff --git a/ProjectSourceCode/src/resources/js/homepage/redirect-to-league-url.js b/ProjectSourceCode/src/resources/js/homepage/redirect-to-league-url.js
deleted file mode 100644
index a9445ef..0000000
--- a/ProjectSourceCode/src/resources/js/homepage/redirect-to-league-url.js
+++ /dev/null
@@ -1,7 +0,0 @@
-function redirectToLeaguePage(leagueName) {
- // Append the league name to the URL
- var url = "/league/" + leagueName.toLowerCase().replace(/\s+/g, '-');
-
- // Redirect to the league page
- window.location.href = url;
-}
\ No newline at end of file
diff --git a/ProjectSourceCode/src/resources/js/league-page/change-goal-difference-color.js b/ProjectSourceCode/src/resources/js/league-page/change-goal-difference-color.js
new file mode 100644
index 0000000..a4e764a
--- /dev/null
+++ b/ProjectSourceCode/src/resources/js/league-page/change-goal-difference-color.js
@@ -0,0 +1,29 @@
+document.addEventListener("DOMContentLoaded", function() {
+ var goalDifferenceCells = document.querySelectorAll("#goal-difference-column"); // Selecting the cells in the goal_difference column
+
+ goalDifferenceCells.forEach(function(cell) {
+ var goalDifference = parseInt(cell.textContent);
+ var color;
+
+ if (goalDifference < 0)
+ {
+ // Gradually darken the text color for negative goal differences
+ var darkenFactor = Math.ceil(goalDifference / -10); // Calculate the darken factor
+ var shade = Math.max(0, 255 - darkenFactor * 25); // Calculate the shade of red
+ color = "rgb(" + shade + ", 0, 0)"; // Create the color value
+ }
+ else if (goalDifference > 0)
+ {
+ // Gradually darken the text color for positive goal differences
+ var darkenFactor = Math.floor(goalDifference / 10); // Calculate the darken factor
+ var shade = Math.max(0, 155 - darkenFactor * 15); // Adjusted the starting point to make greens darker
+ color = "rgb(0, " + shade + ", 0)"; // Create the color value
+ }
+ else
+ {
+ color = "inherit"; // If goal difference is 0, leave text color unchanged
+ }
+
+ cell.style.color = color; // Apply the calculated color
+ });
+});
diff --git a/ProjectSourceCode/src/resources/middleware/clubs-page/get-current-club-information.js b/ProjectSourceCode/src/resources/middleware/clubs-page/get-current-club-information.js
new file mode 100644
index 0000000..c28ec43
--- /dev/null
+++ b/ProjectSourceCode/src/resources/middleware/clubs-page/get-current-club-information.js
@@ -0,0 +1,75 @@
+const axios = require('axios');
+
+// Middleware function to fetch clubs data
+const fetchClubsData = async (req, res, next) => {
+ try {
+ // Extract club ID from the URL
+ const clubID = req.params.clubID;
+
+ // Make GET request to the API endpoint using the club ID
+ const response = await axios.get(`http://api.football-data.org/v4/teams/${clubID}/?offset=&limit=`, {
+ headers: {
+ 'X-Auth-Token': '0aa1ed31245d4a36b1ef5a79150324b3', // Add your API key here
+ },
+ });
+
+ // Extract relevant data from the API response
+ const clubData = response.data;
+
+ // Attach the data to res.locals
+ res.locals.club = {
+ area: {
+ id: clubData.area.id,
+ name: clubData.area.name,
+ code: clubData.area.code,
+ club_flag: clubData.area.flag,
+ },
+ club_id: clubData.id,
+ name: clubData.name,
+ shortName: clubData.shortName,
+ tla: clubData.tla,
+ crest: clubData.crest,
+ address: clubData.address,
+ website: clubData.website,
+ founded: clubData.founded,
+ clubColors: clubData.clubColors,
+ venue: clubData.venue,
+ runningCompetitions: clubData.runningCompetitions.map(competition => ({
+ id: competition.id,
+ name: competition.name,
+ code: competition.code,
+ type: competition.type,
+ emblem: competition.emblem
+ })),
+ coach: {
+ id: clubData.coach.id,
+ firstName: clubData.coach.firstName,
+ lastName: clubData.coach.lastName,
+ name: clubData.coach.name,
+ dateOfBirth: clubData.coach.dateOfBirth,
+ nationality: clubData.coach.nationality,
+ contract: {
+ start: clubData.coach.contract.start,
+ until: clubData.coach.contract.until
+ }
+ },
+ squad: clubData.squad.map(player => ({
+ id: player.id,
+ name: player.name,
+ position: player.position,
+ dateOfBirth: player.dateOfBirth,
+ nationality: player.nationality
+ })),
+ staff: clubData.staff,
+ lastUpdated: clubData.lastUpdated
+ };
+
+ next();
+ } catch (error) {
+ console.error('Error fetching clubs data:', error);
+ res.locals.club = null; // Set to null if there's an error
+ next(); // Call next middleware or route handler
+ }
+};
+
+module.exports = fetchClubsData;
diff --git a/ProjectSourceCode/src/resources/middleware/clubs-page/get-current-club-top-scorers.js b/ProjectSourceCode/src/resources/middleware/clubs-page/get-current-club-top-scorers.js
new file mode 100644
index 0000000..91caaad
--- /dev/null
+++ b/ProjectSourceCode/src/resources/middleware/clubs-page/get-current-club-top-scorers.js
@@ -0,0 +1,44 @@
+const axios = require('axios');
+
+// Middleware function to fetch leagues data
+const fetchLeagueScorerData = async (req, res, next) => {
+ try {
+ // Extract league ID from the URL
+ const leagueID = req.params.leagueID;
+
+ // Make GET request to the API endpoint using the league ID
+ const response = await axios.get(`http://api.football-data.org/v4/competitions/${leagueID}/scorers?season&limit=20`, {
+ headers: {
+ 'X-Auth-Token': '0aa1ed31245d4a36b1ef5a79150324b3', // Add your API key here
+ },
+ });
+
+ // Extract relevant data from the API response
+ const scorerData = response.data;
+
+ // Attach the data to res.locals
+ res.locals.topScorers = {
+ scorers: scorerData.scorers.map(player => ({
+ player: {
+ player_id: player.player.id,
+ player_name: player.player.name,
+ },
+ team: {
+ team_id: player.player.id,
+ team_name: player.team.name,
+ team_crest: player.team.crest,
+ },
+ games_played: player.playedMatches,
+ goals: player.goals,
+ }))
+ };
+
+ next();
+ } catch (error) {
+ console.error('Error fetching leagues data:', error);
+ res.locals.topScorers = null; // Set to null if there's an error
+ next(); // Call next middleware or route handler
+ }
+};
+
+module.exports = fetchLeagueScorerData;
diff --git a/ProjectSourceCode/src/resources/middleware/leagues-page/get-current-league-information.js b/ProjectSourceCode/src/resources/middleware/leagues-page/get-current-league-information.js
new file mode 100644
index 0000000..09eaf0f
--- /dev/null
+++ b/ProjectSourceCode/src/resources/middleware/leagues-page/get-current-league-information.js
@@ -0,0 +1,52 @@
+const axios = require('axios');
+
+// Middleware function to fetch leagues data
+const fetchLeaguesData = async (req, res, next) => {
+ try {
+ // Extract league ID from the URL
+ const leagueID = req.params.leagueID;
+
+ // Make GET request to the API endpoint using the league ID
+ const response = await axios.get(`http://api.football-data.org/v4/competitions/${leagueID}/standings?season`, {
+ headers: {
+ 'X-Auth-Token': '0aa1ed31245d4a36b1ef5a79150324b3', // Add your API key here
+ },
+ });
+
+ // Extract relevant data from the API response
+ const leagueData = response.data;
+
+ // Attach the data to res.locals
+ res.locals.league = {
+ area: {
+ league_flag: leagueData.area.flag,
+ },
+ competition: {
+ league_id: leagueData.competition.id,
+ league_name: leagueData.competition.name,
+ league_emblem: leagueData.competition.emblem
+ },
+ standings: leagueData.standings[0].table.map(team => ({
+ table: {
+ league_position: team.position,
+ team_id: team.team.id,
+ team_name: team.team.name,
+ team_crest: team.team.crest
+ },
+ games_played: team.playedGames,
+ wins: team.won,
+ losses: team.lost,
+ draws: team.draw,
+ goal_difference: team.goalDifference,
+ points: team.points
+ }))
+ };
+ next();
+ } catch (error) {
+ console.error('Error fetching leagues data:', error);
+ res.locals.league = null; // Set to null if there's an error
+ next(); // Call next middleware or route handler
+ }
+};
+
+module.exports = fetchLeaguesData;
diff --git a/ProjectSourceCode/src/resources/middleware/leagues-page/get-current-league-top-scorers.js b/ProjectSourceCode/src/resources/middleware/leagues-page/get-current-league-top-scorers.js
new file mode 100644
index 0000000..8d8fef5
--- /dev/null
+++ b/ProjectSourceCode/src/resources/middleware/leagues-page/get-current-league-top-scorers.js
@@ -0,0 +1,44 @@
+const axios = require('axios');
+
+// Middleware function to fetch leagues data
+const fetchLeagueScorerData = async (req, res, next) => {
+ try {
+ // Extract league ID from the URL
+ const leagueID = req.params.leagueID;
+
+ // Make GET request to the API endpoint using the league ID
+ const response = await axios.get(`http://api.football-data.org/v4/competitions/${leagueID}/scorers?season&limit=20`, {
+ headers: {
+ 'X-Auth-Token': '0aa1ed31245d4a36b1ef5a79150324b3', // Add your API key here
+ },
+ });
+
+ // Extract relevant data from the API response
+ const scorerData = response.data;
+
+ // Attach the data to res.locals
+ res.locals.topScorers = {
+ scorers: scorerData.scorers.map(player => ({
+ player: {
+ player_id: player.player.id,
+ player_name: player.player.name,
+ },
+ team: {
+ team_id: player.team.id,
+ team_name: player.team.name,
+ team_crest: player.team.crest,
+ },
+ games_played: player.playedMatches,
+ goals: player.goals,
+ }))
+ };
+
+ next();
+ } catch (error) {
+ console.error('Error fetching leagues data:', error);
+ res.locals.topScorers = null; // Set to null if there's an error
+ next(); // Call next middleware or route handler
+ }
+};
+
+module.exports = fetchLeagueScorerData;
diff --git a/ProjectSourceCode/src/resources/js/navigation-bar/scoreboard-header/convert-time.js b/ProjectSourceCode/src/resources/middleware/navigation-bar/convert-time.js
similarity index 90%
rename from ProjectSourceCode/src/resources/js/navigation-bar/scoreboard-header/convert-time.js
rename to ProjectSourceCode/src/resources/middleware/navigation-bar/convert-time.js
index 7b826df..68ba8ff 100644
--- a/ProjectSourceCode/src/resources/js/navigation-bar/scoreboard-header/convert-time.js
+++ b/ProjectSourceCode/src/resources/middleware/navigation-bar/convert-time.js
@@ -9,6 +9,9 @@ const convert_time = (req, res, next) => {
if (match.minute === "FINISHED") {
match.minute = "FT";
}
+ else if (match.minute === "IN_PLAY") {
+ match.minute = "IP"
+ }
else if (match.minute === "TIMED") {
match.minute = "TM";
}
diff --git a/ProjectSourceCode/src/resources/routes/navigation-bar/current-match-information.js b/ProjectSourceCode/src/resources/middleware/navigation-bar/current-match-information.js
similarity index 100%
rename from ProjectSourceCode/src/resources/routes/navigation-bar/current-match-information.js
rename to ProjectSourceCode/src/resources/middleware/navigation-bar/current-match-information.js
diff --git a/ProjectSourceCode/src/resources/routes/club-pages/generate-club-routes.js b/ProjectSourceCode/src/resources/routes/club-pages/generate-club-routes.js
new file mode 100644
index 0000000..c3ea81c
--- /dev/null
+++ b/ProjectSourceCode/src/resources/routes/club-pages/generate-club-routes.js
@@ -0,0 +1,18 @@
+const express = require('express');
+const app = express();
+
+// generate-league-routes.js
+
+// Define a function to generate league routes
+module.exports = function generateClubRoutes(app) {
+ // Define a route to handle requests to "/league/:leagueName"
+ app.get('/club/:clubID', (req, res) => {
+ // Extract the league name from the URL parameters
+ const clubID = req.params.clubID;
+
+ // Render the league page template using Handlebars
+ res.render('pages/club-page', { clubID: clubID });
+ });
+};
+
+
diff --git a/ProjectSourceCode/src/resources/routes/club-pages/redirect-to-club-url.js b/ProjectSourceCode/src/resources/routes/club-pages/redirect-to-club-url.js
new file mode 100644
index 0000000..408d964
--- /dev/null
+++ b/ProjectSourceCode/src/resources/routes/club-pages/redirect-to-club-url.js
@@ -0,0 +1,17 @@
+// Add click event listener to club logos
+document.querySelectorAll('#table-club-logo, #club-name, #top-scorers-logo, #club-name-column').forEach(element => {
+ element.addEventListener('click', (event) => {
+ // Get the club ID from the clicked club logo's clubID attribute
+ const clubId = element.getAttribute('clubID');
+ redirectToClubPage(clubId);
+ });
+});
+
+// Function to redirect to the club page
+function redirectToClubPage(clubID) {
+ // Append the club ID to the URL
+ var url = "/club/" + clubID;
+
+ // Redirect to the club page
+ window.location.href = url;
+}
diff --git a/ProjectSourceCode/src/resources/routes/league-pages/generate-league-routes.js b/ProjectSourceCode/src/resources/routes/league-pages/generate-league-routes.js
index 3e91ef7..8dca5e8 100644
--- a/ProjectSourceCode/src/resources/routes/league-pages/generate-league-routes.js
+++ b/ProjectSourceCode/src/resources/routes/league-pages/generate-league-routes.js
@@ -6,12 +6,12 @@ const app = express();
// Define a function to generate league routes
module.exports = function generateLeagueRoutes(app) {
// Define a route to handle requests to "/league/:leagueName"
- app.get('/league/:leagueName', (req, res) => {
+ app.get('/league/:leagueID', (req, res) => {
// Extract the league name from the URL parameters
- const leagueName = req.params.leagueName;
+ const leagueID = req.params.leagueID;
// Render the league page template using Handlebars
- res.render('pages/league-page', { leagueName: leagueName });
+ res.render('pages/leagues-page', { leagueID: leagueID });
});
};
diff --git a/ProjectSourceCode/src/resources/routes/league-pages/get-team-names-for-registry.js b/ProjectSourceCode/src/resources/routes/league-pages/get-team-names-for-registry.js
new file mode 100644
index 0000000..9f61dac
--- /dev/null
+++ b/ProjectSourceCode/src/resources/routes/league-pages/get-team-names-for-registry.js
@@ -0,0 +1,21 @@
+const axios = require('axios');
+
+const fetchTeamNames = async (selectedLeague) => {
+ try {
+ const response = await axios({
+ url: `http://api.football-data.org/v4/competitions/${selectedLeague}/teams`,
+ method: 'GET',
+ headers: {
+ 'X-Auth-Token': '0aa1ed31245d4a36b1ef5a79150324b3',
+ },
+ });
+
+ const teams = response.data.teams.map(team => team.name);
+ return teams;
+ } catch (error) {
+ console.error('Error fetching teams data:', error);
+ return [];
+ }
+};
+
+module.exports = fetchTeamNames;
diff --git a/ProjectSourceCode/src/resources/routes/league-pages/redirect-to-league-url.js b/ProjectSourceCode/src/resources/routes/league-pages/redirect-to-league-url.js
new file mode 100644
index 0000000..7200b4b
--- /dev/null
+++ b/ProjectSourceCode/src/resources/routes/league-pages/redirect-to-league-url.js
@@ -0,0 +1,7 @@
+function redirectToLeaguePage(leagueID) {
+ // Append the league name to the URL
+ var url = "/league/" + leagueID;
+
+ // Redirect to the league page
+ window.location.href = url;
+}
\ No newline at end of file
diff --git a/ProjectSourceCode/src/views/pages/clubs-page.hbs b/ProjectSourceCode/src/views/pages/clubs-page.hbs
new file mode 100644
index 0000000..8ac0445
--- /dev/null
+++ b/ProjectSourceCode/src/views/pages/clubs-page.hbs
@@ -0,0 +1,24 @@
+
diff --git a/ProjectSourceCode/src/views/pages/home.hbs b/ProjectSourceCode/src/views/pages/home.hbs
index 3659c87..3d718bf 100644
--- a/ProjectSourceCode/src/views/pages/home.hbs
+++ b/ProjectSourceCode/src/views/pages/home.hbs
@@ -3,32 +3,32 @@
-
+
{{> homepage/league-card leagueName="Premier League" logo="./img/homepage/premier-league/icon.png" title="./img/homepage/premier-league/title.png"}}
-
+
{{> homepage/league-card leagueName="La Liga" logo="./img/homepage/la-liga/icon.png" title="./img/homepage/la-liga/title.png"}}
-
+
{{> homepage/league-card leagueName="Bundesliga" logo="./img/homepage/bundesliga/icon.png" title="./img/homepage/bundesliga/title.png"}}
-
+
{{> homepage/league-card leagueName="Serie A" logo="./img/homepage/serie-a/icon.png" title="./img/homepage/serie-a/title.png"}}
-
+
{{> homepage/league-card leagueName="Ligue 1" logo="./img/homepage/ligue-1/icon.png" title="./img/homepage/ligue-1/title.png"}}
-
+
{{> homepage/league-card leagueName="Brasileirao" logo="./img/homepage/brasileirao/icon.png" title="./img/homepage/brasileirao/title.png"}}
diff --git a/ProjectSourceCode/src/views/pages/league-page.hbs b/ProjectSourceCode/src/views/pages/league-page.hbs
deleted file mode 100644
index 4a2eaf0..0000000
--- a/ProjectSourceCode/src/views/pages/league-page.hbs
+++ /dev/null
@@ -1,22 +0,0 @@
-
\ No newline at end of file
diff --git a/ProjectSourceCode/src/views/pages/leagues-page.hbs b/ProjectSourceCode/src/views/pages/leagues-page.hbs
new file mode 100644
index 0000000..1b2665d
--- /dev/null
+++ b/ProjectSourceCode/src/views/pages/leagues-page.hbs
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+
+ Club
+ GP
+ W
+ L
+ D
+ GD
+ Pts
+
+
+
+ {{#each league.standings}}
+
+ {{table.league_position}}
+
+ {{table.team_name}}
+ {{games_played}}
+ {{wins}}
+ {{losses}}
+ {{draws}}
+ {{goal_difference}}
+ {{points}}
+
+ {{/each}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Goals
+
+ Name
+ Club
+ GP
+
+
+
+ {{#each topScorers.scorers}}
+
+ {{goals}}
+
+ {{player.player_name}}
+ {{team.team_name}}
+ {{games_played}}
+
+ {{/each}}
+
+
+
+
+
+
+
diff --git a/ProjectSourceCode/src/views/partials/footer.hbs b/ProjectSourceCode/src/views/partials/footer.hbs
index 3f78c75..a9a1901 100644
--- a/ProjectSourceCode/src/views/partials/footer.hbs
+++ b/ProjectSourceCode/src/views/partials/footer.hbs
@@ -11,8 +11,11 @@
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/ProjectSourceCode/src/views/partials/head.hbs b/ProjectSourceCode/src/views/partials/head.hbs
index 3c432ff..92d27bd 100644
--- a/ProjectSourceCode/src/views/partials/head.hbs
+++ b/ProjectSourceCode/src/views/partials/head.hbs
@@ -5,7 +5,8 @@
-
+
+
@@ -22,7 +23,14 @@
-
+
+
+
+
+
+
+
+
Group 6 Final Project
diff --git a/ProjectSourceCode/src/views/partials/navigation-bar/nav.hbs b/ProjectSourceCode/src/views/partials/navigation-bar/nav.hbs
index 152d0ba..38357c1 100644
--- a/ProjectSourceCode/src/views/partials/navigation-bar/nav.hbs
+++ b/ProjectSourceCode/src/views/partials/navigation-bar/nav.hbs
@@ -15,27 +15,27 @@
diff --git a/ProjectSourceCode/src/views/partials/player-card/player-card.hbs b/ProjectSourceCode/src/views/partials/player-card/player-card.hbs
new file mode 100644
index 0000000..dc5c093
--- /dev/null
+++ b/ProjectSourceCode/src/views/partials/player-card/player-card.hbs
@@ -0,0 +1,20 @@
+
+
+
+
+
+ Player Name
+ Nationality
+ Position
+
+
+
+
+ persons.name
+ persons.nationality
+ persons.position
+
+
+
+
+
\ No newline at end of file
diff --git a/TeamMeetingLogs/minutes.txt b/TeamMeetingLogs/minutes.txt
index 51f8665..8ac0625 100644
--- a/TeamMeetingLogs/minutes.txt
+++ b/TeamMeetingLogs/minutes.txt
@@ -11,3 +11,9 @@
15 : 49 : overview of features and display of initial website
15 : 52 : discussion on database
15 : 53 : end of meeting
+
+==== Meeting 3 04/11/2024 ====
+16 : 00 : meeting start
+16 : 01 : progress check and showcase
+16 : 08 : feedback
+16 : 10 : end of meeting