From be4793dfd9d687dfbf034eb46c8040c49dc584f3 Mon Sep 17 00:00:00 2001 From: Harry Mellor <19981378+HMellor@users.noreply.github.com> Date: Sun, 23 Apr 2023 15:46:44 +0100 Subject: [PATCH] Add admin dashboard (#25) * Add title to bid0 of all auctions * Add admin page and links between the two pages * Remove unecessary css * Remove Bootstrap prefixes from data attributes * Admin btn only visible if user doc has admin field * Populate winning column with usernames * Add debug log to show user read * Add is to admin button on admin page * Move admin functions to `admin.js` * Update README.md * Fix table CSS on main page * Move setup logic out of html files * Refactor reset functions to use `getItems()` * Move generateRandomAuctionData data to `demo.js` * Convert everything to data attributes * Document changes * Remove missed bootstrap prefix --- README.md | 31 +++--- admin.html | 108 ++++++++++++++++++++ css/auction-website.css | 2 +- index.html | 13 +-- js/admin.js | 109 ++++++++++++++++++++ js/auctions.js | 139 +++++++------------------- js/demo.js | 35 +++++++ js/firebase.js | 28 +++--- js/popups.js | 214 +++++++++++++++++++++------------------- readme/adminpage.png | Bin 0 -> 60658 bytes 10 files changed, 439 insertions(+), 240 deletions(-) create mode 100644 admin.html create mode 100644 js/admin.js create mode 100644 js/demo.js create mode 100644 readme/adminpage.png diff --git a/README.md b/README.md index 38904edc..99bdba6a 100644 --- a/README.md +++ b/README.md @@ -20,20 +20,20 @@ This is a project I worked on for a charity as a pet project and so the function - Device based login requiring only a username to be provided (no need to store sensitive information). - Popups for more detailed descriptions and additional imagery. - Realtime bidding using event listeners (no need to refresh page). +- Built with Bootstrap so everything is reactive. +- Has a separate page for administrators to monitor the auction. -![](./readme/homepage_desktop.png) ![](./readme/loginpage.png) -![](./readme/infopage.png) ![](./readme/bidpage.png) - -It looks great on mobile too! - -![](./readme/homepage_mobile.png) +| ![](./readme/homepage_desktop.png) | ![](./readme/loginpage.png) | +|:---:|:---:| +| ![](./readme/infopage.png) | ![](./readme/bidpage.png) | +| | ![](./readme/adminpage.png) | ## Setup Here we will cover how to add your own information to the auctions themselves, then how to most a local server to see your changes and finally how to connect it all to Firebase to enable user login and bidding. ### Adding auction information -First, set `demoAuction=False` in `js/auctions.js` (this will keep the cats at bay). +First, set `isDemo=False` in `js/auctions.js` (this will keep the cats at bay). Then, populate the `Object` at the bottom of `js/firebase.js` with the information for of the items you'll be putting up for auction. The fields are: - `primaryImage` (`String`): path or URL to the primary image @@ -41,7 +41,7 @@ Then, populate the `Object` at the bottom of `js/firebase.js` with the informati - `subtitle` (`String`): auction subtitle - `detail` (`String`): auction detail text - `secondaryImage` (`String`): path or URL to the secondary image -- `startingPrice` (`Number`): auction price, +- `startPrice` (`Number`): auction price, - `endTime` (`Number`): auction end time relative to epoch **in milliseconds**. (See [JavaScript's `Date` class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) for more information.) ### Firebase setup @@ -105,18 +105,19 @@ Setting up the database is a little more involved so here are the steps you must - Admins can access all auction and user data. ### Creating an admin account and initialising your auctions -The final step in setting up your auction is to create an admin account and use it to initialise your auctions. +The final step in setting up your auction is to create an admin account and use it to initialise and monitor your auction. To create an admin account: -- Host your website either locally or on GitHub Pages and log in to your website. +- Host your website either locally or on GitHub Pages and log in to the website. - Then go to your Firestore console and find the document for the user you just created. -- There should be a field in the document called `admin` which has the value `"false"`. You must now create a password (or hash) that enables admin access and set the `admin` field to this value. -- Go to your Firestore rules and replace `"insert long random secret string"` with your admin password. -- You have now created your admin account. +- There should be a boolean field in the document called `admin` which has the value `"false"`. Change its type to string and enter your desired admin password*. The longer and more complicated the password the better, consider using something like an MD5 hash. You'll never actually have to enter it anywhere, it's just used when validating your Firestore requests. +- Go to your Firestore rules and replace `insert long random secret string` with the password you **just created**. + +> *_**Please** don't reuse one of your existing passwords! While the Firestore rules should prevent bad actors from reading your user's data, don't risk it. I can't be responsible for leaked passwords due to a misconfigured project_ To initialise the auctions: -- With the device you used to create your admin account, head to your website. +- With the device you used to create your admin account, head to your website and navigate to the admin page by clicking the `Admin` button in the top right. - Open the developer console (F12) and enter `resetAll()` into the console. - This will revert the entire auction to the initial state specified in `js/firebase.js` (as long as you are admin), be careful with this one! - You can also reset individual items using the `resetItem(i)` function. -- Your auction is now ready. +- You can also use this `Admin` page to monitor the status of your auction. diff --git a/admin.html b/admin.html new file mode 100644 index 00000000..c07d1af3 --- /dev/null +++ b/admin.html @@ -0,0 +1,108 @@ + + + + + + + + + + + + Markatplace + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
#TitlePriceBidsWinningTime left
+ + +
+ + + + + + + + + + \ No newline at end of file diff --git a/css/auction-website.css b/css/auction-website.css index 55ba077e..90d6bc45 100644 --- a/css/auction-website.css +++ b/css/auction-website.css @@ -17,6 +17,6 @@ html * { width: 100%; } -.table { +.card > .table { margin-bottom: 0; } \ No newline at end of file diff --git a/index.html b/index.html index 40bb7684..f3f18051 100644 --- a/index.html +++ b/index.html @@ -31,8 +31,11 @@ The Markatplace - - +
+ + + +
@@ -124,12 +127,10 @@ diff --git a/js/admin.js b/js/admin.js new file mode 100644 index 00000000..f4cc37a0 --- /dev/null +++ b/js/admin.js @@ -0,0 +1,109 @@ +// Imports +import { db } from "./firebase.js"; +import { timeBetween, getItems } from "./auctions.js"; +import { doc, setDoc, getDoc, updateDoc, deleteField, onSnapshot } from "https://www.gstatic.com/firebasejs/9.20.0/firebase-firestore.js"; + +let table = document.querySelector("tbody"); + +function createRow(item) { + let row = document.createElement("tr") + row.id = `auction-${item}` + + let header = document.createElement("th") + header.scope = "row" + header.innerText = item + row.appendChild(header) + + row.appendChild(document.createElement("td")) + row.appendChild(document.createElement("td")) + row.appendChild(document.createElement("td")) + row.appendChild(document.createElement("td")) + row.appendChild(document.createElement("td")) + + return row +} + +function dataListener() { + // Listen for updates in active auctions + onSnapshot(doc(db, "auction", "items"), (items) => { + console.debug("dataListener() read from auction/items") + // Parse flat document data into structured Object + let data = {} + for (const [key, details] of Object.entries(items.data())) { + let [item, bid] = key.split("_").map(i => Number(i.match(/\d+/))) + data[item] = data[item] || {} + data[item][bid] = details + } + // Use structured Object to populate the row for each item + for (const [item, bids] of Object.entries(data)) { + let row = table.querySelector(`#auction-${item}`) + if (row == null) { + row = createRow(item) + table.appendChild(row) + } + // Extract bid data + let bidCount = Object.keys(bids).length - 1 + row.children[1].innerText = bids[0].title + row.children[2].innerText = `£${bids[bidCount].amount.toFixed(2)}` + row.children[3].innerText = bidCount + if (bids[bidCount].uid) { + getDoc(doc(db, "users", bids[bidCount].uid)).then((user) => { + row.children[4].innerText = user.get("name") + console.debug("dataListener() read from users") + }) + } else { + // Remove winner name if auction was reset + row.children[4].innerText = "" + } + row.children[5].dataset.endTime = bids[0].endTime + } + }) +} + +function setClocks() { + let now = new Date().getTime() + document.querySelectorAll("tbody > tr").forEach(row => { + row.children[5].innerText = timeBetween(now, row.children[5].dataset.endTime); + }) + setTimeout(setClocks, 1000); +} + +export function setupTable() { + dataListener(); + setClocks(); +} + +function resetItem(i) { + const docRef = doc(db, "auction", "items") + getItems().then(items => { + let initialState = {} + getDoc(docRef).then((doc) => { + console.debug("resetItem() read from auction/items") + // Find all bids for item i + let item = items[i] + let keys = Object.keys(doc.data()).sort() + keys.filter(key => key.includes(`item${i.toString().padStart(5, "0")}`)).forEach((key, idx) => { + // Mark all except bid00000 to be deleted + initialState[key] = idx ? deleteField() : { amount: item.startPrice, title: item.title, endTime: item.endTime } + }) + }).then(() => { + updateDoc(docRef, initialState) + console.debug("resetItem() write to from auction/items") + }) + }) +} + +function resetAll() { + getItems().then(items => { + let initialState = {} + items.forEach(item => { + let field = `item${item.id.toString().padStart(5, "0")}_bid00000` + initialState[field] = { amount: item.startPrice, title: item.title, endTime: item.endTime } + }) + setDoc(doc(db, "auction", "items"), initialState) + console.debug("resetAll() write to auction/items") + }) +} + +window.resetItem = resetItem +window.resetAll = resetAll diff --git a/js/auctions.js b/js/auctions.js index 13160f5b..a076de93 100644 --- a/js/auctions.js +++ b/js/auctions.js @@ -1,52 +1,13 @@ // Imports -import { auth, db } from "./firebase.js"; -import { doc, setDoc, getDoc, updateDoc, deleteField, onSnapshot } from "https://www.gstatic.com/firebasejs/9.20.0/firebase-firestore.js"; +import { db, auctions } from "./firebase.js"; +import { generateRandomAuctionData } from "./demo.js"; +import { doc, onSnapshot } from "https://www.gstatic.com/firebasejs/9.20.0/firebase-firestore.js"; // For a real auction, set this to false -let demoAuction = true; - -// Random auction information -function generateRandomAuctionData() { - let cards = document.querySelectorAll(".card") - - // Random cat names - $.getJSON( - "https://random-data-api.com/api/name/random_name", - { size: auctions.length }, - (data) => { - data.forEach((elem, i) => { - cards[i].querySelector(".title").innerText = elem.name - cards[i].dataset.title = elem.name - }); - } - ); - // Random lorem ipsum cat descriptions - $.getJSON( - "https://random-data-api.com/api/lorem_ipsum/random_lorem_ipsum", - { size: auctions.length }, - (data) => { - data.forEach((elem, i) => { - cards[i].querySelector(".card-subtitle").innerText = elem.short_sentence - cards[i].dataset.subtitle = elem.short_sentence; - cards[i].dataset.detail = elem.very_long_sentence; - }); - } - ); - // Random cat images and end times - for (let i = 0; i < auctions.length; i++) { - cards[i].querySelector("img").src = "https://cataas.com/cat/cute?random=" + i; - cards[i].dataset.primaryImage = "https://cataas.com/cat/cute?random=" + i; - cards[i].dataset.secondaryImage = "https://cataas.com/cat/cute?random=" + i; - - let now = new Date(); - let endTime = new Date().setHours(8 + i, 0, 0, 0) - if (endTime - now < 0) { endTime = new Date(endTime).setDate(now.getDate() + 1) } - auctions[i].endTime = endTime - } -} +export const isDemo = true; // Convert time to string for HTML clocks -function timeBetween(start, end) { +export function timeBetween(start, end) { let _string = "" let secsRemaining = (end - start) / 1000; let d = parseInt(secsRemaining / 86400); @@ -61,16 +22,16 @@ function timeBetween(start, end) { } // Set time on HTML clocks -export function setClocks() { +function setClocks() { let now = new Date(); let nowTime = now.getTime(); - for (let i = 0; i < auctions.length; i++) { - let timer = document.getElementById("time-left-" + i) + document.querySelectorAll(".card").forEach(card => { + let countDown = card.querySelector(".time-left") // remove finished auction after 5 minutes - if (auctions[i].endTime - nowTime < -300) { + if (card.dataset.endTime - nowTime < -300) { document.getElementById("auction-" + i).parentElement.style.display = "none" - if (demoAuction) { - auctions[i].endTime = new Date(auctions[i].endTime).setDate(now.getDate() + 1) // add 1 day + if (isDemo) { + card.dataset.endTime = new Date(card.dataset.endTime).setDate(now.getDate() + 1) // add 1 day document.getElementById("auction-" + i).parentElement.remove() resetItem(i); auctionGrid = document.getElementById("auction-grid"); @@ -78,19 +39,20 @@ export function setClocks() { auctionGrid.appendChild(auctionCard); } // disable bidding on finished auctions - } else if (auctions[i].endTime - nowTime < 0) { - timer.innerHTML = "Auction Complete"; + } else if (card.dataset.endTime - nowTime < 0) { + countDown.innerHTML = "Auction Complete"; document.getElementById("bid-button-" + i).setAttribute('disabled', '') } else { - timer.innerHTML = timeBetween(nowTime, auctions[i].endTime); + countDown.innerHTML = timeBetween(nowTime, card.dataset.endTime); } - } + }) setTimeout(setClocks, 1000); } function argsort(array, key) { - const arrayObject = array.map((value, idx) => { return { value, idx }; }); - return arrayObject.sort((a, b) => (a.value[key] - b.value[key])); + // Insert the index from the unsorted array as the item ID + array.forEach((value, idx) => { array[idx].id = idx }); + return array.sort((a, b) => (a[key] - b[key])); } function generateAuctionCard(auction) { @@ -104,12 +66,14 @@ function generateAuctionCard(auction) { card.dataset.detail = auction.detail card.dataset.primaryImage = auction.primaryImage card.dataset.secondaryImage = auction.secondaryImage - card.id = "auction-" + auction.idx + card.dataset.endTime = auction.endTime + card.dataset.StartPrice = auction.StartPrice + card.dataset.id = auction.id col.appendChild(card); let image = document.createElement("img"); image.classList.add("card-img-top"); - image.src = auction.value.primaryImage; + image.src = auction.primaryImage; card.appendChild(image); let body = document.createElement("div"); @@ -118,12 +82,12 @@ function generateAuctionCard(auction) { let title = document.createElement("h5"); title.classList.add("title"); - title.innerText = auction.value.title; + title.innerText = auction.title; body.appendChild(title); let subtitle = document.createElement("p"); subtitle.classList.add("card-subtitle"); - subtitle.innerText = auction.value.subtitle; + subtitle.innerText = auction.subtitle; body.appendChild(subtitle); // Auction status @@ -144,7 +108,7 @@ function generateAuctionCard(auction) { let bid = document.createElement("td"); bid.innerHTML = "£-.-- [- bids]" - bid.id = "current-bid-" + auction.idx + bid.classList.add("current-bid") bidRow.appendChild(bid); let timeRow = document.createElement("tr"); @@ -156,7 +120,7 @@ function generateAuctionCard(auction) { timeRow.appendChild(timeTitle); let time = document.createElement("td"); - time.id = "time-left-" + auction.idx + time.classList.add("time-left") timeRow.appendChild(time); // Auction actions @@ -184,21 +148,19 @@ function generateAuctionCard(auction) { } // Generatively populate the website with auctions -export function populateAuctionGrid() { +function populateAuctionGrid(auctions) { let auctionGrid = document.getElementById("auction-grid"); - let auctionsSorted = argsort(auctions, "endTime"); - auctionsSorted.forEach((auction) => { + auctions.forEach((auction) => { let auctionCard = generateAuctionCard(auction); auctionGrid.appendChild(auctionCard); }); - if (demoAuction) { generateRandomAuctionData() }; } function numberWithCommas(x) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } -export function dataListener() { +function dataListener() { // Listen for updates in active auctions onSnapshot(doc(db, "auction", "items"), (doc) => { console.debug("dataListener() read from auction/items") @@ -211,47 +173,22 @@ export function dataListener() { } // Use structured Object to populate the "Current bid" for each item for (const [item, bids] of Object.entries(data)) { - let cb = document.getElementById(`current-bid-${item}`) + let card = document.querySelector(`.card[data-id="${item}"]`) + let currentBid = card.querySelector(".current-bid") // Extract bid data let bidCount = Object.keys(bids).length - 1 let currPound = bids[bidCount].toFixed(2) - // Check if the user is winning - if (auth.currentUser) { - let userWinning = bids["bid" + bidCount + "-user"] == auth.currentUser.uid - } // Add bid data to HTML - cb.innerHTML = "£" + numberWithCommas(currPound) + " [" + bidCount + " bid" + (bidCount != 1 ? "s" : "") + "]" + currentBid.innerHTML = `£${numberWithCommas(currPound)} [${bidCount} bid${bidCount != 1 ? "s" : ""}]` } }) } -function resetItem(i) { - const docRef = doc(db, "auction", "items") - const itemId = `item${i.toString().padStart(5, "0")}` - // Find all bids for item i - let initialState = {} - getDoc(docRef).then((doc) => { - console.debug("resetItem() read from auction/items") - let keys = Object.keys(doc.data()).sort() - keys.filter((key) => key.includes(itemId)).forEach((key, idx) => { - // Mark all except bid00000 to be deleted - initialState[key] = idx ? deleteField() : { amount: auctions[i].startingPrice } - }) - }).then(() => { - updateDoc(docRef, initialState) - console.debug("resetItem() write to from auction/items") - }) -} -function resetAll() { - let initialState = {} - for (let i = 0; i < auctions.length; i++) { - let field = `item${i.toString().padStart(5, "0")}_bid00000` - initialState[field] = { amount: auctions[i].startingPrice } - } - setDoc(doc(db, "auction", "items"), initialState) - console.debug("resetAll() write to auction/items") -} +export async function getItems() { + return argsort(isDemo ? await generateRandomAuctionData(auctions) : auctions, "endTime") +} -window.resetItem = resetItem -window.resetAll = resetAll +export function setupItems() { + getItems().then(auctions => populateAuctionGrid(auctions)).then(() => { setClocks(); dataListener() }) +} diff --git a/js/demo.js b/js/demo.js new file mode 100644 index 00000000..525deb10 --- /dev/null +++ b/js/demo.js @@ -0,0 +1,35 @@ +// Random auction information +export async function generateRandomAuctionData(auctions) { + // Random cat names + await $.getJSON( + "https://random-data-api.com/api/name/random_name", + { size: auctions.length }, + (data) => { + data.forEach((elem, i) => { + auctions[i].title = elem.name + }); + } + ); + // Random lorem ipsum cat descriptions + await $.getJSON( + "https://random-data-api.com/api/lorem_ipsum/random_lorem_ipsum", + { size: auctions.length }, + (data) => { + data.forEach((elem, i) => { + auctions[i].subtitle = elem.short_sentence; + auctions[i].detail = elem.very_long_sentence; + }); + } + ); + // Random cat images and end times + for (let i = 0; i < auctions.length; i++) { + auctions[i].primaryImage = "https://cataas.com/cat/cute?random=" + i; + auctions[i].secondaryImage = "https://cataas.com/cat/cute?random=" + i; + + let now = new Date(); + let endTime = new Date().setHours(8 + i, 0, 0, 0) + if (endTime - now < 0) { endTime = new Date(endTime).setDate(now.getDate() + 1) } + auctions[i].endTime = endTime + } + return auctions + } \ No newline at end of file diff --git a/js/firebase.js b/js/firebase.js index 13d244dd..b9a4f75c 100644 --- a/js/firebase.js +++ b/js/firebase.js @@ -20,14 +20,14 @@ const app = initializeApp(firebaseConfig); export const db = getFirestore(app); export const auth = getAuth(app); -const auctions = [ +export const auctions = [ { primaryImage: "", title: "", subtitle: "", detail: "", secondaryImage: "", - startingPrice: 55, + startPrice: 55, endTime: 0 }, { primaryImage: "", @@ -35,7 +35,7 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 60, + startPrice: 60, endTime: 0 }, { primaryImage: "", @@ -43,7 +43,7 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 20, + startPrice: 20, endTime: 0 }, { rimaryImage: "", @@ -51,7 +51,7 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 0, + startPrice: 0, endTime: 0 }, { primaryImage: "", @@ -59,7 +59,7 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 4, + startPrice: 4, endTime: 0 }, { primaryImage: "", @@ -67,7 +67,7 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 0, + startPrice: 0, endTime: 0 }, { primaryImage: "", @@ -75,7 +75,7 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 99, + startPrice: 99, endTime: 0 }, { primaryImage: "", @@ -83,7 +83,7 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 0, + startPrice: 0, endTime: 0 }, { primaryImage: "", @@ -91,7 +91,7 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 12, + startPrice: 12, endTime: 0 }, { primaryImage: "", @@ -99,7 +99,7 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 6, + startPrice: 6, endTime: 0 }, { primaryImage: "", @@ -107,7 +107,7 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 3, + startPrice: 3, endTime: 0 }, { primaryImage: "", @@ -115,8 +115,6 @@ const auctions = [ subtitle: "", detail: "", secondaryImage: "", - startingPrice: 7, + startPrice: 7, endTime: 0 }] - -window.auctions = auctions \ No newline at end of file diff --git a/js/popups.js b/js/popups.js index 747e6c1a..3e1c4a25 100644 --- a/js/popups.js +++ b/js/popups.js @@ -4,6 +4,7 @@ import { doc, setDoc, getDoc, updateDoc } from "https://www.gstatic.com/firebase import { signInAnonymously, onAuthStateChanged, updateProfile } from "https://www.gstatic.com/firebasejs/9.20.0/firebase-auth.js"; // -- Sign up modal and logic -- +const adminButton = document.getElementById('admin-button') const authButton = document.getElementById('auth-button') const signUpModal = document.getElementById('login-modal') const signUpModalObject = new bootstrap.Modal(signUpModal) @@ -17,6 +18,10 @@ export function autoSignIn() { // If user has an anonymous account and a displayName, treat them as signed in authButton.innerText = "Sign out" document.getElementById('username-display').innerText = "Hi " + user.displayName + // If user is admin, display the admin button + getDoc(doc(db, "users", user.uid)).then((user) => { + if ("admin" in user.data()) { adminButton.style.display = "inline-block" } + }) } else { // Automatically create an anonymous account if user doesn't have one signInAnonymously(auth) @@ -61,118 +66,123 @@ function signUp() { // --Bidding modal and logic -- const bidModal = document.getElementById('bid-modal') -const bidModalObject = new bootstrap.Modal(bidModal) -const bidModalTitle = bidModal.querySelector("strong") -const bidModalInput = bidModal.querySelector("input") -const bidModalSubmit = bidModal.querySelector(".btn-primary") +if (bidModal) { + const bidModalObject = new bootstrap.Modal(bidModal) + const bidModalTitle = bidModal.querySelector("strong") + const bidModalInput = bidModal.querySelector("input") + const bidModalSubmit = bidModal.querySelector(".btn-primary") -// Populate bidModal with the correct information before it is visible -bidModal.addEventListener("show.bs.modal", (event) => { - const button = event.relatedTarget - const card = button.closest(".card") || document.getElementById(bidModal.dataset.activeAuction) - bidModalTitle.innerText = card.dataset.title - bidModal.dataset.activeAuction = card.id -}) + // Populate bidModal with the correct information before it is visible + bidModal.addEventListener("show.bs.modal", (event) => { + const button = event.relatedTarget + const card = button.closest(".card") || document.getElementById(bidModal.dataset.activeAuction) + bidModalTitle.innerText = card.dataset.title + bidModal.dataset.activeAuction = card.dataset.id -// Focus the amount input once bidModal is visible -bidModal.addEventListener('shown.bs.modal', () => { - // If not logged in, open signUpModal instead - if (authButton.innerText == "Sign in") { - bidModalObject.hide() - signUpModalObject.show() - } else { - bidModalInput.focus() - } -}) + }) -// Once bidModal is no longer visible, clear the auction specific information -bidModal.addEventListener("hidden.bs.modal", () => { - bidModalInput.value = "" - bidModalInput.classList.remove("is-invalid") - bidModal.removeAttribute("data-bs-active-auction") -}) + // Focus the amount input once bidModal is visible + bidModal.addEventListener('shown.bs.modal', () => { + // If not logged in, open signUpModal instead + if (authButton.innerText == "Sign in") { + bidModalObject.hide() + signUpModalObject.show() + } else { + bidModalInput.focus() + } + }) + + // Once bidModal is no longer visible, clear the auction specific information + bidModal.addEventListener("hidden.bs.modal", () => { + bidModalInput.value = "" + bidModalInput.classList.remove("is-invalid") + bidModal.removeAttribute("data-active-auction") + }) -// A bid can be triggered either by clicking the submit button or by pressing enter -bidModalSubmit.addEventListener("click", () => { placeBid() }) -bidModalInput.addEventListener("keydown", (event) => { if (event.key == 'Enter') { placeBid() } }) + // A bid can be triggered either by clicking the submit button or by pressing enter + bidModalSubmit.addEventListener("click", () => { placeBid() }) + bidModalInput.addEventListener("keydown", (event) => { if (event.key == 'Enter') { placeBid() } }) -// Function that handles bidding logic -function placeBid() { - let nowTime = new Date().getTime(); - bidModalSubmit.setAttribute('disabled', '') // disable the button while we check - let i = bidModal.dataset.activeAuction.match("[0-9]+"); - let feedback = bidModal.querySelector(".invalid-feedback") - // Cleanse input - let amountElement = bidModal.querySelector("input") - let amount = Number(amountElement.value) - if (auctions[i].endTime - nowTime < 0) { - feedback.innerText = "The auction is already over!" - amountElement.classList.add("is-invalid") - setTimeout(() => { - bidModalObject.hide(); - amountElement.classList.remove("is-invalid"); + // Function that handles bidding logic + function placeBid() { + let nowTime = new Date().getTime(); + bidModalSubmit.setAttribute('disabled', '') // disable the button while we check + let i = Number(bidModal.dataset.activeAuction.match("[0-9]+")); + let endTime = document.querySelector(`.card[data-id="${i}"]`).dataset.endTime + let feedback = bidModal.querySelector(".invalid-feedback") + // Cleanse input + let amountElement = bidModal.querySelector("input") + let amount = Number(amountElement.value) + if (endTime - nowTime < 0) { + feedback.innerText = "The auction is already over!" + amountElement.classList.add("is-invalid") + setTimeout(() => { + bidModalObject.hide(); + amountElement.classList.remove("is-invalid"); + bidModalSubmit.removeAttribute('disabled', ''); + }, 1000); + } else if (amount == 0) { + // amount was empty + feedback.innerText = "Please specify an amount!" + amountElement.classList.add("is-invalid") bidModalSubmit.removeAttribute('disabled', ''); - }, 1000); - } else if (amount == 0) { - // amount was empty - feedback.innerText = "Please specify an amount!" - amountElement.classList.add("is-invalid") - bidModalSubmit.removeAttribute('disabled', ''); - } else if (!(/^-?\d*\.?\d{0,2}$/.test(amount))) { - // field is does not contain money - feedback.innerText = "Please specify a valid amount!" - amountElement.classList.add("is-invalid") - bidModalSubmit.removeAttribute('disabled', ''); - } else { - // Check auction database - let docRef = doc(db, "auction", "items"); - getDoc(docRef).then(function (doc) { - console.debug("placeBid() read from auction/items") - let data = doc.data() - let itemId = `item${i.toString().padStart(5, "0")}` - let bids = Object.keys(data).filter((key) => key.includes(itemId)) - let bidId = `bid${(bids.length).toString().padStart(5, "0")}` - let currentBid = data[bids[bids.length - 1]].amount - if (amount >= 1 + currentBid) { - updateDoc(docRef, { - [`${itemId}_${bidId}`]: { amount: amount, uid: auth.currentUser.uid }, - }) - console.debug("placeBid() write to auction/items") - amountElement.classList.add("is-valid") - amountElement.classList.remove("is-invalid") - setTimeout(() => { - bidModalObject.hide(); - amountElement.classList.remove("is-valid"); + } else if (!(/^-?\d*\.?\d{0,2}$/.test(amount))) { + // field is does not contain money + feedback.innerText = "Please specify a valid amount!" + amountElement.classList.add("is-invalid") + bidModalSubmit.removeAttribute('disabled', ''); + } else { + // Check auction database + let docRef = doc(db, "auction", "items"); + getDoc(docRef).then(function (doc) { + console.debug("placeBid() read from auction/items") + let data = doc.data() + let itemId = `item${i.toString().padStart(5, "0")}` + let bids = Object.keys(data).filter((key) => key.includes(itemId)) + let bidId = `bid${(bids.length).toString().padStart(5, "0")}` + let currentBid = data[bids[bids.length - 1]].amount + if (amount >= 1 + currentBid) { + updateDoc(docRef, { + [`${itemId}_${bidId}`]: { amount: amount, uid: auth.currentUser.uid }, + }) + console.debug("placeBid() write to auction/items") + amountElement.classList.add("is-valid") + amountElement.classList.remove("is-invalid") + setTimeout(() => { + bidModalObject.hide(); + amountElement.classList.remove("is-valid"); + bidModalSubmit.removeAttribute('disabled', ''); + }, 1000); + } else { + amountElement.classList.add("is-invalid") + feedback.innerText = "You must bid at least £" + (currentBid + 1).toFixed(2) + "!" bidModalSubmit.removeAttribute('disabled', ''); - }, 1000); - } else { - amountElement.classList.add("is-invalid") - feedback.innerText = "You must bid at least £" + (currentBid + 1).toFixed(2) + "!" - bidModalSubmit.removeAttribute('disabled', ''); - } - }); + } + }); + } } } // -- Info modal -- const infoModal = document.getElementById('info-modal') +if (infoModal) { + // Populate infoModal with the correct information before it is visible + infoModal.addEventListener("show.bs.modal", (event) => { + const infoModalTitle = infoModal.querySelector('.modal-title') + const infoModalDetail = infoModal.querySelector('.modal-body > p') + const infoModalSecondaryImage = infoModal.querySelector('.modal-body > img') + // Update variable content elements + const button = event.relatedTarget + const card = button.closest(".card") + infoModalTitle.innerText = card.dataset.title + infoModalDetail.innerText = card.dataset.detail + infoModalSecondaryImage.src = card.dataset.secondaryImage + // Add the auction ID to the bidModal, in case the user clicks "Submit bid" in infoModal + bidModal.dataset.activeAuction = card.dataset.id + }) -// Populate infoModal with the correct information before it is visible -infoModal.addEventListener("show.bs.modal", (event) => { - const infoModalTitle = infoModal.querySelector('.modal-title') - const infoModalDetail = infoModal.querySelector('.modal-body > p') - const infoModalSecondaryImage = infoModal.querySelector('.modal-body > img') - // Update variable content elements - const button = event.relatedTarget - const card = button.closest(".card") - infoModalTitle.innerText = card.dataset.title - infoModalDetail.innerText = card.dataset.detail - infoModalSecondaryImage.src = card.dataset.secondaryImage - // Add the auction ID to the bidModal, in case the user clicks "Submit bid" in infoModal - bidModal.dataset.activeAuction = card.id -}) - -// Clear the auction specific information from bidModal when hiding infoModal -bidModal.addEventListener("hide.bs.modal", () => { - bidModal.removeAttribute("data-bs-active-auction") -}) \ No newline at end of file + // Clear the auction specific information from bidModal when hiding infoModal + bidModal.addEventListener("hide.bs.modal", () => { + bidModal.removeAttribute("data-active-auction") + }) +} diff --git a/readme/adminpage.png b/readme/adminpage.png new file mode 100644 index 0000000000000000000000000000000000000000..b66dcbbbd012e6adf7300a403b858b6d10a25497 GIT binary patch literal 60658 zcmbrl1yq~e_b!NAaf(|Bw75fY_hQA}trWN7q(G726l*EPwYWRMp-6F;;BEnm1(MXC^1eCQ=j?snBYQv32EEr%!o#7$K|(^pQ&E=JMnXcxMnXcd!oqmI zgQNOL@ce=7rL823RP~4E@c9DGK}KB$38^;m#iJGa^EI}+vXK`O5`N!5Z{#7jQd=aX zlPDE=8C^f~lQlfUmkXUz7u=4$Z#ow`UAR})ahf?N3ps?a7v*!YEz6V2^VPq|D>(HF z@lXkrQWV_D5(?hwH!4D3TgT-qPU=3t(lZ)3mXTCmtTt4r_bvnLR-24mNivwu5Mw7u zVxuUr)+oofSK(kwx=O{mt=)7Dp9USBt-ZZmUwc2)7j z1~*81r8$1&>RgEFS;wi3pUR6JV5!mw@7IK8guxNihRC)x{9hAHArZTq;B^I?kaW0) z;?y)G$_;cqKyK3O3Il0}6uy@nTlF<}!a2esn$zyjc>gsPm2_B_=V3aP1NUjUH$=hB zwQ<|C-Y+ni4KguB{U0-;4uk!_rx`RSRJYbnG;evd8o^JS))Qa<$sxa1P>EC$E>VhDp4v9v2vvzbouZy$hAsm{@;<9vh
1|Bp+D-{e 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 literal 0 HcmV?d00001