This commit is contained in:
RochesterX
2025-11-28 13:54:57 -05:00
parent 881c057b6a
commit 711380db2a
11 changed files with 357 additions and 55 deletions

View File

@@ -89,6 +89,22 @@ body {
margin-top: 30px;
}
.info-container {
display: flex;
flex-direction: row;
gap: 15px
}
.info {
display: flex;
flex-direction: row;
gap: 5px;
}
.info p {
min-width: 0px;
}
form {
display: flex;
flex-direction: column;
@@ -100,6 +116,43 @@ form {
gap: 5px;
}
.success {
display: none;
filter: hue-rotate(110deg);
flex-direction: column;
align-items: center;
border: 2px solid #a34b4b;
background-color: #3a1414;
border-radius: 10px;
padding: 5px;
padding-left: 10px;
padding-right: 10px;
margin-top: -10px;
gap: 5px;
}
.success p {
color: #ff7777;
}
.error {
display: none;
flex-direction: column;
align-items: center;
border: 2px solid #a34b4b;
background-color: #3a1414;
border-radius: 10px;
padding: 5px;
padding-left: 10px;
padding-right: 10px;
margin-top: -10px;
gap: 5px;
}
.error p {
color: #ff7777;
}
.loginForm input {
margin: 5px;
}

View File

@@ -16,7 +16,6 @@ export async function postData(url, data, token = null) {
const resultObject = await res.json();
if (resultObject.logout === true) {
alert("Session expired; please log in again.");
window.location.href = "/login";
return resultObject;
}

View File

@@ -27,6 +27,13 @@
<button type="submit">Update Information</button>
</form>
<div class="error">
<p>Error Message</p>
</div>
<div class="success">
<p>Information updated successfully</p>
</div>
<a href="/home">Return Home</a>
</div>

View File

@@ -5,6 +5,11 @@ const token = window.localStorage.getItem("token");
const infoForm = document.getElementById("infoForm");
const error = document.querySelector(".error");
const errorMessage = document.querySelector(".error p");
const success = document.querySelector(".success");
async function fetchPersonalInformation() {
const userData = await postData("/getInfo", {}, token);
@@ -30,7 +35,17 @@ async function updatePersonalInformation(e) {
}
console.log(userData.dob);
const resultObject = await postData("/setInfo", userData, token);
alert(resultObject.message);
if (resultObject.message.includes("success")) {
error.style.display = "none";
success.style.display = "flex";
} else {
errorMessage.innerHTML = resultObject.message;
error.style.display = "flex";
}
window.localStorage.setItem("token", resultObject.token);
}

View File

@@ -12,6 +12,12 @@
<input type="password" id="logPass" placeholder="Password" required>
<button type="submit">Login</button>
</form>
<div class="error">
<p>Error Message</p>
</div>
<div class="success">
<p>Login successful</p>
</div>
<div class="register">
<p>Don't have an account?</p>
<a href="/register" class="link">Register</a>

View File

@@ -2,13 +2,23 @@ import { postData } from "./client.js";
const loginForm = document.getElementById("loginForm");
const error = document.querySelector(".error");
const errorMessage = document.querySelector(".error p");
const success = document.querySelector(".success");
if (loginForm) loginForm.onsubmit = async e => {
e.preventDefault();
let resultObject = await postData("/login", {
username: document.getElementById("logUser").value,
password: document.getElementById("logPass").value
});
alert(resultObject.message);
if (resultObject.message.includes("success")) {
error.style.display = "none";
success.style.display = "flex";
} else {
errorMessage.innerHTML = resultObject.message;
error.style.display = "flex";
}
if (resultObject.success) {
window.location.href = "/home"
localStorage.setItem("token", resultObject.token);

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title class="attribute-player_name">[Player name]</title>
<title class="attribute-PlayerName">[Player name]</title>
<link rel="stylesheet" href="../assets/css/style.css">
<link rel="stylesheet" href="../public/assets/css/style.css">
</head>
@@ -9,34 +9,45 @@
<div class="center">
<h2 class="attribute-PlayerName">[Player Name]</h2>
<table id="table">
<thead id="header">
<tr>
<td>Name</td>
<td>ID</td>
<td>Contract</td>
<td>Team</td>
<td>Position</td>
</tr>
</thead>
<tbody id="results">
<tr>
<td class="attribute-PlayerName">[Name]</td>
<td class="attribute-PlayerID">[ID]</td>
<td class="attribute-TotalValue format-salary">[Salary]</td>
<td class="attribute-Team">[Team]</td>
<td class="attribute-Position">[Position]</td>
</tr>
</tbody>
<div class="info-container">
<div class="info">
<p><b>Position:</b></p>
<p class="attribute-Position"></p>
</div>
<div class="info">
<p><b>Team:</b></p>
<p class="attribute-Team"></p>
</div>
<div class="info">
<p><b>Height:</b></p>
<p class="attribute-Height"></p>
</div>
<div class="info">
<p><b>Weight:</b></p>
<p class="attribute-Weight"></p>
</div>
</div>
<table id="overview">
<thead></thead>
<tbody></tbody>
</table>
<button id="watch">Watch Player</button>
<a href="#" onclick="if (history.length > 1) history.back(); else if (document.referrer) window.location.href = document.referrer; else window.location.href = '#';">Back</a>
<button id="showStats">Show Full Stats</button>
<table id="stats" style="display: none;">
<thead></thead>
<tbody></tbody>
</table>
<p id="nomatch" style="display: none;">No matches found.</p>
<button id="watch">Watch Player</button>
<br>
<a href="#" onclick="if (history.length > 1) history.back(); else if (document.referrer) window.location.href = document.referrer; else window.location.href = '#';">Back</a>
</div>
<script type="module" src="/player.js"></script>

View File

@@ -10,7 +10,16 @@ const tableBody = document.getElementById("results");
const table = document.getElementById("table");
const nomatch = document.getElementById("nomatch");
const statsTable = document.querySelector("#stats");
const statsHeader = document.querySelector("#stats thead");
const statsBody = document.querySelector("#stats tbody");
const overviewHeader = document.querySelector("#overview thead");
const overviewBody = document.querySelector("#overview tbody");
const watchButton = document.querySelector("#watch");
const showStatsButton = document.querySelector("#showStats");
//const watchlist = await postData("/getWatchlist", {}, token);
@@ -26,6 +35,13 @@ watchButton.onclick = async e => {
updateIsWatched();
}
showStatsButton.onclick = async e => {
e.preventDefault();
statsTable.style.display = statsTable.style.display == "" ? "none" : "";
showStatsButton.innerHTML = statsTable.style.display == "" ? "Hide Full Stats" : "Show Full Stats";
}
async function updateIsWatched() {
const [, , id] = window.location.pathname.split("/");
const resultObject = await postData("/isWatched", {id: id}, token);
@@ -35,15 +51,28 @@ async function updateIsWatched() {
async function populatePlayerData() {
const [, , id] = window.location.pathname.split("/");
const result = await postData("/getPlayer", { id: id }, window.localStorage.getItem("token"));
if (result.success === false) {
let resultObject = await postData("/getPlayerStats", {
playerID: id
}, token);
if (resultObject.success === false) {
console.log("Invalid ID");
window.location.href = "/search";
return;
}
const player = result.match;
for (const [attribute, value] of Object.entries(player)) {
const playerStatsObject = resultObject.matches;
let playerObjectResult = await postData("/getPlayer", {
id: id
}, token);
if (playerObjectResult.success === false) {
console.log("Invalid ID");
return;
}
const playerObject = playerObjectResult.match;
for (const [attribute, value] of Object.entries(playerObject)) {
console.log(`.attribute-${attribute}`);
document.querySelectorAll(`.attribute-${attribute}`).forEach(element => {
if (element.classList.contains("format-salary")) {
@@ -54,5 +83,100 @@ async function populatePlayerData() {
})
};
console.log(player);
createStatsTable(playerStatsObject);
createOverviewTable(playerObject);
}
async function createOverviewTable(playerObject) {
const tableHeader = overviewHeader;
const tableBody = overviewBody;
nomatch.style.display = "none"
tableHeader.innerHTML = "";
const headerRow = document.createElement("tr")
//Object.keys(resultObject.matches[0]).forEach(attribute => {
// headerRow.innerHTML += `<td>${attribute}</td>`;
//});pass_attempts, complete_pass, total_yards, total_tds, interception, receptions, receiving_yards, receiving_touchdown, rush_attempts, rushing_yards, rush_touchdown, fumble
headerRow.innerHTML += `
<td>Contract</td>
<td>APY</td>
<td>Years</td>
<td>Duration</td>
`;
tableHeader.appendChild(headerRow);
tableBody.innerHTML = "";
const row = playerObject;
const rowElement = document.createElement("tr");
//for (attribute in player) {
// row.innerHTML += `<td>${player}</td>l`;
//}
rowElement.innerHTML = `
<td>${formatSalary(row.TrueAvgPerYear * row.Years)}</td>
<td>${formatSalary(row.TrueAvgPerYear)}</td>
<td>${row.Years}</td>
<td>${row.StartYear}-${row.EndYear}</td>
`;
tableBody.appendChild(rowElement);
}
async function createStatsTable(playerObject) {
const tableHeader = statsHeader;
const tableBody = statsBody;
nomatch.style.display = "none"
tableHeader.innerHTML = "";
const headerRow = document.createElement("tr")
//Object.keys(resultObject.matches[0]).forEach(attribute => {
// headerRow.innerHTML += `<td>${attribute}</td>`;
//});pass_attempts, complete_pass, total_yards, total_tds, interception, receptions, receiving_yards, receiving_touchdown, rush_attempts, rushing_yards, rush_touchdown, fumble
headerRow.innerHTML += `
<td>Season</td>
<td>Season Type</td>
<td>Week</td>
<td>Pass Attempts</td>
<td>Complete Passes</td>
<td>Total Yards</td>
<td>Total Touchdowns</td>
<td>Interceptions</td>
<td>Receptions</td>
<td>Recieving Yards</td>
<td>Receiving Touchdowns</td>
<td>Rush Attempts</td>
<td>Rushing Yards</td>
<td>Rushing Touchdowns</td>
<td>Rushing Touchdowns</td>
<td>Fumbles</td>
`;
tableHeader.appendChild(headerRow);
tableBody.innerHTML = "";
playerObject.forEach(row => {
const rowElement = document.createElement("tr");
//for (attribute in player) {
// row.innerHTML += `<td>${player}</td>l`;
//}
rowElement.innerHTML = `
<td><a href="/player/${row.PlayerID}">${row.PlayerName}</a></td>
<td>${row.Season}</td>
<td>${row.SeasonType}</td>
<td>${row.Week}</td>
<td>${row.pass_attempts}</td>
<td>${row.complete_pass}</td>
<td>${row.total_yards}</td>
<td>${row.total_tds}</td>
<td>${row.interception}</td>
<td>${row.receptions}</td>
<td>${row.receiving_yards}</td>
<td>${row.receiving_touchdown}</td>
<td>${row.rush_attempts}</td>
<td>${row.rushing_yards}</td>
<td>${row.rush_touchdown}</td>
<td>${row.fumble}</td>
`;
tableBody.appendChild(rowElement);
});
}
//});pass_attempts, complete_pass, total_yards, total_tds, interception, receptions, receiving_yards, receiving_touchdown, rush_attempts, rushing_yards, rush_touchdown, fumble

View File

@@ -17,6 +17,12 @@
</select>
<button type="submit">Register</button>
</form>
<div class="error">
<p>Error Message</p>
</div>
<div class="success">
<p>Login successful</p>
</div>
<div class="register">
<p>Already have an account?</p>
<a href="/login">Login</a>

View File

@@ -2,10 +2,15 @@ import { postData } from "./client.js";
const registerForm = document.getElementById("registerForm");
const error = document.querySelector(".error");
const errorMessage = document.querySelector(".error p");
const success = document.querySelector(".success");
if (registerForm) registerForm.onsubmit = async e => {
e.preventDefault();
if (registerForm.regPass.value !== registerForm.regVerify.value) {
alert("Passwords must match");
error.style.display = "flex";
errorMessage.innerHTML = "Passwords must match";
return;
}
@@ -14,7 +19,13 @@ if (registerForm) registerForm.onsubmit = async e => {
password: registerForm.regPass.value,
role: registerForm.regRole.value
});
alert(resultObject.message);
if (resultObject.message.includes("success")) {
error.style.display = "none";
success.style.display = "flex";
} else {
errorMessage.innerHTML = resultObject.message;
error.style.display = "flex";
}
if (resultObject.success === true) {
window.location.href = "/login";
}

104
server.js
View File

@@ -218,11 +218,7 @@ SUM(total_yards)
+ (SUM(offense_snaps) * 100.0 / SUM(team_offense_snaps))
- ((SUM(interception) + sum(fumble_lost)) * 75)
- (
CASE
WHEN Player.Position = 'QB'
THEN SUM(qb_dropback) - SUM(pass_attempts) - SUM(qb_scramble)
ELSE 0
END)
SUM(tackled_for_loss))
- (SUM(safety) * 100.0)
AS OffenseScore,
@@ -233,11 +229,7 @@ AvgPerYear,
+ (SUM(offense_snaps) * 100.0 / SUM(team_offense_snaps))
- ((SUM(interception) + sum(fumble_lost)) * 75)
- (
CASE
WHEN Player.Position = 'QB'
THEN SUM(qb_dropback) - SUM(pass_attempts) - SUM(qb_scramble)
ELSE 0
END
SUM(tackled_for_loss)
)
- (SUM(safety) * 100.0)) / AvgPerYear AS PaydirtScore
@@ -250,6 +242,81 @@ ORDER BY OffenseScore DESC;
res.status(200).json({ matches: result.recordset });
});
app.post("/getPlayerStats", authenticate, async (req, res) => {
const { playerID } = req.body;
const result = await pool.request()
.input("playerID", sql.Int, playerID)
.query(`
SELECT Player.PlayerID, Player.PlayerName, Season, SeasonType, Week, pass_attempts, complete_pass, total_yards, total_tds, interception, receptions, receiving_yards, receiving_touchdown, rush_attempts, rushing_yards, rush_touchdown, fumble
FROM Player JOIN DatasetPlayerStats ON Player.PlayerID = DatasetPlayerStats.PlayerID
WHERE Player.PlayerID = @playerID
ORDER BY Season, week;
`);
res.status(200).json({ matches: result.recordset });
});
app.post("/getPlayerScores", authenticate, async (req, res) => {
const { playerID } = req.body;
const result = await pool.request()
.input("playerID", sql.Int, playerID)
.query(`
SELECT Player.PlayerID, Player.[Position], Player.PlayerName, Player.Team,
SUM(total_yards) AS TotalYards,
SUM(passing_yards) AS PassingYards,
SUM(rushing_yards) AS RushingYards,
SUM(receiving_yards) AS RecievingYards,
CASE WHEN Player.Position = 'QB' THEN (SUM(pass_touchdown)) ELSE 0 END + SUM(receiving_touchdown) + SUM(rush_touchdown) AS AmendedTotalTDs,
CASE WHEN Player.Position = 'QB' THEN (SUM(pass_touchdown)) ELSE 0 END AS PassTDs,
SUM(receiving_touchdown) AS ReceivingTDs,
SUM(rush_touchdown) AS RushTDs,
SUM(offense_snaps) * 1.0 / SUM(team_offense_snaps) AS SnapPercentage,
SUM(interception) + sum(fumble_lost) AS Turnovers,
SUM(tackled_for_loss) AS TackledForLoss,
CASE
WHEN Player.Position = 'QB'
THEN SUM(qb_dropback) - SUM(pass_attempts) - SUM(qb_scramble)
ELSE 0
END AS Sacks,
SUM(safety) AS Safties,
SUM(total_yards)
+ ((CASE WHEN Player.Position = 'QB' THEN (SUM(pass_touchdown)) ELSE 0 END + SUM(receiving_touchdown) + SUM(rush_touchdown)) * 50)
+ (SUM(offense_snaps) * 100.0 / SUM(team_offense_snaps))
- ((SUM(interception) + sum(fumble_lost)) * 75)
- (
SUM(tackled_for_loss)
)
- (SUM(safety) * 100.0)
AS OffenseScore,
AvgPerYear,
(SUM(total_yards)
+ ((CASE WHEN Player.Position = 'QB' THEN (SUM(pass_touchdown)) ELSE 0 END + SUM(receiving_touchdown) + SUM(rush_touchdown)) * 50)
+ (SUM(offense_snaps) * 100.0 / SUM(team_offense_snaps))
- ((SUM(interception) + sum(fumble_lost)) * 75)
- (
SUM(tackled_for_loss)
)
- (SUM(safety) * 100.0)) / AvgPerYear * 1000000 AS PaydirtScore
FROM Player JOIN DatasetPlayerStats ON Player.PlayerID = DatasetPlayerStats.PlayerID JOIN Contract ON Player.PlayerID = Contract.PlayerID
WHERE season = 2024 AND SeasonType = 'REG' AND Player.PlayerID = @playerID
GROUP BY Player.PlayerID, Player.PlayerName, Player.Team, Player.[Position], Contract.AvgPerYear
ORDER BY PaydirtScore DESC;
`);
res.status(200).json({ matches: result.recordset });
});
app.post("/getHighestPaydirt", authenticate, async (req, res) => {
const { amount } = req.body;
@@ -280,11 +347,7 @@ SUM(total_yards)
+ (SUM(offense_snaps) * 100.0 / SUM(team_offense_snaps))
- ((SUM(interception) + sum(fumble_lost)) * 75)
- (
CASE
WHEN Player.Position = 'QB'
THEN SUM(qb_dropback) - SUM(pass_attempts) - SUM(qb_scramble)
ELSE 0
END)
SUM(tackled_for_loss))
- (SUM(safety) * 100.0)
AS OffenseScore,
@@ -295,13 +358,10 @@ AvgPerYear,
+ (SUM(offense_snaps) * 100.0 / SUM(team_offense_snaps))
- ((SUM(interception) + sum(fumble_lost)) * 75)
- (
CASE
WHEN Player.Position = 'QB'
THEN SUM(qb_dropback) - SUM(pass_attempts) - SUM(qb_scramble)
ELSE 0
END
SUM(tackled_for_loss)
)
- (SUM(safety) * 100.0)) / AvgPerYear AS PaydirtScore
- (SUM(safety) * 100.0)) / AvgPerYear * 1000000 AS PaydirtScore
FROM Player JOIN DatasetPlayerStats ON Player.PlayerID = DatasetPlayerStats.PlayerID JOIN Contract ON Player.PlayerID = Contract.PlayerID
@@ -318,7 +378,7 @@ app.post("/getPlayer", authenticate, async (req, res) => {
const result = await pool.request()
.input("query", sql.VarChar, id)
.query(`SELECT p.PlayerName, p.PlayerID, c.TotalValue, p.Team, p.Position FROM Player AS p JOIN Contract AS c ON p.PlayerID = c.PlayerID WHERE p.PlayerID = @query`);
.query(`SELECT p.PlayerName, p.PlayerID, c.TotalValue, c.TrueAvgPerYear, c.Years, c.StartYear, c.EndYear, p.Team, p.Position, p.Height, p.Weight FROM Player AS p JOIN Contract AS c ON p.PlayerID = c.PlayerID WHERE p.PlayerID = @query`);
if (result.recordset.length !== 1) {
res.status(400).json({ success: false })