From 6a37e781f7c899336beb61b6cbb2ba3c871597d0 Mon Sep 17 00:00:00 2001 From: yuvigrg Date: Sun, 19 Jul 2020 18:02:30 +0100 Subject: [PATCH 1/9] Added material ui and notistack --- package-lock.json | 262 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 + 2 files changed, 264 insertions(+) diff --git a/package-lock.json b/package-lock.json index d72a10c..53b161a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1186,6 +1186,12 @@ "minimist": "^1.2.0" } }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1857,6 +1863,79 @@ } } }, + "@material-ui/core": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.0.tgz", + "integrity": "sha512-bYo9uIub8wGhZySHqLQ833zi4ZML+XCBE1XwJ8EuUVSpTWWG57Pm+YugQToJNFsEyiKFhPh8DPD0bgupz8n01g==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.10.0", + "@material-ui/system": "^4.9.14", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.10.2", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0", + "react-transition-group": "^4.4.0" + } + }, + "@material-ui/styles": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.10.0.tgz", + "integrity": "sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.9.6", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.0.3", + "jss-plugin-camel-case": "^10.0.3", + "jss-plugin-default-unit": "^10.0.3", + "jss-plugin-global": "^10.0.3", + "jss-plugin-nested": "^10.0.3", + "jss-plugin-props-sort": "^10.0.3", + "jss-plugin-rule-value-function": "^10.0.3", + "jss-plugin-vendor-prefixer": "^10.0.3", + "prop-types": "^15.7.2" + } + }, + "@material-ui/system": { + "version": "4.9.14", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.9.14.tgz", + "integrity": "sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.9.6", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "dev": true + }, + "@material-ui/utils": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.10.2.tgz", + "integrity": "sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + } + }, "@sinonjs/commons": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz", @@ -2002,6 +2081,31 @@ "integrity": "sha512-boy4xPNEtiw6N3abRhBi/e7hNvy3Tt8E9ZRAQrwAGzoCGZS/1wjo9KY7JHhnfnEsG5wSjDbymCozUM9a3ea7OQ==", "dev": true }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", + "dev": true + }, + "@types/react": { + "version": "16.9.43", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.43.tgz", + "integrity": "sha512-PxshAFcnJqIWYpJbLPriClH53Z2WlJcVZE+NP2etUtWQs2s7yIMj3/LDKZT/5CHJ/F62iyjVCDu2H3jHEXIxSg==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "csstype": "^2.2.0" + } + }, + "@types/react-transition-group": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", + "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -3459,6 +3563,12 @@ "shallow-clone": "^3.0.0" } }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", + "dev": true + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -3835,6 +3945,16 @@ } } }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "css-what": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", @@ -3870,6 +3990,12 @@ } } }, + "csstype": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.11.tgz", + "integrity": "sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw==", + "dev": true + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -4159,6 +4285,16 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.4.tgz", + "integrity": "sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^2.6.7" + } + }, "dom-serializer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", @@ -6044,6 +6180,12 @@ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==", + "dev": true + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -6510,6 +6652,12 @@ "is-extglob": "^2.1.1" } }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=", + "dev": true + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -8452,6 +8600,92 @@ "verror": "1.10.0" } }, + "jss": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.3.0.tgz", + "integrity": "sha512-B5sTRW9B6uHaUVzSo9YiMEOEp3UX8lWevU0Fsv+xtRnsShmgCfIYX44bTH8bPJe6LQKqEXku3ulKuHLbxBS97Q==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^2.6.5", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.3.0.tgz", + "integrity": "sha512-tadWRi/SLWqLK3EUZEdDNJL71F3ST93Zrl9JYMjV0QDqKPAl0Liue81q7m/nFUpnSTXczbKDy4wq8rI8o7WFqA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "^10.3.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.3.0.tgz", + "integrity": "sha512-tT5KkIXAsZOSS9WDSe8m8lEHIjoEOj4Pr0WrG0WZZsMXZ1mVLFCSsD2jdWarQWDaRNyMj/I4d7czRRObhOxSuw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "^10.3.0" + } + }, + "jss-plugin-global": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.3.0.tgz", + "integrity": "sha512-etYTG/y3qIR/vxZnKY+J3wXwObyBDNhBiB3l/EW9/pE3WHE//BZdK8LFvQcrCO48sZW1Z6paHo6klxUPP7WbzA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "^10.3.0" + } + }, + "jss-plugin-nested": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.3.0.tgz", + "integrity": "sha512-qWiEkoXNEkkZ+FZrWmUGpf+zBsnEOmKXhkjNX85/ZfWhH9dfGxUCKuJFuOWFM+rjQfxV4csfesq4hY0jk8Qt0w==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "^10.3.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.3.0.tgz", + "integrity": "sha512-boetORqL/lfd7BWeFD3K+IyPqyIC+l3CRrdZr+NPq7Noqp+xyg/0MR7QisgzpxCEulk+j2CRcEUoZsvgPC4nTg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "^10.3.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.3.0.tgz", + "integrity": "sha512-7WiMrKIHH3rwxTuJki9+7nY11r1UXqaUZRhHvqTD4/ZE+SVhvtD5Tx21ivNxotwUSleucA/8boX+NF21oXzr5Q==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "^10.3.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.3.0.tgz", + "integrity": "sha512-sZQbrcZyP5V0ADjCLwUA1spVWoaZvM7XZ+2fSeieZFBj31cRsnV7X70FFDerMHeiHAXKWzYek+67nMDjhrZAVQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "^10.3.0" + } + }, "jsx-ast-utils": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz", @@ -9354,6 +9588,16 @@ "sort-keys": "^1.0.0" } }, + "notistack": { + "version": "0.9.17", + "resolved": "https://registry.npmjs.org/notistack/-/notistack-0.9.17.tgz", + "integrity": "sha512-nypTN6sEe+q98wMaxF/UwatA1yAq948+bZOo9JKYR+tU65DW0ipWyx8DseJ3UJYvb6VDD+Fqo83qwayQ46bEEA==", + "dev": true, + "requires": { + "clsx": "^1.1.0", + "hoist-non-react-statics": "^3.3.0" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -9975,6 +10219,12 @@ "find-up": "^2.1.0" } }, + "popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==", + "dev": true + }, "portfinder": { "version": "1.0.26", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz", @@ -10446,6 +10696,18 @@ "tiny-warning": "^1.0.0" } }, + "react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", diff --git a/package.json b/package.json index 685f952..a13a65e 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@babel/plugin-transform-runtime": "^7.10.3", "@babel/preset-env": "^7.10.3", "@babel/preset-react": "^7.10.1", + "@material-ui/core": "^4.11.0", "babel-eslint": "^10.0.3", "babel-loader": "^8.1.0", "babel-plugin-module-resolver": "^3.2.0", @@ -42,6 +43,7 @@ "jest": "^26.0.1", "mini-css-extract-plugin": "^0.9.0", "node-sass": "^4.14.1", + "notistack": "^0.9.17", "prop-types": "^15.7.2", "sass-loader": "^8.0.2", "webpack": "^4.43.0", From db6499be139960683c674527834dd8d6e065e9cc Mon Sep 17 00:00:00 2001 From: yuvigrg Date: Sun, 19 Jul 2020 18:03:00 +0100 Subject: [PATCH 2/9] Added FM component --- src/app/components/fm.jsx | 90 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/app/components/fm.jsx diff --git a/src/app/components/fm.jsx b/src/app/components/fm.jsx new file mode 100644 index 0000000..452016c --- /dev/null +++ b/src/app/components/fm.jsx @@ -0,0 +1,90 @@ +import React, { useState, useReducer, useCallback } from 'react'; +import { TextField, Button } from '@material-ui/core'; +import axios from 'axios'; +import { useSnackbar } from 'notistack'; + +const initialState = { + title: '', + url: '', + frequency: '', + imageUrl: '', +}; + +const reducer = (state, action) => { + const { data } = action; + switch (action.type) { + case 'reset': + return initialState; + case 'update': + return { ...state, [data.name]: data.value }; + default: + return state; + } +}; + +const FM = () => { + const [state, dispatch] = useReducer(reducer, initialState); + const [submitting, setSubmitting] = useState(false); + const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + + const handleChange = (name, value) => { + dispatch({ type: 'update', data: { name, value } }); + }; + + const submit = useCallback((event) => { + if (event) event.preventDefault(); + closeSnackbar(); + setSubmitting(true); + axios.post('/api', state) + .then((res) => { + if (res) { + dispatch({ type: 'reset' }); + enqueueSnackbar('Successfully Added!!. Add another?'); + } else { + enqueueSnackbar('Oops! Something gone wrong'); + } + }) + .catch(() => { + enqueueSnackbar('Oops! Something gone wrong'); + }); + setSubmitting(false); + }, [closeSnackbar, enqueueSnackbar, state]); + + return ( +
+ handleChange('title', e.target.value)} + /> + handleChange('frequency', e.target.value)} + /> + handleChange('url', e.target.value)} + /> + handleChange('imageUrl', e.target.value)} + /> + +
+ ); +}; + +export default FM; From 3c1fb09f64c282b5511dc410bbd23c9c2dcab09c Mon Sep 17 00:00:00 2001 From: yuvigrg Date: Sun, 19 Jul 2020 18:03:29 +0100 Subject: [PATCH 3/9] Added notification --- src/_content/main.scss | 4 ++++ src/app/components/navbar.jsx | 1 + src/app/components/searchPage.jsx | 2 +- src/app/index.jsx | 11 ++++++++++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/_content/main.scss b/src/_content/main.scss index 8980002..3e59bbc 100644 --- a/src/_content/main.scss +++ b/src/_content/main.scss @@ -38,4 +38,8 @@ img { width: 100px; height: 100px; display: block; +} + +.form-grid { + display: grid; } \ No newline at end of file diff --git a/src/app/components/navbar.jsx b/src/app/components/navbar.jsx index 4091f14..9c3e5a4 100644 --- a/src/app/components/navbar.jsx +++ b/src/app/components/navbar.jsx @@ -4,6 +4,7 @@ import { Link } from 'react-router-dom'; const Navbar = () => (
    Home + Add New
); diff --git a/src/app/components/searchPage.jsx b/src/app/components/searchPage.jsx index 0e18ea4..4de8691 100644 --- a/src/app/components/searchPage.jsx +++ b/src/app/components/searchPage.jsx @@ -46,7 +46,7 @@ const SearchPage = () => { {fm.title} )) - :
Still loading....
} + : <>Still loading....} ); diff --git a/src/app/index.jsx b/src/app/index.jsx index 931953a..f9a4a9f 100644 --- a/src/app/index.jsx +++ b/src/app/index.jsx @@ -1,6 +1,8 @@ import React from 'react'; +import { SnackbarProvider } from 'notistack'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import SearchPage from './components/searchPage'; +import FM from './components/fm'; import Navbar from './components/navbar'; const App = () => ( @@ -8,8 +10,15 @@ const App = () => ( + ); -export default App; +const WrappedApp = () => ( + + + +); + +export default WrappedApp; From 52b4b2127b944b39a67e65c69ce52831d9b893b5 Mon Sep 17 00:00:00 2001 From: yuvigrg Date: Sat, 25 Jul 2020 20:45:59 +0100 Subject: [PATCH 4/9] Extract the button functionality to its components --- src/app/components/buttons/add.jsx | 53 ++++++++++++++++++++++++++ src/app/components/buttons/delete.jsx | 55 +++++++++++++++++++++++++++ src/app/components/buttons/update.jsx | 54 ++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 src/app/components/buttons/add.jsx create mode 100644 src/app/components/buttons/delete.jsx create mode 100644 src/app/components/buttons/update.jsx diff --git a/src/app/components/buttons/add.jsx b/src/app/components/buttons/add.jsx new file mode 100644 index 0000000..e0bcf80 --- /dev/null +++ b/src/app/components/buttons/add.jsx @@ -0,0 +1,53 @@ +import React, { useCallback } from 'react'; +import { Button } from '@material-ui/core'; +import axios from 'axios'; +import { useSnackbar } from 'notistack'; +import { func, shape, string, bool } from 'prop-types'; + +const AddButton = ({ setSubmitting, newRecord, disabled, dispatch }) => { + const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + + const submit = useCallback((event) => { + if (event) event.preventDefault(); + closeSnackbar(); + setSubmitting(true); + axios.post('/api', newRecord) + .then((res) => { + if (res) { + dispatch({ type: 'reset' }); + enqueueSnackbar('Successfully Added. Add another?'); + } else { + enqueueSnackbar('Oops! Something gone wrong'); + } + }) + .catch(() => { + enqueueSnackbar('Oops! Something gone wrong'); + }); + setSubmitting(false); + }, [closeSnackbar, setSubmitting, newRecord, dispatch, enqueueSnackbar]); + + return ( + + ); +}; + +AddButton.propTypes = { + setSubmitting: func.isRequired, + newRecord: shape({ + title: string, + frequency: string, + url: string, + imageUrl: string, + }).isRequired, + disabled: bool.isRequired, + dispatch: func.isRequired, +}; + +export default AddButton; diff --git a/src/app/components/buttons/delete.jsx b/src/app/components/buttons/delete.jsx new file mode 100644 index 0000000..e3244f4 --- /dev/null +++ b/src/app/components/buttons/delete.jsx @@ -0,0 +1,55 @@ +import React, { useState, useCallback } from 'react'; +import axios from 'axios'; +import { Button, Dialog, DialogActions, DialogTitle } from '@material-ui/core'; +import { string } from 'prop-types'; +import { useSnackbar } from 'notistack'; + +const DeleteButton = ({ id }) => { + const [open, setOpen] = useState(false); + const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); + + const deleteRecord = useCallback((event) => { + if (event) event.preventDefault(); + closeSnackbar(); + axios.delete(`/api/${id}`) + .then((res) => { + if (res) { + enqueueSnackbar('Successfully removed the record'); + } else { + enqueueSnackbar('Oh oh, something went horribly wrong'); + } + }) + .catch(() => { + enqueueSnackbar('Oh oh, something went horribly wrong'); + }); + setOpen(false); + }, [closeSnackbar, enqueueSnackbar, id]); + + return ( + <> + + + Are you sure you want to delete this record? + + + + + + + ); +}; + +DeleteButton.propTypes = { id: string.isRequired }; + +export default DeleteButton; diff --git a/src/app/components/buttons/update.jsx b/src/app/components/buttons/update.jsx new file mode 100644 index 0000000..6e1d762 --- /dev/null +++ b/src/app/components/buttons/update.jsx @@ -0,0 +1,54 @@ +import React, { useCallback } from 'react'; +import { Button } from '@material-ui/core'; +import axios from 'axios'; +import { useSnackbar } from 'notistack'; +import { func, shape, string, bool } from 'prop-types'; + +const UpdateButton = ({ setSubmitting, record, disabled }) => { + const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + + const submit = useCallback((event) => { + if (event) event.preventDefault(); + closeSnackbar(); + setSubmitting(true); + const { id, title, frequency, url, imageUrl } = record; + + axios.patch(`/api/${id}?title=${title}&&frequency=${frequency}&&url=${url}&&imageUrl=${imageUrl}`) + .then((res) => { + if (res) { + enqueueSnackbar('Successfully Updated'); + } else { + enqueueSnackbar('Oops! Something gone wrong'); + } + }) + .catch(() => { + enqueueSnackbar('Oops! Something gone wrong'); + }); + setSubmitting(false); + }, [closeSnackbar, setSubmitting, record, enqueueSnackbar]); + + return ( + + ); +}; + +UpdateButton.propTypes = { + setSubmitting: func.isRequired, + record: shape({ + id: string, + title: string, + frequency: string, + url: string, + imageUrl: string, + }).isRequired, + disabled: bool.isRequired, +}; + +export default UpdateButton; From abb30155e1c9f8552099accfd5928d8985bff456 Mon Sep 17 00:00:00 2001 From: yuvigrg Date: Sat, 25 Jul 2020 20:46:35 +0100 Subject: [PATCH 5/9] Updated the changes --- src/app/components/fm.jsx | 117 ++++++++++++++++++------------ src/app/components/searchPage.jsx | 10 ++- 2 files changed, 76 insertions(+), 51 deletions(-) diff --git a/src/app/components/fm.jsx b/src/app/components/fm.jsx index 452016c..ed0c30d 100644 --- a/src/app/components/fm.jsx +++ b/src/app/components/fm.jsx @@ -1,57 +1,51 @@ -import React, { useState, useReducer, useCallback } from 'react'; -import { TextField, Button } from '@material-ui/core'; -import axios from 'axios'; -import { useSnackbar } from 'notistack'; +import React, { useState, useReducer, useEffect } from 'react'; +import { TextField } from '@material-ui/core'; +import { string, shape, bool } from 'prop-types'; +import Delete from './buttons/delete'; +import AddButton from './buttons/add'; +import UpdateButton from './buttons/update'; -const initialState = { - title: '', - url: '', - frequency: '', - imageUrl: '', -}; +const FM = ({ edit, record }) => { + const initialState = { + title: record.title || '', + url: record.url || '', + frequency: record.frequency || '', + imageUrl: record.imageUrl || '', + }; -const reducer = (state, action) => { - const { data } = action; - switch (action.type) { - case 'reset': - return initialState; - case 'update': - return { ...state, [data.name]: data.value }; - default: - return state; - } -}; + const reducer = (state, action) => { + const { data } = action; + switch (action.type) { + case 'reset': + return initialState; + case 'update': + return { ...state, [data.name]: data.value }; + default: + return state; + } + }; -const FM = () => { const [state, dispatch] = useReducer(reducer, initialState); const [submitting, setSubmitting] = useState(false); - const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + const [formError, setFormError] = useState(''); const handleChange = (name, value) => { dispatch({ type: 'update', data: { name, value } }); }; - const submit = useCallback((event) => { - if (event) event.preventDefault(); - closeSnackbar(); - setSubmitting(true); - axios.post('/api', state) - .then((res) => { - if (res) { - dispatch({ type: 'reset' }); - enqueueSnackbar('Successfully Added!!. Add another?'); - } else { - enqueueSnackbar('Oops! Something gone wrong'); - } - }) - .catch(() => { - enqueueSnackbar('Oops! Something gone wrong'); - }); - setSubmitting(false); - }, [closeSnackbar, enqueueSnackbar, state]); + useEffect(() => { + Object.keys(state).forEach((key) => { + if (state[key] === '') { + setFormError('Please add the required information'); + } else { + setFormError(''); + } + }); + }, [state]); return (
+

{formError}

{ value={state.imageUrl} onChange={e => handleChange('imageUrl', e.target.value)} /> - + {!edit && ( + + )} + {edit && ( + <> + + + + )}
); }; +FM.propTypes = { + record: shape({ + title: string, + frequency: string, + url: string, + imageUrl: string, + id: string, + }), + edit: bool, +}; + +FM.defaultProps = { + record: {}, + edit: false, +}; + export default FM; diff --git a/src/app/components/searchPage.jsx b/src/app/components/searchPage.jsx index 4de8691..6f041e4 100644 --- a/src/app/components/searchPage.jsx +++ b/src/app/components/searchPage.jsx @@ -1,5 +1,8 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; +import { Button } from '@material-ui/core'; +import { Route } from 'react-router-dom'; +import FMStation from './fm'; const SearchPage = () => { const [fmList, setFMList] = useState([]); @@ -12,9 +15,6 @@ const SearchPage = () => { }; useEffect(() => { - // TODO - // MOVE THIS TO ITS CUSTOM HOOK - // ADD TEST const fetchData = async () => { const result = await axios('/api'); const { data } = result; @@ -28,6 +28,8 @@ const SearchPage = () => { fetchData(); }, []); + const onClick = fm => } />; + return ( @@ -35,6 +37,7 @@ const SearchPage = () => { + @@ -44,6 +47,7 @@ const SearchPage = () => { + )) : <>Still loading....} From 9d9f4728bd252029f04461afce44b1297173f403 Mon Sep 17 00:00:00 2001 From: yuvigrg Date: Sat, 25 Jul 2020 20:46:49 +0100 Subject: [PATCH 6/9] Updated the links --- src/app/components/navbar.jsx | 2 +- src/app/index.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/components/navbar.jsx b/src/app/components/navbar.jsx index 9c3e5a4..a5b3e1c 100644 --- a/src/app/components/navbar.jsx +++ b/src/app/components/navbar.jsx @@ -4,7 +4,7 @@ import { Link } from 'react-router-dom'; const Navbar = () => (
    Home - Add New + Add New
); diff --git a/src/app/index.jsx b/src/app/index.jsx index f9a4a9f..879cf0c 100644 --- a/src/app/index.jsx +++ b/src/app/index.jsx @@ -2,7 +2,7 @@ import React from 'react'; import { SnackbarProvider } from 'notistack'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import SearchPage from './components/searchPage'; -import FM from './components/fm'; +import FMStation from './components/fm'; import Navbar from './components/navbar'; const App = () => ( @@ -10,7 +10,7 @@ const App = () => ( - + ); From d446b1b49c1538876f57850cb4affcda17a4e45c Mon Sep 17 00:00:00 2001 From: yuvigrg Date: Sat, 25 Jul 2020 22:46:51 +0100 Subject: [PATCH 7/9] Display the existing FM --- src/app/components/buttons/delete.jsx | 5 +++- src/app/components/fm.jsx | 37 ++++++++++----------------- src/app/components/searchPage.jsx | 13 +++++++--- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/app/components/buttons/delete.jsx b/src/app/components/buttons/delete.jsx index e3244f4..09b95f2 100644 --- a/src/app/components/buttons/delete.jsx +++ b/src/app/components/buttons/delete.jsx @@ -3,8 +3,10 @@ import axios from 'axios'; import { Button, Dialog, DialogActions, DialogTitle } from '@material-ui/core'; import { string } from 'prop-types'; import { useSnackbar } from 'notistack'; +import { useHistory } from 'react-router-dom'; const DeleteButton = ({ id }) => { + const history = useHistory(); const [open, setOpen] = useState(false); const { enqueueSnackbar, closeSnackbar } = useSnackbar(); @@ -18,6 +20,7 @@ const DeleteButton = ({ id }) => { .then((res) => { if (res) { enqueueSnackbar('Successfully removed the record'); + history.push({ pathname: '/' }); } else { enqueueSnackbar('Oh oh, something went horribly wrong'); } @@ -26,7 +29,7 @@ const DeleteButton = ({ id }) => { enqueueSnackbar('Oh oh, something went horribly wrong'); }); setOpen(false); - }, [closeSnackbar, enqueueSnackbar, id]); + }, [closeSnackbar, enqueueSnackbar, history, id]); return ( <> diff --git a/src/app/components/fm.jsx b/src/app/components/fm.jsx index ed0c30d..7f2d2d4 100644 --- a/src/app/components/fm.jsx +++ b/src/app/components/fm.jsx @@ -1,11 +1,14 @@ import React, { useState, useReducer, useEffect } from 'react'; import { TextField } from '@material-ui/core'; -import { string, shape, bool } from 'prop-types'; +import { useLocation } from 'react-router-dom'; import Delete from './buttons/delete'; import AddButton from './buttons/add'; import UpdateButton from './buttons/update'; -const FM = ({ edit, record }) => { +const FM = () => { + const location = useLocation(); + const { record = {}, edit } = location; + const initialState = { title: record.title || '', url: record.url || '', @@ -34,13 +37,17 @@ const FM = ({ edit, record }) => { }; useEffect(() => { - Object.keys(state).forEach((key) => { + const errorCount = Object.keys(state).reduce((acc, key) => { if (state[key] === '') { - setFormError('Please add the required information'); - } else { - setFormError(''); + return acc + 1; } - }); + return acc; + }, 0); + if (errorCount > 0) { + setFormError('Please add the required information'); + } else { + setFormError(''); + } }, [state]); return ( @@ -92,20 +99,4 @@ const FM = ({ edit, record }) => { ); }; -FM.propTypes = { - record: shape({ - title: string, - frequency: string, - url: string, - imageUrl: string, - id: string, - }), - edit: bool, -}; - -FM.defaultProps = { - record: {}, - edit: false, -}; - export default FM; diff --git a/src/app/components/searchPage.jsx b/src/app/components/searchPage.jsx index 6f041e4..783b160 100644 --- a/src/app/components/searchPage.jsx +++ b/src/app/components/searchPage.jsx @@ -1,12 +1,12 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { Button } from '@material-ui/core'; -import { Route } from 'react-router-dom'; -import FMStation from './fm'; +import { useHistory } from 'react-router-dom'; const SearchPage = () => { const [fmList, setFMList] = useState([]); const [loading, setLoading] = useState(true); + const history = useHistory(); const sortFMByTitle = (titleA, titleB) => { if (titleA < titleB) return -1; @@ -28,7 +28,13 @@ const SearchPage = () => { fetchData(); }, []); - const onClick = fm => } />; + const onClick = (fm) => { + history.push({ + pathname: '/fm', + record: fm, + edit: true, + }); + }; return (
Station Frequency ImageEdit
{fm.title} {fm.frequency} {fm.title}
@@ -37,7 +43,6 @@ const SearchPage = () => { - From 17011d9510a3b30bcd74fce65b972aa92c64ad4d Mon Sep 17 00:00:00 2001 From: yuvigrg Date: Sat, 25 Jul 2020 22:47:03 +0100 Subject: [PATCH 8/9] Button name change --- src/app/components/buttons/add.jsx | 2 +- src/app/components/buttons/update.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/components/buttons/add.jsx b/src/app/components/buttons/add.jsx index e0bcf80..52702f8 100644 --- a/src/app/components/buttons/add.jsx +++ b/src/app/components/buttons/add.jsx @@ -33,7 +33,7 @@ const AddButton = ({ setSubmitting, newRecord, disabled, dispatch }) => { onClick={submit} disabled={disabled} > - Add New + Submit ); }; diff --git a/src/app/components/buttons/update.jsx b/src/app/components/buttons/update.jsx index 6e1d762..8d28394 100644 --- a/src/app/components/buttons/update.jsx +++ b/src/app/components/buttons/update.jsx @@ -34,7 +34,7 @@ const UpdateButton = ({ setSubmitting, record, disabled }) => { onClick={submit} disabled={disabled} > - Update Record + Submit ); }; From a5210fc0c13e2b603ba14804f324e334e9855c55 Mon Sep 17 00:00:00 2001 From: yuvigrg Date: Sat, 25 Jul 2020 23:31:06 +0100 Subject: [PATCH 9/9] Updated link and css --- src/_content/main.scss | 17 +++++++++ src/app/components/buttons/textLink.jsx | 14 ++++++++ src/app/components/searchPage.jsx | 48 +++++++++++++------------ 3 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 src/app/components/buttons/textLink.jsx diff --git a/src/_content/main.scss b/src/_content/main.scss index 3e59bbc..63b09be 100644 --- a/src/_content/main.scss +++ b/src/_content/main.scss @@ -20,6 +20,23 @@ table { th, td { padding: 0.25rem; border: 1px solid black; + + .textLink { + border-style: none; + cursor: pointer; + display: inline; + perspective-origin: 0 0; + text-align: start; + text-decoration: underline; + color: blue; + font-size: 1em; + font-weight: normal; + font-style: normal; + font-stretch: normal; + line-height: normal; + letter-spacing: normal; + background: rgba(0, 0, 0, 0); + } } th { diff --git a/src/app/components/buttons/textLink.jsx b/src/app/components/buttons/textLink.jsx new file mode 100644 index 0000000..c38d159 --- /dev/null +++ b/src/app/components/buttons/textLink.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { Button } from '@material-ui/core'; +import { func, string } from 'prop-types'; + +const TextLink = ({ text, onClick }) => ( + +); + +TextLink.propTypes = { + text: string.isRequired, + onClick: func.isRequired, +}; + +export default TextLink; diff --git a/src/app/components/searchPage.jsx b/src/app/components/searchPage.jsx index 783b160..533025c 100644 --- a/src/app/components/searchPage.jsx +++ b/src/app/components/searchPage.jsx @@ -1,7 +1,8 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; -import { Button } from '@material-ui/core'; +import { LinearProgress } from '@material-ui/core'; import { useHistory } from 'react-router-dom'; +import TextLink from './buttons/textLink'; const SearchPage = () => { const [fmList, setFMList] = useState([]); @@ -37,27 +38,30 @@ const SearchPage = () => { }; return ( -
Station Frequency ImageEdit
- - - - - - - - - {!loading && fmList.length > 0 - ? fmList.map(fm => ( - - - - - - - )) - : <>Still loading....} - -
StationFrequencyImage
{fm.title}{fm.frequency}{fm.title}
+ <> + {!loading && fmList.length > 0 + ? ( + + + + + + + + + + {fmList.map(fm => ( + onClick(fm)}> + + + + + ))} + +
StationFrequencyImage
onClick(fm)} />{fm.frequency}{fm.title}
+ ) + : } + ); };