diff --git a/README.md b/README.md index 58beeac..c264bff 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,20 @@ -# Getting Started with Create React App - -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). - -## Available Scripts - -In the project directory, you can run: - -### `npm start` - -Runs the app in the development mode.\ -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. - -### `npm test` - -Launches the test runner in the interactive watch mode.\ -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. - -### `npm run build` - -Builds the app for production to the `build` folder.\ -It correctly bundles React in production mode and optimizes the build for the best performance. - -The build is minified and the filenames include the hashes.\ -Your app is ready to be deployed! - -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. - -### `npm run eject` - -**Note: this is a one-way operation. Once you `eject`, you can't go back!** - -If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. - -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. - -You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). - -### Code Splitting - -This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) - -### Analyzing the Bundle Size - -This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) - -### Making a Progressive Web App - -This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) - -### Advanced Configuration - -This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) - -### Deployment - -This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) - -### `npm run build` fails to minify - -This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) +# Tidey - Course Organization Website +### Brief Overview ### +After a year of using random websites to calculate the grades I need to pass my courses, I realized having one place with all this information would be much more helpful. Tidey is a course organization website that calculates and saves your grades, course information, and important files all in one place. + +https://github.com/uzFer/tidey/assets/109243682/c90e0f0d-3baf-44fc-9d02-aeb115942294 + +### Features ### +- Grade calculator (for any non-registered user) +- Course dashboard displayed in carousel + - Users can add, edit, or delete courses to their dashboard + - Each course has its own grade calculator which saves any input changes + - Ability to upload and label files (i.e. syllabi, rubrics, etc.) +- Sign up/login pages + +### Tech Used ### +- Used _React.js_ for building the UI, including animation on homescreen, modals, and course card layouts. +- _Google Firebase_ for account management, specifically: + - _Firestore Database_ for storing all course info + - _Authentication_ for storing user emails + validating upon sign in/sign up + - _Storage_ for holding the users' course-related files diff --git a/package-lock.json b/package-lock.json index a41453c..852a479 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,9 @@ "react-scripts": "^5.0.1", "reactjs-popup": "^2.0.5", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "gh-pages": "^4.0.0" } }, "node_modules/@adobe/css-tools": { @@ -5634,6 +5637,15 @@ "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array.prototype.flat": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", @@ -7546,6 +7558,12 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" }, + "node_modules/email-addresses": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz", + "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==", + "dev": true + }, "node_modules/emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -8740,6 +8758,32 @@ "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==", + "dev": true, + "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==", + "dev": true, + "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", @@ -9245,6 +9289,103 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gh-pages": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-4.0.0.tgz", + "integrity": "sha512-p8S0T3aGJc68MtwOcZusul5qPSNZCalap3NWbhRUZYu1YOdp+EjZ+4kPmRM8h3NNRdqw00yuevRjlkuSzCn7iQ==", + "dev": true, + "dependencies": { + "async": "^2.6.1", + "commander": "^2.18.0", + "email-addresses": "^3.0.1", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^8.1.0", + "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==", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gh-pages/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/gh-pages/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/gh-pages/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "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==", + "dev": true, + "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/gh-pages/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/gh-pages/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -13418,6 +13559,27 @@ "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==", + "dev": true, + "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==", + "dev": true, + "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", @@ -16431,6 +16593,18 @@ "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==", + "dev": true, + "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", @@ -16856,6 +17030,18 @@ "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==", + "dev": true, + "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", @@ -22216,6 +22402,12 @@ "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==", + "dev": true + }, "array.prototype.flat": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", @@ -23614,6 +23806,12 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" }, + "email-addresses": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz", + "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==", + "dev": true + }, "emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -24509,6 +24707,23 @@ } } }, + "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==", + "dev": true + }, + "filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "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", @@ -24860,6 +25075,86 @@ "get-intrinsic": "^1.1.1" } }, + "gh-pages": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-4.0.0.tgz", + "integrity": "sha512-p8S0T3aGJc68MtwOcZusul5qPSNZCalap3NWbhRUZYu1YOdp+EjZ+4kPmRM8h3NNRdqw00yuevRjlkuSzCn7iQ==", + "dev": true, + "requires": { + "async": "^2.6.1", + "commander": "^2.18.0", + "email-addresses": "^3.0.1", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^8.1.0", + "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==", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -27876,6 +28171,21 @@ "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==", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, "pirates": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", @@ -29889,6 +30199,15 @@ "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==", + "dev": true, + "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", @@ -30200,6 +30519,15 @@ "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==", + "dev": true, + "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 432c6d9..fc244a7 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ { + "homepage": "http://uzFer.github.io/tidey", "name": "tidey", "version": "0.1.0", "private": true, @@ -22,6 +23,8 @@ }, "scripts": { "start": "react-scripts start", + "predeploy": "npm run build", + "deploy": "gh-pages -d build", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" @@ -43,5 +46,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "gh-pages": "^4.0.0" } } diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png new file mode 100644 index 0000000..b4df351 Binary files /dev/null and b/public/android-chrome-192x192.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000..591fc5e Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 0000000..b854d31 Binary files /dev/null and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png new file mode 100644 index 0000000..b6f8eb7 Binary files /dev/null and b/public/favicon-32x32.png differ diff --git a/public/favicon.ico b/public/favicon.ico index a11777c..f154962 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/manifest.json b/public/manifest.json index 080d6c7..4216ea3 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -8,7 +8,7 @@ "type": "image/x-icon" }, { - "src": "logo192.png", + "src": "android-chrome-192x192.png", "type": "image/png", "sizes": "192x192" }, diff --git a/public/mstile-150x150.png b/public/mstile-150x150.png new file mode 100644 index 0000000..786e2a0 Binary files /dev/null and b/public/mstile-150x150.png differ diff --git a/src/App.js b/src/App.js index eaf1052..9dbbbde 100644 --- a/src/App.js +++ b/src/App.js @@ -10,13 +10,9 @@ import CourseCalculator from './CourseCalculator'; import Workload from './Workload'; import NotFound from './NotFound'; import Tabs from './Tabs'; -import {db} from './Firebase'; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; - - const App = () => { - return (
@@ -24,16 +20,17 @@ const App = () => {
- } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> } />
diff --git a/src/Calculator.js b/src/Calculator.js index 048553b..bfc5fd0 100644 --- a/src/Calculator.js +++ b/src/Calculator.js @@ -1,19 +1,14 @@ import { useState } from 'react'; import { useEffect} from 'react'; -import { Link } from "react-router-dom"; -import Popup from 'reactjs-popup'; -import {PlusCircle} from 'react-feather'; +import { PlusCircle } from 'react-feather'; const Calculator = () => { - - const [gradeList, setGradeList] = useState([{ desc: "", weight: "", grade: ""}]); const [currentGrade, setCurrentGrade] = useState(0); const [targetGrade, setTargetGrade] = useState(0); const [additionalGrade, setAdditionalGrade] = useState(0); const [errorState, setErrorState] = useState(false); - const handleGradeAdd = () =>{ setGradeList([...gradeList, {desc: "", weight: "", grade: ""}]); } @@ -28,7 +23,6 @@ const Calculator = () => { const newList = [...gradeList]; newList[index][element] = e.target.value; setGradeList(newList); - } const handleGradeCalculation = () => { @@ -42,11 +36,11 @@ const Calculator = () => { tempWeight += thisWeight; } } + setCurrentGrade(100* tempGrade/tempWeight ); let remainingWeight = 100 - tempWeight; let remainingGrade = targetGrade - (tempGrade); setAdditionalGrade(100* remainingGrade/remainingWeight) - } const handleTargetChange = (e) => { @@ -59,11 +53,11 @@ const Calculator = () => { let oneNumberError = false; for (let i = 0; i < gradeList.length; i++) { - if(gradeList[i].weight != 0){ + if(gradeList[i].weight !== 0){ zeroWeightError = false; noInfoError = false; } - if(gradeList[i].grade != 0){ + if(gradeList[i].grade !== 0){ noInfoError = false; } if((!gradeList[i].grade && gradeList[i].weight) || @@ -72,14 +66,12 @@ const Calculator = () => { } - if(zeroWeightError || noInfoError || oneNumberError){ setErrorState(true); } else{ setErrorState(false); } - } } @@ -104,11 +96,11 @@ const Calculator = () => {
-

Grade Calculator

+

Grade Calculator

- + {gradeList.map((singleRow, index) => ( @@ -162,18 +154,9 @@ const Calculator = () => {

Add Row

)} - -
- - - ))} - - - -
@@ -194,7 +177,7 @@ const Calculator = () => { onClick = {() => { handleErrorCheck() - if(errorState == false){ + if(errorState === false){ handleGradeCalculation() } else{ @@ -207,11 +190,6 @@ const Calculator = () => {

Calculate Grade!

- -
- - -
); diff --git a/src/CourseCalculator.js b/src/CourseCalculator.js index a8d2ea3..83835d2 100644 --- a/src/CourseCalculator.js +++ b/src/CourseCalculator.js @@ -1,15 +1,10 @@ import { useState } from 'react'; -import { useEffect, useLayoutEffect} from 'react'; +import { useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import { Link } from "react-router-dom"; -import Popup from 'reactjs-popup'; -import {PlusCircle} from 'react-feather'; -import useFetch from './UseFetch'; +import { PlusCircle } from 'react-feather'; import Tabs from './Tabs'; -import { Tab } from 'bootstrap'; - -import {db} from "./Firebase"; -import {collection, getDocs, addDoc, doc, getDoc, deleteDoc, updateDoc} from 'firebase/firestore'; +import { db} from "./Firebase"; +import { collection, doc, getDoc, updateDoc } from 'firebase/firestore'; @@ -21,8 +16,6 @@ const CourseCalculator = () => { const [targetGrade, setTargetGrade] = useState(100); const [additionalGrade, setAdditionalGrade] = useState(0); const [errorState, setErrorState] = useState(false); - const [courses, setCourses] = useState(); - const coursesCollectionRef = collection(db, "courses"); const [currentCourse, setCurrentCourse] = useState(); const [changesSaved, setChangesSaved] = useState(false); @@ -40,8 +33,6 @@ const CourseCalculator = () => { const newList = [...gradeList]; newList[index][element] = e.target.value; setGradeList(newList); - /*handleDatabaseUpdate();*/ - } const handleGradeCalculation = () => { @@ -73,11 +64,11 @@ const CourseCalculator = () => { let oneNumberError = false; for (let i = 0; i < gradeList.length; i++) { - if(gradeList[i].weight != 0){ + if(gradeList[i].weight !== 0){ zeroWeightError = false; noInfoError = false; } - if(gradeList[i].grade != 0){ + if(gradeList[i].grade !== 0){ noInfoError = false; } if((!gradeList[i].grade && gradeList[i].weight) || @@ -97,16 +88,6 @@ const CourseCalculator = () => { } } - - - const getCourses = async () => { - - const data = await getDocs(coursesCollectionRef); - setCourses(data.docs.map((doc) => ({...doc.data(), id: doc.id}))); - - - }; - const getCurrentCourse = async () =>{ const docRef = doc(db, "courses", id); const docSnap = await getDoc(docRef); @@ -121,10 +102,7 @@ const CourseCalculator = () => { } useEffect(() => { - - getCourses(); getCurrentCourse(); - }, []); useEffect(() => { @@ -155,7 +133,6 @@ const CourseCalculator = () => { return ( -
@@ -176,7 +153,7 @@ const CourseCalculator = () => {
- + {gradeList.map((singleRow, index) => ( @@ -229,23 +206,14 @@ const CourseCalculator = () => {

Add Row

- )} - - + )}
- - - ))} - - - - - +

Enter Target Grade (%): { onClick = {() => { handleErrorCheck() - if(errorState == false){ + if(errorState === false){ handleGradeCalculation() } else{ alert("Please enter valid Grades/Weights"); } - - }} >Calculate/Save Grade!

- ); diff --git a/src/CourseDetails.js b/src/CourseDetails.js index 5816ad4..d378a2f 100644 --- a/src/CourseDetails.js +++ b/src/CourseDetails.js @@ -1,13 +1,12 @@ import { useNavigate, useParams } from "react-router-dom"; -import useFetch from './UseFetch'; import Tabs from './Tabs'; import Modal from 'react-bootstrap/Modal'; import { updateDoc } from "firebase/firestore"; -import {db} from "./Firebase"; -import {useState, useEffect} from 'react'; -import {collection, getDocs, addDoc, doc, getDoc, deleteDoc} from 'firebase/firestore'; +import { db } from "./Firebase"; +import { useState, useEffect } from 'react'; +import { collection, getDocs, doc, getDoc, deleteDoc } from 'firebase/firestore'; import { getAuth, onAuthStateChanged } from "firebase/auth"; -import { ref, uploadBytes, listAll, getDownloadURL, deleteObject } from "firebase/storage"; +import { ref, listAll, getDownloadURL, deleteObject } from "firebase/storage"; import { storage } from './Firebase'; const CourseDetails = () => { @@ -15,14 +14,12 @@ const CourseDetails = () => { const navigate = useNavigate(); const [ courseCode, setCourseCode] = useState( "New Course Code"); const [ courseName, setCourseName] = useState("New Course Name"); - const [ showDeleteModal, setDeleteShow ] = useState(false); const [ showEditModal, setEditShow ] = useState(false); - const handleClose = () => setDeleteShow(false); const handleShow = () => setDeleteShow(true); const handleEditShow = () => setEditShow(true); - const handleEditCancel= () => setEditShow(false); + const handleEditCancel= () => setEditShow(false); const [courses, setCourses] = useState(); const coursesCollectionRef = collection(db, "courses"); @@ -60,10 +57,6 @@ const CourseDetails = () => { getCourses(); getCurrentCourse(); - - - - }, []); @@ -74,7 +67,7 @@ const CourseDetails = () => { const docRef = doc(db, "courses", id); await deleteDoc(docRef); - navigate("../Courses") + navigate("../tidey/Courses") listAll(fileListRef).then((response) => { response.items.forEach((item) => { @@ -92,7 +85,7 @@ const CourseDetails = () => { const docRef = doc(db, "courses", id); await updateDoc( docRef , {courseCode: courseCode, courseName: courseName}); setEditShow(false); - navigate("../Courses"); + navigate("../tidey/Courses"); }; @@ -148,7 +141,7 @@ const CourseDetails = () => { Fill in the inputs with your changes { /> { - - - ) } diff --git a/src/CourseList.js b/src/CourseList.js index 4a13615..cc65bc4 100644 --- a/src/CourseList.js +++ b/src/CourseList.js @@ -1,27 +1,29 @@ import { Link } from 'react-router-dom'; import { db } from './Firebase'; -import {useState, useEffect} from 'react'; -import {collection, getDocs, addDoc} from 'firebase/firestore'; +import { useState, useEffect } from 'react'; +import { collection, getDocs } from 'firebase/firestore'; import { getAuth, onAuthStateChanged } from "firebase/auth"; -import {animationControls, motion, useAnimation} from 'framer-motion'; -import {useRef} from "react"; -import {ChevronsLeft, ChevronsRight} from 'react-feather'; +import { motion, useAnimation } from 'framer-motion'; +import { useRef } from "react"; +import { ChevronsLeft, ChevronsRight } from 'react-feather'; + const courseStyle = { textDecoration: "none", color: 'white' } const CourseList = () => { - const [courses, setCourses] = useState(); + const [ courses, setCourses ] = useState(); const coursesCollectionRef = collection(db, "courses"); - const [userID, setUserID] = useState(''); - const [carouselWidth, setCarouselWidth] = useState(); + const [ userID, setUserID ] = useState(''); + const [ carouselWidth, setCarouselWidth ] = useState(); const carousel = useRef(); const auth = getAuth(); - const swipeString = "<<< SWIPE" const dragRef = useRef(null); const xPos = useRef(0); const animation = useAnimation(); + + onAuthStateChanged(auth, (user) => { if (user) { setUserID(user.uid) @@ -29,45 +31,42 @@ const CourseList = () => { } }); + const handleLeftSwipe = () => { const newXPosition = xPos.current + 300; - animation.start({ x: newXPosition > (carouselWidth * 1.1) ? (carouselWidth * 1.1): newXPosition, }); } + const handleRightSwipe = () => { const newXPosition = xPos.current - 300; - animation.start({ x: newXPosition > -(carouselWidth * 1.1) ? -(carouselWidth * 1.1) : newXPosition, }); } + const onUpdate = (latest) => { xPos.current = latest.x; } + useEffect(() => { - - const getCourses = async () => { - + const getCourses = async () => { const data = await getDocs(coursesCollectionRef); - setCourses(data.docs.map((doc) => ({...doc.data()}))); - //id: doc.id - }; - getCourses(); }, []); + + useEffect(() => { setCarouselWidth(carousel.current.scrollWidth - carousel.current.offsetWidth); - - }, [courses]) + return ( @@ -83,33 +82,26 @@ const CourseList = () => { return( {course.userID === userID && -
-
- +

{ course.courseCode }

-

{ course.courseName }

-
- +
- }
); })} -
+
-

SWIPE

-
); diff --git a/src/Courses.js b/src/Courses.js index 0635285..9290b39 100644 --- a/src/Courses.js +++ b/src/Courses.js @@ -1,9 +1,7 @@ import CourseList from './CourseList'; -import useFetch from './UseFetch'; import { Link } from "react-router-dom"; + const Courses = () => { - - {/*const { data: courses, isPending, error } = useFetch('http://localhost:8000/courses');*/} return (
@@ -18,7 +16,7 @@ const Courses = () => {
- Add a new course + Add a new course
@@ -29,4 +27,4 @@ const Courses = () => { ); } -export default Courses; +export default Courses; \ No newline at end of file diff --git a/src/Create.js b/src/Create.js index 2ede344..72fedf7 100644 --- a/src/Create.js +++ b/src/Create.js @@ -1,15 +1,15 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import {db} from './Firebase'; -import {collection, getDocs, addDoc, doc, updateDoc, setDoc} from 'firebase/firestore'; +import { db } from './Firebase'; +import {collection, doc, setDoc} from 'firebase/firestore'; import { getAuth, onAuthStateChanged } from "firebase/auth"; + const Create = () => { const [courseCode, setCourseCode] = useState(''); const [courseName, setCourseName] = useState(''); const [gradeList, setGradeList] = useState([{ desc: "", weight: "", grade: ""}]); const [fileNameList, setFileNameList] = useState(['']); const [targetGrade, setTargetGrade] = useState(0); - const [isPending, setIsPending] = useState(false); const coursesCollectionRef = collection(db, "courses"); const [userID, setUserID] = useState(''); const navigate = useNavigate(); @@ -22,8 +22,6 @@ const Create = () => { } }); - - const createCourse = async (e) => { e.preventDefault() const docRef = new doc(coursesCollectionRef); @@ -36,7 +34,7 @@ const Create = () => { id: docRef.id, userID: userID }); - navigate(-1); + navigate("../tidey/Courses"); } return ( diff --git a/src/Firebase.js b/src/Firebase.js index f5ea9df..3348b01 100644 --- a/src/Firebase.js +++ b/src/Firebase.js @@ -1,5 +1,4 @@ import { initializeApp } from "firebase/app"; -import { getAnalytics } from "firebase/analytics"; import { getFirestore } from "@firebase/firestore"; import { getAuth, GoogleAuthProvider, signInWithPopup } from 'firebase/auth'; import { getStorage } from "firebase/storage"; @@ -16,7 +15,6 @@ const firebaseConfig = { // Initialize Firebase const app = initializeApp(firebaseConfig); -const analytics = getAnalytics(app); export const db = getFirestore(app); export const auth = getAuth(app); export const storage = getStorage(app); \ No newline at end of file diff --git a/src/HamburgerMenu.js b/src/HamburgerMenu.js index ec094d6..5930022 100644 --- a/src/HamburgerMenu.js +++ b/src/HamburgerMenu.js @@ -1,5 +1,3 @@ -import { useState, useEffect} from 'react'; - export default function Hamburger({ isOpen }){ return( <> @@ -171,10 +169,8 @@ export default function Hamburger({ isOpen }){ cursor: pointer; } } - - - `} - + + `} ) } \ No newline at end of file diff --git a/src/Home.js b/src/Home.js index d33515a..6e2ab1a 100644 --- a/src/Home.js +++ b/src/Home.js @@ -1,11 +1,12 @@ -import { Link } from "react-router-dom"; -import { auth } from "./Firebase"; -import { useState } from 'react'; +import { Link, useNavigate } from "react-router-dom"; +import { useState, useEffect } from 'react'; import { getAuth, onAuthStateChanged } from "firebase/auth"; const Home = () => { + const [windowHeight, setWindowHeight] = useState(window.innerHeight); const [ userID, setUserID ] = useState(); const auth = getAuth(); + const navigate = useNavigate(); onAuthStateChanged(auth, (user) => { if (user) { @@ -14,31 +15,46 @@ const Home = () => { }); const handleAlert = () => { - console.log(userID); - if(!userID) + if(!userID){ alert("To save your courses, you can log in or sign up!"); - else - return; + } else{ + navigate("../tidey/Courses"); + } } + useEffect(() => { + const handleWindowResize = () => { + setWindowHeight(window.innerHeight); + }; + + window.addEventListener('resize', handleWindowResize); + + return () => { + window.removeEventListener('resize', handleWindowResize); + }; + }); + return (
{/* Waves Container*/} -
- - - - - - - - - - - -
+ {windowHeight >= 750 && + ( +
+ + + + + + + + + + + +
+ )} {/**/}
@@ -48,13 +64,13 @@ const Home = () => {
- +
Course dashboard - +
- + Calculate grades
@@ -62,7 +78,6 @@ const Home = () => {
- ); } diff --git a/src/Login.js b/src/Login.js index cbce446..f72cb59 100644 --- a/src/Login.js +++ b/src/Login.js @@ -11,18 +11,20 @@ const headingStyle = { paddingTop: "30px" } - const Login = () => { const navigate = useNavigate(); const [ loginEmail, setLoginEmail ] = useState(""); const [ loginPassword, setLoginPassword ] = useState(""); const [ user, setUser ] = useState({}); + const [ windowHeight, setWindowHeight ] = useState(window.innerHeight); + onAuthStateChanged(auth, (currentUser) => { setUser(currentUser); localStorage.setItem("email", user?.email); }) + const login = async (e) => { e.preventDefault() @@ -34,14 +36,17 @@ const Login = () => { ); alert('You are logged in'); - navigate("./"); - } catch(error) { - console.log(error.message); + navigate("../tidey/"); + } catch(FirebaseError) { + console.log(FirebaseError.message); + alert("Password or email is incorrect") } } + const provider = new GoogleAuthProvider(); + const signInWithGoogle = () => { signInWithPopup(auth, provider) .then((result) => { @@ -49,7 +54,7 @@ const Login = () => { localStorage.setItem("name", name); alert('You are logged in'); if((localStorage.getItem("email") !== "undefined")){ - navigate("../"); + navigate("../tidey/"); } }) .catch((error) => { @@ -57,15 +62,28 @@ const Login = () => { }) }; + useEffect(() => { + const handleWindowResize = () => { + setWindowHeight(window.innerHeight); + }; + + window.addEventListener('resize', handleWindowResize); + + return () => { + window.removeEventListener('resize', handleWindowResize); + }; + }); - }, []) return (
+ {/* Waves Container*/} -
+ {windowHeight >= 750 && + ( +
@@ -79,6 +97,9 @@ const Login = () => {
+ )} + {/* Waves End */} +

Log in to your account

@@ -105,4 +126,4 @@ const Login = () => { ); } -export default Login; +export default Login; \ No newline at end of file diff --git a/src/Navbar.js b/src/Navbar.js index 16bac00..ef0b9ed 100644 --- a/src/Navbar.js +++ b/src/Navbar.js @@ -5,57 +5,8 @@ import { auth } from "./Firebase"; import Modal from 'react-bootstrap/Modal'; import HamburgerMenu from './HamburgerMenu'; -const modalStyle = { - position: "fixed", - fontFamily: "'Quicksand', sans-serif", - zIndex: "100", - top: "10%", - left: "50%", - width: "500px", - marginLeft: "-260px", - backgroundColor: 'white', - border: "1px solid #999", - borderRadius: "6px", - boxShadow: "0 3px 7px rgba(0,0,0,0.3))", - outline: "none", - fontWeight: "bold" -} - -const modalHeaderStyle = { - padding: "9px 15px", - borderBottom: "1px solid #eee", -} - -const modalBodyStyle = { - position: "relative", - overflowY: "auto", - maxHeight: "400px", - padding: "15px" -} - -const modalFooterStyle = { - padding: "14px 15px 15px", - marginBottom: "0", - textAlign: "right", - backgroundColor: "#f5f5f5", - borderTop: "1px solid #ddd", - borderRadius: "0 0 6px 6px", - boxShadow: "inset 0 1px 0 @white", -} - -const modalBtn = { - background: "#2596be", - fontWeight: "bold", - color: "#fff", - border: "0", - padding: "8px", - borderRadius: "8px", - cursor: "pointer", - marginRight: "20px" -} - const Navbar = () => { - const [ isLoggedIn, setIsLoggedIn ] = useState(); + const [ isLoggedIn, setIsLoggedIn ] = useState(false); const [ showModal, setShowModal ] = useState(false); const handleClose = () => setShowModal(false); const handleShow = () => setShowModal(true); @@ -72,26 +23,27 @@ const Navbar = () => { localStorage.setItem("email", "undefined"); setShowModal(false); setIsLoggedIn(false); - navigate("./"); + navigate("../tidey/"); } onAuthStateChanged(auth, (currentUser) => { - if(localStorage.getItem("email") !== "undefined"){ + if(localStorage.email !== null && localStorage.getItem("email") !== "undefined"){ setIsLoggedIn(true); } - else{ + else { setIsLoggedIn(false); } }) useEffect(() => { - console.log(isLoggedIn); - }, [isLoggedIn]) + if(!localStorage.email) + localStorage.setItem("email", "undefined"); + }, []) return (