diff --git a/app.ts b/app.ts new file mode 100644 index 00000000..dee58363 --- /dev/null +++ b/app.ts @@ -0,0 +1,281 @@ +let fromParameter = 0; +let recordCount: number; + +// Gets The 2nd paramater from the 1st parameter +function getParameters(fromParameter: number): number { + let toParameter: number; + let noOfRows = getNoOfRows(); + + toParameter = fromParameter + noOfRows; + return toParameter; +} + +// Gets the number of rows on the screen +function getNoOfRows(): number { + const height = window.innerHeight; + let noOfRows = Math.floor(height / 40); + return noOfRows; +} + +//// Functions To Create The HTML +// Heading Row +function createHeadingColumn(headingData: string) { + const heading: HTMLElement | null = document.getElementById("heading"); + + let headings = `
${headingData}
`; + if (heading !== null) { + heading.innerHTML += headings; + } +} + +// Table Content +function appendTableContent(contentData: string | string[]) { + const content: HTMLElement | null = document.getElementById("content"); + + let table = `
`; + if (content !== null) { + content.innerHTML += table; + } else { + return alert("ERROR"); + } + + let row: HTMLElement | null = document.getElementById("row-" + contentData[0]); + for (let x of contentData) { + let rowCols = `
${x}
`; + if (row !== null) { + row.innerHTML += rowCols; + } + } +} + +//// Fetch Requests +// Response Error Handling +function handleErrors(response: Response) { + if (!response.ok) { + throw Error(response.statusText); + } + return response; +} + +// Heading Row (Getting the columns data) +function getHeadings(): Promise { + return fetch("http://localhost:2050/columns", { + method: "GET", + headers: { "Content-Type": "application/json" }, + }) + .then(handleErrors) + .then((response: Response) => response.json()) + .then((headingData: string[]) => { + for (let heading of headingData) { + createHeadingColumn(heading); + } + }) + .catch((error: Error) => { + console.log(error); + }); +} + +// Table Content (Getting the table's data) +function getTable(): Promise { + const content: HTMLElement | null = document.getElementById("content"); + let toParameter = getParameters(fromParameter); + const pageStats: HTMLElement | null = document.getElementById("pageStats"); + + // Clears Table + if (content !== null) { + content.innerHTML = ""; + } + + // Displays The Current Results Being Shown + let currentStats = `Showing results from ${fromParameter} to ${toParameter} out of ${recordCount} results.`; + if (pageStats !== null) { + pageStats.innerHTML = currentStats; + } + + return fetch(`http://localhost:2050/records?from=${fromParameter}&to=${toParameter}`, { + method: "GET", + headers: { "Content-Type": "application/json" }, + }) + .then(handleErrors) + .then((res: Response) => res.json()) + .then((contentData: string[]) => { + for (let x of contentData) { + appendTableContent(x); + } + }) + .catch((error: Error) => { + console.log(error); + }); +} + +// Gets Total Of All Records +function getRecordCount(): Promise { + return fetch("http://localhost:2050/recordCount", { + method: "GET", + headers: { "Content-Type": "application/json" }, + }) + .then(handleErrors) + .then((res: Response) => res.json()) + .then((data: number) => { + recordCount = data; + }) + .catch((error: Error) => { + console.log(error); + }); +} + +//// Debounce +function debounce(fn: () => void, delay: number) { + let timer: number + return function () { + clearTimeout(timer); + timer = setTimeout(() => { + fn(); + }, delay); + }; +} + +//// Sizing And Resizing +function resizing() { + let end = fromParameter + getNoOfRows(); + let toParameter: number; + let maxRecordsID = recordCount - 1; + + if (end > maxRecordsID) { + toParameter = maxRecordsID; + fromParameter = toParameter - getNoOfRows(); + } + getTable(); +} + +//// Navigation +// Next +class Next { + nextButton: HTMLElement | null; + nextTimer: number = 0; + + constructor() { + this.nextButton = document.getElementById("next"); + + const nextDebounce = (fn: () => void, delay: number) => { + clearTimeout(this.nextTimer); + this.nextTimer = setTimeout(() => { + fn(); + }, delay); + }; + + let next = () => { + let toParameter = getParameters(fromParameter); + let maxRecordsID = recordCount - 1; + + if (toParameter === maxRecordsID) { + alert("You have reached the final page"); + } + + let nextAmount = toParameter - fromParameter + 1; + fromParameter = fromParameter + nextAmount; + toParameter = fromParameter + getNoOfRows(); + + let end = fromParameter + getNoOfRows(); + + if (end > maxRecordsID) { + toParameter = maxRecordsID; + fromParameter = toParameter - getNoOfRows(); + } + + nextDebounce(getTable, 500); + }; + + if (this.nextButton) { + this.nextButton.addEventListener("click", next); + } + } +} + +// Previous +class Prev { + prevButton: HTMLElement | null; + prevTimer: number = 0; + + constructor() { + this.prevButton = document.getElementById("prev"); + + const prevDebounce = (fn: () => void, delay: number) => { + clearTimeout(this.prevTimer); + this.prevTimer = setTimeout(() => { + fn(); + }, delay); + }; + + let prev = () => { + let toParameter = getParameters(fromParameter); + + if (fromParameter === 0) { + alert("You Have Reached The First Page"); + } else { + let prevAmount = toParameter - fromParameter + 1; + + let intOne = fromParameter - prevAmount; + + if (intOne < 0) { + fromParameter = 0; + } else { + fromParameter = intOne; + } + + prevDebounce(getTable, 500); + } + }; + + if (this.prevButton) { + this.prevButton.addEventListener("click", prev); + } + } +} + +// ID Jump +function idJump() { + const input: HTMLInputElement | null = document.querySelector("input"); + let toParameter = getParameters(fromParameter); + let currentID = fromParameter; + let search: string; + if (input) { + search = input.value; + } else { + return alert("ERROR!!!"); + } + let end = parseInt(search) + getNoOfRows(); + let maxRecordsID = recordCount - 1; + + if (search !== "" && parseInt(search) <= maxRecordsID && parseInt(search) >= 0) { + if (end > maxRecordsID) { + toParameter = maxRecordsID; + fromParameter = toParameter - getNoOfRows(); + } else { + fromParameter = parseInt(search); + toParameter = fromParameter + getNoOfRows(); + } + } else if (search !== "") { + alert("Make Sure Your Desired ID Is Not A Negative Number Or Doesn't Exceed 999999"); + fromParameter = currentID; + toParameter = fromParameter + getNoOfRows(); + input.value = ""; + } + + getTable(); +} + +//// On Window Load +window.onload = () => { + const next = new Next(); // next class + const prev = new Prev(); // prev class + window.addEventListener("input", debounce(idJump, 500)); + window.addEventListener("resize", debounce(resizing, 500)); + getRecordCount() + .then(() => { + return getHeadings(); + }) + .then(() => { + return getTable(); + }); +}; diff --git a/index.html b/index.html index add5e736..9da857c8 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,30 @@ - + + - JS Onboard Project + + + + Onboarding JavaScript Task + + -

Hello

+ +
+
- diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..57a8346d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,28 @@ +{ + "name": "onboard-javascript", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/jquery": { + "version": "3.5.14", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.14.tgz", + "integrity": "sha512-X1gtMRMbziVQkErhTQmSe2jFwwENA/Zr+PprCkF63vFq+Yt5PZ4AlKqgmeNlwgn7dhsXEK888eIW2520EpC+xg==", + "dev": true, + "requires": { + "@types/sizzle": "*" + } + }, + "@types/sizzle": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "dev": true + }, + "typescript": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..5f167012 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "onboard-javascript", + "version": "1.0.0", + "description": "This is a JavaScript project for all new developers to complete before venturing into our web frontend codebase.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc --build" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Koumori97/onboard-javascript.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/Koumori97/onboard-javascript/issues" + }, + "homepage": "https://github.com/Koumori97/onboard-javascript#readme", + "dependencies": { + "typescript": "^4.6.3" + }, + "devDependencies": { + "@types/jquery": "^3.5.14" + } +} diff --git a/style.css b/style.css new file mode 100644 index 00000000..64c7b246 --- /dev/null +++ b/style.css @@ -0,0 +1,115 @@ +* { + padding: 0; + margin: 0; + box-sizing: border-box; + overflow-y: hidden; + overflow-x: hidden; +} + +body { + height: 100vh; +} + +/* Navigation */ + +#nav { + background-color: #000; + display: flex; + flex-direction: row; + color: #fff; + height: 5%; + width: 100%; +} + +#pageStats { + position: absolute; + left: 1%; + top: 1%; +} + +#jumpID { + position: absolute; + left: 50%; + top: 1%; + transform: translate(-50%, -1%); +} +#jumpID input { + border: none; + margin-right: 20px; + padding: 7px 10px; + text-align: center; +} + +#btns { + position: absolute; + right: 1%; + top: 1%; +} +#btns .next { + margin-left: 20px; +} + +button { + border: none; + padding: 5px 10px; + border-radius: 10px; + width: 100px; + color: #000; + background-color: #fff; + cursor: pointer; + transition: all 0.3s; + transition-timing-function: ease-in-out; +} +button:hover { + letter-spacing: 1px; + color: #fff; + background-color: #000; + border: 1px solid #fff; +} + +/* Headings */ + +#heading { + display: flex; + justify-content: space-between; + align-items: center; + flex-direction: row; + width: 100%; + height: 10vh; +} +#headings { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + font-size: 1em; + font-weight: bold; + border: 1px solid #000; +} + +/* Table */ +#content { + display: flex; + flex-direction: column; + height: 85vh; + width: 100%; +} +.rows { + display: flex; + justify-content: center; + align-items: center; + flex-direction: row; + height: 100%; + width: 100%; +} +.row_cols { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + font-size: 1em; + border: 1px solid #000; + word-wrap: break-word; +}