diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..02b526f30 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,37 @@ +version: 2 +updates: +- package-ecosystem: npm + directory: "/" + schedule: + interval: daily + time: "04:00" + open-pull-requests-limit: 10 + reviewers: + - dunky11 + ignore: + - dependency-name: "@date-io/date-fns" + versions: + - ">= 2.3.a, < 2.4" + - dependency-name: "@date-io/date-fns" + versions: + - ">= 2.4.a, < 2.5" + - dependency-name: "@date-io/date-fns" + versions: + - ">= 2.a, < 3" + - dependency-name: workbox-strategies + versions: + - 6.1.5 + - dependency-name: "@testing-library/react" + versions: + - 11.2.6 + - dependency-name: "@testing-library/user-event" + versions: + - 12.6.3 + - 12.7.2 + - 13.0.10 + - 13.0.13 + - 13.0.6 + - 13.0.7 + - dependency-name: workbox-google-analytics + versions: + - 6.1.1 diff --git a/README.md b/README.md index 7e17da746..e3bd9abd4 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ Remains of a SaaS business I once tried to build. Now transformed into a templat [**Check out the demo**](https://reactsaastemplate.com) ![Node.js CI](https://github.com/dunky11/react-saas-template/workflows/Node.js%20CI/badge.svg) -[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=dunky11/react-saas-template)](https://dependabot.com) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [](https://reactsaastemplate.com "Go to demo website") @@ -51,13 +50,13 @@ Your browser should now open and show the app. Otherwise open http://localhost:3 If you are new to React, you should watch a [basic React tutorial](https://www.youtube.com/results?search_query=react+tutorial) first. -If you already know React, then most of the information you need is in the [Material-UI documentation](https://material-ui.com/getting-started/usage/). +If you know React, then most of the information you need is in the [Material-UI documentation](https://material-ui.com/getting-started/usage/). You can go into [src/theme.js](/src/theme.js) and change the primary and secondary color codes at the top of the script to the values you like and some magic will happen. ## Deployment -If you are happy with the state of your website you can run: +If you are satisfied with the state of your website you can run: ``` npm run build diff --git a/package-lock.json b/package-lock.json index 9b618f31a..417bbe13e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2327,17 +2327,17 @@ } }, "@stripe/react-stripe-js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.4.0.tgz", - "integrity": "sha512-Pz5QmG8PgJ3pi8gOWxlngk+ns63p2L1Ds192fn55ykZNRKfGz3G6sfssUVThHn/NAt2Hp1eCEsy/hvlKnXJI6g==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.4.1.tgz", + "integrity": "sha512-FjcVrhf72+9fUL3Lz3xi02ni9tzH1A1x6elXlr6tvBDgSD55oPJuodoP8eC7xTnBIKq0olF5uJvgtkJyDCdzjA==", "requires": { "prop-types": "^15.7.2" } }, "@stripe/stripe-js": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.14.0.tgz", - "integrity": "sha512-Zw4EI+ph8RPxRpIX2uwKKDIbe7WM2OarasPjIPRulU1UCj8lRFqWWW/fTj79lZtnX3FNZkiTRM13UG1UZF7yjQ==" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.15.0.tgz", + "integrity": "sha512-KQsNPc+uVQkc8dewwz1A6uHOWeU2cWoZyNIbsx5mtmperr5TPxw4u8M20WOa22n6zmIOh/zLdzEe8DYK/0IjBw==" }, "@surma/rollup-plugin-off-main-thread": { "version": "1.4.2", @@ -2458,9 +2458,9 @@ } }, "@testing-library/dom": { - "version": "7.30.3", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.30.3.tgz", - "integrity": "sha512-7JhIg2MW6WPwyikH2iL3o7z+FTVgSOd2jqCwTAHqK7Qal2gRRYiUQyURAxtbK9VXm/UTyG9bRihv8C5Tznr2zw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.0.0.tgz", + "integrity": "sha512-Ym375MTOpfszlagRnTMO+FOfTt6gRrWiDOWmEnWLu9OvwCPOWtK6i5pBHmZ07wUJiQ7wWz0t8+ZBK2wFo2tlew==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", @@ -2468,33 +2468,42 @@ "@types/aria-query": "^4.2.0", "aria-query": "^4.2.2", "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.4", + "dom-accessibility-api": "^0.5.6", "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" + "pretty-format": "^27.0.2" }, "dependencies": { "@babel/runtime": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", - "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", + "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } }, "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^15.0.0", + "@types/yargs": "^16.0.0", "chalk": "^4.0.0" } }, + "@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2505,9 +2514,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -2536,15 +2545,23 @@ "dev": true }, "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.0.2", "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", + "ansi-styles": "^5.0.0", "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } } }, "react-is": { @@ -2565,9 +2582,9 @@ } }, "@testing-library/jest-dom": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.12.0.tgz", - "integrity": "sha512-N9Y82b2Z3j6wzIoAqajlKVF1Zt7sOH0pPee0sUHXHc5cv2Fdn23r+vpWm0MBBoGJtPOly5+Bdx1lnc3CD+A+ow==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", + "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", "dev": true, "requires": { "@babel/runtime": "^7.9.2", @@ -2576,6 +2593,7 @@ "chalk": "^3.0.0", "css": "^3.0.0", "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", "lodash": "^4.17.15", "redent": "^3.0.0" }, @@ -2625,6 +2643,12 @@ "source-map-resolve": "^0.6.0" } }, + "dom-accessibility-api": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz", + "integrity": "sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2659,19 +2683,19 @@ } }, "@testing-library/react": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.6.tgz", - "integrity": "sha512-TXMCg0jT8xmuU8BkKMtp8l7Z50Ykew5WNX8UoIKTaLFwKkP2+1YDhOLA2Ga3wY4x29jyntk7EWfum0kjlYiSjQ==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.0.0.tgz", + "integrity": "sha512-sh3jhFgEshFyJ/0IxGltRhwZv2kFKfJ3fN1vTZ6hhMXzz9ZbbcTgmDYM4e+zJv+oiVKKEWZPyqPAh4MQBI65gA==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^7.28.1" + "@testing-library/dom": "^8.0.0" }, "dependencies": { "@babel/runtime": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", - "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", + "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" @@ -2680,9 +2704,9 @@ } }, "@testing-library/user-event": { - "version": "13.1.8", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.1.8.tgz", - "integrity": "sha512-M04HgOlJvxILf5xyrkJaEQfFOtcvhy3usLldQIEg9zgFIYQofSmFGVfFlS7BWowqlBGLrItwGMlPXCoBgoHSiw==", + "version": "13.1.9", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.1.9.tgz", + "integrity": "sha512-NZr0zL2TMOs2qk+dNlqrAdbaRW5dAmYwd1yuQ4r7HpkVEOj0MWuUjDWwKhcLd/atdBy8ZSMHSKp+kXSQe47ezg==", "dev": true, "requires": { "@babel/runtime": "^7.12.5" @@ -2831,9 +2855,9 @@ } }, "@types/jest": { - "version": "26.0.22", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.22.tgz", - "integrity": "sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw==", + "version": "26.0.23", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz", + "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==", "dev": true, "requires": { "jest-diff": "^26.0.0", @@ -2939,9 +2963,9 @@ "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==" }, "@types/testing-library__jest-dom": { - "version": "5.9.5", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.5.tgz", - "integrity": "sha512-ggn3ws+yRbOHog9GxnXiEZ/35Mow6YtPZpd7Z5mKDeZS/o7zx3yAle0ov/wjhVB5QT4N2Dt+GNoGCdqkBGCajQ==", + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.0.tgz", + "integrity": "sha512-l2P2GO+hFF4Liye+fAajT1qBqvZOiL79YMpEvgGs1xTK7hECxBI8Wz4J7ntACJNiJ9r0vXQqYovroXRLPDja6A==", "dev": true, "requires": { "@types/jest": "*" @@ -5550,9 +5574,9 @@ } }, "date-fns": { - "version": "2.21.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.21.1.tgz", - "integrity": "sha512-m1WR0xGiC6j6jNFAyW4Nvh4WxAi4JF4w9jRJwSI8nBmNcyZXPcP9VUQG+6gHQXAmqaGEKDKhOqAtENDC941UkA==" + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.22.1.tgz", + "integrity": "sha512-yUFPQjrxEmIsMqlHhAhmxkuH769baF21Kk+nZwZGyrMoyLA+LugaQtC0+Tqf9CBUUULWwUJt6Q5ySI3LJDDCGg==" }, "debug": { "version": "4.3.1", @@ -5839,9 +5863,9 @@ } }, "dom-accessibility-api": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz", - "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz", + "integrity": "sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==", "dev": true }, "dom-converter": { diff --git a/package.json b/package.json index fb0c1f4ae..80fe1691e 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,11 @@ "@material-ui/icons": "^4.11.2", "@material-ui/pickers": "^3.3.10", "@material-ui/system": "^4.11.3", - "@stripe/react-stripe-js": "^1.4.0", - "@stripe/stripe-js": "^1.14.0", + "@stripe/react-stripe-js": "^1.4.1", + "@stripe/stripe-js": "^1.15.0", "aos": "^2.3.4", "classnames": "^2.3.1", - "date-fns": "^2.21.1", + "date-fns": "^2.22.1", "emoji-mart": "^3.0.1", "js-cookie": "^2.2.0", "prop-types": "^15.7.2", @@ -40,9 +40,9 @@ "workbox-streams": "^6.1.5" }, "devDependencies": { - "@testing-library/jest-dom": "^5.12.0", - "@testing-library/react": "^11.2.6", - "@testing-library/user-event": "^13.1.8" + "@testing-library/jest-dom": "^5.14.1", + "@testing-library/react": "^12.0.0", + "@testing-library/user-event": "^13.1.9" }, "scripts": { "start": "react-scripts start", diff --git a/src/logged_in/components/Routing.js b/src/logged_in/components/Routing.js index 519b964d3..c3abb89d7 100644 --- a/src/logged_in/components/Routing.js +++ b/src/logged_in/components/Routing.js @@ -6,6 +6,7 @@ import Dashboard from "./dashboard/Dashboard"; import Posts from "./posts/Posts"; import Subscription from "./subscription/Subscription"; import PropsRoute from "../../shared/components/PropsRoute"; +import useLocationBlocker from "../../shared/functions/useLocationBlocker"; const styles = (theme) => ({ wrapper: { @@ -64,6 +65,7 @@ function Routing(props) { selectSubscription, openAddBalanceDialog, } = props; + useLocationBlocker(); return (
diff --git a/src/logged_out/components/Routing.js b/src/logged_out/components/Routing.js index 5c26807ca..d34eff47d 100644 --- a/src/logged_out/components/Routing.js +++ b/src/logged_out/components/Routing.js @@ -5,9 +5,11 @@ import PropsRoute from "../../shared/components/PropsRoute"; import Home from "./home/Home"; import Blog from "./blog/Blog"; import BlogPost from "./blog/BlogPost"; +import useLocationBlocker from "../../shared/functions/useLocationBlocker"; function Routing(props) { const { blogPosts, selectBlog, selectHome } = props; + useLocationBlocker(); return ( {blogPosts.map((post) => ( diff --git a/src/shared/functions/useLocationBlocker.js b/src/shared/functions/useLocationBlocker.js new file mode 100644 index 000000000..44db63445 --- /dev/null +++ b/src/shared/functions/useLocationBlocker.js @@ -0,0 +1,28 @@ +import { useHistory } from "react-router-dom"; +import { useEffect } from "react"; + + +const useLocationBlocker = () => { + /** + * Prevents react-router from pushing the same + * page to the history twice which leads to + * multiple clicks on the back icon of the browser + * being necessary to go back into the history. + */ + const history = useHistory(); + useEffect( + () => + history.block( + (location, action) => + action !== "PUSH" || + getLocationId(location) !== getLocationId(history.location) + ), + [] // eslint-disable-line react-hooks/exhaustive-deps + ); +} + +const getLocationId = ({ pathname, search, hash }) => { + return pathname + (search ? "?" + search : "") + (hash ? "#" + hash : ""); +} + +export default useLocationBlocker; \ No newline at end of file