diff --git a/README.md b/README.md index 9ea4e26b3..280c82017 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,44 @@ -# Happy Thoughts -Replace this readme with your own information about your project. +![og-image-survey](https://user-images.githubusercontent.com/112956568/227894906-f7cb0d3a-5038-4ca9-9645-7ce4e05e4eda.jpg) -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. + + +# Happy Thoughts aka Junior Science Lab + +In this week's project we practice React state skills by fetching and posting data to an API. + +**What we needed to do** + +✓ Page should follow the design as closely as possible +✓ List the most recent thoughts at the top and older thoughts at the bottom (sorted) +✓ Our thoughts should show the content of the message and how many likes they've received +✓ We should have a form to post new thoughts +✓ We should implement the heart button to send likes on a thought ## The problem -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +Finland has just been selected (6th time in a row) as the happiest country, even if we genuinely love darkness, depression, heavy metal, booze, and knives. +Did you see Antonia’s amazing happy thoughts projects?!? –It was fantastic!! …But because she already shared all the happy thoughts we have in our dear country 😉 I chose to break some rules and do something slightly different: +A website for Junior Science Lab. It’s a website where tech kiddos can share with the rest of the group the project they want to work on next. + +Biggest problems just adapting all the new stuff and things we have learned with JS and React... +This week I had time to do site for just mobile. ...Or the resto of it works as weell but it doesn't look too good + +This is how I sstructured the site: + + 1 Parent: This is the main component that handles fetching thoughts, sending thoughts, and liking thoughts. It renders the SubmitForm and ThoughtCard components. + 2 ThoughtCard: This component takes in a list of thoughts and displays them. It shows the message, hearts (likes), and the time it was posted. It also has a button to like a thought. + 3 SubmitForm: This component handles the form for submitting new thoughts. It has validation to check if the entered text is too short (less than 5 characters). + 4 Footer: Simple footer with text and animation + +CSS files for styling : + 1 ThoughtCard.css: This file contains the styles for the ThoughtCard component. + 2 SubmitForm.css: This file contains the styles for the SubmitForm component. + 3 index.css: This file contains the global styles for the application. ## View it live -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. + +My mobile site: + +https://junior-science-lab.netlify.app diff --git a/code/.eslintrc.json b/code/.eslintrc.json index c9c0675c3..cf6749ee3 100644 --- a/code/.eslintrc.json +++ b/code/.eslintrc.json @@ -9,23 +9,20 @@ }, "env": { "node": true, - "browser": true + "browser": true, + "es6": true }, "parserOptions": { "parser": "@babel/eslint-parser", "requireConfigFile": false, "sourceType": "module", - "ecmaVersion": 2017, - "ecmaFeatures": { - "jsx": true, - "experimentalObjectRestSpread": true, - "modules": true - } + "ecmaVersion": 2018 }, "plugins": [ "react-hooks" ], "rules": { + "no-underscore-dangle": "off", "react/function-component-definition": [ 2, { @@ -128,4 +125,4 @@ "react-hooks/exhaustive-deps": "warn", "semi": "off" } -} +} \ No newline at end of file diff --git a/code/eslintrc.json b/code/eslintrc.json new file mode 100644 index 000000000..ac3150467 --- /dev/null +++ b/code/eslintrc.json @@ -0,0 +1,133 @@ +{ + "extends": [ + "airbnb" + ], + "globals": { + "document": true, + "window": true, + "process": true + }, + "env": { + "node": true, + "browser": true + }, + "parserOptions": { + "parser": "@babel/eslint-parser", + "requireConfigFile": false, + "sourceType": "module", + "ecmaVersion": 2017, + "ecmaFeatures": { + "jsx": true, + "experimentalObjectRestSpread": true, + "modules": true + } + }, + "plugins": [ + "react-hooks" + ], + "rules": { + "react/function-component-definition": [ + 2, + { + "namedComponents": "arrow-function", + "unnamedComponents": "arrow-function" + } + ], + "arrow-body-style": "off", + "linebreak-style": 0, + "class-methods-use-this": "off", + "brace-style": [ + "error", + "1tbs", + { + "allowSingleLine": true + } + ], + "comma-dangle": [ + "error", + "never" + ], + "consistent-return": "off", + "curly": "error", + "eol-last": "off", + "import/extensions": "off", + "import/no-extraneous-dependencies": "off", + "import/no-unresolved": "off", + "import/prefer-default-export": "off", + "indent": [ + "error", + 2, + { + "SwitchCase": 1 + } + ], + "jsx-a11y/anchor-is-valid": "off", + "jsx-a11y/label-has-for": "off", + "jsx-a11y/href-no-hash": "off", + "no-alert": "off", + "no-console": "off", + "no-debugger": "off", + "no-underscore-dangle": "off", + "no-param-reassign": "off", + "no-else-return": "off", + "no-irregular-whitespace": "error", + "no-multiple-empty-lines": [ + "error", + { + "max": 1 + } + ], + "no-restricted-syntax": "off", + "object-curly-newline": [ + "error", + { + "ObjectExpression": { + "consistent": true + }, + "ObjectPattern": { + "multiline": true + } + } + ], + "prefer-template": "error", + "react/destructuring-assignment": "off", + "react/forbid-prop-types": "off", + "react/jsx-closing-bracket-location": [ + "error", + { + "selfClosing": "after-props", + "nonEmpty": "after-props" + } + ], + "react/jsx-curly-spacing": [ + "error", + { + "when": "never", + "children": true + } + ], + "react/jsx-filename-extension": "off", + "react/jsx-no-bind": "error", + "react/jsx-uses-react": "warn", + "react/jsx-wrap-multilines": "off", + "react/jsx-one-expression-per-line": "off", + "react/no-danger": "off", + "react/no-did-mount-set-state": "error", + "react/no-did-update-set-state": "error", + "react/no-direct-mutation-state": "error", + "react/no-multi-comp": [ + "error", + { + "ignoreStateless": true + } + ], + "react/no-string-refs": "error", + "react/prop-types": "off", + "react/require-extension": "off", + "react/sort-comp": "off", + "react/jsx-indent": "off", + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", + "semi": "off" + } +} \ No newline at end of file diff --git a/code/package-lock.json b/code/package-lock.json index f7e97e1e9..a1f66702b 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -8,7 +8,13 @@ "name": "technigo-react-starter", "version": "1.0.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.3.0", + "@fortawesome/free-regular-svg-icons": "^6.3.0", + "@fortawesome/free-solid-svg-icons": "^6.3.0", + "@fortawesome/react-fontawesome": "^0.2.0", "babel-eslint": "^10.1.0", + "babel-plugin-macros": "^3.1.0", + "date-fns": "^2.29.3", "eslint": "^8.21.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.26.0", @@ -2216,6 +2222,63 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz", + "integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz", + "integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-regular-svg-icons": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.3.0.tgz", + "integrity": "sha512-cZnwiVHZ51SVzWHOaNCIA+u9wevZjCuAGSvSYpNlm6A4H4Vhwh8481Bf/5rwheIC3fFKlgXxLKaw8Xeroz8Ntg==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz", + "integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", @@ -3706,8 +3769,7 @@ "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "node_modules/@types/prettier": { "version": "2.6.4", @@ -4890,7 +4952,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -5730,7 +5791,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -6205,6 +6265,18 @@ "node": ">=10" } }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -6652,7 +6724,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -9036,8 +9107,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-bigint": { "version": "1.0.4", @@ -11656,8 +11726,7 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema": { "version": "0.4.0", @@ -11793,8 +11862,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/loader-runner": { "version": "4.3.0", @@ -12591,7 +12659,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -17498,7 +17565,6 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, "engines": { "node": ">= 6" } @@ -19004,6 +19070,43 @@ } } }, + "@fortawesome/fontawesome-common-types": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz", + "integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz", + "integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.3.0" + } + }, + "@fortawesome/free-regular-svg-icons": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.3.0.tgz", + "integrity": "sha512-cZnwiVHZ51SVzWHOaNCIA+u9wevZjCuAGSvSYpNlm6A4H4Vhwh8481Bf/5rwheIC3fFKlgXxLKaw8Xeroz8Ntg==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.3.0" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz", + "integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.3.0" + } + }, + "@fortawesome/react-fontawesome": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "requires": { + "prop-types": "^15.8.1" + } + }, "@humanwhocodes/config-array": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", @@ -20123,8 +20226,7 @@ "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "@types/prettier": { "version": "2.6.4", @@ -21008,7 +21110,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, "requires": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -21669,7 +21770,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, "requires": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -21996,6 +22096,11 @@ "whatwg-url": "^8.0.0" } }, + "date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -22337,7 +22442,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -24082,8 +24186,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "is-bigint": { "version": "1.0.4", @@ -26014,8 +26117,7 @@ "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema": { "version": "0.4.0", @@ -26119,8 +26221,7 @@ "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "loader-runner": { "version": "4.3.0", @@ -26724,7 +26825,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -30266,8 +30366,7 @@ "yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, "yargs": { "version": "16.2.0", diff --git a/code/package.json b/code/package.json index 68869f589..6913800e0 100644 --- a/code/package.json +++ b/code/package.json @@ -3,7 +3,13 @@ "version": "1.0.0", "private": true, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.3.0", + "@fortawesome/free-regular-svg-icons": "^6.3.0", + "@fortawesome/free-solid-svg-icons": "^6.3.0", + "@fortawesome/react-fontawesome": "^0.2.0", "babel-eslint": "^10.1.0", + "babel-plugin-macros": "^3.1.0", + "date-fns": "^2.29.3", "eslint": "^8.21.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.26.0", diff --git a/code/public/001@1-500px.png b/code/public/001@1-500px.png new file mode 100644 index 000000000..d73c73b91 Binary files /dev/null and b/code/public/001@1-500px.png differ diff --git a/code/public/favicon.ico b/code/public/favicon.ico new file mode 100644 index 000000000..ce14c9ff4 Binary files /dev/null and b/code/public/favicon.ico differ diff --git a/code/public/index.html b/code/public/index.html index e6730aa66..164e7f187 100644 --- a/code/public/index.html +++ b/code/public/index.html @@ -3,32 +3,22 @@ - - - Technigo React App + + + + + + + + + + Junior Science Lab®
- + diff --git a/code/public/og-image-survey.jpg b/code/public/og-image-survey.jpg new file mode 100644 index 000000000..2ef716ea3 Binary files /dev/null and b/code/public/og-image-survey.jpg differ diff --git a/code/src/App.js b/code/src/App.js index f2007d229..cdaeee07d 100644 --- a/code/src/App.js +++ b/code/src/App.js @@ -1,9 +1,10 @@ import React from 'react'; +import Parent from './components/Parent' -export const App = () => { +const App = () => { return ( -
- Find me in src/app.js! -
+ ); } + +export default App; \ No newline at end of file diff --git a/code/src/Loader.css b/code/src/Loader.css new file mode 100644 index 000000000..6f2033fec --- /dev/null +++ b/code/src/Loader.css @@ -0,0 +1,43 @@ + + + +.loader { + border: 4px solid #f3f3f3; + border-top: 4px solid #3498db; + border-radius: 50%; + width: 50px; + height: 50px; + animation: spin 1s linear infinite; + z-index: 200; + } + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } + + .loader-container { + display: flex; + align-items: center; + justify-content: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #0061ff; + z-index: 100; + } + + .content-container { + opacity: 0; + transition: opacity 0.5s ease-in-out; + } + + .content-container.visible { + opacity: 1; + } \ No newline at end of file diff --git a/code/src/Loader.js b/code/src/Loader.js new file mode 100644 index 000000000..e05b732e1 --- /dev/null +++ b/code/src/Loader.js @@ -0,0 +1,13 @@ +import React from 'react'; +import './Loader.css'; + +const Loader = () => { + return ( +
+

+ . +

+
+ ); +}; +export default Loader; \ No newline at end of file diff --git a/code/src/components/Footer.js b/code/src/components/Footer.js new file mode 100644 index 000000000..0a12f1156 --- /dev/null +++ b/code/src/components/Footer.js @@ -0,0 +1,15 @@ +import React from 'react' + +const Footer = () => { + return ( +
+
Powered by
+
Big Dada
+
+ Abstract forms like transparent bubbles. +
+
+ ) +} + +export default Footer diff --git a/code/src/components/Parent.js b/code/src/components/Parent.js new file mode 100644 index 000000000..986032555 --- /dev/null +++ b/code/src/components/Parent.js @@ -0,0 +1,142 @@ +/* eslint-disable no-underscore-dangle */ + +import React, { useState, useEffect } from 'react'; +import ThoughtCard from 'components/ThoughtCard'; +import SubmitForm from 'components/SubmitForm'; +import Footer from 'components/Footer'; +import Loader from 'Loader'; +import './parent.css'; + +// *************** MAIN APP *************** // + +// The function starts with declaring, +// the variables and sets the useState value. + +const Parent = () => { + const [latestMessage, setLatestMessage] = useState(null) + const [sendName, setSendName] = useState(''); + const [thoughtsList, setThoughtsList] = useState([]); + const [sendThought, setSendThought] = useState(''); + const [loading, setLoading] = useState(false); + + // Here we are calling the API and gets the JSON. + // The setLoading true shows "Loader" if the API call is delayed. + // .catch is catching eventual errors and displays them in a consol.log + // When everything is loaded we set loading (and loader) to false + const fetchThoughts = () => { + setLoading(true); + fetch('https://science-lab.onrender.com/thoughts') + .then((res) => res.json()) + .then((data) => setThoughtsList(data)) + .catch((error) => console.error(error)) + .finally(() => { setLoading(false) }); + } + + // This is an React hook called useEffect. It executes the fetchThoughts function. + // This function only runs first time the its mounted. + + useEffect(() => { + fetchThoughts(); // <--- This is a callback function. Its executed on every render of the page + }, []); // <--- This is the dependency array. When you put something(variables) in here + // it executs everytime the array change. But when its empty its only called when mounted. + + // Handles heart button click, sends a POST request to increase the likes + const onHeartButtonClick = (_id) => { + const options = { + method: 'POST', + headers: { + 'Content-type': 'application/json' + } + } + fetch(`https://science-lab.onrender.com/thoughts/${_id}/like`, options) + .then((response) => response.json()) + .then(() => fetchThoughts()) + .catch((error) => console.log(error)) + .finally(() => { + setLoading(false); + console.log('new heart'); + }); + } + + // Submits a new thought by sending a POST request to the API. + + const submitThought = () => { + fetch('https://science-lab.onrender.com/thoughts', { + method: 'POST', + body: JSON.stringify({ + name: `${sendName}`, + message: `${sendThought}` + }), + headers: { 'Content-Type': 'application/json' } + }) + .then((response) => response.json()) + .then((data) => { + setThoughtsList([data, ...thoughtsList]) + setLatestMessage(data._id) + }) + .catch((error) => console.log(error)) + .finally(() => { + setLoading(false); + setSendName(''); + setSendThought('') + }); + } + // data represents the new thought object received after submitting the form. + // ...thoughtsList expands the elements of the current thoughtsList array. + // The new array is created by combining data and the expanded thoughtsList. + // The setThoughtsList function updates the state of thoughtsList with the new array. + + // Handles form submission for the new thought. + const onSubmit = (e) => { + e.preventDefault(); + submitThought(); + } + + // *************** MAIN APP RETURNS JXS *************** // + + // The return displays two components inside a
ThoughtsForm & ThoughtsFlow + // The ThoughtForm component is passed 3 props that handle the form submission of new "thoughts" + // The ThoughtsFlow component is passed 2 props loading and thoughts. + + return ( +
+ {loading &&
} +
+ + + +
+
+
+ ); +} + +// The code above checks if the loading state is true. // +// If it is, it renders a Loader component inside a div with a className of "loader-container". +// This is used to display a loading animation while the API call is in progress. // + +// The next div has a dynamic className. It starts with "content-container" and adds "visible"// +// only when loading is false. This is used to control the visibility of the content +// once the data has been fetched from the API.// + +// SubmitForm component is responsible for rendering a form to submit new thoughts. +// It receives the sendThought, setSendThought, and onSubmit props to manage the +// form data and handle the submission process. + +// ThoughtCard component displays the list of thoughts fetched from the API. +// It receives the onHeartButtonClick, thoughtsList, latestMessage, and loading props +// to handle the heart button click event, display the thoughts, show the latest message, +// and manage the loading state, respectively. + +export default Parent; + diff --git a/code/src/components/SubmitForm.css b/code/src/components/SubmitForm.css new file mode 100644 index 000000000..d6cdc97e3 --- /dev/null +++ b/code/src/components/SubmitForm.css @@ -0,0 +1,142 @@ +.submit-box { + margin: 20px 0 0px 0; + padding-bottom: 0px; +} + +.submit-form { + display: flex; + align-items: center; + flex-direction: column; + padding: 14% 10% 20% 10%; + +} + +.submit-title { + + text-align: center; + font-weight: 700; + margin: -2px -48px 50px -40px; + font-size: 26px; + color: whitesmoke; + text-shadow: 0 0 120px rgb(1, 1, 1); + background: #0061ff; +} + +.input-width { + padding: 6% 0% 0% 0%; + border: none; +} + +.input-area { + display: flex; + align-items: center; + font-family: "Sora"; + font-weight: 800; + font-size: 16px; + color: #616161; + padding: 22px 30px 2px 42px; + height: 100%; + width: 100%; + border: none; + outline: none; + border-radius: 30px; + background: #ffffff; + box-shadow: inset 4px 4px 10px #9d9d9d, + inset -8px -8px 16px #ffffff; + box-shadow: 12px 12px 14px rgba(255, 255, 255, 1) -12px -12px 14px rgba(255, 254, 254, 1); +} + + +::placeholder { + color: rgb(118, 118, 118); + font-family: "Sora"; + font-size: 14px; + font-weight: 700; + padding-top: 2px; + letter-spacing: 0.26px; + text-transform: uppercase; +} + +.input-container-name { + position: relative; + display: inline-block; + margin-bottom: 40px; +} + +.input-container-name:first-letter { + text-transform: capitalize; +} + +.input-container-message { + position: relative; + display: inline-block; + margin-bottom: -20px; +} + +.input-container-message:first-letter { + text-transform: capitalize; +} + +.error-message { + font-family: "Sora"; + text-transform: uppercase; + font-weight: 800; + font-size: 16px; + position: absolute; + top: 50%; + left: 32%; + transform: translateY(-50%); + color: rgb(255, 0, 0); + opacity: 0.5; + pointer-events: none; + /* Disables interaction with the error message text */ +} + +.submit-button { + color: whitesmoke; + font-family: 'Sora'; + font-weight: 700; + font-size: 20px; + text-align: center; + width: 60%; + border: none; + border-radius: 25px; + padding: 20px 10px 20px 10px; + margin: 80px 10px -90px 10px; + border-radius: 15px; + background: linear-gradient(145deg, #0068ff, #0057e6); + box-shadow: 7px 7px 14px #003fa6, + -7px -7px 14px #0083ff; +} + +.submit-button:hover { + color: white; + box-shadow: 4px 4px 7px #003fa6, + -4px -4px 7px #0083ff; +} + + +.input-area.fade-in { + opacity: 0; + animation: fade-in 0.9s ease forwards; +} + +.input-area.fade-in { + opacity: 0; + animation: fade-in 0.9s ease forwards; +} + +.fade-in { + opacity: 0; + animation: fade-in 1.2s ease forwards; +} + +@keyframes fade-in { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/code/src/components/SubmitForm.js b/code/src/components/SubmitForm.js new file mode 100644 index 000000000..3f16ecfa6 --- /dev/null +++ b/code/src/components/SubmitForm.js @@ -0,0 +1,94 @@ +import React, { useState } from 'react'; +import './SubmitForm.css'; + +// Define the SubmitForm component with props for managing input and form submission +const SubmitForm = ({ + sendThought, + setSendThought, + sendName, + setSendName, + onSubmit +}) => { + const handleSendThought = (e) => { + setSendThought(e.target.value); + } + + const handleSendName = (e) => { + setSendName(e.target.value); + } + + const pressEnter = (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + if (sendName.trim() !== '') { // if name-field is not empty, execute the handleFormSubmit-function + handleSendThought(e); + } + } + } + + // Declare state variables for input focus, input length, and the latest post + const [isInputFocused, setIsInputFocused] = useState(false); + const isTextTooShort = sendThought.length < 2; + // eslint-disable-next-line no-unused-vars + const [latestPost, setLatestPost] = useState(null); + // Set the input className based on input focus, input length, and latest post + let inputClassName = 'input-area'; + if (isInputFocused) { + inputClassName += ' focus'; + } + if (isTextTooShort && !isInputFocused && sendThought.length > 0) { + inputClassName += ' error'; + } + /* eslint-enable no-unused-vars, no-underscore-dangle */ + inputClassName += latestPost ? ' fade-in' : ''; + + // Display a warning message if the input text is too short + let warningText = null; + if (isTextTooShort && !isInputFocused && sendThought.length > 0) { + warningText = Too short; + } + + // Render the SubmitForm component + return ( +
+
+

Junior Science Lab®

+
+