Final Product
This commit is contained in:
parent
a8cf583569
commit
a9f44c29af
48 changed files with 3908 additions and 581 deletions
|
@ -1,8 +0,0 @@
|
|||
window.addEventListener("load", async (loadEvent) => {
|
||||
await loadCommon();
|
||||
|
||||
await commonTemplates();
|
||||
await template.expand();
|
||||
|
||||
connectNavbar();
|
||||
});
|
167
frontend/webpage/static/scripts/achievement.js
Normal file
167
frontend/webpage/static/scripts/achievement.js
Normal file
|
@ -0,0 +1,167 @@
|
|||
let achievementId = window.location.pathname.split('/').pop();
|
||||
let isReturn = false;
|
||||
let achievementData = null;
|
||||
let myRating = {};
|
||||
const loadAchievement = () => {
|
||||
if (myRating.invalid) {
|
||||
document.querySelector("#achievement-rating").remove();
|
||||
}
|
||||
|
||||
const description = document.querySelector("#achievement-description-text");
|
||||
if (description.textContent === '') {
|
||||
description.remove();
|
||||
}
|
||||
|
||||
// Canvasing
|
||||
|
||||
const completionCanvas = document.querySelector("#achievement-completion-canvas");
|
||||
|
||||
const STROKE_WIDTH = 0.18;
|
||||
const style = window.getComputedStyle(completionCanvas);
|
||||
const context = completionCanvas.getContext('2d');
|
||||
|
||||
const drawCanvas = () => achievementData.then(data => {
|
||||
const width = Number(style.getPropertyValue('width').slice(0, -2));
|
||||
const height = width;
|
||||
|
||||
context.canvas.width = width;
|
||||
context.canvas.height = height;
|
||||
context.clearRect(0, 0, width, height);
|
||||
context.strokeStyle = root.getProperty('--accent-value3');
|
||||
context.lineWidth = (width / 2) * STROKE_WIDTH;
|
||||
context.beginPath();
|
||||
context.arc(width / 2, height / 2, (width / 2) * (1 - STROKE_WIDTH / 2), -0.5 * Math.PI, (-0.5 + (data.completion === null ? 0 : (data.completion / 100) * 2)) * Math.PI);
|
||||
context.stroke();
|
||||
});
|
||||
|
||||
window.addEventListener('resize', drawCanvas);
|
||||
drawCanvas();
|
||||
|
||||
if (!myRating.invalid) {
|
||||
const saveReview = document.querySelector("#rating-save-stack");
|
||||
|
||||
const myDifficulty = document.querySelector("#achievement-difficulty-rating-text");
|
||||
const myQuality = document.querySelector("#achievement-quality-rating-text");
|
||||
const myReview = document.querySelector("#achievement-review-rating-text");
|
||||
|
||||
const reviewInput = () => {
|
||||
saveReview.style.display = 'block';
|
||||
}
|
||||
myDifficulty.addEventListener('input', reviewInput);
|
||||
myQuality.addEventListener('input', reviewInput);
|
||||
myReview.addEventListener('input', reviewInput);
|
||||
|
||||
const saveInputOnEnter = (keyEvent) => {
|
||||
if (keyEvent.key === 'Enter') {
|
||||
saveReview.click();
|
||||
}
|
||||
}
|
||||
myDifficulty.addEventListener('keydown', saveInputOnEnter);
|
||||
myQuality.addEventListener('keydown', saveInputOnEnter);
|
||||
|
||||
saveReview.addEventListener('click', (clickEvent) => {
|
||||
let successful = true;
|
||||
const difficulty = Number(myDifficulty.value);
|
||||
const quality = Number(myQuality.value );
|
||||
if ((Number.isNaN(difficulty) && myDifficulty.value !== '') || difficulty < 0 || difficulty > 10) {
|
||||
myDifficulty.style.backgroundColor = 'var(--error)';
|
||||
successful = false;
|
||||
}
|
||||
if ((Number.isNaN(quality) && myQuality.value !== '') || quality < 0 || quality > 10) {
|
||||
myQuality.style.backgroundColor = 'var(--error)';
|
||||
successful = false;
|
||||
}
|
||||
if (successful) {
|
||||
myDifficulty.style.backgroundColor = 'var(--foreground)';
|
||||
myQuality.style.backgroundColor = 'var(--foreground)';
|
||||
saveReview.style.display = 'none';
|
||||
fetch(`/api/achievement/${achievementId}/rating/${session.id}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
sessionKey: session.key,
|
||||
difficulty: difficulty,
|
||||
quality: quality,
|
||||
review: myReview.value
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
if (response.status === 401) {
|
||||
responese.json().then(data => {
|
||||
myDifficulty.value = data.difficulty ? data.difficulty : '';
|
||||
myQuality.value = data.quality ? data.quality : '';
|
||||
myReview.value = data.review ? data.review : '';
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const ratings = document.querySelectorAll(".list-page-entry.rating");
|
||||
for (const rating of ratings) {
|
||||
rating.addEventListener("click", (clickEvent) => {
|
||||
window.location.href = `/user/${rating.dataset.id}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const expandTemplates = async () => {
|
||||
await commonTemplates();
|
||||
if (session.key) {
|
||||
myRating = await fetch(`/api/achievement/${achievementId}/rating/${session.id}`, { method: 'GET' })
|
||||
.then(response => {
|
||||
if (response.status !== 200) {
|
||||
return { invalid: true };
|
||||
} else {
|
||||
return response.json();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
myRating = { invalid: true };
|
||||
}
|
||||
template.apply("achievement-page").promise(achievementData.then(data => ({
|
||||
id: achievementId,
|
||||
name: data.name,
|
||||
description: data.description ? data.description : '',
|
||||
completion: data.completion === null ? "N/A" : `${data.completion}%`,
|
||||
difficulty: data.difficulty === null ? "N/A" : `${data.difficulty} / 10`,
|
||||
quality: data.quality === null ? "N/A" : `${data.quality} / 10`,
|
||||
my_difficulty: myRating.difficulty ? myRating.difficulty : '',
|
||||
my_quality: myRating.quality ? myRating.quality : '',
|
||||
my_review: myRating.review ? myRating.review : '',
|
||||
})));
|
||||
template.apply("rating-list").promise(achievementData.then(data => data.ratings.map(data => ({
|
||||
user_id: data.userId,
|
||||
user_username: data.username,
|
||||
user_difficulty: data.difficulty,
|
||||
user_quality: data.quality,
|
||||
user_review: data.review
|
||||
}))));
|
||||
}
|
||||
|
||||
window.addEventListener("load", async (loadEvent) => {
|
||||
await loadCommon();
|
||||
|
||||
var importing = document.querySelector("#importing");
|
||||
if (/\d+/.test(achievementId)) {
|
||||
achievementId = Number(achievementId);
|
||||
} else {
|
||||
// Handle error
|
||||
}
|
||||
importing.remove();
|
||||
|
||||
achievementData = fetch(`/api/achievement/${achievementId}`, { method: 'GET' })
|
||||
.then(response => response.json());
|
||||
|
||||
await expandTemplates();
|
||||
await template.expand();
|
||||
|
||||
loadLazyImages();
|
||||
connectNavbar();
|
||||
loadAchievement();
|
||||
});
|
|
@ -9,37 +9,51 @@ const loadRoot = () => {
|
|||
}
|
||||
};
|
||||
|
||||
let session = null;
|
||||
let session = { id: null };
|
||||
const clearSession = () => session = { id: null };
|
||||
const loadSession = async () => {
|
||||
window.addEventListener('beforeunload', (beforeUnloadEvent) => {
|
||||
if (session) {
|
||||
window.sessionStorage.setItem('session', JSON.stringify(session));
|
||||
} else {
|
||||
window.sessionStorage.removeItem('session');
|
||||
}
|
||||
window.sessionStorage.setItem('session', JSON.stringify(session));
|
||||
});
|
||||
|
||||
session = JSON.parse(window.sessionStorage.getItem('session'));
|
||||
if (session) {
|
||||
session = JSON.parse(window.sessionStorage.getItem('session')) || { id: -1 };
|
||||
if (session.hue) {
|
||||
root.setProperty('--accent-hue', session.hue);
|
||||
}
|
||||
|
||||
if (session.id !== null) {
|
||||
await fetch(`/api/auth/refresh`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ key: session.key })
|
||||
body: JSON.stringify({ key: session.key, id: session.id })
|
||||
})
|
||||
.then(async response => ({ status: response.status, data: await response.json() }))
|
||||
.then(response => {
|
||||
if (response.status !== 200 && window.location.pathname != "/login") {
|
||||
delete session.key;
|
||||
window.location.href = "/login";
|
||||
if (response.status !== 200 && window.location.pathname !== "/login") {
|
||||
session.id = null;
|
||||
session.key = null;
|
||||
if (session.id !== -1) {
|
||||
window.location.href = "/login";
|
||||
}
|
||||
} else {
|
||||
session.key = response.data.key;
|
||||
session.id = response.data.id;
|
||||
if (session.id === -1 && window.location.pathname !== '/import') {
|
||||
window.location.href = '/import';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const authenticate = (obj) => {
|
||||
obj.sessionKey = session.key;
|
||||
obj.userId = session.id;
|
||||
return obj;
|
||||
}
|
||||
|
||||
const loadCommon = async () => {
|
||||
loadRoot();
|
||||
await loadSession();
|
||||
|
@ -56,7 +70,7 @@ const commonTemplates = async () => {
|
|||
{ item: "games", title: "Games" },
|
||||
{ item: "import", title: "Import" }
|
||||
]);
|
||||
if (session) {
|
||||
if (session.id !== -1 && session.id !== null) {
|
||||
template.apply("navbar-section-right").values([
|
||||
{ item: "profile", title: "Profile" },
|
||||
{ item: "logout", title: "Logout" }
|
||||
|
@ -76,29 +90,31 @@ const loadLazyImages = () => {
|
|||
}
|
||||
|
||||
const connectNavbar = () => {
|
||||
const navItems = document.querySelectorAll(".navbar-item");
|
||||
if (session.id !== -1) {
|
||||
const navItems = document.querySelectorAll(".navbar-item");
|
||||
|
||||
if (!session || !session.admin) {
|
||||
document.querySelector("#navbar-item-import").remove();
|
||||
}
|
||||
if (!session.admin) {
|
||||
document.querySelector("#navbar-item-import").remove();
|
||||
}
|
||||
|
||||
for (const item of navItems) {
|
||||
if (item.dataset.pageName === "logout") {
|
||||
item.addEventListener("click", (clickEvent) => {
|
||||
fetch(`/api/auth/logout`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ key: session.key })
|
||||
for (const item of navItems) {
|
||||
if (item.dataset.pageName === "logout") {
|
||||
item.addEventListener("click", (clickEvent) => {
|
||||
fetch(`/api/auth/logout`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ key: session.key })
|
||||
});
|
||||
clearSession();
|
||||
window.location.href = "/login";
|
||||
});
|
||||
session = undefined;
|
||||
window.location.href = "/login";
|
||||
});
|
||||
} else if (item.dataset.pageName === "profile") {
|
||||
item.addEventListener("click", (clickEvent) => window.location.href = `/user/${session.id}`);
|
||||
} else {
|
||||
item.addEventListener("click", (clickEvent) => window.location.href = `/${item.dataset.pageName}`);
|
||||
} else if (item.dataset.pageName === "profile") {
|
||||
item.addEventListener("click", (clickEvent) => window.location.href = `/user/${session.id}`);
|
||||
} else {
|
||||
item.addEventListener("click", (clickEvent) => window.location.href = `/${item.dataset.pageName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
105
frontend/webpage/static/scripts/import.js
Normal file
105
frontend/webpage/static/scripts/import.js
Normal file
|
@ -0,0 +1,105 @@
|
|||
let consoleTop = true;
|
||||
let importConsole = null;
|
||||
const appendLine = (line) => {
|
||||
const template = document.createElement("template");
|
||||
template.innerHTML = `<p class="console-entry ${consoleTop ? 'top' : ''}">${line}</p>`
|
||||
importConsole.appendChild(template.content.firstElementChild);
|
||||
consoleTop = false;
|
||||
};
|
||||
|
||||
const loadConsole = () => {
|
||||
importConsole = document.querySelector("#import-console");
|
||||
|
||||
const dropzone = document.querySelector("#import-dropzone");
|
||||
const uploadWrapper = document.querySelector("#upload-wrapper");
|
||||
const upload = (dropEvent) => {
|
||||
dropEvent.preventDefault();
|
||||
|
||||
dropzone.classList.remove('active');
|
||||
if (dropEvent.dataTransfer.files) {
|
||||
const file = dropEvent.dataTransfer.files[0];
|
||||
if (file.type === 'application/json') {
|
||||
importConsole.style.display = 'block';
|
||||
uploadWrapper.style.display = 'none';
|
||||
file.text().then(data => JSON.parse(data)).then(data => {
|
||||
let uploads = Promise.resolve();
|
||||
for (let i = 0; i < data.platforms.length; ++i) {
|
||||
const platform = data.platforms[i];
|
||||
uploads = uploads
|
||||
.then(() => {
|
||||
appendLine(`(${i + 1}/${data.platforms.length}) Creating platform: ${platform.name}`);
|
||||
}).then(() => fetch(
|
||||
'/api/import/platform', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(authenticate(platform))
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
for (let i = 0; i < data.users.length; ++i) {
|
||||
const user = data.users[i];
|
||||
const userPlatforms = user.platforms;
|
||||
delete user.platforms;
|
||||
uploads = uploads
|
||||
.then(() => {
|
||||
appendLine(`(${i + 1}/${data.users.length}) Creating user: ${user.username}`);
|
||||
}).then(() => fetch(
|
||||
'/api/import/user', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(authenticate(user))
|
||||
}
|
||||
)
|
||||
);
|
||||
for (let j = 0; j < userPlatforms.length; ++j) {
|
||||
const platform = userPlatforms[j];
|
||||
platform.userEmail = user.email;
|
||||
uploads = uploads
|
||||
.then(() => {
|
||||
appendLine(` (${j + 1}/${userPlatforms.length}) Importing platform data: ${data.platforms[platform.platformId].name}`);
|
||||
}).then(() => fetch(
|
||||
'/api/import/user/platform', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(authenticate(platform))
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
uploads = uploads.then(() => {
|
||||
if (session.id === -1) {
|
||||
clearSession();
|
||||
window.location.href = '/login';
|
||||
} else {
|
||||
importConsole.innerHTML = '';
|
||||
importConsole.style.display = 'none';
|
||||
uploadWrapper.style.display = 'block';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
dropzone.addEventListener("drop", upload);
|
||||
dropzone.addEventListener("dragover", (dragEvent) => {
|
||||
dragEvent.preventDefault();
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener("load", async (loadEvent) => {
|
||||
await loadCommon();
|
||||
|
||||
await commonTemplates();
|
||||
await template.expand();
|
||||
|
||||
connectNavbar();
|
||||
loadConsole();
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
window.addEventListener("load", async (loadEvent) => {
|
||||
await loadCommon();
|
||||
|
||||
if (session && session.key) {
|
||||
if (session.key) {
|
||||
window.location.href = '/';
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ window.addEventListener("load", async (loadEvent) => {
|
|||
const header = document.querySelector("#login-header-text");
|
||||
const error = document.querySelector("#error-message");
|
||||
|
||||
if (session) {
|
||||
if (!session.key && session.id) {
|
||||
error.style.display = "block";
|
||||
error.textContent = "You have been signed out due to inactivity";
|
||||
}
|
||||
|
|
|
@ -88,6 +88,13 @@ const loadAchievementSearch = () => {
|
|||
loading.style.display = 'none';
|
||||
canSearch = true;
|
||||
loadLazyImages();
|
||||
|
||||
const entries = document.querySelectorAll(".list-page-entry.achievement");
|
||||
for (const entry of entries) {
|
||||
entry.addEventListener("click", (clickEvent) => {
|
||||
window.location.href = `/achievement/${entry.dataset.id}`;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const headers = {
|
||||
|
|
|
@ -85,7 +85,6 @@ const loadGameSearch = () => {
|
|||
}))));
|
||||
await template.expand();
|
||||
data.then(data => {
|
||||
console.log(data);
|
||||
loading.style.display = 'none';
|
||||
canSearch = true;
|
||||
loadLazyImages();
|
||||
|
|
|
@ -60,6 +60,11 @@ const loadProfile = () => {
|
|||
usernameField.value = usernameField.value.substring(0, 32);
|
||||
}
|
||||
});
|
||||
usernameField.addEventListener("keydown", (keyEvent) => {
|
||||
if (keyEvent.key === "Enter") {
|
||||
saveProfileButton.click();
|
||||
}
|
||||
})
|
||||
|
||||
const pfp = document.querySelector("#profile-info-pfp-img");
|
||||
const pfpStack = document.querySelector("#profile-info-pfp");
|
||||
|
@ -188,7 +193,6 @@ const loadProfile = () => {
|
|||
// Canvasing
|
||||
|
||||
const completionCanvas = document.querySelector("#profile-completion-canvas");
|
||||
const completionText = document.querySelector("#profile-completion-text");
|
||||
|
||||
const STROKE_WIDTH = 0.18;
|
||||
const style = window.getComputedStyle(completionCanvas);
|
||||
|
@ -214,6 +218,24 @@ const loadProfile = () => {
|
|||
if (profileId === session.id) {
|
||||
document.querySelector("#profile-page").classList.add("self");
|
||||
}
|
||||
|
||||
{
|
||||
const noteworthy = document.querySelectorAll(".list-page-entry.achievement");
|
||||
for (const achievement of noteworthy) {
|
||||
achievement.addEventListener("click", (clickEvent) => {
|
||||
window.location.href = `/achievement/${achievement.dataset.id}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const ratings = document.querySelectorAll(".list-page-entry.rating");
|
||||
for (const rating of ratings) {
|
||||
rating.addEventListener("click", (clickEvent) => {
|
||||
window.location.href = `/achievement/${rating.dataset.id}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const expandTemplates = async () => {
|
||||
|
@ -225,6 +247,18 @@ const expandTemplates = async () => {
|
|||
average: data.average === null ? "N/A" : data.average + "%",
|
||||
perfect: data.perfect,
|
||||
})));
|
||||
template.apply("profile-noteworthy-list").promise(
|
||||
fetch(`/api/user/${profileId}/noteworthy`, {
|
||||
method: 'GET'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => data.map(data => ({
|
||||
achievement_id: data.ID,
|
||||
achievement_name: data.name,
|
||||
completion: data.completion
|
||||
}))
|
||||
)
|
||||
);
|
||||
template.apply("profile-platforms-list").promise(profileData.then(data =>
|
||||
data.platforms.map(platform => ({
|
||||
platform_id: platform.id,
|
||||
|
@ -238,6 +272,13 @@ const expandTemplates = async () => {
|
|||
"")))
|
||||
}))
|
||||
));
|
||||
template.apply("rating-list").promise(profileData.then(data => data.ratings.map(data => ({
|
||||
achievement_id: data.achievementId,
|
||||
rating_achievement: data.name,
|
||||
rating_difficulty: data.difficulty,
|
||||
rating_quality: data.quality,
|
||||
rating_review: data.review
|
||||
}))));
|
||||
}
|
||||
|
||||
window.addEventListener("load", async (loadEvent) => {
|
||||
|
@ -247,7 +288,7 @@ window.addEventListener("load", async (loadEvent) => {
|
|||
if (!/\d+/.test(profileId)) {
|
||||
isReturn = true;
|
||||
const platform = profileId;
|
||||
if (!session) {
|
||||
if (!session.key) {
|
||||
window.location.href = "/404";
|
||||
} else {
|
||||
profileId = session.lastProfile;
|
||||
|
@ -278,7 +319,7 @@ window.addEventListener("load", async (loadEvent) => {
|
|||
window.history.replaceState({}, '', `/profile/${profileId}`);
|
||||
} else if (/\d+/.test(profileId)) {
|
||||
profileId = Number(profileId);
|
||||
if (session) {
|
||||
if (session.key) {
|
||||
session.lastProfile = profileId;
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue