Skip to content

Commit

Permalink
Merge pull request #278 from hodcroftlab/refactor/change-redux-to-recoil
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-aksamentov committed Feb 22, 2022
2 parents 30f2032 + 0c3fda8 commit 55e9567
Show file tree
Hide file tree
Showing 25 changed files with 76 additions and 1,003 deletions.
7 changes: 0 additions & 7 deletions web/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ module.exports = {
'plugin:jsx-a11y/recommended',
'plugin:lodash/recommended',
'plugin:promise/recommended',
'plugin:react-redux/recommended',
'plugin:react/recommended',
'plugin:redux-saga/recommended',
'plugin:security/recommended',
'plugin:sonarjs/recommended',
'plugin:unicorn/recommended',
Expand All @@ -55,8 +53,6 @@ module.exports = {
'promise',
'react',
'react-hooks',
'react-redux',
'redux-saga',
'security',
'sonarjs',
'unicorn',
Expand Down Expand Up @@ -112,16 +108,13 @@ module.exports = {
'only-ascii/only-ascii': 'warn',
'prefer-for-of': 'off',
'prettier/prettier': 'warn',
'react-redux/no-unused-prop-types': 'off',
'react-redux/prefer-separate-component-file': 'off',
'react/jsx-curly-brace-presence': 'off',
'react/jsx-filename-extension': ['warn', { extensions: ['.js', '.jsx', '.ts', '.tsx'] }],
'react/jsx-props-no-spreading': 'off',
'react/no-unused-prop-types': 'off',
'react/prop-types': 'off',
'react/require-default-props': 'off',
'react/state-in-constructor': 'off',
'redux-saga/no-unhandled-errors': 'off',
'security/detect-non-literal-fs-filename': 'off',
'security/detect-object-injection': 'off',
'sonarjs/cognitive-complexity': ['warn', 20],
Expand Down
Empty file.
8 changes: 0 additions & 8 deletions web/3rdparty/__empty-module/package.json

This file was deleted.

2 changes: 0 additions & 2 deletions web/config/next/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,6 @@ const transpilationListProd = uniq([
'react-router',
'react-share',
'recharts',
'redux-saga',
'redux/es',
'semver',
'split-on-first',
'strict-uri-encode',
Expand Down
21 changes: 1 addition & 20 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@
"bootstrap": "4.5.2",
"bootstrap-icons": "1.2.2",
"classnames": "2.2.6",
"connected-next-router": "3.1.0",
"core-js": "3.6.5",
"country-flag-icons": "1.2.10",
"css.escape": "1.5.1",
Expand Down Expand Up @@ -97,19 +96,13 @@
"react-loader-spinner": "3.1.14",
"react-query": "3.17.2",
"react-reactstrap-pagination": "2.0.3",
"react-redux": "7.2.1",
"react-resize-detector": "6.7.0",
"react-select": "4.0.2",
"react-share": "4.3.1",
"react-super-responsive-table": "5.2.0",
"react-toggle": "4.1.1",
"reactstrap": "8.5.1",
"recharts": "2.0.9",
"redux": "4.0.5",
"redux-logger": "3.0.6",
"redux-saga": "1.1.3",
"redux-saga-test-plan": "4.0.0-rc.3",
"redux-thunk": "2.3.0",
"reflect-metadata": "0.1.13",
"regenerator-runtime": "0.13.7",
"reselect": "4.0.0",
Expand Down Expand Up @@ -170,12 +163,9 @@
"@types/react-dom": "16.9.8",
"@types/react-helmet": "6.1.0",
"@types/react-loader-spinner": "3.1.3",
"@types/react-redux": "7.1.9",
"@types/react-select": "4.0.11",
"@types/react-toggle": "4.0.2",
"@types/reactstrap": "8.5.1",
"@types/redux-logger": "3.0.8",
"@types/redux-testkit": "1.0.5",
"@types/rimraf": "3.0.0",
"@types/semver": "7.3.3",
"@types/serialize-javascript": "5.0.0",
Expand All @@ -193,7 +183,6 @@
"babel-plugin-lodash": "3.3.4",
"babel-plugin-module-resolver": "4.0.0",
"babel-plugin-parameter-decorator": "1.0.16",
"babel-plugin-redux-saga": "1.1.2",
"babel-plugin-smart-webpack-import": "1.7.0",
"babel-plugin-strip-function-call": "1.0.2",
"babel-plugin-styled-components": "1.11.1",
Expand Down Expand Up @@ -234,8 +223,6 @@
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-react": "7.20.6",
"eslint-plugin-react-hooks": "4.1.0",
"eslint-plugin-react-redux": "3.2.0",
"eslint-plugin-redux-saga": "1.1.3",
"eslint-plugin-security": "1.4.0",
"eslint-plugin-sonarjs": "0.5.0",
"eslint-plugin-unicorn": "21.0.0",
Expand Down Expand Up @@ -270,9 +257,7 @@
"postcss-preset-env": "6.7.0",
"prettier": "2.1.1",
"raw-loader": "4.0.1",
"redux-devtools-extension": "2.13.8",
"redux-immutable-state-invariant": "2.1.0",
"redux-testkit": "1.0.6",
"recoil": "0.6.1",
"remark-autolink-headings": "6.0.1",
"remark-breaks": "2.0.1",
"remark-images": "2.0.0",
Expand All @@ -290,7 +275,6 @@
"ts-essentials": "7.0.0",
"ts-jest": "26.3.0",
"ts-node": "9.0.0",
"typed-redux-saga": "1.2.0",
"typescript": "4.0.2",
"url-loader": "4.1.0",
"utility-types": "3.10.0",
Expand Down Expand Up @@ -318,7 +302,6 @@
"babel-jest": "26.3.0",
"babel-plugin-lodash": "3.3.4",
"babel-plugin-module-resolver": "4.0.0",
"babel-plugin-redux-saga": "1.1.2",
"babel-plugin-smart-webpack-import": "1.7.0",
"babel-plugin-styled-components": "1.11.1",
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
Expand All @@ -336,8 +319,6 @@
"react": "16.13.1",
"react-dom": "16.13.1",
"react-error-boundary": "2.2.3",
"react-redux": "7.2.1",
"redux": "4.0.5",
"reflect-metadata": "0.1.13",
"style-loader": "2.0.0",
"styled-components": "5.1.1",
Expand Down
36 changes: 19 additions & 17 deletions web/src/components/ClusterDistribution/ClusterDistributionPage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useCallback, useMemo, useState } from 'react'

import { mapValues, pickBy } from 'lodash'
import { useDispatch, useSelector } from 'react-redux'
import { Card, CardBody, Col, Form, FormGroup, Input, Label, Row } from 'reactstrap'
import { useRecoilState } from 'recoil'
import { tooltipSortAtom, TooltipSortCriterion } from 'src/state/TooltipSort'
import styled from 'styled-components'

import { ClusterState, toggleCluster } from 'src/io/getPerCountryData'
Expand All @@ -25,9 +26,6 @@ import {
toggleCountry,
} from 'src/io/getPlaces'
import PerClusterIntro from 'src/../../content/PerClusterIntro.md'
import { setPerCountryTooltipSortBy, setPerCountryTooltipSortReversed } from 'src/state/ui/ui.actions'
import { PerCountryTooltipSortBy } from 'src/state/ui/ui.reducer'
import { selectPerCountryTooltipSortBy, selectPerCountryTooltipSortReversed } from 'src/state/ui/ui.selectors'

const Dropdown = styled(DropdownBase)`
min-width: 130px;
Expand Down Expand Up @@ -65,15 +63,15 @@ export function filterCountries(places: Places, withClustersFiltered: ClusterDis
const enabledFilters = ['countries', 'clusters']

export interface SortByDropdownProps {
perCountryTooltipSortBy: PerCountryTooltipSortBy
onSortByChange(perCountryTooltipSortBy: PerCountryTooltipSortBy): void
perCountryTooltipSortBy: TooltipSortCriterion
onSortByChange(perCountryTooltipSortBy: TooltipSortCriterion): void
}

const sortByOptions = Object.entries(PerCountryTooltipSortBy).map(([key, value]) => ({ value, label: key }))
const sortByOptions = Object.entries(TooltipSortCriterion).map(([key, value]) => ({ value, label: key }))

export function SortByDropdown({ perCountryTooltipSortBy, onSortByChange }: SortByDropdownProps) {
const handleSortByChange = useCallback(
({ value }) => onSortByChange(PerCountryTooltipSortBy[value as keyof typeof PerCountryTooltipSortBy]),
({ value }) => onSortByChange(TooltipSortCriterion[value as keyof typeof TooltipSortCriterion]),
[onSortByChange],
)

Expand Down Expand Up @@ -119,26 +117,30 @@ const StickyRow = styled(Row)`
`

export function ClusterDistributionPage() {
const perCountryTooltipSortBy = useSelector(selectPerCountryTooltipSortBy)
const perCountryTooltipSortReversed = useSelector(selectPerCountryTooltipSortReversed)
const [tooltipSort, setTooltipSort] = useRecoilState(tooltipSortAtom)

const perCountryTooltipSortBy = tooltipSort.criterion
const perCountryTooltipSortReversed = tooltipSort.reversed

const {
places: initialPlaces,
clusters: initialClusters,
clusterBuildNames,
clusterDistributions,
} = getPerClusterData()

const dispatch = useDispatch()
const setSortBy = useCallback(
(perCountryTooltipSortBy: PerCountryTooltipSortBy) =>
dispatch(setPerCountryTooltipSortBy({ perCountryTooltipSortBy })),
[dispatch],
(criterion: TooltipSortCriterion) => {
setTooltipSort((tooltipSort) => ({ ...tooltipSort, criterion }))
},
[setTooltipSort],
)

const setSortReversed = useCallback(
(perCountryTooltipSortReversed: boolean) =>
dispatch(setPerCountryTooltipSortReversed({ perCountryTooltipSortReversed })),
[dispatch],
(reversed: boolean) => {
setTooltipSort((tooltipSort) => ({ ...tooltipSort, reversed }))
},
[setTooltipSort],
)

const [clusters, setClusters] = useState<ClusterState>(initialClusters)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react'

import { get, sortBy, reverse, uniqBy } from 'lodash'
import { useSelector } from 'react-redux'
import { useRecoilValue } from 'recoil'
import { ColoredHorizontalLineIcon } from 'src/components/Common/ColoredHorizontalLineIcon'
import { tooltipSortAtom } from 'src/state/TooltipSort'
import { theme } from 'src/theme'
import styled from 'styled-components'

import type { Props as DefaultTooltipContentProps } from 'recharts/types/component/DefaultTooltipContent'
import { selectPerCountryTooltipSortBy, selectPerCountryTooltipSortReversed } from 'src/state/ui/ui.selectors'
import { formatDateWeekly, formatProportion } from 'src/helpers/format'
import { getCountryColor, getCountryStrokeDashArray } from 'src/io/getCountryColor'

Expand Down Expand Up @@ -51,8 +51,7 @@ const TooltipTableBody = styled.tbody``
export type ClusterDistributionPlotTooltipProps = DefaultTooltipContentProps<number, string>

export function ClusterDistributionPlotTooltip(props: ClusterDistributionPlotTooltipProps) {
const perCountryTooltipSortBy = useSelector(selectPerCountryTooltipSortBy)
const perCountryTooltipSortReversed = useSelector(selectPerCountryTooltipSortReversed)
const { criterion, reversed } = useRecoilValue(tooltipSortAtom)

const { payload } = props
if (!payload || payload.length === 0) {
Expand All @@ -69,14 +68,11 @@ export function ClusterDistributionPlotTooltip(props: ClusterDistributionPlotToo
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const week = formatDateWeekly(data?.week)

let payloadSorted = sortBy(payload, perCountryTooltipSortBy === 'country' ? 'name' : 'value')
let payloadSorted = sortBy(payload, criterion === 'country' ? 'name' : 'value')

// sortBy sorts in ascending order, but if sorting by frequency the natural/non-reversed order is descending

if (
(perCountryTooltipSortBy !== 'frequency' && perCountryTooltipSortReversed) ||
(perCountryTooltipSortBy === 'frequency' && !perCountryTooltipSortReversed)
) {
if ((criterion !== 'frequency' && reversed) || (criterion === 'frequency' && !reversed)) {
payloadSorted = reverse(payloadSorted)
}

Expand Down
20 changes: 3 additions & 17 deletions web/src/components/Layout/NavigationBar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useRouter } from 'next/router'
import React, { useState } from 'react'

import { connect } from 'react-redux'
import styled from 'styled-components'
import {
Collapse,
Expand All @@ -20,9 +20,6 @@ import { Link } from 'src/components/Link/Link'
import { LinkExternal } from 'src/components/Link/LinkExternal'
import { TWITTER_USERNAME_RAW, URL_GITHUB } from 'src/constants'

import { State } from 'src/state/reducer'
import { selectPathname } from 'src/state/router/router.selectors'

let navLinksLeft: Record<string, string> = {
'/': 'Home',
'/faq': 'FAQ',
Expand Down Expand Up @@ -141,19 +138,8 @@ export const BrandLogoLarge = styled(BrandLogoLargeBase)`
margin: 7px 10px 10px;
`

export interface NavigationBarProps {
pathname: string
}

const mapStateToProps = (state: State) => ({
pathname: selectPathname(state),
})

const mapDispatchToProps = {}

export const NavigationBar = connect(mapStateToProps, mapDispatchToProps)(NavigationBarDisconnected)

export function NavigationBarDisconnected({ pathname }: NavigationBarProps) {
export function NavigationBar() {
const { pathname } = useRouter()
const [isOpen, setIsOpen] = useState(false)
const toggle = () => setIsOpen(!isOpen)

Expand Down
38 changes: 14 additions & 24 deletions web/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,14 @@ import 'resize-observer-polyfill/dist/ResizeObserver.global'

import 'css.escape'

import 'map.prototype.tojson' // to visualize Map in Redux Dev Tools
import 'set.prototype.tojson' // to visualize Set in Redux Dev Tools
import 'src/helpers/errorPrototypeTojson' // to visualize Error in Redux Dev Tools
import 'src/helpers/functionPrototypeTojson' // to visualize Function in Redux Dev Tools

import { enableES5 } from 'immer'
import dynamic from 'next/dynamic'
import React, { useMemo } from 'react'
import { QueryClient, QueryClientProvider } from 'react-query'
import { RecoilRoot } from 'recoil'
import { ReactQueryDevtools } from 'react-query/devtools'

import type { AppProps } from 'next/app'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'connected-next-router'
import { ThemeProvider } from 'styled-components'
import { MDXProvider } from '@mdx-js/react'

Expand All @@ -25,32 +19,28 @@ import { DOMAIN_STRIPPED } from 'src/constants'
import { Plausible } from 'src/components/Common/Plausible'
import { SeoApp } from 'src/components/Common/SeoApp'

import { configureStore } from 'src/state/store'
import { mdxComponents } from 'src/components/Common/MdxComponents'

import 'src/styles/global.scss'

enableES5()

function MyApp({ Component, pageProps, router }: AppProps) {
const store = useMemo(() => configureStore({ router }), [router])
function MyApp({ Component, pageProps }: AppProps) {
const queryClient = useMemo(() => new QueryClient(), [])

return (
<Provider store={store}>
<ConnectedRouter>
<ThemeProvider theme={theme}>
<MDXProvider components={(components) => ({ ...components, ...mdxComponents })}>
<Plausible domain={DOMAIN_STRIPPED} />
<SeoApp />
<QueryClientProvider client={queryClient}>
<Component {...pageProps} />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</MDXProvider>
</ThemeProvider>
</ConnectedRouter>
</Provider>
<RecoilRoot>
<ThemeProvider theme={theme}>
<MDXProvider components={(components) => ({ ...components, ...mdxComponents })}>
<Plausible domain={DOMAIN_STRIPPED} />
<SeoApp />
<QueryClientProvider client={queryClient}>
<Component {...pageProps} />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</MDXProvider>
</ThemeProvider>
</RecoilRoot>
)
}

Expand Down
14 changes: 14 additions & 0 deletions web/src/state/TooltipSort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { atom } from 'recoil'

export enum TooltipSortCriterion {
country = 'country',
frequency = 'frequency',
}

export const tooltipSortAtom = atom({
key: 'TooltipSort',
default: {
criterion: TooltipSortCriterion.frequency,
reversed: false,
},
})

0 comments on commit 55e9567

Please sign in to comment.