From b64cc8481b7645684f6b67b987d10b4930b3c905 Mon Sep 17 00:00:00 2001 From: Jeffrey Carl Faden Date: Thu, 8 Jun 2023 13:10:29 -0700 Subject: [PATCH 1/8] Fix dependency issues --- package.json | 12 - src/client.tsx | 3 - src/middlewares/invitation.ts | 3 +- src/routes/team/home/Home.tsx | 14 ++ yarn.lock | 439 ++-------------------------------- 5 files changed, 38 insertions(+), 433 deletions(-) diff --git a/package.json b/package.json index c7cb11e46..2f25553c4 100644 --- a/package.json +++ b/package.json @@ -28,14 +28,12 @@ "cors": "^2.8.3", "dayjs": "^1.11.7", "dotenv": "^2.0.0", - "eventemitter3": "^1.2.0", "express": "^4.17.3", "express-body-parser-error-handler": "^1.0.4", "express-jwt": "^8.4.1", "express-session": "^1.17.3", "express-sslify": "^1.2.0", "express-ws": "^5.0.2", - "fastclick": "^1.0.6", "fbjs": "^3.0.4", "fetch-mock": "^9.11.0", "flip-toolkit": "^7.1.0", @@ -78,7 +76,6 @@ "sequelize-typescript": "^2.1.5", "serialize-javascript": "^6.0.1", "source-map-support": "^0.5.21", - "sqlite3": "^5.1.5", "universal-router": "^8.1.0", "uuid": "^9.0.0" }, @@ -124,7 +121,6 @@ "@types/webpack-env": "^1.18.0", "@typescript-eslint/eslint-plugin": "^5.59.1", "@typescript-eslint/parser": "^5.59.1", - "assets-webpack-plugin": "^7.1.1", "autoprefixer": "^9.1.5", "browser-sync": "2.29.1", "chai": "4.3.7", @@ -132,10 +128,7 @@ "chokidar": "^3.5.3", "cross-env": "^5.0.1", "css-loader": "^6.7.3", - "custom-event-polyfill": "^0.3.0", "cypress": "^12.5.1", - "del": "^2.2.2", - "es6-promise": "^4.1.0", "eslint": "^8.34.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.8.0", @@ -148,13 +141,10 @@ "eslint-plugin-react-hooks": "^4.6.0", "file-loader": "^6.2.0", "fork-ts-checker-webpack-plugin": "^7.3.0", - "git-repository": "^0.1.4", "glob": "^7.1.3", "global-jsdom": "^9.0.1", "husky": "^8.0.3", - "identity-obj-proxy": "^3.0.0", "jsdom": "^22.0.0", - "json-loader": "^0.5.7", "lint-staged": "^13.2.2", "mkdirp": "^2.1.3", "mocha": "^10.2.0", @@ -170,13 +160,11 @@ "react-dev-utils": "^12.0.1", "react-error-overlay": "^4.0.1", "react-refresh": "^0.14.0", - "react-test-renderer": "^18.2.0", "rimraf": "^2.6.2", "sass": "^1.58.0", "sass-loader": "^13.2.0", "sequelize-mock": "^0.7.0", "sinon": "^15.1.0", - "style-loader": "^0.13.2", "stylelint": "^15.6.2", "stylelint-config-standard-scss": "^9.0.0", "stylelint-order": "^6.0.3", diff --git a/src/client.tsx b/src/client.tsx index fced1d19b..f73988a6f 100644 --- a/src/client.tsx +++ b/src/client.tsx @@ -7,7 +7,6 @@ * LICENSE.txt file in the root directory of this source tree. */ -import es6Promise from "es6-promise"; import React, { useEffect } from "react"; import { createRoot, hydrateRoot } from "react-dom/client"; import qs from "qs"; @@ -19,8 +18,6 @@ import { updateMeta } from "./DOMUtils"; import routerCreator from "./router"; import { AppContext, App as AppType } from "./interfaces"; -es6Promise.polyfill(); - let subdomain: string | undefined; interface WindowWithApp extends Window { diff --git a/src/middlewares/invitation.ts b/src/middlewares/invitation.ts index 5d8932ac1..288a0a90d 100644 --- a/src/middlewares/invitation.ts +++ b/src/middlewares/invitation.ts @@ -1,5 +1,4 @@ import { Request, Router } from "express"; -import qs from "qs"; import { bsHost } from "../config"; import generateToken from "../helpers/generateToken"; import generateUrl from "../helpers/generateUrl"; @@ -53,7 +52,7 @@ export default () => { Add them here: ${generateUrl( req, bsHost, - `/users/new?email=${qs.stringify(invitation.email)}` + `/users/new?email=${encodeURIComponent(invitation.email)}` )}`, }); } diff --git a/src/routes/team/home/Home.tsx b/src/routes/team/home/Home.tsx index c23166170..9ea6808a8 100644 --- a/src/routes/team/home/Home.tsx +++ b/src/routes/team/home/Home.tsx @@ -11,6 +11,9 @@ import RestaurantAddFormContainer from "../../../components/RestaurantAddForm/Re import TagFilterFormContainer from "../../../components/TagFilterForm/TagFilterFormContainer"; import { User } from "../../../interfaces"; import s from "./Home.scss"; +import GoogleMapsLoaderContext, { + IGoogleMapsLoaderContext, +} from "../../../components/GoogleMapsLoaderContext/GoogleMapsLoaderContext"; export interface HomeProps { user?: User | null; @@ -28,6 +31,8 @@ export interface HomeProps { } export class _Home extends Component { + static contextType = GoogleMapsLoaderContext; + fetchAllInterval: NodeJS.Timer; pingInterval: NodeJS.Timer; @@ -38,6 +43,15 @@ export class _Home extends Component { user: null, }; + constructor(props: HomeProps, context: IGoogleMapsLoaderContext) { + super(props); + + if (canUseDOM) { + const { loader } = context; + loader?.load(); + } + } + componentDidMount() { const { messageReceived, wsPort } = this.props; diff --git a/yarn.lock b/yarn.lock index e7da4fb12..deee412f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1496,7 +1496,7 @@ __metadata: languageName: node linkType: hard -"@gar/promisify@npm:^1.0.1, @gar/promisify@npm:^1.1.3": +"@gar/promisify@npm:^1.1.3": version: 1.1.3 resolution: "@gar/promisify@npm:1.1.3" checksum: 4059f790e2d07bf3c3ff3e0fec0daa8144fe35c1f6e0111c9921bd32106adaa97a4ab096ad7dab1e28ee6a9060083c4d1a4ada42a7f5f3f7a96b8812e2b757c1 @@ -1698,7 +1698,7 @@ __metadata: languageName: node linkType: hard -"@mapbox/node-pre-gyp@npm:^1.0.0, @mapbox/node-pre-gyp@npm:^1.0.10": +"@mapbox/node-pre-gyp@npm:^1.0.10": version: 1.0.10 resolution: "@mapbox/node-pre-gyp@npm:1.0.10" dependencies: @@ -1751,16 +1751,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/fs@npm:^1.0.0": - version: 1.1.1 - resolution: "@npmcli/fs@npm:1.1.1" - dependencies: - "@gar/promisify": ^1.0.1 - semver: ^7.3.5 - checksum: f5ad92f157ed222e4e31c352333d0901df02c7c04311e42a81d8eb555d4ec4276ea9c635011757de20cc476755af33e91622838de573b17e52e2e7703f0a9965 - languageName: node - linkType: hard - "@npmcli/fs@npm:^2.1.0": version: 2.1.2 resolution: "@npmcli/fs@npm:2.1.2" @@ -1771,16 +1761,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/move-file@npm:^1.0.1": - version: 1.1.2 - resolution: "@npmcli/move-file@npm:1.1.2" - dependencies: - mkdirp: ^1.0.4 - rimraf: ^3.0.2 - checksum: c96381d4a37448ea280951e46233f7e541058cf57a57d4094dd4bdcaae43fa5872b5f2eb6bfb004591a68e29c5877abe3cdc210cb3588cbf20ab2877f31a7de7 - languageName: node - linkType: hard - "@npmcli/move-file@npm:^2.0.0": version: 2.0.1 resolution: "@npmcli/move-file@npm:2.0.1" @@ -2162,13 +2142,6 @@ __metadata: languageName: node linkType: hard -"@tootallnate/once@npm:1": - version: 1.1.2 - resolution: "@tootallnate/once@npm:1.1.2" - checksum: e1fb1bbbc12089a0cb9433dc290f97bddd062deadb6178ce9bcb93bb7c1aecde5e60184bc7065aec42fe1663622a213493c48bbd4972d931aae48315f18e1be9 - languageName: node - linkType: hard - "@tootallnate/once@npm:2": version: 2.0.0 resolution: "@tootallnate/once@npm:2.0.0" @@ -3383,7 +3356,7 @@ __metadata: languageName: node linkType: hard -"agentkeepalive@npm:^4.1.3, agentkeepalive@npm:^4.2.1": +"agentkeepalive@npm:^4.2.1": version: 4.3.0 resolution: "agentkeepalive@npm:4.3.0" dependencies: @@ -3659,15 +3632,6 @@ __metadata: languageName: node linkType: hard -"array-union@npm:^1.0.1": - version: 1.0.2 - resolution: "array-union@npm:1.0.2" - dependencies: - array-uniq: ^1.0.1 - checksum: 82cec6421b6e6766556c484835a6d476a873f1b71cace5ab2b4f1b15b1e3162dc4da0d16f7a2b04d4aec18146c6638fe8f661340b31ba8e469fd811a1b45dc8d - languageName: node - linkType: hard - "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" @@ -3675,13 +3639,6 @@ __metadata: languageName: node linkType: hard -"array-uniq@npm:^1.0.1": - version: 1.0.3 - resolution: "array-uniq@npm:1.0.3" - checksum: 1625f06b093d8bf279b81adfec6e72951c0857d65b5e3f65f053fffe9f9dd61c2fc52cff57e38a4700817e7e3f01a4faa433d505ea9e33cdae4514c334e0bf9e - languageName: node - linkType: hard - "array.prototype.flat@npm:^1.3.1": version: 1.3.1 resolution: "array.prototype.flat@npm:1.3.1" @@ -3719,7 +3676,7 @@ __metadata: languageName: node linkType: hard -"arrify@npm:^1.0.0, arrify@npm:^1.0.1": +"arrify@npm:^1.0.1": version: 1.0.1 resolution: "arrify@npm:1.0.1" checksum: 745075dd4a4624ff0225c331dacb99be501a515d39bcb7c84d24660314a6ec28e68131b137e6f7e16318170842ce97538cd298fc4cd6b2cc798e0b957f2747e7 @@ -3756,19 +3713,6 @@ __metadata: languageName: node linkType: hard -"assets-webpack-plugin@npm:^7.1.1": - version: 7.1.1 - resolution: "assets-webpack-plugin@npm:7.1.1" - dependencies: - camelcase: ^6.0.0 - escape-string-regexp: ^4.0.0 - lodash: ^4.17.21 - peerDependencies: - webpack: ">=5.0.0" - checksum: 7a42f71173ba273cf89543acd1d6f19c16a1594053449d8af2dd5275ebc88eb56028667c7cc063d3a789aa779fb4d2374066a48195aaa35d3bda65723a9471e6 - languageName: node - linkType: hard - "ast-types-flow@npm:^0.0.7": version: 0.0.7 resolution: "ast-types-flow@npm:0.0.7" @@ -4257,32 +4201,6 @@ __metadata: languageName: node linkType: hard -"cacache@npm:^15.2.0": - version: 15.3.0 - resolution: "cacache@npm:15.3.0" - dependencies: - "@npmcli/fs": ^1.0.0 - "@npmcli/move-file": ^1.0.1 - chownr: ^2.0.0 - fs-minipass: ^2.0.0 - glob: ^7.1.4 - infer-owner: ^1.0.4 - lru-cache: ^6.0.0 - minipass: ^3.1.1 - minipass-collect: ^1.0.2 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.2 - mkdirp: ^1.0.3 - p-map: ^4.0.0 - promise-inflight: ^1.0.1 - rimraf: ^3.0.2 - ssri: ^8.0.1 - tar: ^6.0.2 - unique-filename: ^1.1.1 - checksum: a07327c27a4152c04eb0a831c63c00390d90f94d51bb80624a66f4e14a6b6360bbf02a84421267bd4d00ca73ac9773287d8d7169e8d2eafe378d2ce140579db8 - languageName: node - linkType: hard - "cacache@npm:^16.1.0": version: 16.1.3 resolution: "cacache@npm:16.1.3" @@ -5198,13 +5116,6 @@ __metadata: languageName: node linkType: hard -"custom-event-polyfill@npm:^0.3.0": - version: 0.3.0 - resolution: "custom-event-polyfill@npm:0.3.0" - checksum: 449d8e8497699ef5fe8ce6a9b041b6d7e36099c40710a5e853afe5912a530e71ac177f52f1b1836403c9973dc2668df82006935d0517f1549d3e11e97f55043d - languageName: node - linkType: hard - "cypress@npm:^12.5.1": version: 12.5.1 resolution: "cypress@npm:12.5.1" @@ -5471,21 +5382,6 @@ __metadata: languageName: node linkType: hard -"del@npm:^2.2.2": - version: 2.2.2 - resolution: "del@npm:2.2.2" - dependencies: - globby: ^5.0.0 - is-path-cwd: ^1.0.0 - is-path-in-cwd: ^1.0.0 - object-assign: ^4.0.1 - pify: ^2.0.0 - pinkie-promise: ^2.0.0 - rimraf: ^2.2.8 - checksum: 053ed28031653f92365b6405a2154d1b415d2ab2f809532c64cc2de1640a694cbcce06e162d4b61d4299e303ef0301eba70dc6c5bdaca9bbe8dc0790758caf68 - languageName: node - linkType: hard - "delayed-stream@npm:~1.0.0": version: 1.0.0 resolution: "delayed-stream@npm:1.0.0" @@ -5827,7 +5723,7 @@ __metadata: languageName: node linkType: hard -"encoding@npm:^0.1.12, encoding@npm:^0.1.13": +"encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" dependencies: @@ -6082,7 +5978,7 @@ __metadata: languageName: node linkType: hard -"es6-promise@npm:^4.1.0, es6-promise@npm:^4.2.8": +"es6-promise@npm:^4.2.8": version: 4.2.8 resolution: "es6-promise@npm:4.2.8" checksum: 95614a88873611cb9165a85d36afa7268af5c03a378b35ca7bda9508e1d4f1f6f19a788d4bc755b3fd37c8ebba40782018e02034564ff24c9d6fa37e959ad57d @@ -6513,13 +6409,6 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:^1.2.0": - version: 1.2.0 - resolution: "eventemitter3@npm:1.2.0" - checksum: 1ce3c91340f5038bd611c31a32c69167ccc598049a6844f58400583b4d70f5c0c2d13a201c763624f81de461498fe2767d0bfadcb2c0c417e37556a481b00c1d - languageName: node - linkType: hard - "eventemitter3@npm:^4.0.0, eventemitter3@npm:^4.0.4": version: 4.0.7 resolution: "eventemitter3@npm:4.0.7" @@ -6768,13 +6657,6 @@ __metadata: languageName: node linkType: hard -"fastclick@npm:^1.0.6": - version: 1.0.6 - resolution: "fastclick@npm:1.0.6" - checksum: 5da932e7d6744995d283cf46a2a2efa363548e4741441bf1d39627f3cdf36ebfd567126418e4c63ff25135597628f5d5e2b62a26249de9c1d5e8a0f72b402201 - languageName: node - linkType: hard - "fastest-levenshtein@npm:^1.0.12, fastest-levenshtein@npm:^1.0.16": version: 1.0.16 resolution: "fastest-levenshtein@npm:1.0.16" @@ -7423,13 +7305,6 @@ __metadata: languageName: node linkType: hard -"git-repository@npm:^0.1.4": - version: 0.1.4 - resolution: "git-repository@npm:0.1.4" - checksum: b3f2451eca7ee0aa41b2e9415bb1ca3c234ec6dcb34178c441a6520e387371e3a98cc0a559d21d792e355e0a5b1e703302c169ac34201241cdf748eb1bc0db88 - languageName: node - linkType: hard - "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -7469,7 +7344,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.3, glob@npm:^7.0.5, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": +"glob@npm:^7.0.5, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -7593,20 +7468,6 @@ __metadata: languageName: node linkType: hard -"globby@npm:^5.0.0": - version: 5.0.0 - resolution: "globby@npm:5.0.0" - dependencies: - array-union: ^1.0.1 - arrify: ^1.0.0 - glob: ^7.0.3 - object-assign: ^4.0.1 - pify: ^2.0.0 - pinkie-promise: ^2.0.0 - checksum: c8d7fb42aa55da87c13ed1f7e0f815c566ceb1bb05257ae1349f882d7a10f3f41d1fbe5604148d6c864df3a65d0b9c9e20cbae5f22b6abc8a4924f45bdad8d8f - languageName: node - linkType: hard - "globjoin@npm:^0.1.4": version: 0.1.4 resolution: "globjoin@npm:0.1.4" @@ -7686,13 +7547,6 @@ __metadata: languageName: node linkType: hard -"harmony-reflect@npm:^1.4.6": - version: 1.6.0 - resolution: "harmony-reflect@npm:1.6.0" - checksum: ca1dd0b52c0eab603dae6e7693470ead23a2ae377222fba50edf13a50cb73fdfdb5869e6b79772c1012d9b7ad6655d63ba0690511eab0aaa5404b35d6d57d0b9 - languageName: node - linkType: hard - "has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2": version: 1.0.2 resolution: "has-bigints@npm:1.0.2" @@ -7896,17 +7750,6 @@ __metadata: languageName: node linkType: hard -"http-proxy-agent@npm:^4.0.1": - version: 4.0.1 - resolution: "http-proxy-agent@npm:4.0.1" - dependencies: - "@tootallnate/once": 1 - agent-base: 6 - debug: 4 - checksum: c6a5da5a1929416b6bbdf77b1aca13888013fe7eb9d59fc292e25d18e041bb154a8dfada58e223fc7b76b9b2d155a87e92e608235201f77d34aa258707963a82 - languageName: node - linkType: hard - "http-proxy-agent@npm:^5.0.0": version: 5.0.0 resolution: "http-proxy-agent@npm:5.0.0" @@ -8016,15 +7859,6 @@ __metadata: languageName: node linkType: hard -"identity-obj-proxy@npm:^3.0.0": - version: 3.0.0 - resolution: "identity-obj-proxy@npm:3.0.0" - dependencies: - harmony-reflect: ^1.4.6 - checksum: 97559f8ea2aeaa1a880d279d8c49550dce01148321e00a2102cda5ddf9ce622fa1d7f3efc7bed63458af78889de888fdaebaf31c816312298bb3fdd0ef8aaf2c - languageName: node - linkType: hard - "ieee754@npm:^1.1.13, ieee754@npm:^1.2.1": version: 1.2.1 resolution: "ieee754@npm:1.2.1" @@ -8437,31 +8271,6 @@ __metadata: languageName: node linkType: hard -"is-path-cwd@npm:^1.0.0": - version: 1.0.0 - resolution: "is-path-cwd@npm:1.0.0" - checksum: ade6d8d59bb6a00079fb515ad78a741b757a66bc6208a2dab2c9f8ad535bc61e21b6823ae8b23df2bf4d2b9dac8df4f3df2e68105698eb3e15ceb5ca90dac097 - languageName: node - linkType: hard - -"is-path-in-cwd@npm:^1.0.0": - version: 1.0.1 - resolution: "is-path-in-cwd@npm:1.0.1" - dependencies: - is-path-inside: ^1.0.0 - checksum: bacfc67c0dacd09002668abb1565fa77ee9593914f1502ec8ecae9821ddd39a2a98e7a95053e3446421b3429c3b3df1a26669c95cecc9f4f556609ec9760ba2a - languageName: node - linkType: hard - -"is-path-inside@npm:^1.0.0": - version: 1.0.1 - resolution: "is-path-inside@npm:1.0.1" - dependencies: - path-is-inside: ^1.0.1 - checksum: 07e52c81163937ff89b4700b7ad474de3b396846b55ed87530fb0a22cb9103926152939f673bc1a0592448e7e4e9d75eb734be21b4ad411311065c6a509fae54 - languageName: node - linkType: hard - "is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" @@ -9003,13 +8812,6 @@ __metadata: languageName: node linkType: hard -"json-loader@npm:^0.5.7": - version: 0.5.7 - resolution: "json-loader@npm:0.5.7" - checksum: c7d054edf7fd5338847f49008df3cdf744f64507584dff3e6d28f500604eedd9130ca1639caa61747b36ab141e7e8db0e86f8514b2244b6d8b0eb634f1154875 - languageName: node - linkType: hard - "json-parse-better-errors@npm:^1.0.1": version: 1.0.2 resolution: "json-parse-better-errors@npm:1.0.2" @@ -9346,7 +9148,7 @@ __metadata: languageName: node linkType: hard -"loader-utils@npm:^1.0.2, loader-utils@npm:^1.2.3": +"loader-utils@npm:^1.2.3": version: 1.4.2 resolution: "loader-utils@npm:1.4.2" dependencies: @@ -9647,7 +9449,6 @@ __metadata: "@types/webpack-env": ^1.18.0 "@typescript-eslint/eslint-plugin": ^5.59.1 "@typescript-eslint/parser": ^5.59.1 - assets-webpack-plugin: ^7.1.1 autoprefixer: ^9.1.5 bcrypt: ^5.1.0 body-parser: ^1.18.3 @@ -9665,12 +9466,9 @@ __metadata: cors: ^2.8.3 cross-env: ^5.0.1 css-loader: ^6.7.3 - custom-event-polyfill: ^0.3.0 cypress: ^12.5.1 dayjs: ^1.11.7 - del: ^2.2.2 dotenv: ^2.0.0 - es6-promise: ^4.1.0 eslint: ^8.34.0 eslint-config-airbnb: ^19.0.4 eslint-config-prettier: ^8.8.0 @@ -9681,30 +9479,25 @@ __metadata: eslint-plugin-jsx-a11y: ^6.7.1 eslint-plugin-react: ^7.32.2 eslint-plugin-react-hooks: ^4.6.0 - eventemitter3: ^1.2.0 express: ^4.17.3 express-body-parser-error-handler: ^1.0.4 express-jwt: ^8.4.1 express-session: ^1.17.3 express-sslify: ^1.2.0 express-ws: ^5.0.2 - fastclick: ^1.0.6 fbjs: ^3.0.4 fetch-mock: ^9.11.0 file-loader: ^6.2.0 flip-toolkit: ^7.1.0 fork-ts-checker-webpack-plugin: ^7.3.0 - git-repository: ^0.1.4 glob: ^7.1.3 global-jsdom: ^9.0.1 google-map-react: ^2.2.0 history: ^5.3.0 husky: ^8.0.3 - identity-obj-proxy: ^3.0.0 immutability-helper: ^3.1.1 isomorphic-style-loader: ^5.3.2 jsdom: ^22.0.0 - json-loader: ^0.5.7 jsonwebtoken: ^9.0.0 lint-staged: ^13.2.2 lodash.get: ^4.4.2 @@ -9743,7 +9536,6 @@ __metadata: react-redux: ^8.0.5 react-refresh: ^0.14.0 react-scroll: ^1.8.9 - react-test-renderer: ^18.2.0 react-transition-group: ^4.4.5 redux: ^4.2.1 reflect-metadata: ^0.1.13 @@ -9761,8 +9553,6 @@ __metadata: serialize-javascript: ^6.0.1 sinon: ^15.1.0 source-map-support: ^0.5.21 - sqlite3: ^5.1.5 - style-loader: ^0.13.2 stylelint: ^15.6.2 stylelint-config-standard-scss: ^9.0.0 stylelint-order: ^6.0.3 @@ -9843,30 +9633,6 @@ __metadata: languageName: node linkType: hard -"make-fetch-happen@npm:^9.1.0": - version: 9.1.0 - resolution: "make-fetch-happen@npm:9.1.0" - dependencies: - agentkeepalive: ^4.1.3 - cacache: ^15.2.0 - http-cache-semantics: ^4.1.0 - http-proxy-agent: ^4.0.1 - https-proxy-agent: ^5.0.0 - is-lambda: ^1.0.1 - lru-cache: ^6.0.0 - minipass: ^3.1.3 - minipass-collect: ^1.0.2 - minipass-fetch: ^1.3.2 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.4 - negotiator: ^0.6.2 - promise-retry: ^2.0.1 - socks-proxy-agent: ^6.0.0 - ssri: ^8.0.0 - checksum: 0eb371c85fdd0b1584fcfdf3dc3c62395761b3c14658be02620c310305a9a7ecf1617a5e6fb30c1d081c5c8aaf177fa133ee225024313afabb7aa6a10f1e3d04 - languageName: node - linkType: hard - "map-obj@npm:^1.0.0": version: 1.0.1 resolution: "map-obj@npm:1.0.1" @@ -10153,21 +9919,6 @@ __metadata: languageName: node linkType: hard -"minipass-fetch@npm:^1.3.2": - version: 1.4.1 - resolution: "minipass-fetch@npm:1.4.1" - dependencies: - encoding: ^0.1.12 - minipass: ^3.1.0 - minipass-sized: ^1.0.3 - minizlib: ^2.0.0 - dependenciesMeta: - encoding: - optional: true - checksum: ec93697bdb62129c4e6c0104138e681e30efef8c15d9429dd172f776f83898471bc76521b539ff913248cc2aa6d2b37b652c993504a51cc53282563640f29216 - languageName: node - linkType: hard - "minipass-fetch@npm:^2.0.3": version: 2.1.2 resolution: "minipass-fetch@npm:2.1.2" @@ -10192,7 +9943,7 @@ __metadata: languageName: node linkType: hard -"minipass-pipeline@npm:^1.2.2, minipass-pipeline@npm:^1.2.4": +"minipass-pipeline@npm:^1.2.4": version: 1.2.4 resolution: "minipass-pipeline@npm:1.2.4" dependencies: @@ -10210,7 +9961,7 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^3.0.0, minipass@npm:^3.1.0, minipass@npm:^3.1.1, minipass@npm:^3.1.3, minipass@npm:^3.1.6": +"minipass@npm:^3.0.0, minipass@npm:^3.1.1, minipass@npm:^3.1.6": version: 3.3.6 resolution: "minipass@npm:3.3.6" dependencies: @@ -10219,7 +9970,7 @@ __metadata: languageName: node linkType: hard -"minizlib@npm:^2.0.0, minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": +"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": version: 2.1.2 resolution: "minizlib@npm:2.1.2" dependencies: @@ -10406,7 +10157,7 @@ __metadata: languageName: node linkType: hard -"negotiator@npm:0.6.3, negotiator@npm:^0.6.2, negotiator@npm:^0.6.3": +"negotiator@npm:0.6.3, negotiator@npm:^0.6.3": version: 0.6.3 resolution: "negotiator@npm:0.6.3" checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 @@ -10454,15 +10205,6 @@ __metadata: languageName: node linkType: hard -"node-addon-api@npm:^4.2.0": - version: 4.3.0 - resolution: "node-addon-api@npm:4.3.0" - dependencies: - node-gyp: latest - checksum: 3de396e23cc209f539c704583e8e99c148850226f6e389a641b92e8967953713228109f919765abc1f4355e801e8f41842f96210b8d61c7dcc10a477002dcf00 - languageName: node - linkType: hard - "node-addon-api@npm:^5.0.0": version: 5.1.0 resolution: "node-addon-api@npm:5.1.0" @@ -10500,26 +10242,6 @@ __metadata: languageName: node linkType: hard -"node-gyp@npm:8.x": - version: 8.4.1 - resolution: "node-gyp@npm:8.4.1" - dependencies: - env-paths: ^2.2.0 - glob: ^7.1.4 - graceful-fs: ^4.2.6 - make-fetch-happen: ^9.1.0 - nopt: ^5.0.0 - npmlog: ^6.0.0 - rimraf: ^3.0.2 - semver: ^7.3.5 - tar: ^6.1.2 - which: ^2.0.2 - bin: - node-gyp: bin/node-gyp.js - checksum: 341710b5da39d3660e6a886b37e210d33f8282047405c2e62c277bcc744c7552c5b8b972ebc3a7d5c2813794e60cc48c3ebd142c46d6e0321db4db6c92dd0355 - languageName: node - linkType: hard - "node-gyp@npm:latest": version: 9.3.1 resolution: "node-gyp@npm:9.3.1" @@ -10772,7 +10494,7 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4, object-assign@npm:^4.0.1, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": +"object-assign@npm:^4, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f @@ -11179,13 +10901,6 @@ __metadata: languageName: node linkType: hard -"path-is-inside@npm:^1.0.1": - version: 1.0.2 - resolution: "path-is-inside@npm:1.0.2" - checksum: 0b5b6c92d3018b82afb1f74fe6de6338c4c654de4a96123cb343f2b747d5606590ac0c890f956ed38220a4ab59baddfd7b713d78a62d240b20b14ab801fa02cb - languageName: node - linkType: hard - "path-key@npm:^2.0.1": version: 2.0.1 resolution: "path-key@npm:2.0.1" @@ -11399,7 +11114,7 @@ __metadata: languageName: node linkType: hard -"pify@npm:^2.0.0, pify@npm:^2.2.0": +"pify@npm:^2.2.0": version: 2.3.0 resolution: "pify@npm:2.3.0" checksum: 9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba @@ -11413,22 +11128,6 @@ __metadata: languageName: node linkType: hard -"pinkie-promise@npm:^2.0.0": - version: 2.0.1 - resolution: "pinkie-promise@npm:2.0.1" - dependencies: - pinkie: ^2.0.0 - checksum: b53a4a2e73bf56b6f421eef711e7bdcb693d6abb474d57c5c413b809f654ba5ee750c6a96dd7225052d4b96c4d053cdcb34b708a86fceed4663303abee52fcca - languageName: node - linkType: hard - -"pinkie@npm:^2.0.0": - version: 2.0.4 - resolution: "pinkie@npm:2.0.4" - checksum: b12b10afea1177595aab036fc220785488f67b4b0fc49e7a27979472592e971614fa1c728e63ad3e7eb748b4ec3c3dbd780819331dad6f7d635c77c10537b9db - languageName: node - linkType: hard - "pkg-dir@npm:^4.1.0, pkg-dir@npm:^4.2.0": version: 4.2.0 resolution: "pkg-dir@npm:4.2.0" @@ -12110,13 +11809,6 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^16.12.0 || ^17.0.0 || ^18.0.0, react-is@npm:^18.0.0, react-is@npm:^18.2.0": - version: 18.2.0 - resolution: "react-is@npm:18.2.0" - checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e - languageName: node - linkType: hard - "react-is@npm:^16.13.1, react-is@npm:^16.3.2, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" @@ -12131,6 +11823,13 @@ __metadata: languageName: node linkType: hard +"react-is@npm:^18.0.0": + version: 18.2.0 + resolution: "react-is@npm:18.2.0" + checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e + languageName: node + linkType: hard + "react-lifecycles-compat@npm:^3.0.4": version: 3.0.4 resolution: "react-lifecycles-compat@npm:3.0.4" @@ -12190,31 +11889,6 @@ __metadata: languageName: node linkType: hard -"react-shallow-renderer@npm:^16.15.0": - version: 16.15.0 - resolution: "react-shallow-renderer@npm:16.15.0" - dependencies: - object-assign: ^4.1.1 - react-is: ^16.12.0 || ^17.0.0 || ^18.0.0 - peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: 6052c7e3e9627485120ebd8257f128aad8f56386fe8d42374b7743eac1be457c33506d153c7886b4e32923c0c352d402ab805ef9ca02dbcd8393b2bdeb6e5af8 - languageName: node - linkType: hard - -"react-test-renderer@npm:^18.2.0": - version: 18.2.0 - resolution: "react-test-renderer@npm:18.2.0" - dependencies: - react-is: ^18.2.0 - react-shallow-renderer: ^16.15.0 - scheduler: ^0.23.0 - peerDependencies: - react: ^18.2.0 - checksum: 6b6980ced93fa2b72662d5e4ab3b4896833586940047ce52ca9aca801e5432adf05fcbe28289b0af3ce6a2a7c590974e25dcc8aa43d0de658bfe8bbcd686f958 - languageName: node - linkType: hard - "react-themeable@npm:^1.1.0": version: 1.1.0 resolution: "react-themeable@npm:1.1.0" @@ -12703,7 +12377,7 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^2.2.8, rimraf@npm:^2.6.2": +"rimraf@npm:^2.6.2": version: 2.6.2 resolution: "rimraf@npm:2.6.2" dependencies: @@ -13410,17 +13084,6 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:^6.0.0": - version: 6.2.1 - resolution: "socks-proxy-agent@npm:6.2.1" - dependencies: - agent-base: ^6.0.2 - debug: ^4.3.3 - socks: ^2.6.2 - checksum: 9ca089d489e5ee84af06741135c4b0d2022977dad27ac8d649478a114cdce87849e8d82b7c22b51501a4116e231241592946fc7fae0afc93b65030ee57084f58 - languageName: node - linkType: hard - "socks-proxy-agent@npm:^7.0.0": version: 7.0.0 resolution: "socks-proxy-agent@npm:7.0.0" @@ -13570,26 +13233,6 @@ __metadata: languageName: node linkType: hard -"sqlite3@npm:^5.1.5": - version: 5.1.5 - resolution: "sqlite3@npm:5.1.5" - dependencies: - "@mapbox/node-pre-gyp": ^1.0.0 - node-addon-api: ^4.2.0 - node-gyp: 8.x - tar: ^6.1.11 - peerDependencies: - node-gyp: 8.x - dependenciesMeta: - node-gyp: - optional: true - peerDependenciesMeta: - node-gyp: - optional: true - checksum: b7df68c8d4a16cd1d8d42e34035973c2e4cff33e0b917ff8830fa21c84e3bc0d16beaf51589a4a45df9c52e30bf0224122e6c67d0f17ff1d776be738d8706b02 - languageName: node - linkType: hard - "sshpk@npm:^1.14.1": version: 1.17.0 resolution: "sshpk@npm:1.17.0" @@ -13611,15 +13254,6 @@ __metadata: languageName: node linkType: hard -"ssri@npm:^8.0.0, ssri@npm:^8.0.1": - version: 8.0.1 - resolution: "ssri@npm:8.0.1" - dependencies: - minipass: ^3.1.1 - checksum: bc447f5af814fa9713aa201ec2522208ae0f4d8f3bda7a1f445a797c7b929a02720436ff7c478fb5edc4045adb02b1b88d2341b436a80798734e2494f1067b36 - languageName: node - linkType: hard - "ssri@npm:^9.0.0": version: 9.0.1 resolution: "ssri@npm:9.0.1" @@ -13891,15 +13525,6 @@ __metadata: languageName: node linkType: hard -"style-loader@npm:^0.13.2": - version: 0.13.2 - resolution: "style-loader@npm:0.13.2" - dependencies: - loader-utils: ^1.0.2 - checksum: 68bdfbf4e759abf6e5195880966ac9407b758ca9f1fd96dc2584554707d25d8dbbe1a9d6524a617513e7d28d9f51bdd754689c1e6ae12ac1c4ff62781f5e7ccc - languageName: node - linkType: hard - "style-search@npm:^0.1.0": version: 0.1.0 resolution: "style-search@npm:0.1.0" @@ -14181,7 +13806,7 @@ __metadata: languageName: node linkType: hard -"tar@npm:^6.0.2, tar@npm:^6.1.11, tar@npm:^6.1.2": +"tar@npm:^6.1.11, tar@npm:^6.1.2": version: 6.1.11 resolution: "tar@npm:6.1.11" dependencies: @@ -14776,15 +14401,6 @@ __metadata: languageName: node linkType: hard -"unique-filename@npm:^1.1.1": - version: 1.1.1 - resolution: "unique-filename@npm:1.1.1" - dependencies: - unique-slug: ^2.0.0 - checksum: cf4998c9228cc7647ba7814e255dec51be43673903897b1786eff2ac2d670f54d4d733357eb08dea969aa5e6875d0e1bd391d668fbdb5a179744e7c7551a6f80 - languageName: node - linkType: hard - "unique-filename@npm:^2.0.0": version: 2.0.1 resolution: "unique-filename@npm:2.0.1" @@ -14794,15 +14410,6 @@ __metadata: languageName: node linkType: hard -"unique-slug@npm:^2.0.0": - version: 2.0.0 - resolution: "unique-slug@npm:2.0.0" - dependencies: - imurmurhash: ^0.1.4 - checksum: 230f42acc7b60479bd9e05c283e2f8da11f0331471ad7a8f7d0b32a7ea6bfdaa09dd1623c8ff52932147cf7b6137b9906abcd87d9093f069671a126cf9160bb6 - languageName: node - linkType: hard - "unique-slug@npm:^3.0.0": version: 3.0.0 resolution: "unique-slug@npm:3.0.0" From 56db3bc20f1966efba8aa971eba14324f555dfcc Mon Sep 17 00:00:00 2001 From: Jeffrey Carl Faden Date: Thu, 8 Jun 2023 16:38:32 -0700 Subject: [PATCH 2/8] Reduce Bootstrap CSS size, remove React Intl --- package.json | 1 - .../AddUserForm/AddUserForm.test.tsx | 23 +--- src/components/AddUserForm/AddUserForm.tsx | 22 +-- .../AddUserForm/AddUserFormContainer.ts | 6 +- src/components/App.tsx | 9 +- .../IntlProvider/IntlProviderContainer.ts | 12 -- .../RestaurantAddForm/RestaurantAddForm.tsx | 11 +- .../RestaurantAddFormContainer.ts | 3 +- src/components/TeamForm/TeamFormContainer.ts | 6 +- src/core/messages/en.json | 9 -- src/core/messages/index.ts | 1 - src/helpers/generateMessageDescriptor.ts | 12 -- src/initialState.ts | 1 - src/interfaces.ts | 1 - src/reducerMaps/index.ts | 1 - src/routes/team/team/Team.tsx | 28 ++-- src/routes/team/team/TeamContainer.ts | 7 +- src/selectors/locale.ts | 23 ---- src/styles/_mixins.scss | 8 -- src/styles/globalCss.scss | 18 ++- yarn.lock | 130 +----------------- 21 files changed, 41 insertions(+), 291 deletions(-) delete mode 100644 src/components/IntlProvider/IntlProviderContainer.ts delete mode 100644 src/core/messages/en.json delete mode 100644 src/core/messages/index.ts delete mode 100644 src/helpers/generateMessageDescriptor.ts delete mode 100644 src/selectors/locale.ts diff --git a/package.json b/package.json index 2f25553c4..50451babc 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,6 @@ "react-flip-toolkit": "^7.0.17", "react-geosuggest": "^2.14.1", "react-icons": "^4.7.1", - "react-intl": "^6.4.2", "react-redux": "^8.0.5", "react-scroll": "^1.8.9", "react-transition-group": "^4.4.5", diff --git a/src/components/AddUserForm/AddUserForm.test.tsx b/src/components/AddUserForm/AddUserForm.test.tsx index 6f67bc5e3..19cd1dff7 100644 --- a/src/components/AddUserForm/AddUserForm.test.tsx +++ b/src/components/AddUserForm/AddUserForm.test.tsx @@ -4,27 +4,11 @@ /* eslint-disable no-unused-expressions */ import React from "react"; import { expect } from "chai"; -import proxyquire from "proxyquire"; -import PropTypes from "prop-types"; import { render, screen, within } from "../../../test/test-utils"; -import { AddUserFormProps } from "./AddUserForm"; - -const proxyquireStrict = proxyquire.noCallThru(); - -const AddUserForm = proxyquireStrict("./AddUserForm", { - "react-intl": { - intlShape: { - isRequired: PropTypes.shape({}).isRequired, - }, - }, -}).default; - -interface MockAddUserFormProps extends Omit { - intl: unknown; -} +import AddUserForm, { AddUserFormProps } from "./AddUserForm"; describe("AddUserForm", () => { - let props: MockAddUserFormProps; + let props: AddUserFormProps; beforeEach(() => { props = { @@ -32,9 +16,6 @@ describe("AddUserForm", () => { hasGuestRole: false, hasMemberRole: false, hasOwnerRole: false, - intl: { - formatMessage: () => "", - }, }; }); diff --git a/src/components/AddUserForm/AddUserForm.tsx b/src/components/AddUserForm/AddUserForm.tsx index 315b1e659..42c212d0e 100644 --- a/src/components/AddUserForm/AddUserForm.tsx +++ b/src/components/AddUserForm/AddUserForm.tsx @@ -3,8 +3,6 @@ import Button from "react-bootstrap/Button"; import Col from "react-bootstrap/Col"; import Form from "react-bootstrap/Form"; import Row from "react-bootstrap/Row"; -import { IntlShape } from "react-intl"; -import { globalMessageDescriptor as gm } from "../../helpers/generateMessageDescriptor"; import { RoleType } from "../../interfaces"; interface AddUserFormState { @@ -18,7 +16,6 @@ export interface AddUserFormProps { hasGuestRole: boolean; hasMemberRole: boolean; hasOwnerRole: boolean; - intl: IntlShape; } class AddUserForm extends Component { @@ -50,12 +47,7 @@ class AddUserForm extends Component { }; render() { - const { - hasGuestRole, - hasMemberRole, - hasOwnerRole, - intl: { formatMessage: f }, - } = this.props; + const { hasGuestRole, hasMemberRole, hasOwnerRole } = this.props; const { email, name, type } = this.state; return ( @@ -96,15 +88,9 @@ class AddUserForm extends Component { value={type} required > - {hasGuestRole && ( - - )} - {hasMemberRole && ( - - )} - {hasOwnerRole && ( - - )} + {hasGuestRole && } + {hasMemberRole && } + {hasOwnerRole && } diff --git a/src/components/AddUserForm/AddUserFormContainer.ts b/src/components/AddUserForm/AddUserFormContainer.ts index 05248ad0a..af92c3396 100644 --- a/src/components/AddUserForm/AddUserFormContainer.ts +++ b/src/components/AddUserForm/AddUserFormContainer.ts @@ -1,5 +1,4 @@ import { connect } from "react-redux"; -import { injectIntl } from "react-intl"; import { addUser } from "../../actions/users"; import { currentUserHasRole, isUserListReady } from "../../selectors"; import AddUserForm from "./AddUserForm"; @@ -16,7 +15,4 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ addUserToTeam: (payload: Partial) => dispatch(addUser(payload)), }); -export default connect( - mapStateToProps, - mapDispatchToProps -)(injectIntl(AddUserForm)); +export default connect(mapStateToProps, mapDispatchToProps)(AddUserForm); diff --git a/src/components/App.tsx b/src/components/App.tsx index 3a0886ec8..cba74cd8d 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -13,7 +13,6 @@ import React, { Children, ReactNode } from "react"; import { Provider as ReduxProvider } from "react-redux"; import { Libraries, Loader } from "@googlemaps/js-api-loader"; import { AppContext } from "../interfaces"; -import IntlProviderContainer from "./IntlProvider/IntlProviderContainer"; import GoogleMapsLoaderContext from "./GoogleMapsLoaderContext/GoogleMapsLoaderContext"; const ContextType = { @@ -88,11 +87,9 @@ class App extends React.PureComponent { return ( - - - {Children.only(this.props.children)} - - + + {Children.only(this.props.children)} + ); diff --git a/src/components/IntlProvider/IntlProviderContainer.ts b/src/components/IntlProvider/IntlProviderContainer.ts deleted file mode 100644 index 493901319..000000000 --- a/src/components/IntlProvider/IntlProviderContainer.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { connect } from "react-redux"; -import { IntlConfig, IntlProvider } from "react-intl"; -import { State } from "../../interfaces"; -import { getLocale, getMessages } from "../../selectors/locale"; - -const mapStateToProps = (state: State, ownProps: Partial) => ({ - locale: getLocale(state), - messages: getMessages(state), - ...ownProps, -}); - -export default connect(mapStateToProps)(IntlProvider); diff --git a/src/components/RestaurantAddForm/RestaurantAddForm.tsx b/src/components/RestaurantAddForm/RestaurantAddForm.tsx index 1b9c1bbe1..2d026e680 100644 --- a/src/components/RestaurantAddForm/RestaurantAddForm.tsx +++ b/src/components/RestaurantAddForm/RestaurantAddForm.tsx @@ -2,18 +2,14 @@ import React, { Component, RefObject, Suspense, createRef, lazy } from "react"; import GeosuggestClass, { GeosuggestProps, Suggest } from "react-geosuggest"; -import { IntlShape } from "react-intl"; import { canUseDOM } from "fbjs/lib/ExecutionEnvironment"; import withStyles from "isomorphic-style-loader/withStyles"; -import generateMessageDescriptor from "../../helpers/generateMessageDescriptor"; import { LatLng } from "../../interfaces"; import GoogleMapsLoaderContext, { IGoogleMapsLoaderContext, } from "../GoogleMapsLoaderContext/GoogleMapsLoaderContext"; import s from "./RestaurantAddForm.scss"; -const m = generateMessageDescriptor("RestaurantAddForm"); - const Geosuggest = lazy( () => import(/* webpackChunkName: 'geosuggest' */ "react-geosuggest") ); @@ -27,7 +23,6 @@ interface RestaurantAddFormProps geosuggest: GeosuggestClass ) => void; latLng: LatLng; - intl: IntlShape; } class RestaurantAddForm extends Component { @@ -76,10 +71,6 @@ class RestaurantAddForm extends Component { }; render() { - const { - intl: { formatMessage: f }, - } = this.props; - return (
{this.maps ? ( @@ -101,7 +92,7 @@ class RestaurantAddForm extends Component { suggestItemClassName={s.suggestItem} suggestItemActiveClassName={s.suggestItemActive} suggestsClassName={s.suggests} - placeholder={f(m("addPlaces"))} + placeholder="Add places" onBlur={this.props.clearTempMarker} onActivateSuggest={this.getCoordsForMarker} onSuggestSelect={this.handleSuggestSelect} diff --git a/src/components/RestaurantAddForm/RestaurantAddFormContainer.ts b/src/components/RestaurantAddForm/RestaurantAddFormContainer.ts index e0fe92e09..74b9d1726 100644 --- a/src/components/RestaurantAddForm/RestaurantAddFormContainer.ts +++ b/src/components/RestaurantAddForm/RestaurantAddFormContainer.ts @@ -1,7 +1,6 @@ import Geosuggest, { Suggest } from "react-geosuggest"; import { connect } from "react-redux"; import { scroller } from "react-scroll"; -import { injectIntl } from "react-intl"; import { Dispatch, State } from "../../interfaces"; import { getRestaurants } from "../../selectors/restaurants"; import { getTeamLatLng } from "../../selectors/team"; @@ -95,4 +94,4 @@ export default connect( mapStateToProps, mapDispatchToProps, mergeProps -)(injectIntl(RestaurantAddForm)); +)(RestaurantAddForm); diff --git a/src/components/TeamForm/TeamFormContainer.ts b/src/components/TeamForm/TeamFormContainer.ts index f8913b60b..933aec9cb 100644 --- a/src/components/TeamForm/TeamFormContainer.ts +++ b/src/components/TeamForm/TeamFormContainer.ts @@ -1,5 +1,4 @@ import { connect } from "react-redux"; -import { injectIntl } from "react-intl"; import { flashSuccess } from "../../actions/flash"; import { updateTeam } from "../../actions/team"; import { Dispatch, State, Team } from "../../interfaces"; @@ -19,7 +18,4 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({ ), }); -export default connect( - mapStateToProps, - mapDispatchToProps -)(injectIntl(TeamForm)); +export default connect(mapStateToProps, mapDispatchToProps)(TeamForm); diff --git a/src/core/messages/en.json b/src/core/messages/en.json deleted file mode 100644 index d750d470a..000000000 --- a/src/core/messages/en.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "RestaurantAddForm": { - "addPlaces": "Add places" - }, - "memberRole": "Member", - "noUserName": "(Name not entered)", - "ownerRole": "Owner", - "guestRole": "Guest" -} diff --git a/src/core/messages/index.ts b/src/core/messages/index.ts deleted file mode 100644 index da7e48846..000000000 --- a/src/core/messages/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as en } from "./en.json"; diff --git a/src/helpers/generateMessageDescriptor.ts b/src/helpers/generateMessageDescriptor.ts deleted file mode 100644 index 864c3b0ef..000000000 --- a/src/helpers/generateMessageDescriptor.ts +++ /dev/null @@ -1,12 +0,0 @@ -import get from "lodash.get"; -import * as messages from "../core/messages"; - -export const globalMessageDescriptor = (id: string) => ({ - id, - defaultMessage: get(messages.en, id), -}); - -export default (component: string) => (id: string) => { - const namespacedId = `${component}.${id}`; - return globalMessageDescriptor(namespacedId); -}; diff --git a/src/initialState.ts b/src/initialState.ts index ccc6ab128..2f333bf4a 100644 --- a/src/initialState.ts +++ b/src/initialState.ts @@ -20,7 +20,6 @@ const getInitialState = (): NonNormalizedState => ({ listUi: { flipMove: true, }, - locale: "en", mapUi: { infoWindow: {}, showUnvoted: true, diff --git a/src/interfaces.ts b/src/interfaces.ts index f7c1f9ff5..7cab4c4e5 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -500,7 +500,6 @@ interface BaseState { flipMove: boolean; newlyAdded?: NewlyAdded; }; - locale: "en"; mapUi: { center?: { lat: number; diff --git a/src/reducerMaps/index.ts b/src/reducerMaps/index.ts index 6c0df0f24..6a4cd1d3f 100644 --- a/src/reducerMaps/index.ts +++ b/src/reducerMaps/index.ts @@ -17,5 +17,4 @@ export { default as user } from "./user"; export { default as users } from "./users"; export const host: Reducer<"host"> = (state) => state; -export const locale: Reducer<"locale"> = (state) => state; export const wsPort: Reducer<"wsPort"> = (state) => state; diff --git a/src/routes/team/team/Team.tsx b/src/routes/team/team/Team.tsx index 9e8b2c80a..1381b8611 100644 --- a/src/routes/team/team/Team.tsx +++ b/src/routes/team/team/Team.tsx @@ -16,13 +16,11 @@ import Container from "react-bootstrap/Container"; import Tab from "react-bootstrap/Tab"; import Tabs from "react-bootstrap/Tabs"; import Table from "react-bootstrap/Table"; -import { IntlShape } from "react-intl"; import Loading from "../../../components/Loading/Loading"; import AddUserFormContainer from "../../../components/AddUserForm/AddUserFormContainer"; import ChangeTeamURLModalContainer from "../../../components/ChangeTeamURLModal/ChangeTeamURLModalContainer"; import DeleteTeamModalContainer from "../../../components/DeleteTeamModal/DeleteTeamModalContainer"; import TeamFormContainer from "../../../components/TeamForm/TeamFormContainer"; -import { globalMessageDescriptor as gm } from "../../../helpers/generateMessageDescriptor"; import getRole from "../../../helpers/getRole"; import canChangeUser from "../../../helpers/canChangeUser"; import { @@ -46,7 +44,6 @@ interface TeamProps { hasGuestRole: boolean; hasMemberRole: boolean; hasOwnerRole: boolean; - intl: IntlShape; removeUserFromTeam: (userId: number) => void; userListReady: boolean; users: User[]; @@ -99,7 +96,6 @@ class Team extends React.Component { hasGuestRole, hasMemberRole, hasOwnerRole, - intl: { formatMessage: f }, team, users, } = this.props; @@ -107,26 +103,20 @@ class Team extends React.Component { if (canChangeUser(currentUser, user, team, users)) { return ( ); } - return f(gm(`${user.type}Role`)); + return user.type + ? user.type.charAt(0).toUpperCase() + user.type.slice(1) + : ""; }; renderUsers = () => { - const { - currentUser, - hasMemberRole, - hasOwnerRole, - intl: { formatMessage: f }, - team, - users, - } = this.props; + const { currentUser, hasMemberRole, hasOwnerRole, team, users } = + this.props; return (
@@ -143,7 +133,7 @@ class Team extends React.Component { {users.map((user) => ( - {user.name ? user.name : f(gm("noUserName"))} + {user.name} {hasOwnerRole && {user.email}} {this.roleOptions(user)} diff --git a/src/routes/team/team/TeamContainer.ts b/src/routes/team/team/TeamContainer.ts index cad60da84..ad5d58c0a 100644 --- a/src/routes/team/team/TeamContainer.ts +++ b/src/routes/team/team/TeamContainer.ts @@ -1,5 +1,4 @@ import { connect } from "react-redux"; -import { injectIntl } from "react-intl"; import { showModal } from "../../../actions/modals"; import { changeUserRole, @@ -46,8 +45,4 @@ const mergeProps = ( dispatchProps.dispatch(removeUser(id, stateProps.team!)), }); -export default connect( - mapStateToProps, - mapDispatchToProps, - mergeProps -)(injectIntl(Team)); +export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(Team); diff --git a/src/selectors/locale.ts b/src/selectors/locale.ts deleted file mode 100644 index f3d7cb976..000000000 --- a/src/selectors/locale.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { createSelector } from "reselect"; -import * as messages from "../core/messages"; -import { State } from "../interfaces"; - -export const getLocale = (state: State) => state.locale; -export const getMessages = createSelector(getLocale, (locale) => { - const messagesForLocale = messages[locale]; - const flattenedMessages: { [index: string]: string } = {}; - Object.keys(messagesForLocale).forEach((component) => { - const componentKey = component as keyof typeof messagesForLocale; - const messagesForComponent = messagesForLocale[componentKey]; - if (typeof messagesForComponent === "string") { - flattenedMessages[componentKey] = messagesForComponent; - } else { - Object.keys(messagesForComponent).forEach((id) => { - const idKey = id as keyof typeof messagesForComponent; - flattenedMessages[`${componentKey}.${id}`] = - messagesForComponent[idKey]; - }); - } - }); - return flattenedMessages; -}); diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss index 4dbd02d11..7e369b0c5 100644 --- a/src/styles/_mixins.scss +++ b/src/styles/_mixins.scss @@ -123,11 +123,3 @@ overflow: hidden; padding: 0; } - -@mixin clearfix { - &::after { - content: ""; - display: table; - clear: both; - } -} diff --git a/src/styles/globalCss.scss b/src/styles/globalCss.scss index b91e3a8a5..70e285a3c 100644 --- a/src/styles/globalCss.scss +++ b/src/styles/globalCss.scss @@ -2,7 +2,23 @@ @import "~react-geosuggest/module/geosuggest.css"; @import "./variables"; -@import "~bootstrap/scss/bootstrap"; +@import "~bootstrap/scss/functions"; +@import "~bootstrap/scss/variables"; +@import "~bootstrap/scss/maps"; +@import "~bootstrap/scss/mixins"; +@import "~bootstrap/scss/utilities"; +@import "~bootstrap/scss/root"; +@import "~bootstrap/scss/reboot"; +@import "~bootstrap/scss/type"; +@import "~bootstrap/scss/containers"; +@import "~bootstrap/scss/grid"; +@import "~bootstrap/scss/tables"; +@import "~bootstrap/scss/forms"; +@import "~bootstrap/scss/buttons"; +@import "~bootstrap/scss/nav"; +@import "~bootstrap/scss/list-group"; +@import "~bootstrap/scss/helpers/visually-hidden"; +@import "~bootstrap/scss/utilities/api"; html, body, diff --git a/yarn.lock b/yarn.lock index deee412f9..f1a12d96a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1405,97 +1405,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:1.15.0": - version: 1.15.0 - resolution: "@formatjs/ecma402-abstract@npm:1.15.0" - dependencies: - "@formatjs/intl-localematcher": 0.2.32 - tslib: ^2.4.0 - checksum: c9feca174f9490026ef75b2de363d17fcac57848fb73bc8001a5c6c733db33a6674cdd506d69414067bd4ad670587f721d1e446b134e38e998b5f44b0c1412d3 - languageName: node - linkType: hard - -"@formatjs/fast-memoize@npm:2.0.1": - version: 2.0.1 - resolution: "@formatjs/fast-memoize@npm:2.0.1" - dependencies: - tslib: ^2.4.0 - checksum: e434cdc53354666459c47556c403f0ed3391ebab0e851a64e5622d8d81e3b684a74a09c4bf5189885c66e743004601f64e2e2c8c70adf6b00071d4afea20f69d - languageName: node - linkType: hard - -"@formatjs/icu-messageformat-parser@npm:2.4.0": - version: 2.4.0 - resolution: "@formatjs/icu-messageformat-parser@npm:2.4.0" - dependencies: - "@formatjs/ecma402-abstract": 1.15.0 - "@formatjs/icu-skeleton-parser": 1.4.0 - tslib: ^2.4.0 - checksum: 9bf9537b30e6f542a2f3d6763c6baf10010d3fc8e82a7a5a3899b1eaa38f3338ba9f59959fff5837bbd9154e44cf23e0f5503a969e80cce1fa57c2bb6c17ac22 - languageName: node - linkType: hard - -"@formatjs/icu-skeleton-parser@npm:1.4.0": - version: 1.4.0 - resolution: "@formatjs/icu-skeleton-parser@npm:1.4.0" - dependencies: - "@formatjs/ecma402-abstract": 1.15.0 - tslib: ^2.4.0 - checksum: 00f016b4d9b446c395ec88d979baeaef97ed2006848b888ea0a6a44e08b875b7f16a2e4b54297161ecf7d8be64736ac4168c140ab42006b0b13274a955c0f26a - languageName: node - linkType: hard - -"@formatjs/intl-displaynames@npm:6.3.2": - version: 6.3.2 - resolution: "@formatjs/intl-displaynames@npm:6.3.2" - dependencies: - "@formatjs/ecma402-abstract": 1.15.0 - "@formatjs/intl-localematcher": 0.2.32 - tslib: ^2.4.0 - checksum: fa736c6c6bd40782a630ee9dc1bb36be2bffddfa66adcca554417f6ce5f9d4bf84422c1b47b308278f74b52b12f7e0f8fce064678b96299a7f9d9f1bb4f69b98 - languageName: node - linkType: hard - -"@formatjs/intl-listformat@npm:7.2.2": - version: 7.2.2 - resolution: "@formatjs/intl-listformat@npm:7.2.2" - dependencies: - "@formatjs/ecma402-abstract": 1.15.0 - "@formatjs/intl-localematcher": 0.2.32 - tslib: ^2.4.0 - checksum: 97b06bc65e64b4f1b9bdf329ab4908df3fa7d78ac93affb19aa5beeca1b81f56d9e6d3980acc9f44e6f15662bd672eafaca52d7518939b4580c1a1e277e5498c - languageName: node - linkType: hard - -"@formatjs/intl-localematcher@npm:0.2.32": - version: 0.2.32 - resolution: "@formatjs/intl-localematcher@npm:0.2.32" - dependencies: - tslib: ^2.4.0 - checksum: 477e18aabaf2e6e90fc12952a3cb6c0ebb40ad99414d6b9d2501c6348fbad58cacb433ec6630955cfd1491ea7630f32a9dc280bb27d0fb8a784251404a54140a - languageName: node - linkType: hard - -"@formatjs/intl@npm:2.7.2": - version: 2.7.2 - resolution: "@formatjs/intl@npm:2.7.2" - dependencies: - "@formatjs/ecma402-abstract": 1.15.0 - "@formatjs/fast-memoize": 2.0.1 - "@formatjs/icu-messageformat-parser": 2.4.0 - "@formatjs/intl-displaynames": 6.3.2 - "@formatjs/intl-listformat": 7.2.2 - intl-messageformat: 10.3.5 - tslib: ^2.4.0 - peerDependencies: - typescript: ^4.7 || 5 - peerDependenciesMeta: - typescript: - optional: true - checksum: 00c41a857b18bd249927e167dda1755d215cce9cf4e98967b2430cadc6c1afb19f31bc521c5db2dcbc3c1daeb4c9aa05058019ab0e331e2ccb47f9f7b425e0c7 - languageName: node - linkType: hard - "@gar/promisify@npm:^1.1.3": version: 1.1.3 resolution: "@gar/promisify@npm:1.1.3" @@ -2747,7 +2656,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11": +"@types/react@npm:*, @types/react@npm:>=16.9.11": version: 18.0.27 resolution: "@types/react@npm:18.0.27" dependencies: @@ -8021,18 +7930,6 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:10.3.5": - version: 10.3.5 - resolution: "intl-messageformat@npm:10.3.5" - dependencies: - "@formatjs/ecma402-abstract": 1.15.0 - "@formatjs/fast-memoize": 2.0.1 - "@formatjs/icu-messageformat-parser": 2.4.0 - tslib: ^2.4.0 - checksum: a52526a02ee54fda870e5a83900ba089332c5a820bec033ffd5c422e68e90269e36e2aa144dc3728a43b5df506d8a5e261e162227410463d5d8a03864f39170e - languageName: node - linkType: hard - "invariant@npm:^2.2.4": version: 2.2.4 resolution: "invariant@npm:2.2.4" @@ -9532,7 +9429,6 @@ __metadata: react-flip-toolkit: ^7.0.17 react-geosuggest: ^2.14.1 react-icons: ^4.7.1 - react-intl: ^6.4.2 react-redux: ^8.0.5 react-refresh: ^0.14.0 react-scroll: ^1.8.9 @@ -11785,30 +11681,6 @@ __metadata: languageName: node linkType: hard -"react-intl@npm:^6.4.2": - version: 6.4.2 - resolution: "react-intl@npm:6.4.2" - dependencies: - "@formatjs/ecma402-abstract": 1.15.0 - "@formatjs/icu-messageformat-parser": 2.4.0 - "@formatjs/intl": 2.7.2 - "@formatjs/intl-displaynames": 6.3.2 - "@formatjs/intl-listformat": 7.2.2 - "@types/hoist-non-react-statics": ^3.3.1 - "@types/react": 16 || 17 || 18 - hoist-non-react-statics: ^3.3.2 - intl-messageformat: 10.3.5 - tslib: ^2.4.0 - peerDependencies: - react: ^16.6.0 || 17 || 18 - typescript: ^4.7 || 5 - peerDependenciesMeta: - typescript: - optional: true - checksum: b24fba98915f101e791aa37295b9d80deca09058d3cf4dfcb56af937be99e556c6cf6915768056938fcd2bc5a121de43888f11159a7ba2851f4d66ac1e0402b7 - languageName: node - linkType: hard - "react-is@npm:^16.13.1, react-is@npm:^16.3.2, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" From 7de152efb32498554960864ee6f7706333eb50cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 21:09:55 +0000 Subject: [PATCH 3/8] Bump dottie from 2.0.3 to 2.0.4 Bumps [dottie](https://github.com/mickhansen/dottie.js) from 2.0.3 to 2.0.4. - [Release notes](https://github.com/mickhansen/dottie.js/releases) - [Commits](https://github.com/mickhansen/dottie.js/compare/v2.0.3...v2.0.4) --- updated-dependencies: - dependency-name: dottie dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index f1a12d96a..bcb4e6bed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5508,9 +5508,9 @@ __metadata: linkType: hard "dottie@npm:^2.0.2": - version: 2.0.3 - resolution: "dottie@npm:2.0.3" - checksum: 4f5300f7f349b6d5f0be1b39d244e5bbc94f97b480ba746a7d9626ca946bf8fc6a1db2eee7af71be0024d3d5f0b6b805e14a893b893c384c6b37831e8ed94ab1 + version: 2.0.4 + resolution: "dottie@npm:2.0.4" + checksum: 9d25445a446f781aae275d36d3c88a6a94d4d8acf15403aa93f4118bcfc6547a5d7c71f9c533da6c6af5a55ffd2f0b3915999ecd80bb6bf447e476ff2be47cff languageName: node linkType: hard From 9b913b18a2e6b8bd1943185cf260081c481c7b6f Mon Sep 17 00:00:00 2001 From: Jeffrey Carl Faden Date: Sat, 17 Jun 2023 15:00:08 -0700 Subject: [PATCH 4/8] Remove qs and uuid --- package.json | 5 +--- src/actions/flash.ts | 6 ++-- src/client.tsx | 3 +- .../RestaurantMarker/RestaurantMarker.tsx | 5 ---- src/interfaces.ts | 3 +- src/reducerMaps/notifications.ts | 4 +-- src/routes/helpers/redirectToLogin.ts | 3 +- src/routes/login/Login.tsx | 15 ++++++++-- src/routes/login/index.tsx | 2 +- src/routes/main/invitation/create/index.tsx | 4 +-- src/routes/main/invitation/new/index.tsx | 2 +- src/routes/main/password/create/Create.tsx | 2 +- src/routes/main/password/create/index.tsx | 2 +- src/routes/main/password/edit/index.tsx | 2 +- src/routes/main/password/new/index.tsx | 2 +- src/routes/main/users/new/index.tsx | 2 +- src/routes/main/welcome/index.tsx | 4 +-- src/server.tsx | 6 ++-- src/store/configureStore.ts | 6 ++-- tools/webpack.config.js | 1 + yarn.lock | 28 ------------------- 21 files changed, 40 insertions(+), 67 deletions(-) diff --git a/package.json b/package.json index 50451babc..2f581c0af 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,6 @@ "pg": "^8.9.0", "pretty-error": "^3.0.4", "prop-types": "^15.8.1", - "qs": "^6.11.2", "react": "^18.2.0", "react-autosuggest": "^10.0.2", "react-bootstrap": "^2.7.0", @@ -75,8 +74,7 @@ "sequelize-typescript": "^2.1.5", "serialize-javascript": "^6.0.1", "source-map-support": "^0.5.21", - "universal-router": "^8.1.0", - "uuid": "^9.0.0" + "universal-router": "^8.1.0" }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.2", @@ -115,7 +113,6 @@ "@types/serialize-javascript": "^5.0.2", "@types/sinon": "^10.0.15", "@types/supertest": "^2.0.12", - "@types/uuid": "^9.0.0", "@types/validator": "^13.7.17", "@types/webpack-env": "^1.18.0", "@typescript-eslint/eslint-plugin": "^5.59.1", diff --git a/src/actions/flash.ts b/src/actions/flash.ts index a18c9fbc6..e62634053 100644 --- a/src/actions/flash.ts +++ b/src/actions/flash.ts @@ -1,11 +1,11 @@ -import { v1 } from "uuid"; +import crypto from "crypto"; import { Action } from "../interfaces"; export function flashError(message: string): Action { return { type: "FLASH_ERROR", message, - id: v1(), + id: crypto.randomUUID(), }; } @@ -13,7 +13,7 @@ export function flashSuccess(message: string): Action { return { type: "FLASH_SUCCESS", message, - id: v1(), + id: crypto.randomUUID(), }; } diff --git a/src/client.tsx b/src/client.tsx index f73988a6f..e8b990abe 100644 --- a/src/client.tsx +++ b/src/client.tsx @@ -9,7 +9,6 @@ import React, { useEffect } from "react"; import { createRoot, hydrateRoot } from "react-dom/client"; -import qs from "qs"; import { Action, createPath, Location } from "history"; import App from "./components/App"; import configureStore from "./store/configureStore"; @@ -111,7 +110,7 @@ const onLocationChange = async ({ const isInitialRender = !action; try { context.pathname = location.pathname; - context.query = qs.parse(location.search, { ignoreQueryPrefix: true }); + context.query = new URLSearchParams(location.search); // Traverses the list of routes in the order they are defined until // it finds the first route that matches provided URL path string diff --git a/src/components/RestaurantMarker/RestaurantMarker.tsx b/src/components/RestaurantMarker/RestaurantMarker.tsx index 0d6cb5f0b..22db95835 100644 --- a/src/components/RestaurantMarker/RestaurantMarker.tsx +++ b/src/components/RestaurantMarker/RestaurantMarker.tsx @@ -1,4 +1,3 @@ -import PropTypes from "prop-types"; import React from "react"; import { canUseDOM } from "fbjs/lib/ExecutionEnvironment"; import withStyles from "isomorphic-style-loader/withStyles"; @@ -110,8 +109,4 @@ const RestaurantMarker = ({ restaurant, ...props }: RestaurantMarkerProps) => { ); }; -RestaurantMarker.defaultProps = { - query: undefined, -}; - export default RestaurantMarker; diff --git a/src/interfaces.ts b/src/interfaces.ts index 7cab4c4e5..860af9b47 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -2,7 +2,6 @@ import { Application, RequestHandler } from "express"; import { EnhancedStore, ThunkAction, ThunkDispatch } from "@reduxjs/toolkit"; import { BrowserHistory } from "history"; import { InsertCSS } from "isomorphic-style-loader/StyleContext"; -import { ParsedQs } from "qs"; import { ReactNode } from "react"; import { ResolveContext } from "universal-router"; import { WebSocket } from "ws"; @@ -599,7 +598,7 @@ export interface AppContext extends ResolveContext { insertCss: InsertCSS; googleApiKey: string; pathname: string; - query?: ParsedQs; + query?: URLSearchParams; store: EnhancedStore; } diff --git a/src/reducerMaps/notifications.ts b/src/reducerMaps/notifications.ts index b959dda85..d8274eed8 100644 --- a/src/reducerMaps/notifications.ts +++ b/src/reducerMaps/notifications.ts @@ -1,4 +1,4 @@ -import { v1 } from "uuid"; +import crypto from "crypto"; import { Notification, Reducer } from "../interfaces"; const notifications: Reducer<"notifications"> = (state, action) => { @@ -7,7 +7,7 @@ const notifications: Reducer<"notifications"> = (state, action) => { const { realAction } = action; const baseNotification = { actionType: realAction.type, - id: v1(), + id: crypto.randomUUID(), }; let notification: Notification; switch (realAction.type) { diff --git a/src/routes/helpers/redirectToLogin.ts b/src/routes/helpers/redirectToLogin.ts index 60cf5b5a8..3848d19b2 100644 --- a/src/routes/helpers/redirectToLogin.ts +++ b/src/routes/helpers/redirectToLogin.ts @@ -1,8 +1,7 @@ -import qs from "qs"; import { AppContext } from "../../interfaces"; export default (context: AppContext) => { - const stringifiedQuery = qs.stringify(context.query); + const stringifiedQuery = context.query?.toString(); let params = ""; if (context.path !== "/" || stringifiedQuery) { params = `?next=${context.path}`; diff --git a/src/routes/login/Login.tsx b/src/routes/login/Login.tsx index 3d349832a..2c6517507 100644 --- a/src/routes/login/Login.tsx +++ b/src/routes/login/Login.tsx @@ -1,5 +1,4 @@ import React, { ChangeEvent, Component } from "react"; -import qs from "qs"; import withStyles from "isomorphic-style-loader/withStyles"; import Button from "react-bootstrap/Button"; import Col from "react-bootstrap/Col"; @@ -45,8 +44,18 @@ class Login extends Component { const { host, next, team } = this.props; const { email, password } = this.state; - const googleQuery = qs.stringify({ team, next }); - const nextQuery = qs.stringify({ next }); + const googleParams: Record = {}; + const nextParams: Record = {}; + if (team) { + googleParams.team = team; + } + if (next) { + googleParams.next = next; + nextParams.next = next; + } + + const googleQuery = new URLSearchParams(googleParams).toString(); + const nextQuery = new URLSearchParams(nextParams).toString(); return (
diff --git a/src/routes/login/index.tsx b/src/routes/login/index.tsx index 3c27d90ee..851b383f4 100644 --- a/src/routes/login/index.tsx +++ b/src/routes/login/index.tsx @@ -17,7 +17,7 @@ function action(context: AppContext) { const state = context.store.getState(); const subdomain = context.subdomain; - const next = context.query?.next as string | undefined; + const next = context.query?.get("next") as string | undefined; return renderIfLoggedOut(state, () => ({ chunks: ["login"], diff --git a/src/routes/main/invitation/create/index.tsx b/src/routes/main/invitation/create/index.tsx index f1071a406..aa97b221c 100644 --- a/src/routes/main/invitation/create/index.tsx +++ b/src/routes/main/invitation/create/index.tsx @@ -13,8 +13,8 @@ import { AppContext } from "../../../../interfaces"; import Create from "./Create"; export default (context: AppContext) => { - const success = context.query?.success; - const token = context.query?.token; + const success = context.query?.get("success"); + const token = context.query?.get("token"); if (!success && !token) { return { diff --git a/src/routes/main/invitation/new/index.tsx b/src/routes/main/invitation/new/index.tsx index 25134ec98..646b3c428 100644 --- a/src/routes/main/invitation/new/index.tsx +++ b/src/routes/main/invitation/new/index.tsx @@ -13,7 +13,7 @@ import { AppContext } from "../../../../interfaces"; import New from "./New"; export default (context: AppContext) => { - const email = context.query?.email; + const email = context.query?.get("email"); return { component: ( diff --git a/src/routes/main/password/create/Create.tsx b/src/routes/main/password/create/Create.tsx index 8685359e8..6d312dab1 100644 --- a/src/routes/main/password/create/Create.tsx +++ b/src/routes/main/password/create/Create.tsx @@ -28,7 +28,7 @@ class Create extends Component {

Password reset

- Your password has been reset. Go ahead and + Your password has been reset. Go ahead and{" "} log in.

diff --git a/src/routes/main/password/create/index.tsx b/src/routes/main/password/create/index.tsx index 5cecf1946..bfd8fb7b5 100644 --- a/src/routes/main/password/create/index.tsx +++ b/src/routes/main/password/create/index.tsx @@ -16,7 +16,7 @@ import Create from "./Create"; export default (context: AppContext) => { const state = context.store.getState(); - const success = context.query?.success; + const success = context.query?.get("success"); return renderIfLoggedOut(state, () => { if (!success) { diff --git a/src/routes/main/password/edit/index.tsx b/src/routes/main/password/edit/index.tsx index 48a355dbc..d63ea096a 100644 --- a/src/routes/main/password/edit/index.tsx +++ b/src/routes/main/password/edit/index.tsx @@ -16,7 +16,7 @@ import Edit from "./Edit"; export default (context: AppContext) => { const state = context.store.getState(); - const token = context.query?.token as string | undefined; + const token = context.query?.get("token") as string | undefined; return renderIfLoggedOut(state, () => { if (!token) { diff --git a/src/routes/main/password/new/index.tsx b/src/routes/main/password/new/index.tsx index a18c7610b..c28468868 100644 --- a/src/routes/main/password/new/index.tsx +++ b/src/routes/main/password/new/index.tsx @@ -16,7 +16,7 @@ import New from "./New"; export default (context: AppContext) => { const state = context.store.getState(); - const email = context.query?.email; + const email = context.query?.get("email"); return renderIfLoggedOut(state, () => ({ component: ( diff --git a/src/routes/main/users/new/index.tsx b/src/routes/main/users/new/index.tsx index cd470a384..7b933e68f 100644 --- a/src/routes/main/users/new/index.tsx +++ b/src/routes/main/users/new/index.tsx @@ -17,7 +17,7 @@ export default (context: AppContext) => { const state = context.store.getState(); const user = state.user; - const email = context.query?.email; + const email = context.query?.get("email"); if (user?.superuser) { return { diff --git a/src/routes/main/welcome/index.tsx b/src/routes/main/welcome/index.tsx index 13119ef26..93a176a2b 100644 --- a/src/routes/main/welcome/index.tsx +++ b/src/routes/main/welcome/index.tsx @@ -26,8 +26,8 @@ export default (context: AppContext) => { component: ( ), diff --git a/src/server.tsx b/src/server.tsx index b01fb999a..e39465fae 100644 --- a/src/server.tsx +++ b/src/server.tsx @@ -17,6 +17,7 @@ import express, { RequestHandler, } from "express"; import cors from "cors"; +import crypto from "crypto"; import http from "http"; import https from "https"; import enforce from "express-sslify"; @@ -34,7 +35,6 @@ import ReactDOM from "react-dom/server"; import expressWs from "express-ws"; import Honeybadger from "@honeybadger-io/js"; import PrettyError from "pretty-error"; -import { v1 } from "uuid"; import AppComponent from "./components/App"; import Html, { HtmlProps } from "./components/Html"; import { ErrorPageWithoutStyle } from "./components/ErrorPage/ErrorPage"; @@ -341,7 +341,7 @@ const render: RequestHandler = async (req, res, next) => { flashKeys.forEach((k) => { flashes[k].forEach((f) => { stateData.flashes!.push({ - id: v1(), + id: crypto.randomUUID(), message: f, type: k as Flash["type"], }); @@ -367,7 +367,7 @@ const render: RequestHandler = async (req, res, next) => { googleApiKey: config.googleApiKey!, // The twins below are wild, be careful! pathname: req.path, - query: req.query, + query: new URLSearchParams(req.query as { [key: string]: string }), // You can access redux through react-redux connect store, }; diff --git a/src/store/configureStore.ts b/src/store/configureStore.ts index 340441160..6694180ef 100644 --- a/src/store/configureStore.ts +++ b/src/store/configureStore.ts @@ -1,6 +1,8 @@ -import { combineReducers } from "redux"; import { normalize } from "normalizr"; -import { configureStore as reduxConfigureStore } from "@reduxjs/toolkit"; +import { + combineReducers, + configureStore as reduxConfigureStore, +} from "@reduxjs/toolkit"; import * as schemas from "../schemas"; import * as reducerMaps from "../reducerMaps"; import createHelpers from "./createHelpers"; diff --git a/tools/webpack.config.js b/tools/webpack.config.js index 3cf2c765f..30fc48ce7 100644 --- a/tools/webpack.config.js +++ b/tools/webpack.config.js @@ -77,6 +77,7 @@ const config = { fallback: { buffer: false, console: false, + crypto: false, process: false, }, }, diff --git a/yarn.lock b/yarn.lock index bcb4e6bed..e78deeca7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2803,13 +2803,6 @@ __metadata: languageName: node linkType: hard -"@types/uuid@npm:^9.0.0": - version: 9.0.0 - resolution: "@types/uuid@npm:9.0.0" - checksum: 59ae56d9547c8758588659da2a2b4c97cce79c2aae1798c892bb29452ef08e87859dea2ec3a66bfa88d0d2153147520be2b1893be920f9f0bc9c53a3207ea6aa - languageName: node - linkType: hard - "@types/validator@npm:^13.7.1": version: 13.7.12 resolution: "@types/validator@npm:13.7.12" @@ -9341,7 +9334,6 @@ __metadata: "@types/serialize-javascript": ^5.0.2 "@types/sinon": ^10.0.15 "@types/supertest": ^2.0.12 - "@types/uuid": ^9.0.0 "@types/validator": ^13.7.17 "@types/webpack-env": ^1.18.0 "@typescript-eslint/eslint-plugin": ^5.59.1 @@ -9418,7 +9410,6 @@ __metadata: pretty-error: ^3.0.4 prop-types: ^15.8.1 proxyquire: ^1.7.11 - qs: ^6.11.2 raw-loader: ^0.5.1 react: ^18.2.0 react-autosuggest: ^10.0.2 @@ -9459,7 +9450,6 @@ __metadata: typescript: ^5.1.3 universal-router: ^8.1.0 url-loader: ^4.1.1 - uuid: ^9.0.0 webpack: ^5.76.0 webpack-assets-manifest: ^5.1.0 webpack-bundle-analyzer: ^4.8.0 @@ -11453,15 +11443,6 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.11.2": - version: 6.11.2 - resolution: "qs@npm:6.11.2" - dependencies: - side-channel: ^1.0.4 - checksum: e812f3c590b2262548647d62f1637b6989cc56656dc960b893fe2098d96e1bd633f36576f4cd7564dfbff9db42e17775884db96d846bebe4f37420d073ecdc0b - languageName: node - linkType: hard - "qs@npm:~6.5.2": version: 6.5.3 resolution: "qs@npm:6.5.3" @@ -14449,15 +14430,6 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^9.0.0": - version: 9.0.0 - resolution: "uuid@npm:9.0.0" - bin: - uuid: dist/bin/uuid - checksum: 8dd2c83c43ddc7e1c71e36b60aea40030a6505139af6bee0f382ebcd1a56f6cd3028f7f06ffb07f8cf6ced320b76aea275284b224b002b289f89fe89c389b028 - languageName: node - linkType: hard - "v8-compile-cache-lib@npm:^3.0.1": version: 3.0.1 resolution: "v8-compile-cache-lib@npm:3.0.1" From d133c5194aaff203732c74d7e5d4a3cd70649ac5 Mon Sep 17 00:00:00 2001 From: Jeffrey Carl Faden Date: Mon, 19 Jun 2023 11:01:01 -0700 Subject: [PATCH 5/8] Fix use of crypto, remove fbjs --- package.json | 2 - src/actions/flash.ts | 5 +- src/actions/users.ts | 2 +- src/components/Layout/Layout.tsx | 11 +- .../RestaurantAddForm/RestaurantAddForm.tsx | 2 +- .../RestaurantMarker/RestaurantMarker.tsx | 2 +- .../TeamGeosuggest/TeamGeosuggest.tsx | 2 +- src/helpers/canUseDOM.ts | 5 + src/reducerMaps/notifications.ts | 7 +- src/routes/team/home/Home.test.tsx | 5 +- src/routes/team/home/Home.tsx | 2 +- src/styles/globalCss.scss | 3 +- test/setup.ts | 12 +- yarn.lock | 103 +----------------- 14 files changed, 41 insertions(+), 122 deletions(-) create mode 100644 src/helpers/canUseDOM.ts diff --git a/package.json b/package.json index 2f581c0af..bd74717bf 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "express-session": "^1.17.3", "express-sslify": "^1.2.0", "express-ws": "^5.0.2", - "fbjs": "^3.0.4", "fetch-mock": "^9.11.0", "flip-toolkit": "^7.1.0", "google-map-react": "^2.2.0", @@ -93,7 +92,6 @@ "@types/express-session": "^1.17.6", "@types/express-sslify": "^1.2.2", "@types/express-ws": "^3.0.1", - "@types/fbjs": "^3.0.4", "@types/google-map-react": "^2.1.7", "@types/google.analytics": "^0.0.42", "@types/google.maps": "^3.52.1", diff --git a/src/actions/flash.ts b/src/actions/flash.ts index e62634053..4134eb04c 100644 --- a/src/actions/flash.ts +++ b/src/actions/flash.ts @@ -1,5 +1,8 @@ -import crypto from "crypto"; +import nodeCrypto from "crypto"; import { Action } from "../interfaces"; +import canUseDOM from "../helpers/canUseDOM"; + +const crypto = canUseDOM ? window.crypto : nodeCrypto; export function flashError(message: string): Action { return { diff --git a/src/actions/users.ts b/src/actions/users.ts index c4f9fe6fa..aa3c56f88 100644 --- a/src/actions/users.ts +++ b/src/actions/users.ts @@ -1,6 +1,6 @@ import { ThunkAction } from "@reduxjs/toolkit"; -import { canUseDOM } from "fbjs/lib/ExecutionEnvironment"; import { credentials, jsonHeaders, processResponse } from "../core/ApiClient"; +import canUseDOM from "../helpers/canUseDOM"; import { Action, RoleType, State, Team, User } from "../interfaces"; import { getCurrentUser } from "../selectors/user"; diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index 8700afb05..7904e00f3 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -9,16 +9,17 @@ import React, { Component, ReactNode } from "react"; import PropTypes from "prop-types"; -import { canUseDOM } from "fbjs/lib/ExecutionEnvironment"; -import emptyFunction from "fbjs/lib/emptyFunction"; +import { InsertCSS } from "isomorphic-style-loader/StyleContext"; +// eslint-disable-next-line css-modules/no-unused-class, no-unused-vars +import globalCss from "../../styles/globalCss.scss"; +import canUseDOM from "../../helpers/canUseDOM"; import HeaderContainer from "../Header/HeaderContainer"; import FooterContainer from "../Footer/FooterContainer"; import NotificationListContainer from "../NotificationList/NotificationListContainer"; import ConfirmModalContainer from "../ConfirmModal/ConfirmModalContainer"; import s from "./Layout.scss"; -// eslint-disable-next-line css-modules/no-unused-class, no-unused-vars -import globalCss from "../../styles/globalCss.scss"; -import { InsertCSS } from "isomorphic-style-loader/StyleContext"; + +const emptyFunction = () => undefined; export interface LayoutProps { children: ReactNode; diff --git a/src/components/RestaurantAddForm/RestaurantAddForm.tsx b/src/components/RestaurantAddForm/RestaurantAddForm.tsx index 2d026e680..197f62742 100644 --- a/src/components/RestaurantAddForm/RestaurantAddForm.tsx +++ b/src/components/RestaurantAddForm/RestaurantAddForm.tsx @@ -2,8 +2,8 @@ import React, { Component, RefObject, Suspense, createRef, lazy } from "react"; import GeosuggestClass, { GeosuggestProps, Suggest } from "react-geosuggest"; -import { canUseDOM } from "fbjs/lib/ExecutionEnvironment"; import withStyles from "isomorphic-style-loader/withStyles"; +import canUseDOM from "../../helpers/canUseDOM"; import { LatLng } from "../../interfaces"; import GoogleMapsLoaderContext, { IGoogleMapsLoaderContext, diff --git a/src/components/RestaurantMarker/RestaurantMarker.tsx b/src/components/RestaurantMarker/RestaurantMarker.tsx index 22db95835..6d2e8106c 100644 --- a/src/components/RestaurantMarker/RestaurantMarker.tsx +++ b/src/components/RestaurantMarker/RestaurantMarker.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { canUseDOM } from "fbjs/lib/ExecutionEnvironment"; import withStyles from "isomorphic-style-loader/withStyles"; +import canUseDOM from "../../helpers/canUseDOM"; import { AppContext, Restaurant } from "../../interfaces"; import App from "../App"; import RestaurantContainer from "../Restaurant/RestaurantContainer"; diff --git a/src/components/TeamGeosuggest/TeamGeosuggest.tsx b/src/components/TeamGeosuggest/TeamGeosuggest.tsx index 816a83a0c..e877ec4bc 100644 --- a/src/components/TeamGeosuggest/TeamGeosuggest.tsx +++ b/src/components/TeamGeosuggest/TeamGeosuggest.tsx @@ -1,6 +1,6 @@ import React, { Component, Suspense, lazy } from "react"; import { Suggest } from "react-geosuggest"; -import { canUseDOM } from "fbjs/lib/ExecutionEnvironment"; +import canUseDOM from "../../helpers/canUseDOM"; import { LatLng } from "../../interfaces"; import GoogleMapsLoaderContext, { IGoogleMapsLoaderContext, diff --git a/src/helpers/canUseDOM.ts b/src/helpers/canUseDOM.ts new file mode 100644 index 000000000..05df21497 --- /dev/null +++ b/src/helpers/canUseDOM.ts @@ -0,0 +1,5 @@ +export default !!( + typeof window !== "undefined" && + window.document && + window.document.createElement +); diff --git a/src/reducerMaps/notifications.ts b/src/reducerMaps/notifications.ts index d8274eed8..bc26a78dc 100644 --- a/src/reducerMaps/notifications.ts +++ b/src/reducerMaps/notifications.ts @@ -1,5 +1,8 @@ -import crypto from "crypto"; +import nodeCrypto from "crypto"; import { Notification, Reducer } from "../interfaces"; +import canUseDOM from "../helpers/canUseDOM"; + +const crypto = canUseDOM ? window.crypto : nodeCrypto; const notifications: Reducer<"notifications"> = (state, action) => { switch (action.type) { @@ -146,6 +149,8 @@ const notifications: Reducer<"notifications"> = (state, action) => { case "EXPIRE_NOTIFICATION": { return state.filter((n) => n.id !== action.id); } + default: + break; } return state; }; diff --git a/src/routes/team/home/Home.test.tsx b/src/routes/team/home/Home.test.tsx index aa790b070..e2985fa4c 100644 --- a/src/routes/team/home/Home.test.tsx +++ b/src/routes/team/home/Home.test.tsx @@ -8,6 +8,7 @@ import proxyquire from "proxyquire"; import { render, screen } from "../../../../test/test-utils"; import { HomeProps } from "./Home"; import { User } from "../../../interfaces"; +import mockEsmodule from "test/mockEsmodule"; const proxy = proxyquire.noCallThru(); @@ -33,7 +34,9 @@ const TagFilterFormContainer = () => ( // eslint-disable-next-line no-underscore-dangle const Home = proxy("./Home", { - "fbjs/lib/ExecutionEnvironment": { canUseDOM: false }, + "../../../helpers/canUseDOM": mockEsmodule({ + default: false, + }), "../../../components/RestaurantAddForm/RestaurantAddFormContainer": RestaurantAddFormContainer, "../../../components/Footer/FooterContainer": FooterContainer, diff --git a/src/routes/team/home/Home.tsx b/src/routes/team/home/Home.tsx index 9ea6808a8..d1bf0e976 100644 --- a/src/routes/team/home/Home.tsx +++ b/src/routes/team/home/Home.tsx @@ -1,5 +1,4 @@ import React, { Component } from "react"; -import { canUseDOM } from "fbjs/lib/ExecutionEnvironment"; import RobustWebSocket from "robust-websocket"; import withStyles from "isomorphic-style-loader/withStyles"; import FooterContainer from "../../../components/Footer/FooterContainer"; @@ -9,6 +8,7 @@ import RestaurantMapContainer from "../../../components/RestaurantMap/Restaurant import RestaurantListContainer from "../../../components/RestaurantList/RestaurantListContainer"; import RestaurantAddFormContainer from "../../../components/RestaurantAddForm/RestaurantAddFormContainer"; import TagFilterFormContainer from "../../../components/TagFilterForm/TagFilterFormContainer"; +import canUseDOM from "../../../helpers/canUseDOM"; import { User } from "../../../interfaces"; import s from "./Home.scss"; import GoogleMapsLoaderContext, { diff --git a/src/styles/globalCss.scss b/src/styles/globalCss.scss index 70e285a3c..fd7d05054 100644 --- a/src/styles/globalCss.scss +++ b/src/styles/globalCss.scss @@ -15,8 +15,9 @@ @import "~bootstrap/scss/tables"; @import "~bootstrap/scss/forms"; @import "~bootstrap/scss/buttons"; +@import "~bootstrap/scss/dropdown"; @import "~bootstrap/scss/nav"; -@import "~bootstrap/scss/list-group"; +@import "~bootstrap/scss/bootstrap"; @import "~bootstrap/scss/helpers/visually-hidden"; @import "~bootstrap/scss/utilities/api"; diff --git a/test/setup.ts b/test/setup.ts index 0eae4c723..1125a5e35 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -9,12 +9,10 @@ /* Configure Mocha test runner, see package.json/scripts/test */ -require("global-jsdom/register"); - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { use } = require("chai"); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const chaiJSDOM = require("chai-jsdom"); +import "global-jsdom/register"; +import { use } from "chai"; +import chaiJSDOM from "chai-jsdom"; +import nodeCrypto from "crypto"; use(chaiJSDOM); @@ -24,6 +22,8 @@ function noop() { return null; } +window.crypto.randomUUID = nodeCrypto.randomUUID; + require.extensions[".css"] = noop; require.extensions[".scss"] = noop; require.extensions[".md"] = noop; diff --git a/yarn.lock b/yarn.lock index e78deeca7..8f144e7c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2299,15 +2299,6 @@ __metadata: languageName: node linkType: hard -"@types/fbjs@npm:^3.0.4": - version: 3.0.4 - resolution: "@types/fbjs@npm:3.0.4" - dependencies: - "@types/jsdom": "*" - checksum: c251ab9561f9d3b127d8669f16130a205dfbba5b3ece7ac3da9d8fe202f4e78bc32afc59e0ee4a03aabb0b0a149c821a579ef1db59ee96dd9756734dbbb91511 - languageName: node - linkType: hard - "@types/google-map-react@npm:^2.1.7": version: 2.1.7 resolution: "@types/google-map-react@npm:2.1.7" @@ -2383,17 +2374,6 @@ __metadata: languageName: node linkType: hard -"@types/jsdom@npm:*": - version: 21.1.1 - resolution: "@types/jsdom@npm:21.1.1" - dependencies: - "@types/node": "*" - "@types/tough-cookie": "*" - parse5: ^7.0.0 - checksum: 7450d6e23aa31b837a1682f0e59b06838aacca85c9d030035f40e21d559169c773aee5cee9244f23c3004b78f7064f0c540ceb808d2f187deb3140f2b0449dee - languageName: node - linkType: hard - "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": version: 7.0.11 resolution: "@types/json-schema@npm:7.0.11" @@ -2782,13 +2762,6 @@ __metadata: languageName: node linkType: hard -"@types/tough-cookie@npm:*": - version: 4.0.2 - resolution: "@types/tough-cookie@npm:4.0.2" - checksum: e055556ffdaa39ad85ede0af192c93f93f986f4bd9e9426efdc2948e3e2632db3a4a584d4937dbf6d7620527419bc99e6182d3daf2b08685e710f2eda5291905 - languageName: node - linkType: hard - "@types/trusted-types@npm:^2.0.2": version: 2.0.2 resolution: "@types/trusted-types@npm:2.0.2" @@ -3585,7 +3558,7 @@ __metadata: languageName: node linkType: hard -"asap@npm:^2.0.0, asap@npm:~2.0.3": +"asap@npm:^2.0.0": version: 2.0.6 resolution: "asap@npm:2.0.6" checksum: b296c92c4b969e973260e47523207cd5769abd27c245a68c26dc7a0fe8053c55bb04360237cb51cab1df52be939da77150ace99ad331fb7fb13b3423ed73ff3d @@ -4853,15 +4826,6 @@ __metadata: languageName: node linkType: hard -"cross-fetch@npm:^3.1.5": - version: 3.1.5 - resolution: "cross-fetch@npm:3.1.5" - dependencies: - node-fetch: 2.6.7 - checksum: f6b8c6ee3ef993ace6277fd789c71b6acf1b504fd5f5c7128df4ef2f125a429e29cd62dc8c127523f04a5f2fa4771ed80e3f3d9695617f441425045f505cf3bb - languageName: node - linkType: hard - "cross-spawn@npm:^5.1.0": version: 5.1.0 resolution: "cross-spawn@npm:5.1.0" @@ -6575,28 +6539,6 @@ __metadata: languageName: node linkType: hard -"fbjs-css-vars@npm:^1.0.0": - version: 1.0.2 - resolution: "fbjs-css-vars@npm:1.0.2" - checksum: 72baf6d22c45b75109118b4daecb6c8016d4c83c8c0f23f683f22e9d7c21f32fff6201d288df46eb561e3c7d4bb4489b8ad140b7f56444c453ba407e8bd28511 - languageName: node - linkType: hard - -"fbjs@npm:^3.0.4": - version: 3.0.4 - resolution: "fbjs@npm:3.0.4" - dependencies: - cross-fetch: ^3.1.5 - fbjs-css-vars: ^1.0.0 - loose-envify: ^1.0.0 - object-assign: ^4.1.0 - promise: ^7.1.1 - setimmediate: ^1.0.5 - ua-parser-js: ^0.7.30 - checksum: 8b23a3550fcda8a9109fca9475a3416590c18bb6825ea884192864ed686f67fcd618e308a140c9e5444fbd0168732e1ff3c092ba3d0c0ae1768969f32ba280c7 - languageName: node - linkType: hard - "fd-slicer@npm:~1.1.0": version: 1.1.0 resolution: "fd-slicer@npm:1.1.0" @@ -9314,7 +9256,6 @@ __metadata: "@types/express-session": ^1.17.6 "@types/express-sslify": ^1.2.2 "@types/express-ws": ^3.0.1 - "@types/fbjs": ^3.0.4 "@types/google-map-react": ^2.1.7 "@types/google.analytics": ^0.0.42 "@types/google.maps": ^3.52.1 @@ -9374,7 +9315,6 @@ __metadata: express-session: ^1.17.3 express-sslify: ^1.2.0 express-ws: ^5.0.2 - fbjs: ^3.0.4 fetch-mock: ^9.11.0 file-loader: ^6.2.0 flip-toolkit: ^7.1.0 @@ -10100,20 +10040,6 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:2.6.7": - version: 2.6.7 - resolution: "node-fetch@npm:2.6.7" - dependencies: - whatwg-url: ^5.0.0 - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: 8d816ffd1ee22cab8301c7756ef04f3437f18dace86a1dae22cf81db8ef29c0bf6655f3215cb0cdb22b420b6fe141e64b26905e7f33f9377a7fa59135ea3e10b - languageName: node - linkType: hard - "node-fetch@npm:^2.6.7": version: 2.6.9 resolution: "node-fetch@npm:2.6.9" @@ -10380,7 +10306,7 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": +"object-assign@npm:^4, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f @@ -10701,7 +10627,7 @@ __metadata: languageName: node linkType: hard -"parse5@npm:^7.0.0, parse5@npm:^7.1.2": +"parse5@npm:^7.1.2": version: 7.1.2 resolution: "parse5@npm:7.1.2" dependencies: @@ -11319,15 +11245,6 @@ __metadata: languageName: node linkType: hard -"promise@npm:^7.1.1": - version: 7.3.1 - resolution: "promise@npm:7.3.1" - dependencies: - asap: ~2.0.3 - checksum: 475bb069130179fbd27ed2ab45f26d8862376a137a57314cf53310bdd85cc986a826fd585829be97ebc0aaf10e9d8e68be1bfe5a4a0364144b1f9eedfa940cf1 - languageName: node - linkType: hard - "prompts@npm:^2.4.2": version: 2.4.2 resolution: "prompts@npm:2.4.2" @@ -12699,13 +12616,6 @@ __metadata: languageName: node linkType: hard -"setimmediate@npm:^1.0.5": - version: 1.0.5 - resolution: "setimmediate@npm:1.0.5" - checksum: c9a6f2c5b51a2dabdc0247db9c46460152ffc62ee139f3157440bd48e7c59425093f42719ac1d7931f054f153e2d26cf37dfeb8da17a794a58198a2705e527fd - languageName: node - linkType: hard - "setprototypeof@npm:1.1.0": version: 1.1.0 resolution: "setprototypeof@npm:1.1.0" @@ -14158,13 +14068,6 @@ __metadata: languageName: node linkType: hard -"ua-parser-js@npm:^0.7.30": - version: 0.7.33 - resolution: "ua-parser-js@npm:0.7.33" - checksum: 1510e9ec26fcaf0d8c6ae8f1078a8230e8816f083e1b5f453ea19d06b8ef2b8a596601c92148fd41899e8b3e5f83fa69c42332bd5729b931a721040339831696 - languageName: node - linkType: hard - "ua-parser-js@npm:^1.0.33": version: 1.0.35 resolution: "ua-parser-js@npm:1.0.35" From 12139820d136782fbac10c6eda6b06b9d0a8b4de Mon Sep 17 00:00:00 2001 From: Jeffrey Carl Faden Date: Mon, 19 Jun 2023 12:36:55 -0700 Subject: [PATCH 6/8] Fix crypto for Electron --- src/client.tsx | 5 +++++ src/styles/globalCss.scss | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/client.tsx b/src/client.tsx index e8b990abe..d1bcc7a46 100644 --- a/src/client.tsx +++ b/src/client.tsx @@ -37,6 +37,11 @@ if (teamSlug && host.indexOf(teamSlug) === 0) { } window.App.state.host = host; +// Hack for Electron (Cypress) +window.crypto.randomUUID = + window.crypto.randomUUID || + (() => Math.round(Math.random() * 10 ** 16).toString()); + if (!subdomain) { // escape domain periods to not appear as regex wildcards const subdomainMatch = window.location.host.match( diff --git a/src/styles/globalCss.scss b/src/styles/globalCss.scss index fd7d05054..380c34fa7 100644 --- a/src/styles/globalCss.scss +++ b/src/styles/globalCss.scss @@ -17,7 +17,8 @@ @import "~bootstrap/scss/buttons"; @import "~bootstrap/scss/dropdown"; @import "~bootstrap/scss/nav"; -@import "~bootstrap/scss/bootstrap"; +@import "~bootstrap/scss/list-group"; +@import "~bootstrap/scss/modal"; @import "~bootstrap/scss/helpers/visually-hidden"; @import "~bootstrap/scss/utilities/api"; From 6e6b881654db77a87bc059ab39571c23e5df67fc Mon Sep 17 00:00:00 2001 From: Jeffrey Carl Faden Date: Mon, 19 Jun 2023 15:04:10 -0700 Subject: [PATCH 7/8] Replace immutability-helper with immer --- .eslintrc.js | 4 + package.json | 1 - src/api/tests/decisions.test.ts | 3 +- src/api/tests/user.test.ts | 3 +- src/api/tests/users.test.ts | 3 +- .../ConfirmModal/ConfirmModalContainer.ts | 4 +- src/interfaces.ts | 12 +- src/middlewares/tests/invitation.test.ts | 5 +- src/middlewares/tests/login.test.ts | 3 +- src/reducerMaps/decisions.ts | 85 ---- src/reducerMaps/helpers/isFetching.ts | 10 - src/reducerMaps/listUi.ts | 60 --- src/reducerMaps/mapUi.ts | 144 ------ src/reducerMaps/modals.ts | 28 -- src/reducerMaps/pageUi.ts | 24 - src/reducerMaps/restaurants.ts | 417 ------------------ src/reducerMaps/tags.ts | 125 ------ src/reducerMaps/teams.ts | 53 --- src/reducerMaps/user.ts | 66 --- src/reducerMaps/users.ts | 96 ---- src/reducers/decisions.ts | 56 +++ src/{reducerMaps => reducers}/flashes.ts | 2 + src/{reducerMaps => reducers}/index.ts | 0 src/reducers/listUi.ts | 50 +++ src/reducers/mapUi.ts | 87 ++++ src/reducers/modals.ts | 26 ++ .../notifications.ts | 0 src/reducers/pageUi.ts | 20 + src/reducers/restaurants.ts | 226 ++++++++++ .../tagExclusions.ts | 2 + src/{reducerMaps => reducers}/tagFilters.ts | 2 + src/reducers/tags.ts | 64 +++ src/{reducerMaps => reducers}/team.ts | 2 + src/reducers/teams.ts | 34 ++ .../tests/restaurants.test.ts | 2 +- .../tests/teams.test.ts | 2 +- .../tests/user.test.ts | 2 +- .../tests/users.test.ts | 2 +- src/reducers/user.ts | 55 +++ src/reducers/users.ts | 56 +++ src/store/configureStore.ts | 24 +- yarn.lock | 8 - 42 files changed, 719 insertions(+), 1149 deletions(-) delete mode 100644 src/reducerMaps/decisions.ts delete mode 100644 src/reducerMaps/helpers/isFetching.ts delete mode 100644 src/reducerMaps/listUi.ts delete mode 100644 src/reducerMaps/mapUi.ts delete mode 100644 src/reducerMaps/modals.ts delete mode 100644 src/reducerMaps/pageUi.ts delete mode 100644 src/reducerMaps/restaurants.ts delete mode 100644 src/reducerMaps/tags.ts delete mode 100644 src/reducerMaps/teams.ts delete mode 100644 src/reducerMaps/user.ts delete mode 100644 src/reducerMaps/users.ts create mode 100644 src/reducers/decisions.ts rename src/{reducerMaps => reducers}/flashes.ts (96%) rename src/{reducerMaps => reducers}/index.ts (100%) create mode 100644 src/reducers/listUi.ts create mode 100644 src/reducers/mapUi.ts create mode 100644 src/reducers/modals.ts rename src/{reducerMaps => reducers}/notifications.ts (100%) create mode 100644 src/reducers/pageUi.ts create mode 100644 src/reducers/restaurants.ts rename src/{reducerMaps => reducers}/tagExclusions.ts (94%) rename src/{reducerMaps => reducers}/tagFilters.ts (93%) create mode 100644 src/reducers/tags.ts rename src/{reducerMaps => reducers}/team.ts (89%) create mode 100644 src/reducers/teams.ts rename src/{reducerMaps => reducers}/tests/restaurants.test.ts (98%) rename src/{reducerMaps => reducers}/tests/teams.test.ts (97%) rename src/{reducerMaps => reducers}/tests/user.test.ts (99%) rename src/{reducerMaps => reducers}/tests/users.test.ts (96%) create mode 100644 src/reducers/user.ts create mode 100644 src/reducers/users.ts diff --git a/.eslintrc.js b/.eslintrc.js index fecd7b37c..1af7ec0b4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -100,6 +100,10 @@ module.exports = { "import/no-relative-packages": "off", "import/no-import-module-exports": "off", "no-use-before-define": "off", + "no-param-reassign": [ + "error", + { props: true, ignorePropertyModificationsFor: ["draftState"] }, + ], "@typescript-eslint/no-use-before-define": ["error"], }, diff --git a/package.json b/package.json index bd74717bf..778cc65b9 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "flip-toolkit": "^7.1.0", "google-map-react": "^2.2.0", "history": "^5.3.0", - "immutability-helper": "^3.1.1", "isomorphic-style-loader": "^5.3.2", "jsonwebtoken": "^9.0.0", "lodash.get": "^4.4.2", diff --git a/src/api/tests/decisions.test.ts b/src/api/tests/decisions.test.ts index b377b63bd..ea46d3cfc 100644 --- a/src/api/tests/decisions.test.ts +++ b/src/api/tests/decisions.test.ts @@ -4,8 +4,7 @@ import { expect } from "chai"; import { SinonSpy, match, spy, stub } from "sinon"; import bodyParser from "body-parser"; -import { Response } from "superagent"; -import request from "supertest"; +import request, { Response } from "supertest"; import express, { Application, RequestHandler } from "express"; import proxyquire from "proxyquire"; import SequelizeMock from "sequelize-mock"; diff --git a/src/api/tests/user.test.ts b/src/api/tests/user.test.ts index 461bc8fa0..4e40bf052 100644 --- a/src/api/tests/user.test.ts +++ b/src/api/tests/user.test.ts @@ -4,8 +4,7 @@ import { expect } from "chai"; import { SinonSpy, spy, stub } from "sinon"; import bodyParser from "body-parser"; -import { Response } from "superagent"; -import request from "supertest"; +import request, { Response } from "supertest"; import express, { Application } from "express"; import proxyquire from "proxyquire"; import SequelizeMock from "sequelize-mock"; diff --git a/src/api/tests/users.test.ts b/src/api/tests/users.test.ts index f7faca52d..c6f42ac4e 100644 --- a/src/api/tests/users.test.ts +++ b/src/api/tests/users.test.ts @@ -4,8 +4,7 @@ import { expect } from "chai"; import { SinonSpy, SinonStub, match, spy, stub } from "sinon"; import bodyParser from "body-parser"; -import { Response } from "superagent"; -import request from "supertest"; +import request, { Response } from "supertest"; import express, { Application, RequestHandler } from "express"; import proxyquire from "proxyquire"; import SequelizeMock from "sequelize-mock"; diff --git a/src/components/ConfirmModal/ConfirmModalContainer.ts b/src/components/ConfirmModal/ConfirmModalContainer.ts index 71a8396dc..b548c9f7f 100644 --- a/src/components/ConfirmModal/ConfirmModalContainer.ts +++ b/src/components/ConfirmModal/ConfirmModalContainer.ts @@ -6,7 +6,7 @@ import { Dispatch, State } from "../../interfaces"; const modalName = "confirm"; const mapStateToProps = (state: State) => ({ - actionLabel: state.modals[modalName].actionLabel, + actionLabel: state.modals[modalName].actionLabel!, body: state.modals[modalName].body, action: state.modals[modalName].action, shown: !!state.modals[modalName].shown, @@ -24,7 +24,7 @@ const mergeProps = ( ...stateProps, ...dispatchProps, handleSubmit: () => { - dispatchProps.dispatch(stateProps.action); + dispatchProps.dispatch(stateProps.action!); dispatchProps.hideModal(); }, }); diff --git a/src/interfaces.ts b/src/interfaces.ts index 860af9b47..93b4a055d 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -389,6 +389,10 @@ export type Action = name: "confirm"; opts: ConfirmOpts; } + | { + type: "SHOW_MODAL"; + name: string; + } | { type: "HIDE_MODAL"; name: string; @@ -486,9 +490,11 @@ interface BaseState { notifications: Notification[]; modals: { [index: string]: { - action: () => void; - actionLabel: string; - body: ReactNode; + action?: + | Action + | ThunkAction | void, State, unknown, Action>; + actionLabel?: string; + body?: ReactNode; restaurantId?: number; shown: boolean; }; diff --git a/src/middlewares/tests/invitation.test.ts b/src/middlewares/tests/invitation.test.ts index 5b75b3cc6..84758f91c 100644 --- a/src/middlewares/tests/invitation.test.ts +++ b/src/middlewares/tests/invitation.test.ts @@ -4,9 +4,8 @@ import { expect } from "chai"; import { SinonSpy, match, spy, stub } from "sinon"; import bodyParser from "body-parser"; -import { Response } from "superagent"; -import request from "supertest"; -import express, { Application, RequestHandler } from "express"; +import request, { Response } from "supertest"; +import express, { Application } from "express"; import session, { Session } from "express-session"; import proxyquire from "proxyquire"; import SequelizeMock from "sequelize-mock"; diff --git a/src/middlewares/tests/login.test.ts b/src/middlewares/tests/login.test.ts index 9c90c2e49..eb8c92663 100644 --- a/src/middlewares/tests/login.test.ts +++ b/src/middlewares/tests/login.test.ts @@ -3,8 +3,7 @@ import { expect } from "chai"; import { SinonSpy, SinonStub, match, spy, stub } from "sinon"; -import { Response } from "superagent"; -import request from "supertest"; +import request, { Response } from "supertest"; import express, { Application, NextFunction, RequestHandler } from "express"; import proxyquire from "proxyquire"; import mockEsmodule from "../../../test/mockEsmodule"; diff --git a/src/reducerMaps/decisions.ts b/src/reducerMaps/decisions.ts deleted file mode 100644 index a1dff6429..000000000 --- a/src/reducerMaps/decisions.ts +++ /dev/null @@ -1,85 +0,0 @@ -import update from "immutability-helper"; -import { normalize } from "normalizr"; -import { Reducer } from "../interfaces"; -import * as schemas from "../schemas"; -import isFetching from "./helpers/isFetching"; - -const decisions: Reducer<"decisions"> = (state, action) => { - switch (action.type) { - case "INVALIDATE_DECISIONS": { - return update(state, { - $merge: { - didInvalidate: true, - }, - }); - } - case "REQUEST_DECISIONS": - case "POST_DECISION": - case "DELETE_DECISION": { - return isFetching(state); - } - case "RECEIVE_DECISIONS": { - return update(state, { - $merge: { - isFetching: false, - didInvalidate: false, - items: normalize(action.items, [schemas.decision]), - }, - }); - } - case "DECISION_POSTED": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - entities: { - decisions: state.items.entities.decisions - ? { - $merge: { - [action.decision.id]: action.decision, - }, - } - : { - $set: { - [action.decision.id]: action.decision, - }, - }, - }, - result: { - $apply: (result: number[]) => { - const deselectedIds = action.deselected.map((d) => d.id); - return result.reduce( - (acc, curr) => { - if (deselectedIds.indexOf(curr) === -1) { - acc.push(curr); - } - return acc; - }, - [action.decision.id] - ); - }, - }, - }, - }); - } - case "DECISIONS_DELETED": { - const decisionIds = action.decisions.map((d) => d.id); - const newState = { - isFetching: { - $set: false, - }, - items: { - result: { - $apply: (result: number[]) => - result.filter((id) => decisionIds.indexOf(id) === -1), - }, - }, - }; - return update(state, newState); - } - } - return state; -}; - -export default decisions; diff --git a/src/reducerMaps/helpers/isFetching.ts b/src/reducerMaps/helpers/isFetching.ts deleted file mode 100644 index 256afd8e5..000000000 --- a/src/reducerMaps/helpers/isFetching.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { State } from "../../interfaces"; - -type StateWithFetching = Extract; - -const isFetching = (state: T) => ({ - ...state, - isFetching: true, -}); - -export default isFetching; diff --git a/src/reducerMaps/listUi.ts b/src/reducerMaps/listUi.ts deleted file mode 100644 index 7e226143c..000000000 --- a/src/reducerMaps/listUi.ts +++ /dev/null @@ -1,60 +0,0 @@ -import update from "immutability-helper"; -import { Reducer } from "../interfaces"; - -const listUi: Reducer<"listUi"> = (state, action) => { - switch (action.type) { - case "RESTAURANT_RENAMED": - case "RESTAURANT_DELETED": { - return update(state, { - $merge: { - [action.id]: {}, - }, - }); - } - case "RESTAURANT_POSTED": { - return update(state, { - newlyAdded: { - $set: { - id: action.restaurant.id, - userId: action.userId, - }, - }, - $merge: { - [action.restaurant.id]: {}, - }, - }); - } - case "SET_EDIT_NAME_FORM_VALUE": { - return update(state, { - [action.id]: (stateValue) => - update(stateValue || {}, { - $merge: { editNameFormValue: action.value }, - }), - }); - } - case "SHOW_EDIT_NAME_FORM": { - return update(state, { - [action.id]: (stateValue) => - update(stateValue || {}, { $merge: { isEditingName: true } }), - }); - } - case "HIDE_EDIT_NAME_FORM": { - return update(state, { - [action.id]: (stateValue) => - update(stateValue || {}, { $merge: { isEditingName: false } }), - }); - } - case "SET_FLIP_MOVE": { - return update(state, { - flipMove: { - $set: action.val, - }, - }); - } - default: - break; - } - return state; -}; - -export default listUi; diff --git a/src/reducerMaps/mapUi.ts b/src/reducerMaps/mapUi.ts deleted file mode 100644 index 1c04211ea..000000000 --- a/src/reducerMaps/mapUi.ts +++ /dev/null @@ -1,144 +0,0 @@ -import update, { Spec } from "immutability-helper"; -import { Reducer } from "../interfaces"; - -const mapUi: Reducer<"mapUi"> = (state, action) => { - switch (action.type) { - case "RECEIVE_RESTAURANTS": { - return update(state, { - infoWindow: { - $set: {}, - }, - showPOIs: { - $set: !action.items.length, - }, - showUnvoted: { - $set: true, - }, - }); - } - case "RESTAURANT_POSTED": { - return update(state, { - newlyAdded: { - $set: { - id: action.restaurant.id, - userId: action.userId, - }, - }, - }); - } - case "SHOW_GOOGLE_INFO_WINDOW": { - return update(state, { - center: { - $set: { - lat: action.latLng.lat, - lng: action.latLng.lng, - }, - }, - infoWindow: { - $set: { - latLng: action.latLng, - placeId: action.placeId, - }, - }, - }); - } - case "SHOW_RESTAURANT_INFO_WINDOW": { - return update(state, { - center: { - $set: { - lat: action.restaurant.lat, - lng: action.restaurant.lng, - }, - }, - infoWindow: { - $set: { - id: action.restaurant.id, - }, - }, - }); - } - case "HIDE_INFO_WINDOW": { - return update(state, { - infoWindow: { - $set: {}, - }, - }); - } - case "SET_SHOW_POIS": { - let updates = { - showPOIs: { - $set: action.val, - }, - } as Spec; - - if (!action.val) { - updates = { - ...updates, - infoWindow: { - latLng: { - $set: undefined, - }, - placeId: { - $set: undefined, - }, - }, - }; - } - - return update(state, updates); - } - case "SET_SHOW_UNVOTED": { - return update(state, { - $merge: { - showUnvoted: action.val, - }, - }); - } - case "SET_CENTER": { - return update(state, { - center: { - $set: action.center, - }, - }); - } - case "CLEAR_CENTER": { - return update(state, { - center: { - $set: undefined, - }, - }); - } - case "CREATE_TEMP_MARKER": { - return update(state, { - center: { - $set: action.result.latLng, - }, - tempMarker: { - $set: action.result, - }, - }); - } - case "CLEAR_TEMP_MARKER": { - return update(state, { - center: { - $set: undefined, - }, - tempMarker: { - $set: undefined, - }, - }); - } - case "CLEAR_MAP_UI_NEWLY_ADDED": { - return update(state, { - newlyAdded: { - $set: undefined, - }, - }); - } - default: - break; - } - return state; -}; - -export default mapUi; diff --git a/src/reducerMaps/modals.ts b/src/reducerMaps/modals.ts deleted file mode 100644 index cda11ad2e..000000000 --- a/src/reducerMaps/modals.ts +++ /dev/null @@ -1,28 +0,0 @@ -import update from "immutability-helper"; -import { Reducer } from "../interfaces"; - -const modals: Reducer<"modals"> = (state, action) => { - switch (action.type) { - case "SHOW_MODAL": { - return update(state, { - $merge: { - [action.name]: { - shown: true, - ...action.opts, - }, - }, - }); - } - case "HIDE_MODAL": { - return update(state, { - [action.name]: (stateValue) => - update(stateValue || {}, { $merge: { shown: false } }), - }); - } - default: - break; - } - return state; -}; - -export default modals; diff --git a/src/reducerMaps/pageUi.ts b/src/reducerMaps/pageUi.ts deleted file mode 100644 index ddd37508a..000000000 --- a/src/reducerMaps/pageUi.ts +++ /dev/null @@ -1,24 +0,0 @@ -import update from "immutability-helper"; -import { Reducer } from "../interfaces"; - -const pageUi: Reducer<"pageUi"> = (state, action) => { - switch (action.type) { - case "SCROLL_TO_TOP": { - return update(state, { - $merge: { - shouldScrollToTop: true, - }, - }); - } - case "SCROLLED_TO_TOP": { - return update(state, { - $merge: { - shouldScrollToTop: false, - }, - }); - } - } - return state; -}; - -export default pageUi; diff --git a/src/reducerMaps/restaurants.ts b/src/reducerMaps/restaurants.ts deleted file mode 100644 index 2aeb1e328..000000000 --- a/src/reducerMaps/restaurants.ts +++ /dev/null @@ -1,417 +0,0 @@ -import { normalize } from "normalizr"; -import update, { Spec } from "immutability-helper"; -import { getRestaurantIds, getRestaurantById } from "../selectors/restaurants"; -import * as schemas from "../schemas"; -import isFetching from "./helpers/isFetching"; -import { Reducer } from "../interfaces"; -import maybeAddToString from "../helpers/maybeAddToString"; - -const restaurants: Reducer<"restaurants"> = (state, action) => { - switch (action.type) { - case "SORT_RESTAURANTS": { - return update(state, { - items: { - result: { - $apply: (result: number[]) => { - const sortIndexes: { [index: number]: number } = {}; - result.forEach((id, index) => { - sortIndexes[id] = index; - }); - const sortedResult = Array.from(result).sort((a, b) => { - if ( - action.newlyAdded !== undefined && - action.user.id === action.newlyAdded.userId - ) { - if (a === action.newlyAdded.id) { - return -1; - } - if (b === action.newlyAdded.id) { - return 1; - } - } - if (action.decision !== undefined) { - if (action.decision.restaurantId === a) { - return -1; - } - if (action.decision.restaurantId === b) { - return 1; - } - } - const restaurantA = getRestaurantById( - { restaurants: state }, - a - ); - const restaurantB = getRestaurantById( - { restaurants: state }, - b - ); - - if (restaurantA.votes.length !== restaurantB.votes.length) { - return restaurantB.votes.length - restaurantA.votes.length; - } - if ( - restaurantA.all_decision_count !== - restaurantB.all_decision_count - ) { - return ( - Number(restaurantA.all_decision_count) - - Number(restaurantB.all_decision_count) - ); - } - if (restaurantA.all_vote_count !== restaurantB.all_vote_count) { - return ( - Number(restaurantB.all_vote_count) - - Number(restaurantA.all_vote_count) - ); - } - // stable sort - return sortIndexes[a] - sortIndexes[b]; - }); - // If array contents match, return original (for shallow comparison) - return sortedResult.some((r, i) => r !== result[i]) - ? sortedResult - : result; - }, - }, - }, - }); - } - case "INVALIDATE_RESTAURANTS": { - return update(state, { - $merge: { - didInvalidate: true, - }, - }); - } - case "REQUEST_RESTAURANTS": { - return update(state, { - $merge: { - isFetching: true, - }, - }); - } - case "RECEIVE_RESTAURANTS": { - return update(state, { - $merge: { - isFetching: false, - didInvalidate: false, - items: normalize(action.items, [schemas.restaurant]), - }, - }); - } - case "POST_RESTAURANT": - case "DELETE_RESTAURANT": - case "RENAME_RESTAURANT": - case "POST_VOTE": - case "DELETE_VOTE": - case "POST_NEW_TAG_TO_RESTAURANT": - case "POST_TAG_TO_RESTAURANT": - case "DELETE_TAG_FROM_RESTAURANT": { - return isFetching(state); - } - case "RESTAURANT_POSTED": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - entities: { - restaurants: state.items.entities.restaurants - ? { - $merge: { - [action.restaurant.id]: action.restaurant, - }, - } - : { - $set: { - [action.restaurant.id]: action.restaurant, - }, - }, - }, - result: { - $apply: (result: number[]) => { - if (result.indexOf(action.restaurant.id) === -1) { - return [action.restaurant.id, ...result]; - } - return result; - }, - }, - }, - }); - } - case "RESTAURANT_DELETED": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - result: { - $splice: [ - [getRestaurantIds({ restaurants: state }).indexOf(action.id), 1], - ], - }, - }, - }); - } - case "RESTAURANT_RENAMED": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - entities: { - restaurants: { - [action.id]: { - $merge: action.fields, - }, - }, - }, - }, - }); - } - case "VOTE_POSTED": { - const updates: Spec = { - isFetching: { - $set: false, - }, - items: { - entities: { - votes: state.items.entities.votes - ? { - $merge: { - [action.vote.id]: action.vote, - }, - } - : { - $set: { - [action.vote.id]: action.vote, - }, - }, - restaurants: { - $apply: (r) => { - let ret = r; - if ( - r[action.vote.restaurantId].votes.indexOf(action.vote.id) === - -1 - ) { - const restaurant = r[action.vote.restaurantId]; - ret = { - ...r, - [action.vote.restaurantId]: { - ...restaurant, - votes: [...restaurant.votes, action.vote.id], - all_vote_count: maybeAddToString( - restaurant.all_vote_count, - 1 - ), - }, - }; - } - return ret; - }, - }, - }, - }, - }; - - return update(state, updates); - } - case "VOTE_DELETED": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - entities: { - restaurants: { - [action.restaurantId]: { - votes: { - $splice: [ - [ - getRestaurantById( - { restaurants: state }, - action.restaurantId - ).votes.indexOf(action.id), - 1, - ], - ], - }, - all_vote_count: { - $apply: (count) => maybeAddToString(count, -1), - }, - }, - }, - }, - }, - }); - } - case "POSTED_NEW_TAG_TO_RESTAURANT": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - entities: { - restaurants: { - [action.restaurantId]: { - tags: { - $push: [action.tag.id], - }, - }, - }, - }, - }, - }); - } - case "POSTED_TAG_TO_RESTAURANT": { - const updates: Spec = { - isFetching: { - $set: false, - }, - }; - - if ( - state.items.entities.restaurants[action.restaurantId].tags.indexOf( - action.id - ) === -1 - ) { - updates.items = { - entities: { - restaurants: { - [action.restaurantId]: { - tags: { - $push: [action.id], - }, - }, - }, - }, - }; - } - - return update(state, updates); - } - case "DELETED_TAG_FROM_RESTAURANT": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - entities: { - restaurants: { - [action.restaurantId]: { - tags: { - $splice: [ - [ - getRestaurantById( - { restaurants: state }, - action.restaurantId - ).tags.indexOf(action.id), - 1, - ], - ], - }, - }, - }, - }, - }, - }); - } - case "TAG_DELETED": { - return update(state, { - items: { - entities: { - restaurants: { - $apply: (r) => { - const changedRestaurants = { ...r }; - Object.keys(changedRestaurants).forEach((i) => { - const index = Number(i); - const changedRestaurant = changedRestaurants[index]; - if (changedRestaurant.tags.indexOf(action.id) > -1) { - changedRestaurants[index] = update(changedRestaurant, { - $merge: { - tags: update(changedRestaurant.tags, { - $splice: [ - [changedRestaurant.tags.indexOf(action.id), 1], - ], - }), - }, - }); - } - }); - return changedRestaurants; - }, - }, - }, - }, - }); - } - case "DECISION_POSTED": { - return update(state, { - items: { - entities: { - restaurants: { - $apply: (r) => { - const decision = r[action.decision.restaurantId]; - // eslint-disable-next-line no-param-reassign - r[action.decision.restaurantId] = { - ...r[action.decision.restaurantId], - all_decision_count: maybeAddToString( - decision.all_decision_count, - 1 - ), - }; - action.deselected.forEach((i) => { - // eslint-disable-next-line no-param-reassign - r[i.restaurantId] = { - ...r[i.restaurantId], - all_decision_count: maybeAddToString( - r[i.restaurantId].all_decision_count, - -1 - ), - }; - }); - return r; - }, - }, - }, - }, - }); - } - case "DECISIONS_DELETED": { - return update(state, { - items: { - entities: { - restaurants: { - $apply: (r) => { - const ret = r; - action.decisions.forEach((decision) => { - const restaurant = r[decision.restaurantId]; - ret[decision.restaurantId] = { - ...restaurant, - all_decision_count: maybeAddToString( - restaurant.all_decision_count, - -1 - ), - }; - }); - return ret; - }, - }, - }, - }, - }); - } - case "SET_NAME_FILTER": { - return update(state, { - nameFilter: { - $set: action.val, - }, - }); - } - default: - break; - } - return state; -}; - -export default restaurants; diff --git a/src/reducerMaps/tags.ts b/src/reducerMaps/tags.ts deleted file mode 100644 index 9285a3d64..000000000 --- a/src/reducerMaps/tags.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { normalize } from "normalizr"; -import update from "immutability-helper"; -import { getTagIds, getTagById } from "../selectors/tags"; -import * as schemas from "../schemas"; -import isFetching from "./helpers/isFetching"; -import { Reducer } from "../interfaces"; -import maybeAddToString from "../helpers/maybeAddToString"; - -const tags: Reducer<"tags"> = (state, action) => { - switch (action.type) { - case "INVALIDATE_TAGS": { - return update(state, { - $merge: { - didInvalidate: true, - }, - }); - } - case "REQUEST_TAGS": { - return update(state, { - $merge: { - isFetching: true, - }, - }); - } - case "RECEIVE_TAGS": { - return update(state, { - $merge: { - isFetching: false, - didInvalidate: false, - items: normalize(action.items, [schemas.tag]), - }, - }); - } - case "POSTED_TAG_TO_RESTAURANT": { - return update(state, { - items: { - entities: { - tags: { - [action.id]: { - restaurant_count: { - $set: maybeAddToString( - getTagById({ tags: state }, action.id).restaurant_count, - 1 - ), - }, - }, - }, - }, - }, - }); - } - case "POSTED_NEW_TAG_TO_RESTAURANT": { - return update(state, { - items: { - result: { - $push: [action.tag.id], - }, - entities: { - tags: state.items.entities.tags - ? { - $merge: { - [action.tag.id]: action.tag, - }, - } - : { - $set: { - [action.tag.id]: action.tag, - }, - }, - }, - }, - }); - } - case "DELETED_TAG_FROM_RESTAURANT": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - entities: { - tags: { - [action.id]: { - $merge: { - restaurant_count: maybeAddToString( - state.items.entities.tags[action.id].restaurant_count, - -1 - ), - }, - }, - }, - }, - }, - }); - } - case "DELETE_TAG": { - return isFetching(state); - } - case "TAG_DELETED": { - const tagIndex = getTagIds({ tags: state }).indexOf(action.id); - return update(state, { - isFetching: { - $set: false, - }, - items: { - $apply: (items) => { - if (tagIndex !== -1) { - const result = [...items.result]; - result.splice(tagIndex, 1); - return { - ...items, - result, - }; - } - return items; - }, - }, - }); - } - default: - break; - } - return state; -}; - -export default tags; diff --git a/src/reducerMaps/teams.ts b/src/reducerMaps/teams.ts deleted file mode 100644 index 2b112f264..000000000 --- a/src/reducerMaps/teams.ts +++ /dev/null @@ -1,53 +0,0 @@ -import update from "immutability-helper"; -import { Reducer } from "../interfaces"; -import isFetching from "./helpers/isFetching"; - -const teams: Reducer<"teams"> = (state, action) => { - switch (action.type) { - case "POST_TEAM": { - return isFetching(state); - } - case "TEAM_POSTED": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - result: { - $push: [action.team.id], - }, - entities: { - teams: state.items.entities.teams - ? { - $merge: { - [action.team.id]: action.team, - }, - } - : { - $set: { - [action.team.id]: action.team, - }, - }, - }, - }, - }); - } - case "USER_DELETED": { - if (action.isSelf) { - return update(state, { - items: { - result: { - $splice: [[state.items.result.indexOf(action.team.id), 1]], - }, - }, - }); - } - return state; - } - default: - break; - } - return state; -}; - -export default teams; diff --git a/src/reducerMaps/user.ts b/src/reducerMaps/user.ts deleted file mode 100644 index 17599e390..000000000 --- a/src/reducerMaps/user.ts +++ /dev/null @@ -1,66 +0,0 @@ -import update from "immutability-helper"; -import { Reducer, User } from "../interfaces"; - -const user: Reducer<"user"> = (state, action) => { - switch (action.type) { - case "TEAM_POSTED": { - let newState: typeof state | undefined; - if (action.team.roles) { - action.team.roles.forEach((role) => { - if (role.userId === state!.id) { - newState = update(newState || state, { - roles: { - $push: [role], - }, - }); - } - }); - } - - return newState || state; - } - case "USER_DELETED": { - if (action.isSelf) { - return update(state, { - roles: { - $splice: [ - [ - state!.roles.map((role) => role.teamId).indexOf(action.team.id), - 1, - ], - ], - }, - }); - } - return state; - } - case "USER_PATCHED": { - if (action.isSelf) { - return { - ...state, - ...action.user, - roles: state!.roles.map((role) => { - if (role.teamId === action.team.id) { - return { - ...role, - type: action.user.type!, - }; - } - return role; - }), - type: undefined, - } as User; - } - return state; - } - case "CURRENT_USER_PATCHED": { - return action.user; - } - default: { - break; - } - } - return state; -}; - -export default user; diff --git a/src/reducerMaps/users.ts b/src/reducerMaps/users.ts deleted file mode 100644 index 3eac820f0..000000000 --- a/src/reducerMaps/users.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { normalize } from "normalizr"; -import update from "immutability-helper"; -import { getUserIds } from "../selectors/users"; -import * as schemas from "../schemas"; -import isFetching from "./helpers/isFetching"; -import { Reducer, State } from "../interfaces"; - -const users: Reducer<"users"> = (state, action) => { - switch (action.type) { - case "INVALIDATE_USERS": { - return update(state, { - $merge: { - didInvalidate: true, - }, - }); - } - case "REQUEST_USERS": { - return update(state, { - $merge: { - isFetching: true, - }, - }); - } - case "RECEIVE_USERS": { - return update(state, { - $merge: { - isFetching: false, - didInvalidate: false, - items: normalize(action.items, [schemas.user]), - }, - }); - } - case "DELETE_USER": - case "POST_USER": - case "PATCH_USER": { - return isFetching(state); - } - case "USER_DELETED": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - result: { - $splice: [ - [getUserIds({ users: state } as State).indexOf(action.id), 1], - ], - }, - }, - }); - } - case "USER_POSTED": { - return update(state, { - items: { - result: { - $push: [action.user.id], - }, - entities: { - users: state.items.entities.users - ? { - $merge: { - [action.user.id]: action.user, - }, - } - : { - $set: { - [action.user.id]: action.user, - }, - }, - }, - }, - }); - } - case "USER_PATCHED": { - return update(state, { - isFetching: { - $set: false, - }, - items: { - entities: { - users: { - [action.id]: { - $merge: action.user, - }, - }, - }, - }, - }); - } - default: - break; - } - return state; -}; - -export default users; diff --git a/src/reducers/decisions.ts b/src/reducers/decisions.ts new file mode 100644 index 000000000..6fc3dcdf9 --- /dev/null +++ b/src/reducers/decisions.ts @@ -0,0 +1,56 @@ +import { createNextState } from "@reduxjs/toolkit"; +import { normalize } from "normalizr"; +import { Reducer } from "../interfaces"; +import * as schemas from "../schemas"; + +const decisions: Reducer<"decisions"> = (state, action) => + createNextState(state, (draftState) => { + switch (action.type) { + case "INVALIDATE_DECISIONS": { + draftState.didInvalidate = true; + return; + } + case "REQUEST_DECISIONS": + case "POST_DECISION": + case "DELETE_DECISION": { + draftState.isFetching = true; + return; + } + case "RECEIVE_DECISIONS": { + draftState.isFetching = false; + draftState.didInvalidate = false; + draftState.items = normalize(action.items, [schemas.decision]); + return; + } + case "DECISION_POSTED": { + draftState.isFetching = false; + draftState.items.entities.decisions = { + ...draftState.items.entities.decisions, + [action.decision.id]: action.decision, + }; + const deselectedIds = action.deselected.map((d) => d.id); + draftState.items.result = draftState.items.result.reduce( + (acc, curr) => { + if (deselectedIds.indexOf(curr) === -1) { + acc.push(curr); + } + return acc; + }, + [action.decision.id] + ); + return; + } + case "DECISIONS_DELETED": { + const decisionIds = action.decisions.map((d) => d.id); + draftState.isFetching = false; + draftState.items.result = draftState.items.result.filter( + (id) => decisionIds.indexOf(id) === -1 + ); + break; + } + default: + break; + } + }); + +export default decisions; diff --git a/src/reducerMaps/flashes.ts b/src/reducers/flashes.ts similarity index 96% rename from src/reducerMaps/flashes.ts rename to src/reducers/flashes.ts index 3a0238edc..65c3d93e7 100644 --- a/src/reducerMaps/flashes.ts +++ b/src/reducers/flashes.ts @@ -25,6 +25,8 @@ const flashes: Reducer<"flashes"> = (state, action) => { case "EXPIRE_FLASH": { return state.filter((arr) => arr.id !== action.id); } + default: + break; } return state; }; diff --git a/src/reducerMaps/index.ts b/src/reducers/index.ts similarity index 100% rename from src/reducerMaps/index.ts rename to src/reducers/index.ts diff --git a/src/reducers/listUi.ts b/src/reducers/listUi.ts new file mode 100644 index 000000000..5146e019b --- /dev/null +++ b/src/reducers/listUi.ts @@ -0,0 +1,50 @@ +import { createNextState } from "@reduxjs/toolkit"; +import { Reducer } from "../interfaces"; + +const listUi: Reducer<"listUi"> = (state, action) => + createNextState(state, (draftState) => { + switch (action.type) { + case "RESTAURANT_RENAMED": + case "RESTAURANT_DELETED": { + draftState[action.id] = {}; + return; + } + case "RESTAURANT_POSTED": { + draftState.newlyAdded = { + id: action.restaurant.id, + userId: action.userId, + }; + draftState[action.restaurant.id] = {}; + return; + } + case "SET_EDIT_NAME_FORM_VALUE": { + draftState[action.id] = { + ...draftState[action.id], + editNameFormValue: action.value, + }; + return; + } + case "SHOW_EDIT_NAME_FORM": { + draftState[action.id] = { + ...draftState[action.id], + isEditingName: true, + }; + return; + } + case "HIDE_EDIT_NAME_FORM": { + draftState[action.id] = { + ...draftState[action.id], + isEditingName: false, + }; + return; + } + case "SET_FLIP_MOVE": { + draftState.flipMove = action.val; + break; + } + default: + break; + } + }); + +export default listUi; diff --git a/src/reducers/mapUi.ts b/src/reducers/mapUi.ts new file mode 100644 index 000000000..f427b27ec --- /dev/null +++ b/src/reducers/mapUi.ts @@ -0,0 +1,87 @@ +import { createNextState } from "@reduxjs/toolkit"; +import { Reducer } from "../interfaces"; + +const mapUi: Reducer<"mapUi"> = (state, action) => + createNextState(state, (draftState) => { + switch (action.type) { + case "RECEIVE_RESTAURANTS": { + draftState.infoWindow = {}; + draftState.showPOIs = !action.items.length; + draftState.showUnvoted = true; + return; + } + case "RESTAURANT_POSTED": { + draftState.newlyAdded = { + id: action.restaurant.id, + userId: action.userId, + }; + return; + } + case "SHOW_GOOGLE_INFO_WINDOW": { + draftState.center = { + lat: action.latLng.lat, + lng: action.latLng.lng, + }; + draftState.infoWindow = { + latLng: action.latLng, + placeId: action.placeId, + }; + return; + } + case "SHOW_RESTAURANT_INFO_WINDOW": { + draftState.center = { + lat: action.restaurant.lat, + lng: action.restaurant.lng, + }; + draftState.infoWindow = { + id: action.restaurant.id, + }; + return; + } + case "HIDE_INFO_WINDOW": { + draftState.infoWindow = {}; + return; + } + case "SET_SHOW_POIS": { + draftState.showPOIs = action.val; + + if (!action.val) { + draftState.infoWindow = { + latLng: undefined, + placeId: undefined, + }; + } + return; + } + case "SET_SHOW_UNVOTED": { + draftState.showUnvoted = action.val; + return; + } + case "SET_CENTER": { + draftState.center = action.center; + return; + } + case "CLEAR_CENTER": { + draftState.center = undefined; + return; + } + case "CREATE_TEMP_MARKER": { + draftState.center = action.result.latLng; + draftState.tempMarker = action.result; + return; + } + case "CLEAR_TEMP_MARKER": { + draftState.center = undefined; + draftState.tempMarker = undefined; + return; + } + case "CLEAR_MAP_UI_NEWLY_ADDED": { + draftState.newlyAdded = undefined; + break; + } + default: + break; + } + }); + +export default mapUi; diff --git a/src/reducers/modals.ts b/src/reducers/modals.ts new file mode 100644 index 000000000..876db74a3 --- /dev/null +++ b/src/reducers/modals.ts @@ -0,0 +1,26 @@ +import { createNextState } from "@reduxjs/toolkit"; +import { Reducer } from "../interfaces"; + +const modals: Reducer<"modals"> = (state, action) => + createNextState(state, (draftState) => { + switch (action.type) { + case "SHOW_MODAL": { + draftState[action.name] = { + shown: true, + ...("opts" in action ? action.opts : undefined), + }; + return; + } + case "HIDE_MODAL": { + draftState[action.name] = { + ...draftState[action.name], + shown: false, + }; + break; + } + default: + break; + } + }); + +export default modals; diff --git a/src/reducerMaps/notifications.ts b/src/reducers/notifications.ts similarity index 100% rename from src/reducerMaps/notifications.ts rename to src/reducers/notifications.ts diff --git a/src/reducers/pageUi.ts b/src/reducers/pageUi.ts new file mode 100644 index 000000000..236960ab0 --- /dev/null +++ b/src/reducers/pageUi.ts @@ -0,0 +1,20 @@ +import { createNextState } from "@reduxjs/toolkit"; +import { Reducer } from "../interfaces"; + +const pageUi: Reducer<"pageUi"> = (state, action) => + createNextState(state, (draftState) => { + switch (action.type) { + case "SCROLL_TO_TOP": { + draftState.shouldScrollToTop = true; + return; + } + case "SCROLLED_TO_TOP": { + draftState.shouldScrollToTop = false; + break; + } + default: + break; + } + }); + +export default pageUi; diff --git a/src/reducers/restaurants.ts b/src/reducers/restaurants.ts new file mode 100644 index 000000000..208930dbc --- /dev/null +++ b/src/reducers/restaurants.ts @@ -0,0 +1,226 @@ +import { normalize } from "normalizr"; +import { createNextState } from "@reduxjs/toolkit"; +import { getRestaurantIds, getRestaurantById } from "../selectors/restaurants"; +import * as schemas from "../schemas"; +import { Reducer } from "../interfaces"; +import maybeAddToString from "../helpers/maybeAddToString"; + +const restaurants: Reducer<"restaurants"> = (state, action) => + createNextState(state, (draftState) => { + switch (action.type) { + case "SORT_RESTAURANTS": { + const sortIndexes: { [index: number]: number } = {}; + draftState.items.result.forEach((id, index) => { + sortIndexes[id] = index; + }); + const sortedResult = Array.from(draftState.items.result).sort( + (a, b) => { + if ( + action.newlyAdded !== undefined && + action.user.id === action.newlyAdded.userId + ) { + if (a === action.newlyAdded.id) { + return -1; + } + if (b === action.newlyAdded.id) { + return 1; + } + } + if (action.decision !== undefined) { + if (action.decision.restaurantId === a) { + return -1; + } + if (action.decision.restaurantId === b) { + return 1; + } + } + const restaurantA = getRestaurantById({ restaurants: state }, a); + const restaurantB = getRestaurantById({ restaurants: state }, b); + + if (restaurantA.votes.length !== restaurantB.votes.length) { + return restaurantB.votes.length - restaurantA.votes.length; + } + if ( + restaurantA.all_decision_count !== restaurantB.all_decision_count + ) { + return ( + Number(restaurantA.all_decision_count) - + Number(restaurantB.all_decision_count) + ); + } + if (restaurantA.all_vote_count !== restaurantB.all_vote_count) { + return ( + Number(restaurantB.all_vote_count) - + Number(restaurantA.all_vote_count) + ); + } + // stable sort + return sortIndexes[a] - sortIndexes[b]; + } + ); + // If array contents match, return original (for shallow comparison) + if (sortedResult.some((r, i) => r !== draftState.items.result[i])) + draftState.items.result = sortedResult; + return; + } + case "INVALIDATE_RESTAURANTS": { + draftState.didInvalidate = true; + return; + } + case "RECEIVE_RESTAURANTS": { + draftState.isFetching = false; + draftState.didInvalidate = false; + draftState.items = normalize(action.items, [schemas.restaurant]); + return; + } + case "REQUEST_RESTAURANTS": + case "POST_RESTAURANT": + case "DELETE_RESTAURANT": + case "RENAME_RESTAURANT": + case "POST_VOTE": + case "DELETE_VOTE": + case "POST_NEW_TAG_TO_RESTAURANT": + case "POST_TAG_TO_RESTAURANT": + case "DELETE_TAG_FROM_RESTAURANT": { + draftState.isFetching = true; + return; + } + case "RESTAURANT_POSTED": { + draftState.isFetching = false; + draftState.items.entities.restaurants = { + ...draftState.items.entities.restaurants, + [action.restaurant.id]: action.restaurant, + }; + if (draftState.items.result.indexOf(action.restaurant.id) === -1) { + draftState.items.result.unshift(action.restaurant.id); + } + return; + } + case "RESTAURANT_DELETED": { + draftState.isFetching = false; + draftState.items.result.splice( + getRestaurantIds({ restaurants: draftState }).indexOf(action.id), + 1 + ); + return; + } + case "RESTAURANT_RENAMED": { + draftState.isFetching = false; + draftState.items.entities.restaurants = { + ...draftState.items.entities.restaurants, + [action.id]: { + ...draftState.items.entities.restaurants[action.id], + ...action.fields, + }, + }; + return; + } + case "VOTE_POSTED": { + draftState.isFetching = false; + draftState.items.entities.votes = { + ...draftState.items.entities.votes, + [action.vote.id]: action.vote, + }; + const r = + draftState.items.entities.restaurants[action.vote.restaurantId]; + if (r.votes.indexOf(action.vote.id) === -1) { + r.votes.push(action.vote.id); + r.all_vote_count = maybeAddToString(r.all_vote_count, 1); + } + return; + } + case "VOTE_DELETED": { + draftState.isFetching = false; + draftState.items.entities.restaurants[action.restaurantId].votes.splice( + getRestaurantById( + { restaurants: state }, + action.restaurantId + ).votes.indexOf(action.id), + 1 + ); + draftState.items.entities.restaurants[ + action.restaurantId + ].all_vote_count = maybeAddToString( + draftState.items.entities.restaurants[action.restaurantId] + .all_vote_count, + -1 + ); + return; + } + case "POSTED_NEW_TAG_TO_RESTAURANT": { + draftState.isFetching = false; + draftState.items.entities.restaurants[action.restaurantId].tags.push( + action.tag.id + ); + return; + } + case "POSTED_TAG_TO_RESTAURANT": { + draftState.isFetching = false; + if ( + state.items.entities.restaurants[action.restaurantId].tags.indexOf( + action.id + ) === -1 + ) { + draftState.items.entities.restaurants[action.restaurantId].tags.push( + action.id + ); + } + return; + } + case "DELETED_TAG_FROM_RESTAURANT": { + draftState.isFetching = false; + draftState.items.entities.restaurants[action.restaurantId].tags.splice( + getRestaurantById( + { restaurants: state }, + action.restaurantId + ).tags.indexOf(action.id), + 1 + ); + return; + } + case "TAG_DELETED": { + const { restaurants: r } = draftState.items.entities; + if (r) { + Object.keys(r).forEach((i) => { + const index = Number(i); + const changedRestaurant = r[index]; + if (changedRestaurant.tags.indexOf(action.id) > -1) { + draftState.items.entities.restaurants[index].tags.splice( + changedRestaurant.tags.indexOf(action.id), + 1 + ); + } + }); + } + return; + } + case "DECISION_POSTED": { + const decision = + draftState.items.entities.restaurants[action.decision.restaurantId]; + draftState.items.entities.restaurants[ + action.decision.restaurantId + ].all_decision_count = maybeAddToString(decision.all_decision_count, 1); + action.deselected.forEach((i) => { + const r = draftState.items.entities.restaurants[i.restaurantId]; + r.all_decision_count = maybeAddToString(r.all_decision_count, -1); + }); + return; + } + case "DECISIONS_DELETED": { + action.decisions.forEach((decision) => { + const r = + draftState.items.entities.restaurants[decision.restaurantId]; + r.all_decision_count = maybeAddToString(r.all_decision_count, -1); + }); + return; + } + case "SET_NAME_FILTER": { + draftState.nameFilter = action.val; + break; + } + default: + break; + } + }); + +export default restaurants; diff --git a/src/reducerMaps/tagExclusions.ts b/src/reducers/tagExclusions.ts similarity index 94% rename from src/reducerMaps/tagExclusions.ts rename to src/reducers/tagExclusions.ts index 6efee6017..a9d641ba0 100644 --- a/src/reducerMaps/tagExclusions.ts +++ b/src/reducers/tagExclusions.ts @@ -11,6 +11,8 @@ const tagExclusions: Reducer<"tagExclusions"> = (state, action) => { case "CLEAR_TAG_EXCLUSIONS": { return []; } + default: + break; } return state; }; diff --git a/src/reducerMaps/tagFilters.ts b/src/reducers/tagFilters.ts similarity index 93% rename from src/reducerMaps/tagFilters.ts rename to src/reducers/tagFilters.ts index 7c4050b8f..1b21a7ef2 100644 --- a/src/reducerMaps/tagFilters.ts +++ b/src/reducers/tagFilters.ts @@ -11,6 +11,8 @@ const tagFilters: Reducer<"tagFilters"> = (state, action) => { case "CLEAR_TAG_FILTERS": { return []; } + default: + break; } return state; }; diff --git a/src/reducers/tags.ts b/src/reducers/tags.ts new file mode 100644 index 000000000..793d3d847 --- /dev/null +++ b/src/reducers/tags.ts @@ -0,0 +1,64 @@ +import { normalize } from "normalizr"; +import { createNextState } from "@reduxjs/toolkit"; +import { getTagIds, getTagById } from "../selectors/tags"; +import * as schemas from "../schemas"; +import { Reducer } from "../interfaces"; +import maybeAddToString from "../helpers/maybeAddToString"; + +const tags: Reducer<"tags"> = (state, action) => + createNextState(state, (draftState) => { + switch (action.type) { + case "INVALIDATE_TAGS": { + draftState.didInvalidate = true; + return; + } + case "REQUEST_TAGS": + case "DELETE_TAG": { + draftState.isFetching = true; + return; + } + case "RECEIVE_TAGS": { + draftState.isFetching = false; + draftState.didInvalidate = false; + draftState.items = normalize(action.items, [schemas.tag]); + return; + } + case "POSTED_TAG_TO_RESTAURANT": { + draftState.items.entities.tags[action.id].restaurant_count = + maybeAddToString( + getTagById({ tags: draftState }, action.id).restaurant_count, + 1 + ); + return; + } + case "POSTED_NEW_TAG_TO_RESTAURANT": { + draftState.items.result.push(action.tag.id); + draftState.items.entities.tags = { + ...draftState.items.entities.tags, + [action.tag.id]: action.tag, + }; + return; + } + case "DELETED_TAG_FROM_RESTAURANT": { + draftState.isFetching = false; + draftState.items.entities.tags[action.id].restaurant_count = + maybeAddToString( + state.items.entities.tags[action.id].restaurant_count, + -1 + ); + return; + } + case "TAG_DELETED": { + draftState.isFetching = false; + const tagIndex = getTagIds({ tags: draftState }).indexOf(action.id); + if (tagIndex !== -1) { + draftState.items.result.splice(tagIndex, 1); + } + break; + } + default: + break; + } + }); + +export default tags; diff --git a/src/reducerMaps/team.ts b/src/reducers/team.ts similarity index 89% rename from src/reducerMaps/team.ts rename to src/reducers/team.ts index 3df8dfe4f..2c077a977 100644 --- a/src/reducerMaps/team.ts +++ b/src/reducers/team.ts @@ -5,6 +5,8 @@ const team: Reducer<"team"> = (state, action) => { case "TEAM_PATCHED": { return action.team; } + default: + break; } return state; }; diff --git a/src/reducers/teams.ts b/src/reducers/teams.ts new file mode 100644 index 000000000..d7873e5c0 --- /dev/null +++ b/src/reducers/teams.ts @@ -0,0 +1,34 @@ +import { createNextState } from "@reduxjs/toolkit"; +import { Reducer } from "../interfaces"; + +const teams: Reducer<"teams"> = (state, action) => + createNextState(state, (draftState) => { + switch (action.type) { + case "POST_TEAM": { + draftState.isFetching = true; + return; + } + case "TEAM_POSTED": { + draftState.isFetching = false; + draftState.items.result.push(action.team.id); + draftState.items.entities.teams = { + ...draftState.items.entities.teams, + [action.team.id]: action.team, + }; + return; + } + case "USER_DELETED": { + if (action.isSelf) { + draftState.items.result.splice( + state.items.result.indexOf(action.team.id), + 1 + ); + } + break; + } + default: + break; + } + }); + +export default teams; diff --git a/src/reducerMaps/tests/restaurants.test.ts b/src/reducers/tests/restaurants.test.ts similarity index 98% rename from src/reducerMaps/tests/restaurants.test.ts rename to src/reducers/tests/restaurants.test.ts index f098ee79a..db6c0240f 100644 --- a/src/reducerMaps/tests/restaurants.test.ts +++ b/src/reducers/tests/restaurants.test.ts @@ -4,7 +4,7 @@ import { expect } from "chai"; import { Decision, Restaurant, State, User } from "../../interfaces"; import restaurants from "../restaurants"; -describe("reducerMaps/restaurants", () => { +describe("reducers/restaurants", () => { let beforeState: State["restaurants"]; let afterState: State["restaurants"]; diff --git a/src/reducerMaps/tests/teams.test.ts b/src/reducers/tests/teams.test.ts similarity index 97% rename from src/reducerMaps/tests/teams.test.ts rename to src/reducers/tests/teams.test.ts index 7e968b881..49dcdc6f5 100644 --- a/src/reducerMaps/tests/teams.test.ts +++ b/src/reducers/tests/teams.test.ts @@ -5,7 +5,7 @@ import { expect } from "chai"; import { State, Team } from "../../interfaces"; import teams from "../teams"; -describe("reducerMaps/teams", () => { +describe("reducers/teams", () => { describe("USER_DELETED", () => { let beforeState: State["teams"]; let afterState: State["teams"]; diff --git a/src/reducerMaps/tests/user.test.ts b/src/reducers/tests/user.test.ts similarity index 99% rename from src/reducerMaps/tests/user.test.ts rename to src/reducers/tests/user.test.ts index 704efae56..362c51492 100644 --- a/src/reducerMaps/tests/user.test.ts +++ b/src/reducers/tests/user.test.ts @@ -5,7 +5,7 @@ import { expect } from "chai"; import { State, Team, User } from "../../interfaces"; import users from "../user"; -describe("reducerMaps/user", () => { +describe("reducers/user", () => { let beforeState: State["user"]; let afterState: State["user"]; diff --git a/src/reducerMaps/tests/users.test.ts b/src/reducers/tests/users.test.ts similarity index 96% rename from src/reducerMaps/tests/users.test.ts rename to src/reducers/tests/users.test.ts index 71085083e..122a6c74b 100644 --- a/src/reducerMaps/tests/users.test.ts +++ b/src/reducers/tests/users.test.ts @@ -5,7 +5,7 @@ import { expect } from "chai"; import { State, Team, User } from "../../interfaces"; import users from "../users"; -describe("reducerMaps/users", () => { +describe("reducers/users", () => { let beforeState: State["users"]; let afterState: State["users"]; diff --git a/src/reducers/user.ts b/src/reducers/user.ts new file mode 100644 index 000000000..85a6f3df6 --- /dev/null +++ b/src/reducers/user.ts @@ -0,0 +1,55 @@ +/* eslint-disable consistent-return */ +import { createNextState } from "@reduxjs/toolkit"; +import { Reducer, User } from "../interfaces"; + +const user: Reducer<"user"> = (state, action) => + createNextState(state, (draftState) => { + switch (action.type) { + case "TEAM_POSTED": { + if (action.team.roles) { + action.team.roles.forEach((role) => { + if (draftState && role.userId === draftState.id) { + draftState.roles.push(role); + } + }); + } + return; + } + case "USER_DELETED": { + if (draftState && action.isSelf) { + draftState.roles.splice( + draftState.roles.map((role) => role.teamId).indexOf(action.team.id), + 1 + ); + } + return; + } + case "USER_PATCHED": { + if (draftState && action.isSelf) { + return { + ...draftState, + ...action.user, + roles: draftState.roles.map((role) => { + if (role.teamId === action.team.id) { + return { + ...role, + type: action.user.type, + }; + } + return role; + }), + type: undefined, + } as User; + } + return; + } + case "CURRENT_USER_PATCHED": { + return action.user; + } + default: { + break; + } + } + }); + +export default user; diff --git a/src/reducers/users.ts b/src/reducers/users.ts new file mode 100644 index 000000000..14a298277 --- /dev/null +++ b/src/reducers/users.ts @@ -0,0 +1,56 @@ +import { normalize } from "normalizr"; +import { createNextState } from "@reduxjs/toolkit"; +import { getUserIds } from "../selectors/users"; +import * as schemas from "../schemas"; +import { Reducer, State } from "../interfaces"; + +const users: Reducer<"users"> = (state, action) => + createNextState(state, (draftState) => { + switch (action.type) { + case "INVALIDATE_USERS": { + draftState.didInvalidate = true; + return; + } + case "REQUEST_USERS": + case "DELETE_USER": + case "POST_USER": + case "PATCH_USER": { + draftState.isFetching = true; + return; + } + case "RECEIVE_USERS": { + draftState.isFetching = false; + draftState.didInvalidate = false; + draftState.items = normalize(action.items, [schemas.user]); + return; + } + case "USER_DELETED": { + draftState.isFetching = false; + draftState.items.result.splice( + getUserIds({ users: draftState } as State).indexOf(action.id), + 1 + ); + return; + } + case "USER_POSTED": { + draftState.items.result.push(action.user.id); + draftState.items.entities.users = { + ...draftState.items.entities.users, + [action.user.id]: action.user, + }; + return; + } + case "USER_PATCHED": { + draftState.isFetching = false; + draftState.items.entities.users[action.id] = { + ...draftState.items.entities.users[action.id], + ...action.user, + }; + break; + } + default: + break; + } + }); + +export default users; diff --git a/src/store/configureStore.ts b/src/store/configureStore.ts index 6694180ef..0a4a2302b 100644 --- a/src/store/configureStore.ts +++ b/src/store/configureStore.ts @@ -4,7 +4,7 @@ import { configureStore as reduxConfigureStore, } from "@reduxjs/toolkit"; import * as schemas from "../schemas"; -import * as reducerMaps from "../reducerMaps"; +import * as reducers from "../reducers"; import createHelpers from "./createHelpers"; import { Action, @@ -24,17 +24,17 @@ const generateReducers = ( newReducers: { [key in T]: Reducer }, normalizedInitialState: State ) => { - const reducers: Partial<{ [key in T]: Reducer }> = {}; + const rs: Partial<{ [key in T]: Reducer }> = {}; let name: T; for (name in newReducers) { - reducers[name] = generateReducer( + rs[name] = generateReducer( newReducers[name], normalizedInitialState[name] ); } - return reducers; + return rs; }; // Add the reducer to your store on the `routing` key @@ -60,12 +60,12 @@ export default function configureStore( normalizedInitialState.restaurants.items.entities.votes = normalizedInitialState.restaurants.items.entities.votes || {}; - const reducers = generateReducers(reducerMaps, normalizedInitialState); + const allReducers = generateReducers(reducers, normalizedInitialState); const helpers = createHelpers(helpersConfig); const store = reduxConfigureStore({ - reducer: combineReducers(reducers), + reducer: combineReducers(allReducers), middleware: (getDefaultMiddleware) => getDefaultMiddleware({ thunk: { @@ -76,14 +76,14 @@ export default function configureStore( // Hot reload reducers (requires Webpack or Browserify HMR to be enabled) if (__DEV__ && module.hot) { - module.hot.accept("../reducerMaps", () => { - // eslint-disable-next-line global-require - const newReducerMaps = require("../reducerMaps"); - const newReducers = generateReducers( - newReducerMaps, + module.hot.accept("../reducers", () => { + // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires + const newReducers = require("../reducers"); + const newAllReducers = generateReducers( + newReducers, normalizedInitialState ); - return store.replaceReducer(combineReducers(newReducers)); + return store.replaceReducer(combineReducers(newAllReducers)); }); } diff --git a/yarn.lock b/yarn.lock index 8f144e7c3..585aaab22 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7724,13 +7724,6 @@ __metadata: languageName: node linkType: hard -"immutability-helper@npm:^3.1.1": - version: 3.1.1 - resolution: "immutability-helper@npm:3.1.1" - checksum: 6fdbf6d2123efa567263e904bbaff07aca0e24560d270d34967b03aab8ec20bd3e4057f394d59e50eb6c4718c9415591a6281692bb0aafd522ad72cf4887133f - languageName: node - linkType: hard - "immutable@npm:^3": version: 3.8.2 resolution: "immutable@npm:3.8.2" @@ -9324,7 +9317,6 @@ __metadata: google-map-react: ^2.2.0 history: ^5.3.0 husky: ^8.0.3 - immutability-helper: ^3.1.1 isomorphic-style-loader: ^5.3.2 jsdom: ^22.0.0 jsonwebtoken: ^9.0.0 From b16aaaca005e94c4fd5ac586e5f99891d7d1792c Mon Sep 17 00:00:00 2001 From: Jeffrey Carl Faden Date: Tue, 20 Jun 2023 11:22:33 -0700 Subject: [PATCH 8/8] Silence Redux warnings by not storing functions in the state --- src/actions/index.ts | 22 +++++++++++++ src/actions/modals.ts | 6 +++- src/actions/restaurants.ts | 2 +- src/actions/users.ts | 4 +-- .../ConfirmModal/ConfirmModalContainer.ts | 26 +++++++++------ .../PastDecisionsModalContainer.ts | 9 ++++-- .../RestaurantDropdownContainer.ts | 3 +- .../TagManagerItem/TagManagerItemContainer.ts | 8 ++--- src/interfaces.ts | 32 +++++++++++-------- src/routes/main/teams/Teams.tsx | 15 +++++---- src/routes/main/teams/TeamsContainer.ts | 17 +++------- src/routes/team/team/Team.tsx | 14 ++++---- src/routes/team/team/TeamContainer.ts | 3 +- 13 files changed, 100 insertions(+), 61 deletions(-) create mode 100644 src/actions/index.ts diff --git a/src/actions/index.ts b/src/actions/index.ts new file mode 100644 index 000000000..2c67d5deb --- /dev/null +++ b/src/actions/index.ts @@ -0,0 +1,22 @@ +import { ThunkAction } from "@reduxjs/toolkit"; +import { Action, State } from "../interfaces"; +import { removeRestaurant } from "./restaurants"; +import { removeTag } from "./tags"; +import { changeUserRole, removeUser } from "./users"; + +const generateConfirmableActions = < + T extends { + [K in keyof T]: ( + ...args: Parameters + ) => ThunkAction, State, unknown, Action>; + } +>( + actions: T +) => actions; + +export const confirmableActions = generateConfirmableActions({ + changeUserRole, + removeRestaurant, + removeTag, + removeUser, +}); diff --git a/src/actions/modals.ts b/src/actions/modals.ts index 8ac4675c7..0346c7399 100644 --- a/src/actions/modals.ts +++ b/src/actions/modals.ts @@ -1,3 +1,4 @@ +import { confirmableActions } from "."; import { Action, ConfirmOpts, PastDecisionsOpts } from "../interfaces"; export function showModal(name: string): Action; @@ -5,7 +6,10 @@ export function showModal( name: "pastDecisions", opts?: PastDecisionsOpts ): Action; -export function showModal(name: "confirm", opts?: ConfirmOpts): Action; +export function showModal( + name: "confirm", + opts?: ConfirmOpts +): Action; export function showModal(name: unknown, opts?: unknown): unknown { return { diff --git a/src/actions/restaurants.ts b/src/actions/restaurants.ts index d5eab3d42..4abef9db5 100644 --- a/src/actions/restaurants.ts +++ b/src/actions/restaurants.ts @@ -274,7 +274,7 @@ export function addRestaurant( export function removeRestaurant( id: number -): ThunkAction, State, unknown, Action> { +): ThunkAction, State, unknown, Action> { return (dispatch) => { dispatch(deleteRestaurant(id)); return fetch(`/api/restaurants/${id}`, { diff --git a/src/actions/users.ts b/src/actions/users.ts index aa3c56f88..fecc4c14d 100644 --- a/src/actions/users.ts +++ b/src/actions/users.ts @@ -93,7 +93,7 @@ export function userDeleted(id: number, team: Team, isSelf: boolean): Action { export function removeUser( id: number, team: Team -): ThunkAction { +): ThunkAction, State, unknown, Action> { return (dispatch, getState) => { const state = getState(); let isSelf = false; @@ -182,7 +182,7 @@ export function userPatched( export function changeUserRole( id: number, type: RoleType -): ThunkAction { +): ThunkAction, State, unknown, Action> { const payload = { id, type }; return (dispatch, getState) => { const state = getState(); diff --git a/src/components/ConfirmModal/ConfirmModalContainer.ts b/src/components/ConfirmModal/ConfirmModalContainer.ts index b548c9f7f..1a9abffdc 100644 --- a/src/components/ConfirmModal/ConfirmModalContainer.ts +++ b/src/components/ConfirmModal/ConfirmModalContainer.ts @@ -1,30 +1,36 @@ import { connect } from "react-redux"; +import { confirmableActions } from "../../actions"; import { hideModal } from "../../actions/modals"; import ConfirmModal from "./ConfirmModal"; -import { Dispatch, State } from "../../interfaces"; +import { + ConfirmModal as ConfirmModalType, + Dispatch, + State, +} from "../../interfaces"; const modalName = "confirm"; -const mapStateToProps = (state: State) => ({ - actionLabel: state.modals[modalName].actionLabel!, - body: state.modals[modalName].body, - action: state.modals[modalName].action, - shown: !!state.modals[modalName].shown, -}); +const mapStateToProps = ( + state: State +) => state.modals[modalName] as ConfirmModalType; const mapDispatchToProps = (dispatch: Dispatch) => ({ dispatch, hideModal: () => dispatch(hideModal("confirm")), }); -const mergeProps = ( - stateProps: ReturnType, +const mergeProps = ( + stateProps: ConfirmModalType, dispatchProps: ReturnType ) => ({ ...stateProps, ...dispatchProps, handleSubmit: () => { - dispatchProps.dispatch(stateProps.action!); + dispatchProps.dispatch( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + confirmableActions[stateProps.action](...stateProps.actionArgs) + ); dispatchProps.hideModal(); }, }); diff --git a/src/components/PastDecisionsModal/PastDecisionsModalContainer.ts b/src/components/PastDecisionsModal/PastDecisionsModalContainer.ts index 5a6997f45..b9c3a9e52 100644 --- a/src/components/PastDecisionsModal/PastDecisionsModalContainer.ts +++ b/src/components/PastDecisionsModal/PastDecisionsModalContainer.ts @@ -1,7 +1,11 @@ import { connect } from "react-redux"; import { decide } from "../../actions/decisions"; import { hideModal } from "../../actions/modals"; -import { Dispatch, State } from "../../interfaces"; +import { + Dispatch, + State, + PastDecisionsModal as PastDecisionsModalType, +} from "../../interfaces"; import { getDecisionsByDay } from "../../selectors/decisions"; import { getRestaurantEntities } from "../../selectors/restaurants"; import PastDecisionsModal from "./PastDecisionsModal"; @@ -10,7 +14,8 @@ const modalName = "pastDecisions"; const mapStateToProps = (state: State) => ({ decisionsByDay: getDecisionsByDay(state), - restaurantId: state.modals[modalName].restaurantId, + restaurantId: (state.modals[modalName] as PastDecisionsModalType) + .restaurantId, restaurantEntities: getRestaurantEntities(state), shown: !!state.modals[modalName].shown, }); diff --git a/src/components/RestaurantDropdown/RestaurantDropdownContainer.ts b/src/components/RestaurantDropdown/RestaurantDropdownContainer.ts index daea85225..f72f82066 100644 --- a/src/components/RestaurantDropdown/RestaurantDropdownContainer.ts +++ b/src/components/RestaurantDropdown/RestaurantDropdownContainer.ts @@ -56,7 +56,8 @@ const mergeProps = ( showModal("confirm", { actionLabel: "Delete", body: `Are you sure you want to delete ${stateProps.restaurant.name}?`, - action: removeRestaurant(ownProps.id), + action: "removeRestaurant", + actionArgs: [ownProps.id], }) ), showEditNameForm: () => { diff --git a/src/components/TagManagerItem/TagManagerItemContainer.ts b/src/components/TagManagerItem/TagManagerItemContainer.ts index 578a32059..885bbd492 100644 --- a/src/components/TagManagerItem/TagManagerItemContainer.ts +++ b/src/components/TagManagerItem/TagManagerItemContainer.ts @@ -1,8 +1,7 @@ import { connect } from "react-redux"; import { getTagById } from "../../selectors/tags"; import { showModal } from "../../actions/modals"; -import { removeTag } from "../../actions/tags"; -import { Dispatch, State } from "../../interfaces"; +import { ConfirmOpts, Dispatch, State } from "../../interfaces"; import TagManagerItem from "./TagManagerItem"; interface OwnProps { @@ -28,11 +27,12 @@ const mergeProps = ( handleDeleteClicked() { dispatchProps.dispatch( showModal("confirm", { + action: "removeTag", + actionArgs: [ownProps.id], actionLabel: "Delete", body: `Are you sure you want to delete the “${stateProps.tag.name}” tag? All restaurants will be untagged.`, - action: removeTag(ownProps.id), - }) + } as ConfirmOpts<"removeTag">) ); }, }); diff --git a/src/interfaces.ts b/src/interfaces.ts index 93b4a055d..0e54a6852 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -1,10 +1,11 @@ import { Application, RequestHandler } from "express"; -import { EnhancedStore, ThunkAction, ThunkDispatch } from "@reduxjs/toolkit"; +import { EnhancedStore, ThunkDispatch } from "@reduxjs/toolkit"; import { BrowserHistory } from "history"; import { InsertCSS } from "isomorphic-style-loader/StyleContext"; import { ReactNode } from "react"; import { ResolveContext } from "universal-router"; import { WebSocket } from "ws"; +import { confirmableActions } from "./actions"; import { Decision as DecisionModel, Restaurant as RestaurantModel, @@ -387,7 +388,7 @@ export type Action = | { type: "SHOW_MODAL"; name: "confirm"; - opts: ConfirmOpts; + opts: ConfirmOpts; } | { type: "SHOW_MODAL"; @@ -451,12 +452,25 @@ export interface Notification { ); } -export type ConfirmOpts = { +export type ConfirmOpts = { actionLabel: string; body: string; - action: Action | ThunkAction; + action: T; + actionArgs: Parameters<(typeof confirmableActions)[T]>; }; +export type BaseModal = { + shown: boolean; +}; + +export type ConfirmModal = + BaseModal & ConfirmOpts; +export type PastDecisionsModal = BaseModal & PastDecisionsOpts; +export type Modal = + | BaseModal + | ConfirmModal + | PastDecisionsModal; + export interface ListUiItem { isEditingName?: boolean; editNameFormValue?: string; @@ -489,15 +503,7 @@ interface BaseState { host: string; notifications: Notification[]; modals: { - [index: string]: { - action?: - | Action - | ThunkAction | void, State, unknown, Action>; - actionLabel?: string; - body?: ReactNode; - restaurantId?: number; - shown: boolean; - }; + [index: string]: Modal; }; listUi: { [index: number]: ListUiItem; diff --git a/src/routes/main/teams/Teams.tsx b/src/routes/main/teams/Teams.tsx index fd7d03e89..9efa8901e 100644 --- a/src/routes/main/teams/Teams.tsx +++ b/src/routes/main/teams/Teams.tsx @@ -5,29 +5,30 @@ import ListGroup from "react-bootstrap/ListGroup"; import { FaTimes } from "react-icons/fa"; import Container from "react-bootstrap/Container"; import Link from "../../../components/Link/Link"; -import { ConfirmOpts, Team } from "../../../interfaces"; +import { ConfirmOpts, Team, User } from "../../../interfaces"; import s from "./Teams.scss"; interface TeamsProps { - confirm: (props: ConfirmOpts) => void; + confirm: (props: ConfirmOpts<"removeUser">) => void; host: string; - leaveTeam: (team: Team) => () => void; teams: Team[]; + user: User; } class Teams extends Component { - confirmLeave = (team: Team) => (event: MouseEvent) => { + confirmLeave = (user: User, team: Team) => (event: MouseEvent) => { event.preventDefault(); this.props.confirm({ actionLabel: "Leave", body: `Are you sure you want to leave this team? You will need to be invited back by another member.`, - action: this.props.leaveTeam(team), + action: "removeUser", + actionArgs: [user.id, team], }); }; render() { - const { host, teams } = this.props; + const { host, teams, user } = this.props; return (
@@ -46,7 +47,7 @@ You will need to be invited back by another member.`,
{team.name}