From 8487ca928744509edebd446d77c7e1802f44193b Mon Sep 17 00:00:00 2001 From: charlesleezhaoyi Date: Tue, 31 Oct 2023 21:07:59 +0800 Subject: [PATCH 01/10] Commit #1: Initialised Bootstrap and added NavBar --- package-lock.json | 41 +++++++++++++++++++++++++++++++++++++++++ package.json | 1 + public/index.html | 11 +++++++++++ src/App.css | 5 +++++ src/App.js | 27 ++++++++++++++++++++------- src/index.js | 3 +++ 6 files changed, 81 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index c205fc57..c879bf5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "project1-bootcamp", "version": "0.1.0", "dependencies": { + "bootstrap": "^5.3.2", "react": "^18.1.0", "react-dom": "^18.1.0", "react-scripts": "5.0.1" @@ -2866,6 +2867,16 @@ } } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -4635,6 +4646,24 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "node_modules/bootstrap": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz", + "integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -17810,6 +17839,12 @@ "source-map": "^0.7.3" } }, + "@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "peer": true + }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -19142,6 +19177,12 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "bootstrap": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz", + "integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==", + "requires": {} + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", diff --git a/package.json b/package.json index a100866d..71a66ab1 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "bootstrap": "^5.3.2", "react": "^18.1.0", "react-dom": "^18.1.0", "react-scripts": "5.0.1" diff --git a/public/index.html b/public/index.html index bd669818..bb0e841a 100644 --- a/public/index.html +++ b/public/index.html @@ -9,6 +9,12 @@ name="description" content="Web site created using create-react-app" /> + + diff --git a/src/App.css b/src/App.css index 97b7c578..3c088e4e 100644 --- a/src/App.css +++ b/src/App.css @@ -17,3 +17,8 @@ font-size: calc(10px + 2vmin); color: white; } + +.navbar { + top: 0; + position: sticky; +} diff --git a/src/App.js b/src/App.js index 4a6f800f..5a13b9ed 100644 --- a/src/App.js +++ b/src/App.js @@ -1,17 +1,30 @@ import React from "react"; import logo from "./logo.png"; import "./App.css"; +//Initialised bootstrap +import "bootstrap/dist/css/bootstrap.min.css"; +import "bootstrap/dist/js/bootstrap.bundle.min"; class App extends React.Component { render() { return ( -
-
- logo -

- Edit src/App.js and save to reload. -

-
+
+ + +
+
+ logo +

+ Edit src/App.js and save to reload. +

+
+
); } diff --git a/src/index.js b/src/index.js index 31508db1..256a8210 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,9 @@ import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; +//Initialised bootstrap +import "bootstrap/dist/css/bootstrap.min.css"; +import "bootstrap/dist/js/bootstrap.bundle.min"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( From cee3706615885e25efe3b9ca5ba353a9cebc0737 Mon Sep 17 00:00:00 2001 From: charlesleezhaoyi Date: Sat, 4 Nov 2023 12:03:38 +0800 Subject: [PATCH 02/10] Commit #1 - Completed Top Bar. Basic functionality for Module Form. Pending fixes to add to Module List --- src/App.css | 20 ---- src/App.js | 22 +---- .../ModuleControl/ModuleController.css | 0 .../ModuleControl/ModuleController.js | 0 src/Components/ModuleForm/ModuleForm.css | 16 ++++ src/Components/ModuleForm/ModuleForm.js | 96 +++++++++++++++++++ src/Components/NavBar/Navbar.css | 4 + src/Components/NavBar/Navbar.js | 13 +++ 8 files changed, 133 insertions(+), 38 deletions(-) create mode 100644 src/Components/ModuleControl/ModuleController.css create mode 100644 src/Components/ModuleControl/ModuleController.js create mode 100644 src/Components/ModuleForm/ModuleForm.css create mode 100644 src/Components/ModuleForm/ModuleForm.js create mode 100644 src/Components/NavBar/Navbar.css create mode 100644 src/Components/NavBar/Navbar.js diff --git a/src/App.css b/src/App.css index 3c088e4e..1c0059be 100644 --- a/src/App.css +++ b/src/App.css @@ -1,23 +1,3 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - .navbar { top: 0; position: sticky; diff --git a/src/App.js b/src/App.js index 5a13b9ed..de0e82ce 100644 --- a/src/App.js +++ b/src/App.js @@ -1,30 +1,16 @@ import React from "react"; -import logo from "./logo.png"; import "./App.css"; -//Initialised bootstrap import "bootstrap/dist/css/bootstrap.min.css"; import "bootstrap/dist/js/bootstrap.bundle.min"; +import Navbar from "./Components/NavBar/Navbar"; +import ModuleForm from "./Components/ModuleForm/ModuleForm"; class App extends React.Component { render() { return (
- - -
-
- logo -

- Edit src/App.js and save to reload. -

-
-
+ +
); } diff --git a/src/Components/ModuleControl/ModuleController.css b/src/Components/ModuleControl/ModuleController.css new file mode 100644 index 00000000..e69de29b diff --git a/src/Components/ModuleControl/ModuleController.js b/src/Components/ModuleControl/ModuleController.js new file mode 100644 index 00000000..e69de29b diff --git a/src/Components/ModuleForm/ModuleForm.css b/src/Components/ModuleForm/ModuleForm.css new file mode 100644 index 00000000..ba7f5c42 --- /dev/null +++ b/src/Components/ModuleForm/ModuleForm.css @@ -0,0 +1,16 @@ +.button-enabled { + background-color: #4caf50; + color: white; + border: none; + border-radius: 5px; + padding: 10px; + cursor: pointer; +} + +.button-disabled { + background-color: #cccccc; + border: none; + border-radius: 5px; + padding: 10px; + cursor: not-allowed; +} diff --git a/src/Components/ModuleForm/ModuleForm.js b/src/Components/ModuleForm/ModuleForm.js new file mode 100644 index 00000000..4f8efb99 --- /dev/null +++ b/src/Components/ModuleForm/ModuleForm.js @@ -0,0 +1,96 @@ +import React, { Component } from "react"; + +class ModuleForm extends Component { + constructor(props) { + super(props); + this.state = { + enabled: "1", + userAction: "", + moduleName: "", + moduleList: [], + grade: "", + }; + } + + handleActionChange = (event) => { + this.setState({ + userAction: event.target.value, + }); + }; + + handleSubmit = (event) => { + const { userAction, moduleList, moduleName, grade } = this.state; + + if (userAction === "Add") { + //Add a new module to the list + const newModule = { moduleName, grade }; + this.setState({ + moduleList: [...moduleList, newModule], + moduleName: "", + grade: "", + }); + } else if (userAction === "Update") { + // Add logic for updating modules + } else if (userAction === "Delete") { + // Add logic for deleting modules + } + + event.preventDefault(); + }; + + render() { + const { enabled, moduleName, grade, userAction, moduleList } = this.state; + return ( +
+ + this.setState({ moduleName: e.target.value })} + placeholder="Module Name" + /> + + + + {/* Display the module list */} +
+

Module List

+
    + {moduleList.map((module, index) => ( +
  • + {moduleName} - {grade} +
  • + ))} +
+
+
+ ); + } +} + +export default ModuleForm; diff --git a/src/Components/NavBar/Navbar.css b/src/Components/NavBar/Navbar.css new file mode 100644 index 00000000..1c0059be --- /dev/null +++ b/src/Components/NavBar/Navbar.css @@ -0,0 +1,4 @@ +.navbar { + top: 0; + position: sticky; +} diff --git a/src/Components/NavBar/Navbar.js b/src/Components/NavBar/Navbar.js new file mode 100644 index 00000000..836360f3 --- /dev/null +++ b/src/Components/NavBar/Navbar.js @@ -0,0 +1,13 @@ +import React from "react"; + +class Navbar extends React.Component { + render() { + return ( +
+

GPA Calculator

+
+ ); + } +} + +export default Navbar; From ededf28de07cce136636e6b71fd3bc88a6c21e89 Mon Sep 17 00:00:00 2001 From: charlesleezhaoyi Date: Sat, 4 Nov 2023 16:21:57 +0800 Subject: [PATCH 03/10] Commit #2 - Completed MVP for Add Module function. Added ability to set localStorage. Pending fixes for State initialisation for userAction and grade, and implementation for fetching from localStorage --- src/Components/ModuleForm/ModuleForm.js | 56 ++++++++++++++++--------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/src/Components/ModuleForm/ModuleForm.js b/src/Components/ModuleForm/ModuleForm.js index 4f8efb99..1ed79bd7 100644 --- a/src/Components/ModuleForm/ModuleForm.js +++ b/src/Components/ModuleForm/ModuleForm.js @@ -5,41 +5,58 @@ class ModuleForm extends Component { super(props); this.state = { enabled: "1", - userAction: "", + userAction: "Add", moduleName: "", moduleList: [], - grade: "", + grade: "A", }; } - handleActionChange = (event) => { - this.setState({ - userAction: event.target.value, - }); - }; - handleSubmit = (event) => { const { userAction, moduleList, moduleName, grade } = this.state; + console.log("handleSubmit"); + if (userAction === "Add") { //Add a new module to the list const newModule = { moduleName, grade }; - this.setState({ - moduleList: [...moduleList, newModule], - moduleName: "", - grade: "", - }); + console.log("Add Module"); + this.setState( + { + moduleList: [...moduleList, newModule], + moduleName: "", + grade: "", + userAction: "Add", + }, + () => { + localStorage.setItem( + "moduleList", + JSON.stringify(this.state.moduleList) + ); + } + ); } else if (userAction === "Update") { + console.log("Update Module"); + // Add logic for updating modules } else if (userAction === "Delete") { // Add logic for deleting modules + console.log("Delete Module"); } event.preventDefault(); }; + handleActionChange = (event) => { + this.setState({ + userAction: event.target.value, + }); + console.log("Action Change"); + event.preventDefault(); + }; + render() { - const { enabled, moduleName, grade, userAction, moduleList } = this.state; + const { enabled, userAction, moduleName, moduleList, grade } = this.state; return (
@@ -70,6 +126,7 @@ class ModuleForm extends Component { onChange={(e) => this.setState({ moduleName: e.target.value })} placeholder="Module Name" /> + - - - - - this.setState({ moduleName: e.target.value })} - placeholder="Module Name" - /> +
+ + this.setState({ moduleName: e.target.value })} + className="module-name" + placeholder="Module Name" + /> - - - {error &&
{error}
} - {/* Display the module list */} + + + + {/* Display the module list */} + + {error &&
{error}
} +

Module List

-

Module List

-
    + + {moduleList && + moduleList.map((module, index) => ( + {module.moduleName} + ))} {moduleList && moduleList.map((module, index) => ( -
  • - {module.moduleName} - {module.grade} -
  • + {module.grade} ))} -
+ +
+ {/* Display the GPA */} +
+

GPA: {gpa.toFixed(2)}

- +
); } } diff --git a/src/Components/NavBar/Navbar.js b/src/Components/NavBar/Navbar.js index 836360f3..44d764cc 100644 --- a/src/Components/NavBar/Navbar.js +++ b/src/Components/NavBar/Navbar.js @@ -1,4 +1,5 @@ import React from "react"; +import "./Navbar.css"; class Navbar extends React.Component { render() { From 9a047f80cc2d9093199fe7295017edc76dc237a4 Mon Sep 17 00:00:00 2001 From: charlesleezhaoyi Date: Tue, 14 Nov 2023 19:56:47 +0800 Subject: [PATCH 06/10] Commit #5 - Fixed local storage bug, ensured prevent.Default is present to prevent re-rendering and light styling --- src/App.css | 5 + src/App.js | 2 +- src/Components/ModuleForm/ModuleForm.css | 54 +++++---- src/Components/ModuleForm/ModuleForm.js | 147 ++++++++++++++++++++--- 4 files changed, 172 insertions(+), 36 deletions(-) diff --git a/src/App.css b/src/App.css index 1c0059be..ef3f706a 100644 --- a/src/App.css +++ b/src/App.css @@ -2,3 +2,8 @@ top: 0; position: sticky; } + +.app { + background-color: antiquewhite; + height: 100vh; +} diff --git a/src/App.js b/src/App.js index de0e82ce..3650179f 100644 --- a/src/App.js +++ b/src/App.js @@ -8,7 +8,7 @@ import ModuleForm from "./Components/ModuleForm/ModuleForm"; class App extends React.Component { render() { return ( -
+
diff --git a/src/Components/ModuleForm/ModuleForm.css b/src/Components/ModuleForm/ModuleForm.css index c3aee36b..edae0127 100644 --- a/src/Components/ModuleForm/ModuleForm.css +++ b/src/Components/ModuleForm/ModuleForm.css @@ -17,8 +17,6 @@ cursor: not-allowed; } -.module-form-card { -} .module-form { background-color: rgb(255, 255, 255); display: flex; @@ -27,45 +25,59 @@ justify-content: center; } -.module-list { - display: flex; - flex-direction: column; - width: 100%; - align-items: center; -} - .module-list-title { width: 100%; align-items: left; } - -.module-list-item { +/* Thead */ +/* TO FIX ALL OF THE FOLLOWING*/ +table { + display: table-row; + margin-left: 50; width: 100%; - align-items: center; + border-collapse: collapse; + border-spacing: 0; +} + +tr { + height: 30px; +} + +.list-group { + width: 40em; + align-content: center; } .list-group-item { - width: 100%; + height: 55px; + vertical-align: center; align-content: center; - padding-left: 20%; } +.remove-button { + margin-right: 0; +} + +/* GPA */ + .gpa-result { display: flex; flex-direction: column; align-items: center; } -.action-selector { - height: 2%; - margin-left: 5%; +/* Module Form */ + +.module-name { padding: 1%; + height: 2%; border-radius: 10px; } -.module-name { - padding: 1%; +.action-selector { height: 2%; + margin-left: 5%; + padding: 1%; border-radius: 10px; } @@ -78,6 +90,6 @@ .error-message { color: red; - font-size: 12px; - align-item: center; + font-size: 20px; + margin-left: 50%; } diff --git a/src/Components/ModuleForm/ModuleForm.js b/src/Components/ModuleForm/ModuleForm.js index 4448af93..7e621c0c 100644 --- a/src/Components/ModuleForm/ModuleForm.js +++ b/src/Components/ModuleForm/ModuleForm.js @@ -12,7 +12,7 @@ class ModuleForm extends Component { moduleName: "", moduleList: JSON.parse(localStorage.getItem("moduleList")) || [], grade: "A", - error: null, + error: "", }; } @@ -21,6 +21,13 @@ class ModuleForm extends Component { console.log("handleSubmit"); + if (moduleName === "") { + this.setState({ + error: "Module Name cannot be empty", + }); + event.preventDefault(); + return; + } // Add logic for adding modules if (userAction === "Add") { const newModule = { moduleName, grade }; @@ -34,6 +41,7 @@ class ModuleForm extends Component { error: "Duplicate Module Name", moduleList: [...moduleList], }); + event.preventDefault(); return; } else { this.setState({ error: null }); @@ -197,20 +205,131 @@ class ModuleForm extends Component { {/* Display the module list */} - {error &&
{error}
} + {error ?
{error}
:
}

Module List

-
- - {moduleList && - moduleList.map((module, index) => ( - {module.moduleName} - ))} - {moduleList && - moduleList.map((module, index) => ( - {module.grade} - ))} - -
+ + + + {moduleList && + moduleList.map((module, index) => ( + + {module.moduleName} + + ))} + + + + + + {moduleList && + moduleList.map((module, index) => ( + + {module.grade} + + ))} + + + + + + {moduleList && + moduleList.map((module, index) => ( + + + + ))} + + + + + + {/* + Modules + + + {moduleList && + moduleList.map((module, index) => ( + + {module.moduleName} + + ))} + + + + + {moduleList && + moduleList.map((module, index) => ( + {module.grade} + ))} + + + + */} +
+ + {" "} + Modules +
+ {" "} + Grades +
+ {" "} + Action +
+ Grades +
+ Action + + {moduleList && + moduleList.map((module, index) => ( + + + + ))} + +
{/* Display the GPA */}

GPA: {gpa.toFixed(2)}

From 56ffebad069bf4d4d648241a0af7fe4b26d93e12 Mon Sep 17 00:00:00 2001 From: charlesleezhaoyi Date: Tue, 14 Nov 2023 21:15:07 +0800 Subject: [PATCH 07/10] Commit #7 - Added mobile responsiveness --- src/Components/ModuleForm/ModuleForm.css | 53 ++++- src/Components/ModuleForm/ModuleForm.js | 283 +++++++++-------------- 2 files changed, 158 insertions(+), 178 deletions(-) diff --git a/src/Components/ModuleForm/ModuleForm.css b/src/Components/ModuleForm/ModuleForm.css index edae0127..87aa191a 100644 --- a/src/Components/ModuleForm/ModuleForm.css +++ b/src/Components/ModuleForm/ModuleForm.css @@ -21,41 +21,73 @@ background-color: rgb(255, 255, 255); display: flex; flex-direction: row; + padding: 3% 3% 2% 2%; width: 100%; justify-content: center; } +@media screen and (max-width: 600px) { + .module-form { + flex-direction: column; + } +} + .module-list-title { width: 100%; align-items: left; } /* Thead */ /* TO FIX ALL OF THE FOLLOWING*/ + table { - display: table-row; - margin-left: 50; + display: flex; + flex-direction: row; + justify-content: center; + margin: 0 auto; width: 100%; + padding: 1% 1% 2% 2%; border-collapse: collapse; border-spacing: 0; } -tr { +td { height: 30px; + font-size: 14px; + vertical-align: center; +} + +tr { + vertical-align: center; } .list-group { - width: 40em; + width: 25vw; align-content: center; + overflow: hidden; + text-align: center; } .list-group-item { - height: 55px; - vertical-align: center; - align-content: center; + height: 6vh; + align-items: center; +} + +/* Mobile Responsive */ +@media only screen and (max-width: 374px) { + table { + margin-left: 0; + } + td { + display: block; + height: 10vh; + } } .remove-button { - margin-right: 0; + background-color: #ef4444; + border: none; + border-radius: 5px; + cursor: pointer; } /* GPA */ @@ -69,6 +101,7 @@ tr { /* Module Form */ .module-name { + margin-left: 5%; padding: 1%; height: 2%; border-radius: 10px; @@ -90,6 +123,6 @@ tr { .error-message { color: red; - font-size: 20px; - margin-left: 50%; + font-size: 12px; + text-align: center; } diff --git a/src/Components/ModuleForm/ModuleForm.js b/src/Components/ModuleForm/ModuleForm.js index 7e621c0c..fa52b53f 100644 --- a/src/Components/ModuleForm/ModuleForm.js +++ b/src/Components/ModuleForm/ModuleForm.js @@ -1,7 +1,6 @@ import React, { Component } from "react"; import "./ModuleForm.css"; -import { Button, ListGroup } from "react-bootstrap"; -import ListGroupItem from "react-bootstrap"; +import { Button, ListGroup, Card } from "react-bootstrap"; class ModuleForm extends Component { constructor(props) { @@ -161,175 +160,123 @@ class ModuleForm extends Component { const gpa = this.calculateGPA(); return (
-
- this.setState({ moduleName: e.target.value })} - className="module-name" - placeholder="Module Name" - /> + + + this.setState({ moduleName: e.target.value })} + className="module-name" + placeholder="Module Name" + /> - - - - {/* Display the module list */} - + + + + {/* Display the module list */} + +
{error ?
{error}
:
}

Module List

- - - - {moduleList && - moduleList.map((module, index) => ( - - {module.moduleName} - - ))} - - - - - - {moduleList && - moduleList.map((module, index) => ( - - {module.grade} - - ))} - - - - - - {moduleList && - moduleList.map((module, index) => ( - - - - ))} - - - - - - {/* - Modules - - - {moduleList && - moduleList.map((module, index) => ( - - {module.moduleName} - - ))} - - - - - {moduleList && - moduleList.map((module, index) => ( - {module.grade} - ))} - - - - */} -
- - {" "} - Modules -
- {" "} - Grades -
- {" "} - Action -
- Grades -
- Action - - {moduleList && - moduleList.map((module, index) => ( - - - - ))} - -
+ + + + + {moduleList && + moduleList.map((module, index) => ( + + {module.moduleName} + + ))} + + + + + + {moduleList && + moduleList.map((module, index) => ( + + {module.grade} + + ))} + + + + + + {moduleList && + moduleList.map((module, index) => ( + + + + ))} + + + + +
+ + {" "} +

Modules

+
+ {" "} +

Grades

+
+ {" "} +

Action

+
+
{/* Display the GPA */}

GPA: {gpa.toFixed(2)}

From 6f0a051ef5b6b35554c840735ae592a79f300aac Mon Sep 17 00:00:00 2001 From: charlesleezhaoyi Date: Sat, 18 Nov 2023 10:00:14 +0800 Subject: [PATCH 08/10] Commit #8 - Added new error messages --- src/Components/ModuleForm/ModuleForm.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Components/ModuleForm/ModuleForm.js b/src/Components/ModuleForm/ModuleForm.js index fa52b53f..27ee29c2 100644 --- a/src/Components/ModuleForm/ModuleForm.js +++ b/src/Components/ModuleForm/ModuleForm.js @@ -73,6 +73,16 @@ class ModuleForm extends Component { } }); + if (updatedModuleList.length === moduleList.length) { + console.log("No module found"); + this.setState({ + error: "No module found", + moduleList: [...moduleList], + }); + event.preventDefault(); + return; + } + this.setState( { moduleList: updatedModuleList, @@ -94,6 +104,17 @@ class ModuleForm extends Component { const updatedModuleList = moduleList.filter( (module) => module.moduleName !== newModule.moduleName ); + + if (updatedModuleList.length === moduleList.length) { + console.log("No module found"); + this.setState({ + error: "No module found", + moduleList: [...moduleList], + }); + event.preventDefault(); + return; + } + this.setState( { moduleList: [...updatedModuleList], From 7ebb8edd514af3c43354ce927f09edd54125c0a3 Mon Sep 17 00:00:00 2001 From: charlesleezhaoyi <62235863+charlesleezhaoyi@users.noreply.github.com> Date: Sat, 18 Nov 2023 11:45:23 +0800 Subject: [PATCH 09/10] Update README.md --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e273017e..0ba63d24 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,17 @@ # Rocket Academy Coding Bootcamp: Project 1: Frontend App -https://bc.rocketacademy.co/1-frontend/1.p-frontend-app +# Background +This project was created in a bid to simplify the user experience for users who would like to compute their GPA, for their university modules. There are a few assumptions: +1. This project caters specifically to NUS academic grading system +2. This project assumes that each module is of 4 academic credits ## Available Scripts This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). In the project directory, you can run: +### `npm install` +Installs the packages and libraries required to run the application + ### `npm start` Runs the app in the development mode.\ @@ -13,3 +19,8 @@ Open [http://localhost:3000](http://localhost:3000) to view it in your browser. The page will reload when you make changes.\ You may also see any lint errors in the console. + +# Future Enhancements +1. Allow user to configure the weightage of each module +2. Allow user to choose from a list of pre-selected module codes/names +3. Allow user to specify university and conditionally change GPA computation logic. From caaf7396ae6e0b1330e6191bd201b12c4b9e6525 Mon Sep 17 00:00:00 2001 From: charlesleezhaoyi Date: Sat, 18 Nov 2023 12:10:17 +0800 Subject: [PATCH 10/10] Commit #10 - Deploy to Github Pages --- package-lock.json | 275 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 + 2 files changed, 278 insertions(+) diff --git a/package-lock.json b/package-lock.json index acdb7e1c..92875db4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "bootstrap": "^5.3.2", + "gh-pages": "^6.0.0", "react": "^18.1.0", "react-bootstrap": "^2.9.1", "react-dom": "^18.1.0", @@ -4231,6 +4232,14 @@ "node": ">=8" } }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array.prototype.flat": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", @@ -6105,6 +6114,11 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.131.tgz", "integrity": "sha512-oi3YPmaP87hiHn0c4ePB67tXaF+ldGhxvZnT19tW9zX6/Ej+pLN0Afja5rQ6S+TND7I9EuwQTT8JYn1k7R7rrw==" }, + "node_modules/email-addresses": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==" + }, "node_modules/emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -7228,6 +7242,30 @@ "node": ">=10" } }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/filesize": { "version": "8.0.7", "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", @@ -7663,6 +7701,79 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gh-pages": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.0.0.tgz", + "integrity": "sha512-FXZWJRsvP/fK2HJGY+Di6FRNHvqFF6gOIELaopDjXXgjeOYSNURcuYwEO/6bwuq6koP5Lnkvnr5GViXzuOB89g==", + "dependencies": { + "async": "^3.2.4", + "commander": "^11.0.0", + "email-addresses": "^5.0.0", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^11.1.1", + "globby": "^6.1.0" + }, + "bin": { + "gh-pages": "bin/gh-pages.js", + "gh-pages-clean": "bin/gh-pages-clean.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gh-pages/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gh-pages/node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/gh-pages/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "engines": { + "node": ">=16" + } + }, + "node_modules/gh-pages/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/gh-pages/node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -11633,6 +11744,33 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/pirates": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", @@ -14445,6 +14583,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/style-loader": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", @@ -14909,6 +15058,17 @@ "node": ">=8" } }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tryer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", @@ -19094,6 +19254,11 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==" + }, "array.prototype.flat": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", @@ -20454,6 +20619,11 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.131.tgz", "integrity": "sha512-oi3YPmaP87hiHn0c4ePB67tXaF+ldGhxvZnT19tW9zX6/Ej+pLN0Afja5rQ6S+TND7I9EuwQTT8JYn1k7R7rrw==" }, + "email-addresses": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==" + }, "emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -21283,6 +21453,21 @@ } } }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==" + }, + "filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + } + }, "filesize": { "version": "8.0.7", "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", @@ -21576,6 +21761,62 @@ "get-intrinsic": "^1.1.1" } }, + "gh-pages": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.0.0.tgz", + "integrity": "sha512-FXZWJRsvP/fK2HJGY+Di6FRNHvqFF6gOIELaopDjXXgjeOYSNURcuYwEO/6bwuq6koP5Lnkvnr5GViXzuOB89g==", + "requires": { + "async": "^3.2.4", + "commander": "^11.0.0", + "email-addresses": "^5.0.0", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^11.1.1", + "globby": "^6.1.0" + }, + "dependencies": { + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "requires": { + "array-uniq": "^1.0.1" + } + }, + "async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==" + }, + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + } + } + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -24450,6 +24691,24 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "requires": { + "pinkie": "^2.0.0" + } + }, "pirates": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", @@ -26373,6 +26632,14 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "style-loader": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", @@ -26719,6 +26986,14 @@ "punycode": "^2.1.1" } }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "tryer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", diff --git a/package.json b/package.json index 7c3b81d6..6f96152d 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,15 @@ "private": true, "dependencies": { "bootstrap": "^5.3.2", + "gh-pages": "^6.0.0", "react": "^18.1.0", "react-bootstrap": "^2.9.1", "react-dom": "^18.1.0", "react-scripts": "5.0.1" }, "scripts": { + "predeploy": "npm run build", + "deploy": "gh-pages -b master -d build", "start": "react-scripts start", "build": "react-scripts build" },