From c39bbb5190e164c382f0521868b19da7d9a9c13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Nunes?= Date: Mon, 22 Jul 2024 07:39:24 +0100 Subject: [PATCH 001/142] refactor: remix migration --- docs/remix.md | 26 + index.html | 2 +- package.json | 9 + packages/components/.storybook/preview.tsx | 9 +- .../src/Breadcrumbs/BreadcrumbsItem.tsx | 2 +- .../src/CreateComment/CreateComment.tsx | 2 +- .../src/FollowButton/FollowButton.tsx | 2 +- .../src/InternalLink/InternalLink.tsx | 4 +- .../{MapPin.tsx => MapPin.client.tsx} | 0 .../src/MapWithPin/MapPin.stories.tsx | 2 +- .../{MapWithPin.tsx => MapWithPin.client.tsx} | 2 +- .../src/MapWithPin/MapWithPin.stories.tsx | 2 +- .../UsefulStatsButton/UsefulStatsButton.tsx | 2 +- packages/components/src/index.ts | 2 +- packages/components/src/test/utils.tsx | 8 +- packages/cypress/src/support/db/endpoints.ts | 2 +- remix.env.d.ts | 2 + src/.eslintrc.json | 14 +- src/common/Alerts/AlertIncompleteProfile.tsx | 2 +- src/common/Analytics/GoogleAnalytics.tsx | 2 +- src/common/AuthWrapper.tsx | 7 +- src/common/DownloadWithDonationAsk.test.tsx | 2 +- src/common/DownloadWithDonationAsk.tsx | 2 +- src/common/Form/UnsavedChangesDialog.tsx | 2 +- src/common/ScrollToTop.test.tsx | 6 +- src/common/ScrollToTop.tsx | 2 +- src/config/config.ts | 35 +- src/config/devSiteConfig.ts | 4 + src/entry.client.tsx | 28 + src/entry.server.tsx | 139 + src/index.tsx | 10 - src/pages/Academy/Academy.tsx | 2 +- .../Academy/ExternalEmbed/ExternalEmbed.tsx | 2 +- .../Howto/Content/Common/Howto.form.test.tsx | 8 +- .../Howto/Content/Common/SubmitStatus.tsx | 2 +- .../Howto/Content/EditHowto/EditHowto.tsx | 2 +- src/pages/Howto/Content/Howto/Howto.test.tsx | 8 +- src/pages/Howto/Content/Howto/Howto.tsx | 2 +- .../HowtoDescription/HowtoDescription.tsx | 2 +- .../Howto/Content/HowtoList/HowToCard.tsx | 2 +- .../Content/HowtoList/HowtoFilterHeader.tsx | 2 +- .../Howto/Content/HowtoList/HowtoList.tsx | 2 +- src/pages/Howto/Howto.tsx | 39 - src/pages/Layout.tsx | 32 + src/pages/Maps/Content/Controls/Controls.tsx | 2 +- .../{Cluster.tsx => Cluster.client.tsx} | 0 .../{MapView.tsx => MapView.client.tsx} | 4 +- .../MapView/{Popup.tsx => Popup.client.tsx} | 0 src/pages/Maps/Content/index.ts | 2 +- src/pages/Maps/{Maps.tsx => Maps.client.tsx} | 2 +- src/pages/Maps/Maps.test.tsx | 10 +- src/pages/NotFound/NotFound.tsx | 2 +- src/pages/PageList.tsx | 180 +- src/pages/Patreon/Patreon.tsx | 2 +- .../FormFields/QuestionCategory.field.tsx | 2 +- .../Question/Content/Common/QuestionForm.tsx | 2 +- src/pages/Question/QuestionEdit.tsx | 2 +- src/pages/Question/QuestionFilterHeader.tsx | 2 +- src/pages/Question/QuestionListing.tsx | 14 +- src/pages/Question/QuestionPage.test.tsx | 8 +- src/pages/Question/QuestionPage.tsx | 2 +- src/pages/Question/index.tsx | 16 +- src/pages/Question/question.routes.test.tsx | 12 +- src/pages/Question/question.routes.tsx | 18 +- .../Common/ResearchUpdate.form.test.tsx | 8 +- .../Research/Content/Common/SubmitStatus.tsx | 2 +- .../Content/CreateUpdate/CreateUpdate.tsx | 2 +- .../Research/Content/EditResearch/index.tsx | 2 +- .../Research/Content/EditUpdate/index.tsx | 2 +- .../Research/Content/ResearchArticle.test.tsx | 8 +- .../Research/Content/ResearchArticle.tsx | 2 +- .../Research/Content/ResearchDescription.tsx | 2 +- .../Research/Content/ResearchFilterHeader.tsx | 2 +- src/pages/Research/Content/ResearchList.tsx | 2 +- src/pages/Research/Content/ResearchUpdate.tsx | 2 +- src/pages/Research/index.tsx | 35 - src/pages/Research/research.routes.test.tsx | 12 +- src/pages/Research/research.routes.tsx | 46 +- src/pages/SignIn/SignIn.tsx | 2 +- src/pages/SignUp/SignUp.tsx | 2 +- src/pages/SignUp/SignUpMessage.tsx | 2 +- src/pages/Unsubscribe/Unsubscribe.tsx | 2 +- .../User/contact/UserContactNotLoggedIn.tsx | 2 +- .../User/content/UserCreatedDocumentsItem.tsx | 2 +- src/pages/User/content/UserProfile.tsx | 2 +- src/pages/User/user.routes.test.tsx | 7 +- src/pages/User/user.routes.tsx | 2 +- .../formSections/Impact/Impact.section.tsx | 2 +- .../Impact/ImpactYear.section.tsx | 2 +- .../formSections/UserInfos.section.tsx | 12 +- .../content/formSections/UserProfile.test.tsx | 8 +- src/pages/common/AuthRoute.tsx | 2 +- .../common/DevSiteHeader/DevSiteHeader.tsx | 8 +- .../GlobalSiteFooter/GlobalSiteFooter.tsx | 4 +- src/pages/common/Header/Menu/Logo/Logo.tsx | 2 +- src/pages/common/Header/Menu/MenuDesktop.tsx | 26 +- .../Header/Menu/MenuMobile/MenuMobileLink.tsx | 2 +- .../common/Header/Menu/Profile/Profile.tsx | 9 +- .../Header/Menu/Profile/ProfileButtonItem.tsx | 2 +- .../Header/Menu/ProfileModal/ProfileModal.tsx | 2 +- .../Header/getFormattedNotifications.test.tsx | 8 +- src/pages/common/Layout/Main.tsx | 30 +- src/pages/index.tsx | 113 - src/root.tsx | 73 + src/routes/$.tsx | 14 + src/routes/_index.tsx | 9 + src/routes/academy.$.tsx | 24 + src/routes/how-to.$slug._index.tsx | 20 + src/routes/how-to.$slug.edit.tsx | 23 + src/routes/how-to._index.tsx | 20 + src/routes/how-to.create.tsx | 23 + src/routes/map.tsx | 28 + src/routes/patreon.tsx | 19 + src/routes/privacy.tsx | 19 + src/routes/questions.$slug._index.tsx | 33 + src/routes/questions.$slug.edit.tsx | 36 + src/routes/questions._index.tsx | 41 + src/routes/questions.create.tsx | 36 + src/routes/research.$slug._index.tsx | 26 + .../research.$slug.edit-update.$update.tsx | 32 + src/routes/research.$slug.edit.tsx | 32 + src/routes/research.$slug.new-update.tsx | 32 + src/routes/research._index.tsx | 19 + src/routes/research.create.tsx | 32 + src/routes/settings.tsx | 35 + src/routes/sign-in.tsx | 20 + src/routes/sign-up-message.tsx | 20 + src/routes/sign-up.tsx | 20 + src/routes/terms.tsx | 19 + src/routes/u.$id.edit.tsx | 23 + src/routes/u.$id.tsx | 19 + src/routes/unsubscribe.tsx | 19 + src/server.js | 98 + src/stores/Discussions/discussions.store.tsx | 4 +- src/stores/Research/research.store.tsx | 4 +- src/stores/Theme/theme.store.tsx | 3 +- src/stores/User/user.store.ts | 4 +- src/stores/databaseV2/DatabaseV2.ts | 8 +- src/stores/databaseV2/endpoints.ts | 2 +- src/styles/context.ts | 19 + src/styles/createEmotionCache.ts | 5 + tsconfig.json | 2 +- vite.config.ts | 16 +- yarn.lock | 2926 ++++++++++++++++- 144 files changed, 4222 insertions(+), 737 deletions(-) create mode 100644 docs/remix.md rename packages/components/src/MapWithPin/{MapPin.tsx => MapPin.client.tsx} (100%) rename packages/components/src/MapWithPin/{MapWithPin.tsx => MapWithPin.client.tsx} (98%) create mode 100644 remix.env.d.ts create mode 100644 src/config/devSiteConfig.ts create mode 100644 src/entry.client.tsx create mode 100644 src/entry.server.tsx delete mode 100644 src/index.tsx delete mode 100644 src/pages/Howto/Howto.tsx create mode 100644 src/pages/Layout.tsx rename src/pages/Maps/Content/MapView/{Cluster.tsx => Cluster.client.tsx} (100%) rename src/pages/Maps/Content/MapView/{MapView.tsx => MapView.client.tsx} (95%) rename src/pages/Maps/Content/MapView/{Popup.tsx => Popup.client.tsx} (100%) rename src/pages/Maps/{Maps.tsx => Maps.client.tsx} (98%) delete mode 100644 src/pages/Research/index.tsx delete mode 100644 src/pages/index.tsx create mode 100644 src/root.tsx create mode 100644 src/routes/$.tsx create mode 100644 src/routes/_index.tsx create mode 100644 src/routes/academy.$.tsx create mode 100644 src/routes/how-to.$slug._index.tsx create mode 100644 src/routes/how-to.$slug.edit.tsx create mode 100644 src/routes/how-to._index.tsx create mode 100644 src/routes/how-to.create.tsx create mode 100644 src/routes/map.tsx create mode 100644 src/routes/patreon.tsx create mode 100644 src/routes/privacy.tsx create mode 100644 src/routes/questions.$slug._index.tsx create mode 100644 src/routes/questions.$slug.edit.tsx create mode 100644 src/routes/questions._index.tsx create mode 100644 src/routes/questions.create.tsx create mode 100644 src/routes/research.$slug._index.tsx create mode 100644 src/routes/research.$slug.edit-update.$update.tsx create mode 100644 src/routes/research.$slug.edit.tsx create mode 100644 src/routes/research.$slug.new-update.tsx create mode 100644 src/routes/research._index.tsx create mode 100644 src/routes/research.create.tsx create mode 100644 src/routes/settings.tsx create mode 100644 src/routes/sign-in.tsx create mode 100644 src/routes/sign-up-message.tsx create mode 100644 src/routes/sign-up.tsx create mode 100644 src/routes/terms.tsx create mode 100644 src/routes/u.$id.edit.tsx create mode 100644 src/routes/u.$id.tsx create mode 100644 src/routes/unsubscribe.tsx create mode 100644 src/server.js create mode 100644 src/styles/context.ts create mode 100644 src/styles/createEmotionCache.ts diff --git a/docs/remix.md b/docs/remix.md new file mode 100644 index 0000000000..0fb35874a1 --- /dev/null +++ b/docs/remix.md @@ -0,0 +1,26 @@ +### What is Remix? +A React Fullstack Framework that provides server-side rendering and an API Layer. + +## Routing +It follows a [File System Route Convention](https://remix.run/docs/en/main/start/v2#file-system-route-convention) where each route is defined in the *routes* folder. + +Each route is a normal React component file that should include a [loader](https://remix.run/docs/en/main/route/loader) function, that function runs exclusively on the server (or clientLoader for browser only). +Parts of the component might be rendered client side, for that we can use React.lazy or wrap them with component from `remix-utils`. + +Additionally, routes could also export [Links](https://remix.run/docs/en/main/route/links) and [Meta](https://remix.run/docs/en/main/route/meta) functions that will be added to the html head. + +For the API, we can use [action](https://remix.run/docs/en/main/route/action) routes. + +## Migration +- Most files have changes only to update the imports from 'react-router' to '@remix-run/react'. +- MapPin.tsx file name changed to MapPin.client.tsx [so it's not run server-side](https://remix.run/docs/en/main/discussion/server-vs-client#splitting-up-client-and-server-code). Without this change, it throws an error 'window' isn't defined - from the leaflet package. +- A `routes` folder was created, following [Remix routing convention](https://remix.run/docs/en/main/file-conventions/routes) + - Notice the $ in `academy.$.tsx` it ensures academy sub-routes still load the academy page. + - _index.tsx was created to replicate the current behaviour of redirecting to the Academy page. Later it could be used for the `HubPage`. + - All routes have already been migrated + - More routing details in the link above 😊 + +- Current issues + - unit and e2e tests are not passing + - localStorage/sessionStorage/window usage might need a refactor + - DevSiteHeader (minor) -> needs a navigation/refresh after changing theme \ No newline at end of file diff --git a/index.html b/index.html index 00ca487d54..baa3dcdd81 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ - + diff --git a/package.json b/package.json index 8d8398f098..3fd9dc3bbf 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,11 @@ }, "dependencies": { "@emotion/react": "^11.11.4", + "@emotion/server": "^11.11.0", "@emotion/styled": "^11.11.5", + "@remix-run/node": "^2.10.3", + "@remix-run/react": "^2.10.3", + "@remix-run/serve": "^2.10.3", "@sentry/react": "^6.15.0", "@uppy/compressor": "^1.1.4", "@uppy/core": "^3.11.3", @@ -85,6 +89,7 @@ "@uppy/file-input": "^3.1.2", "@uppy/progress-bar": "^3.1.1", "@uppy/react": "^3.3.1", + "compression": "^1.7.4", "countries-list": "^2.6.1", "date-fns": "^3.3.0", "debounce": "^1.2.0", @@ -97,6 +102,8 @@ "framer-motion": "^11.2.10", "fs-extra": "^10.0.0", "fuse.js": "^6.4.6", + "helmet": "^7.1.0", + "isbot": "^5.1.13", "leaflet": "^1.5.1", "leaflet.markercluster": "^1.4.1", "mobx": "6.9.0", @@ -117,6 +124,7 @@ "react-leaflet-markercluster": "^2.0.0-rc3", "react-router": "^6.24.1", "react-router-dom": "^6.24.1", + "remix-utils": "^7.6.0", "rxjs": "^7.8.1", "theme-ui": "^0.16.2", "tslog": "^4.9.2", @@ -129,6 +137,7 @@ "@emotion/babel-plugin": "^11.11.0", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@faker-js/faker": "^8.4.1", + "@remix-run/dev": "^2.10.3", "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", "@testing-library/jest-dom": "^6.4.6", diff --git a/packages/components/.storybook/preview.tsx b/packages/components/.storybook/preview.tsx index 7844c708d9..7534fdc1f2 100644 --- a/packages/components/.storybook/preview.tsx +++ b/packages/components/.storybook/preview.tsx @@ -10,13 +10,8 @@ import { projectKampTheme, fixingFashionTheme, } from 'oa-themes' - -import { - Route, - RouterProvider, - createMemoryRouter, - createRoutesFromElements, -} from 'react-router-dom' +import { Route, createRoutesFromElements } from '@remix-run/react' +import { RouterProvider, createMemoryRouter } from 'react-router-dom' const themes = { pp: preciousPlasticTheme.styles, diff --git a/packages/components/src/Breadcrumbs/BreadcrumbsItem.tsx b/packages/components/src/Breadcrumbs/BreadcrumbsItem.tsx index d71a221791..89a64dc4b0 100644 --- a/packages/components/src/Breadcrumbs/BreadcrumbsItem.tsx +++ b/packages/components/src/Breadcrumbs/BreadcrumbsItem.tsx @@ -1,4 +1,4 @@ -import { Link } from 'react-router-dom' +import { Link } from '@remix-run/react' import { Box, Text } from 'theme-ui' import { Button } from '../Button/Button' diff --git a/packages/components/src/CreateComment/CreateComment.tsx b/packages/components/src/CreateComment/CreateComment.tsx index 8012a35564..05ad401014 100644 --- a/packages/components/src/CreateComment/CreateComment.tsx +++ b/packages/components/src/CreateComment/CreateComment.tsx @@ -1,4 +1,4 @@ -import { Link } from 'react-router-dom' +import { Link } from '@remix-run/react' import { Box, Button, Flex, Text, Textarea } from 'theme-ui' import { MemberBadge } from '../MemberBadge/MemberBadge' diff --git a/packages/components/src/FollowButton/FollowButton.tsx b/packages/components/src/FollowButton/FollowButton.tsx index e52f9cd153..5540e755f3 100644 --- a/packages/components/src/FollowButton/FollowButton.tsx +++ b/packages/components/src/FollowButton/FollowButton.tsx @@ -1,4 +1,4 @@ -import { useNavigate } from 'react-router-dom' +import { useNavigate } from '@remix-run/react' import { Button } from '../Button/Button' import { Tooltip } from '../Tooltip/Tooltip' diff --git a/packages/components/src/InternalLink/InternalLink.tsx b/packages/components/src/InternalLink/InternalLink.tsx index f3fc4502c5..80ec54a498 100644 --- a/packages/components/src/InternalLink/InternalLink.tsx +++ b/packages/components/src/InternalLink/InternalLink.tsx @@ -1,8 +1,8 @@ /* eslint-disable no-restricted-imports */ -import { Link as RouterLink } from 'react-router-dom' +import { Link as RouterLink } from '@remix-run/react' import { Link } from 'theme-ui' -import type { LinkProps as RouterLinkProps } from 'react-router-dom' +import type { LinkProps as RouterLinkProps } from '@remix-run/react' import type { LinkProps as ThemedUILinkProps } from 'theme-ui' export type Props = RouterLinkProps & ThemedUILinkProps diff --git a/packages/components/src/MapWithPin/MapPin.tsx b/packages/components/src/MapWithPin/MapPin.client.tsx similarity index 100% rename from packages/components/src/MapWithPin/MapPin.tsx rename to packages/components/src/MapWithPin/MapPin.client.tsx diff --git a/packages/components/src/MapWithPin/MapPin.stories.tsx b/packages/components/src/MapWithPin/MapPin.stories.tsx index 7aff225c5e..a27b446661 100644 --- a/packages/components/src/MapWithPin/MapPin.stories.tsx +++ b/packages/components/src/MapWithPin/MapPin.stories.tsx @@ -1,4 +1,4 @@ -import { MapPin } from './MapPin' +import { MapPin } from './MapPin.client' import type { Meta, StoryFn } from '@storybook/react' diff --git a/packages/components/src/MapWithPin/MapWithPin.tsx b/packages/components/src/MapWithPin/MapWithPin.client.tsx similarity index 98% rename from packages/components/src/MapWithPin/MapWithPin.tsx rename to packages/components/src/MapWithPin/MapWithPin.client.tsx index f0b4502b15..22a58f99c4 100644 --- a/packages/components/src/MapWithPin/MapWithPin.tsx +++ b/packages/components/src/MapWithPin/MapWithPin.client.tsx @@ -4,7 +4,7 @@ import { Alert, Box, Flex, Text } from 'theme-ui' import { Button } from '../Button/Button' import { OsmGeocoding } from '../OsmGeocoding/OsmGeocoding' -import { MapPin } from './MapPin' +import { MapPin } from './MapPin.client' import type { Result } from '../OsmGeocoding/types' diff --git a/packages/components/src/MapWithPin/MapWithPin.stories.tsx b/packages/components/src/MapWithPin/MapWithPin.stories.tsx index 4977ce25db..8928f5309b 100644 --- a/packages/components/src/MapWithPin/MapWithPin.stories.tsx +++ b/packages/components/src/MapWithPin/MapWithPin.stories.tsx @@ -1,4 +1,4 @@ -import { MapWithPin } from './MapWithPin' +import { MapWithPin } from './MapWithPin.client' import type { Meta, StoryFn } from '@storybook/react' diff --git a/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx b/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx index bcaf769656..c1ee686ac2 100644 --- a/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx +++ b/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx @@ -1,6 +1,6 @@ import { useState } from 'react' -import { useNavigate } from 'react-router-dom' import { useTheme } from '@emotion/react' +import { useNavigate } from '@remix-run/react' import { Text } from 'theme-ui' import { Button } from '../Button/Button' diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 3943e2c349..b520b130f0 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -37,7 +37,7 @@ export { InternalLink } from './InternalLink/InternalLink' export { LinkifyText } from './LinkifyText/LinkifyText' export { Loader } from './Loader/Loader' export { MapMemberCard } from './MapMemberCard/MapMemberCard' -export { MapWithPin } from './MapWithPin/MapWithPin' +export { MapWithPin } from './MapWithPin/MapWithPin.client' export { MemberBadge } from './MemberBadge/MemberBadge' export { Modal } from './Modal/Modal' export { ModerationStatus } from './ModerationStatus/ModerationStatus' diff --git a/packages/components/src/test/utils.tsx b/packages/components/src/test/utils.tsx index 2f15e430d4..2836b56b6e 100644 --- a/packages/components/src/test/utils.tsx +++ b/packages/components/src/test/utils.tsx @@ -1,10 +1,6 @@ -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' +import { createRoutesFromElements, Route } from '@remix-run/react' import { render as testLibReact } from '@testing-library/react' import { preciousPlasticTheme } from 'oa-themes' diff --git a/packages/cypress/src/support/db/endpoints.ts b/packages/cypress/src/support/db/endpoints.ts index 4c09245e68..0ffb2668a4 100644 --- a/packages/cypress/src/support/db/endpoints.ts +++ b/packages/cypress/src/support/db/endpoints.ts @@ -11,7 +11,7 @@ const e = process.env || ({} as any) * e.g. oa_ * SessionStorage prefixes are used to allow test ci environments to dynamically set a db endpoint */ -const DB_PREFIX = sessionStorage.DB_PREFIX || e.REACT_APP_DB_PREFIX || '' +const DB_PREFIX = e.REACT_APP_DB_PREFIX || '' // sessionStorage.DB_PREFIX /** * Mapping of generic database endpoints to specific prefixed and revisioned versions for the diff --git a/remix.env.d.ts b/remix.env.d.ts new file mode 100644 index 0000000000..dcf8c45e1d --- /dev/null +++ b/remix.env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/src/.eslintrc.json b/src/.eslintrc.json index 31813b0715..6479217883 100644 --- a/src/.eslintrc.json +++ b/src/.eslintrc.json @@ -1,15 +1,5 @@ { "rules": { - "no-console": "error", - "prefer-arrow-functions/prefer-arrow-functions": [ - "error", - { - "classPropertiesAllowed": false, - "disallowPrototype": false, - "returnStyle": "unchanged", - "singleReturnOnly": false - } - ] - }, - "plugins": ["prefer-arrow-functions"] + "no-console": "warn" + } } diff --git a/src/common/Alerts/AlertIncompleteProfile.tsx b/src/common/Alerts/AlertIncompleteProfile.tsx index f11edfdb55..a2100056e1 100644 --- a/src/common/Alerts/AlertIncompleteProfile.tsx +++ b/src/common/Alerts/AlertIncompleteProfile.tsx @@ -1,4 +1,4 @@ -import { Link } from 'react-router-dom' +import { Link } from '@remix-run/react' import { observer } from 'mobx-react-lite' import { useCommonStores } from 'src/common/hooks/useCommonStores' import { Alert, Flex } from 'theme-ui' diff --git a/src/common/Analytics/GoogleAnalytics.tsx b/src/common/Analytics/GoogleAnalytics.tsx index 520bc765b2..2faf9d8734 100644 --- a/src/common/Analytics/GoogleAnalytics.tsx +++ b/src/common/Analytics/GoogleAnalytics.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react' import ReactGA from 'react-ga4' -import { useLocation } from 'react-router-dom' +import { useLocation } from '@remix-run/react' import { GA_TRACKING_ID } from 'src/config/config' export const GoogleAnalytics = () => { diff --git a/src/common/AuthWrapper.tsx b/src/common/AuthWrapper.tsx index a3f99f5c42..08bb95be10 100644 --- a/src/common/AuthWrapper.tsx +++ b/src/common/AuthWrapper.tsx @@ -1,7 +1,8 @@ import React from 'react' import { observer } from 'mobx-react' import { useCommonStores } from 'src/common/hooks/useCommonStores' -import { DEV_SITE_ROLE, SITE } from 'src/config/config' +import { SITE } from 'src/config/config' +import { getDevSiteRole } from 'src/config/devSiteConfig' import { isTestEnvironment } from 'src/utils/isTestEnvironment' import type { UserRole } from 'oa-shared' @@ -47,8 +48,8 @@ const isUserAuthorized = ( // if running dev or preview site allow wwwuser-overridden permissions (ignoring db user role) if (!isTestEnvironment && (SITE === 'dev_site' || SITE === 'preview')) { - if (DEV_SITE_ROLE) { - return rolesRequired.includes(DEV_SITE_ROLE) + if (getDevSiteRole()) { + return rolesRequired.includes(getDevSiteRole()) } } // otherwise use logged in user profile values diff --git a/src/common/DownloadWithDonationAsk.test.tsx b/src/common/DownloadWithDonationAsk.test.tsx index 19a18fafe1..f3bd103bc8 100644 --- a/src/common/DownloadWithDonationAsk.test.tsx +++ b/src/common/DownloadWithDonationAsk.test.tsx @@ -13,7 +13,7 @@ import type { IUploadedFileMeta } from 'src/stores/storage' import type { Mock } from 'vitest' const mockedUsedNavigate = vi.fn() -vi.mock('react-router-dom', () => ({ +vi.mock('@remix-run/react', () => ({ useNavigate: () => mockedUsedNavigate, })) diff --git a/src/common/DownloadWithDonationAsk.tsx b/src/common/DownloadWithDonationAsk.tsx index 46cd06170f..023ff267a8 100644 --- a/src/common/DownloadWithDonationAsk.tsx +++ b/src/common/DownloadWithDonationAsk.tsx @@ -1,5 +1,5 @@ import { useState } from 'react' -import { useNavigate } from 'react-router-dom' +import { useNavigate } from '@remix-run/react' import { DonationRequestModal, DownloadButton, diff --git a/src/common/Form/UnsavedChangesDialog.tsx b/src/common/Form/UnsavedChangesDialog.tsx index 7bda832668..1b2e1066d9 100644 --- a/src/common/Form/UnsavedChangesDialog.tsx +++ b/src/common/Form/UnsavedChangesDialog.tsx @@ -1,4 +1,4 @@ -import { useBlocker } from 'react-router' +import { useBlocker } from '@remix-run/react' import { ConfirmModal } from 'oa-components' const CONFIRM_DIALOG_MSG = diff --git a/src/common/ScrollToTop.test.tsx b/src/common/ScrollToTop.test.tsx index 9e2a10fbe5..dfe4d9b410 100644 --- a/src/common/ScrollToTop.test.tsx +++ b/src/common/ScrollToTop.test.tsx @@ -1,5 +1,5 @@ import { act } from 'react' -import { useLocation } from 'react-router-dom' +import { useLocation } from '@remix-run/react' import { render } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' @@ -7,8 +7,8 @@ import { ScrollToTop } from './ScrollToTop' import type { Mock } from 'vitest' -vi.mock('react-router-dom', async () => ({ - ...(await vi.importActual('react-router-dom')), +vi.mock('@remix-run/react', async () => ({ + ...(await vi.importActual('@remix-run/react')), useLocation: vi.fn(), })) diff --git a/src/common/ScrollToTop.tsx b/src/common/ScrollToTop.tsx index 77178f0c50..02e91a6461 100644 --- a/src/common/ScrollToTop.tsx +++ b/src/common/ScrollToTop.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react' -import { useLocation } from 'react-router-dom' +import { useLocation } from '@remix-run/react' export const ScrollToTop = () => { const { pathname } = useLocation() diff --git a/src/config/config.ts b/src/config/config.ts index 906afa410d..c1cf59d420 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -10,7 +10,6 @@ Dev config is hardcoded - You can find more information about potential security https://javebratt.com/hide-firebase-api/ *****************************************************************************************/ -import type { UserRole } from '../models' import type { ConfigurationOption } from './constants' import type { IFirebaseConfig, ISentryConfig, siteVariants } from './types' @@ -41,12 +40,13 @@ export const getConfigurationOption = _c /********************************************************************************************** */ // On dev sites user can override default role -const devSiteRole: UserRole = localStorage.getItem('devSiteRole') as UserRole +// const devSiteRole: UserRole = localStorage.getItem('devSiteRole') as UserRole const getSiteVariant = (): siteVariants => { - const devSiteVariant: siteVariants = localStorage.getItem( - 'devSiteVariant', - ) as any + const devSiteVariant: siteVariants = + typeof localStorage !== 'undefined' && + localStorage && + (localStorage.getItem('devSiteVariant') as any) if (devSiteVariant === 'preview') { return 'preview' @@ -57,15 +57,17 @@ const getSiteVariant = (): siteVariants => { if (devSiteVariant === 'dev_site') { return 'dev_site' } - if (location.host === 'localhost:4000') { - return 'emulated_site' - } - if ( - location.host === 'localhost:3456' || - _c('REACT_APP_SITE_VARIANT') === 'test-ci' - ) { - return 'test-ci' - } + + // TODO: Find alternative to this + // if (location.host === 'localhost:4000') { + // return 'emulated_site' + // } + // if ( + // location.host === 'localhost:3456' || + // _c('REACT_APP_SITE_VARIANT') === 'test-ci' + // ) { + // return 'test-ci' + // } if (_c('REACT_APP_SITE_VARIANT') === 'preview') { return 'preview' } @@ -144,7 +146,7 @@ const firebaseConfigs: { [variant in siteVariants]: IFirebaseConfig } = { /********************************************************************************************** */ export const SITE = siteVariant -export const DEV_SITE_ROLE = devSiteRole +// export const DEV_SITE_ROLE = devSiteRole export const FIREBASE_CONFIG = firebaseConfigs[siteVariant] export const SENTRY_CONFIG: ISentryConfig = { dsn: _c( @@ -162,7 +164,8 @@ export const API_URL = _c('REACT_APP_API_URL', '') export const isPreciousPlastic = (): boolean => { return ( - (_c('REACT_APP_PLATFORM_THEME') || + _c('REACT_APP_PLATFORM_THEME') === 'precious-plastic' || + (typeof localStorage !== 'undefined' && localStorage.getItem('platformTheme')) === 'precious-plastic' ) } diff --git a/src/config/devSiteConfig.ts b/src/config/devSiteConfig.ts new file mode 100644 index 0000000000..97ab8f7d21 --- /dev/null +++ b/src/config/devSiteConfig.ts @@ -0,0 +1,4 @@ +import type { UserRole } from '../models' + +export const getDevSiteRole = () => + localStorage.getItem('devSiteRole') as UserRole diff --git a/src/entry.client.tsx b/src/entry.client.tsx new file mode 100644 index 0000000000..6dc628d74f --- /dev/null +++ b/src/entry.client.tsx @@ -0,0 +1,28 @@ +import { startTransition, useCallback, useState } from 'react' +import { hydrateRoot } from 'react-dom/client' +import { CacheProvider } from '@emotion/react' +import { RemixBrowser } from '@remix-run/react' + +import { ClientStyleContext } from './styles/context' +import createEmotionCache from './styles/createEmotionCache' + +const ClientCacheProvider = ({ children }) => { + const [cache, setCache] = useState(createEmotionCache()) + + const reset = useCallback(() => setCache(createEmotionCache()), []) + + return ( + + {children} + + ) +} + +startTransition(() => { + hydrateRoot( + document, + + + , + ) +}) diff --git a/src/entry.server.tsx b/src/entry.server.tsx new file mode 100644 index 0000000000..d92ed1a30e --- /dev/null +++ b/src/entry.server.tsx @@ -0,0 +1,139 @@ +import { renderToPipeableStream, renderToString } from 'react-dom/server' +import { CacheProvider } from '@emotion/react' +import createEmotionServer from '@emotion/server/create-instance' +import { createReadableStreamFromReadable } from '@remix-run/node' +import { RemixServer } from '@remix-run/react' +import { isbot } from 'isbot' +import { PassThrough } from 'node:stream' + +import { ServerStyleContext } from './styles/context' +import createEmotionCache from './styles/createEmotionCache' + +import type { EntryContext } from '@remix-run/node' + +const ABORT_DELAY = 5_000 + +export default function handleRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, + // loadContext: AppLoadContext, +) { + return isbot(request.headers.get('user-agent') || '') + ? handleBotRequest( + request, + responseStatusCode, + responseHeaders, + remixContext, + ) + : handleBrowserRequest( + request, + responseStatusCode, + responseHeaders, + remixContext, + ) +} + +function handleBotRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, +) { + return new Promise((resolve, reject) => { + const { pipe, abort } = renderToPipeableStream( + , + { + onAllReady() { + const body = new PassThrough() + + responseHeaders.set('Content-Type', 'text/html') + + resolve( + new Response(createReadableStreamFromReadable(body), { + headers: responseHeaders, + status: responseStatusCode, + }), + ) + + pipe(body) + }, + onShellError(error: unknown) { + reject(error) + }, + onError(error: unknown) { + responseStatusCode = 500 + // eslint-disable-next-line no-console + console.error(error) + }, + }, + ) + + setTimeout(abort, ABORT_DELAY) + }) +} + +function handleBrowserRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, +) { + const cache = createEmotionCache() + const { extractCriticalToChunks } = createEmotionServer(cache) + + const html = renderToString( + + + + + , + ) + + const chunks = extractCriticalToChunks(html) + + return new Promise((resolve, reject) => { + const { pipe, abort } = renderToPipeableStream( + + + + + , + { + onShellReady() { + const body = new PassThrough() + + responseHeaders.set('Content-Type', 'text/html') + + resolve( + new Response(createReadableStreamFromReadable(body), { + headers: responseHeaders, + status: responseStatusCode, + }), + ) + + pipe(body) + }, + onShellError(error: unknown) { + reject(error) + }, + onError(error: unknown) { + // eslint-disable-next-line no-console + console.error(error) + responseStatusCode = 500 + }, + }, + ) + + setTimeout(abort, ABORT_DELAY) + }) +} diff --git a/src/index.tsx b/src/index.tsx deleted file mode 100644 index 311e8dbef7..0000000000 --- a/src/index.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { createRoot } from 'react-dom/client' - -import { initErrorHandler } from './common/Error/handler' -import { App } from './App' - -initErrorHandler() - -const container = document.getElementById('root') -const root = createRoot(container!) -root.render() diff --git a/src/pages/Academy/Academy.tsx b/src/pages/Academy/Academy.tsx index d97160c8c4..1038ceaa9d 100644 --- a/src/pages/Academy/Academy.tsx +++ b/src/pages/Academy/Academy.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { useLocation } from 'react-router-dom' +import { useLocation } from '@remix-run/react' import { useCommonStores } from 'src/common/hooks/useCommonStores' import ExternalEmbed from 'src/pages/Academy/ExternalEmbed/ExternalEmbed' diff --git a/src/pages/Academy/ExternalEmbed/ExternalEmbed.tsx b/src/pages/Academy/ExternalEmbed/ExternalEmbed.tsx index 5898ab56b9..36645a8498 100644 --- a/src/pages/Academy/ExternalEmbed/ExternalEmbed.tsx +++ b/src/pages/Academy/ExternalEmbed/ExternalEmbed.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from 'react' -import { useNavigate } from 'react-router-dom' +import { useNavigate } from '@remix-run/react' /************************************************************************************* * Embed an Iframe diff --git a/src/pages/Howto/Content/Common/Howto.form.test.tsx b/src/pages/Howto/Content/Common/Howto.form.test.tsx index dc994434f0..291176ebac 100644 --- a/src/pages/Howto/Content/Common/Howto.form.test.tsx +++ b/src/pages/Howto/Content/Common/Howto.form.test.tsx @@ -1,12 +1,8 @@ import '@testing-library/jest-dom/vitest' -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' +import { createRoutesFromElements, Route } from '@remix-run/react' import { act, fireEvent, render, waitFor } from '@testing-library/react' import { Provider } from 'mobx-react' import { useCommonStores } from 'src/common/hooks/useCommonStores' diff --git a/src/pages/Howto/Content/Common/SubmitStatus.tsx b/src/pages/Howto/Content/Common/SubmitStatus.tsx index 81c4a20b7c..70641cc996 100644 --- a/src/pages/Howto/Content/Common/SubmitStatus.tsx +++ b/src/pages/Howto/Content/Common/SubmitStatus.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { useNavigate } from 'react-router-dom' +import { useNavigate } from '@remix-run/react' import { observer } from 'mobx-react' import { Button, Icon, Modal } from 'oa-components' import { useCommonStores } from 'src/common/hooks/useCommonStores' diff --git a/src/pages/Howto/Content/EditHowto/EditHowto.tsx b/src/pages/Howto/Content/EditHowto/EditHowto.tsx index f56bad5643..8c8e6ee02c 100644 --- a/src/pages/Howto/Content/EditHowto/EditHowto.tsx +++ b/src/pages/Howto/Content/EditHowto/EditHowto.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react' -import { Navigate, useParams } from 'react-router-dom' +import { Navigate, useParams } from '@remix-run/react' import { toJS } from 'mobx' import { Loader } from 'oa-components' import { useCommonStores } from 'src/common/hooks/useCommonStores' diff --git a/src/pages/Howto/Content/Howto/Howto.test.tsx b/src/pages/Howto/Content/Howto/Howto.test.tsx index da05ede55a..253ecf63f3 100644 --- a/src/pages/Howto/Content/Howto/Howto.test.tsx +++ b/src/pages/Howto/Content/Howto/Howto.test.tsx @@ -1,13 +1,9 @@ import '@testing-library/jest-dom/vitest' -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' import { faker } from '@faker-js/faker' +import { createRoutesFromElements, Route } from '@remix-run/react' import { act, render, waitFor, within } from '@testing-library/react' import { Provider } from 'mobx-react' import { preciousPlasticTheme } from 'oa-themes' diff --git a/src/pages/Howto/Content/Howto/Howto.tsx b/src/pages/Howto/Content/Howto/Howto.tsx index 43d73ef911..4e3b3d8024 100644 --- a/src/pages/Howto/Content/Howto/Howto.tsx +++ b/src/pages/Howto/Content/Howto/Howto.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react' -import { Navigate, useParams } from 'react-router-dom' +import { Navigate, useParams } from '@remix-run/react' import { observer } from 'mobx-react' import { ArticleCallToAction, diff --git a/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx b/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx index 6f860e49b8..09c1d9a64d 100644 --- a/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx +++ b/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx @@ -1,5 +1,5 @@ import { Fragment, useEffect, useState } from 'react' -import { Link, useNavigate } from 'react-router-dom' +import { Link, useNavigate } from '@remix-run/react' import { Button, Category, diff --git a/src/pages/Howto/Content/HowtoList/HowToCard.tsx b/src/pages/Howto/Content/HowtoList/HowToCard.tsx index ff7f6bfcb6..1a854b7958 100644 --- a/src/pages/Howto/Content/HowtoList/HowToCard.tsx +++ b/src/pages/Howto/Content/HowtoList/HowToCard.tsx @@ -1,4 +1,4 @@ -import { Link as RouterLink } from 'react-router-dom' +import { Link as RouterLink } from '@remix-run/react' import { Category, IconCountWithTooltip, diff --git a/src/pages/Howto/Content/HowtoList/HowtoFilterHeader.tsx b/src/pages/Howto/Content/HowtoList/HowtoFilterHeader.tsx index 12e85d1738..7f5a22fc05 100644 --- a/src/pages/Howto/Content/HowtoList/HowtoFilterHeader.tsx +++ b/src/pages/Howto/Content/HowtoList/HowtoFilterHeader.tsx @@ -1,5 +1,5 @@ import { useCallback, useEffect, useState } from 'react' -import { useSearchParams } from 'react-router-dom' +import { useSearchParams } from '@remix-run/react' import debounce from 'debounce' import { Select } from 'oa-components' import { FieldContainer } from 'src/common/Form/FieldContainer' diff --git a/src/pages/Howto/Content/HowtoList/HowtoList.tsx b/src/pages/Howto/Content/HowtoList/HowtoList.tsx index 28efe0361f..9b0789a396 100644 --- a/src/pages/Howto/Content/HowtoList/HowtoList.tsx +++ b/src/pages/Howto/Content/HowtoList/HowtoList.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react' -import { Link, useSearchParams } from 'react-router-dom' +import { Link, useSearchParams } from '@remix-run/react' import { observer } from 'mobx-react' import { Button, Loader, MoreContainer } from 'oa-components' import { useCommonStores } from 'src/common/hooks/useCommonStores' diff --git a/src/pages/Howto/Howto.tsx b/src/pages/Howto/Howto.tsx deleted file mode 100644 index 0f849caa9f..0000000000 --- a/src/pages/Howto/Howto.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { lazy, Suspense } from 'react' -import { Route, Routes } from 'react-router-dom' - -import { AuthRoute } from '../common/AuthRoute' -import { Howto } from './Content/Howto/Howto' -import { HowtoList } from './Content/HowtoList/HowtoList' - -// lazy load editor pages -const CreateHowto = lazy(() => import('./Content/CreateHowto/CreateHowto')) -const EditHowto = lazy(() => import('./Content/EditHowto/EditHowto')) - -const HowtoPage = () => { - return ( - }> - - } /> - - - - } - /> - } /> - - - - } - /> - - - ) -} - -export default HowtoPage diff --git a/src/pages/Layout.tsx b/src/pages/Layout.tsx new file mode 100644 index 0000000000..dc2d96361e --- /dev/null +++ b/src/pages/Layout.tsx @@ -0,0 +1,32 @@ +import { Global, ThemeProvider } from '@emotion/react' +import { GlobalStyles } from 'oa-components' +import { Analytics } from 'src/common/Analytics' +import { ScrollToTop } from 'src/common/ScrollToTop' +import { Flex } from 'theme-ui' + +import { useCommonStores } from '../common/hooks/useCommonStores' +import { StickyButton } from './common/StickyButton' + +import type { ReactNode } from 'react' + +const Layout = (props: { children: ReactNode | ReactNode[] }) => { + const rootStore = useCommonStores() + + return ( + + + + + {props.children} + + + + + + ) +} + +export { Layout } diff --git a/src/pages/Maps/Content/Controls/Controls.tsx b/src/pages/Maps/Content/Controls/Controls.tsx index 8defe174f6..e130cbd2af 100644 --- a/src/pages/Maps/Content/Controls/Controls.tsx +++ b/src/pages/Maps/Content/Controls/Controls.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react' -import { Link, useNavigate } from 'react-router-dom' import styled from '@emotion/styled' +import { Link, useNavigate } from '@remix-run/react' import { Button, Modal, OsmGeocoding } from 'oa-components' import filterIcon from 'src/assets/icons/icon-filters-mobile.png' import { useCommonStores } from 'src/common/hooks/useCommonStores' diff --git a/src/pages/Maps/Content/MapView/Cluster.tsx b/src/pages/Maps/Content/MapView/Cluster.client.tsx similarity index 100% rename from src/pages/Maps/Content/MapView/Cluster.tsx rename to src/pages/Maps/Content/MapView/Cluster.client.tsx diff --git a/src/pages/Maps/Content/MapView/MapView.tsx b/src/pages/Maps/Content/MapView/MapView.client.tsx similarity index 95% rename from src/pages/Maps/Content/MapView/MapView.tsx rename to src/pages/Maps/Content/MapView/MapView.client.tsx index d5e6f58220..f20806be64 100644 --- a/src/pages/Maps/Content/MapView/MapView.tsx +++ b/src/pages/Maps/Content/MapView/MapView.client.tsx @@ -1,8 +1,8 @@ import React, { useEffect } from 'react' import { Map, TileLayer } from 'react-leaflet' -import { Clusters } from './Cluster' -import { Popup } from './Popup' +import { Clusters } from './Cluster.client' +import { Popup } from './Popup.client' import type { LatLngExpression } from 'leaflet' import type { ILatLng, IMapPin } from 'src/models/maps.models' diff --git a/src/pages/Maps/Content/MapView/Popup.tsx b/src/pages/Maps/Content/MapView/Popup.client.tsx similarity index 100% rename from src/pages/Maps/Content/MapView/Popup.tsx rename to src/pages/Maps/Content/MapView/Popup.client.tsx diff --git a/src/pages/Maps/Content/index.ts b/src/pages/Maps/Content/index.ts index 5b522e1d75..0a8d8bee9b 100644 --- a/src/pages/Maps/Content/index.ts +++ b/src/pages/Maps/Content/index.ts @@ -1,2 +1,2 @@ -export { MapView } from './MapView/MapView' +export { MapView } from './MapView/MapView.client' export { Controls } from './Controls/Controls' diff --git a/src/pages/Maps/Maps.tsx b/src/pages/Maps/Maps.client.tsx similarity index 98% rename from src/pages/Maps/Maps.tsx rename to src/pages/Maps/Maps.client.tsx index 08aaff7f30..40616baccf 100644 --- a/src/pages/Maps/Maps.tsx +++ b/src/pages/Maps/Maps.client.tsx @@ -1,5 +1,5 @@ import React, { useContext, useEffect, useMemo, useState } from 'react' -import { useLocation, useNavigate } from 'react-router-dom' +import { useLocation, useNavigate } from '@remix-run/react' import { observer } from 'mobx-react' import { useCommonStores } from 'src/common/hooks/useCommonStores' import { filterMapPinsByType } from 'src/stores/Maps/filter' diff --git a/src/pages/Maps/Maps.test.tsx b/src/pages/Maps/Maps.test.tsx index 3ae0d81f38..1a31f5782b 100644 --- a/src/pages/Maps/Maps.test.tsx +++ b/src/pages/Maps/Maps.test.tsx @@ -1,12 +1,8 @@ import '@testing-library/jest-dom/vitest' -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' +import { createRoutesFromElements, Route } from '@remix-run/react' import { act, render, waitFor } from '@testing-library/react' import { Provider } from 'mobx-react' import { IModerationStatus } from 'oa-shared' @@ -17,7 +13,7 @@ import { testingThemeStyles } from 'src/test/utils/themeUtils' import { describe, expect, it, vi } from 'vitest' import { MapPinServiceContext } from './map.service' -import Maps from './Maps' +import Maps from './Maps.client' import type { IMapPinService } from './map.service' diff --git a/src/pages/NotFound/NotFound.tsx b/src/pages/NotFound/NotFound.tsx index 3d88b76cec..50d971580c 100644 --- a/src/pages/NotFound/NotFound.tsx +++ b/src/pages/NotFound/NotFound.tsx @@ -1,4 +1,4 @@ -import { Link } from 'react-router-dom' +import { Link } from '@remix-run/react' import Main from 'src/pages/common/Layout/Main' import { Flex, Image, Text } from 'theme-ui' diff --git a/src/pages/PageList.tsx b/src/pages/PageList.tsx index 4341ebcee6..7288595a8a 100644 --- a/src/pages/PageList.tsx +++ b/src/pages/PageList.tsx @@ -1,178 +1,60 @@ -import { lazy } from 'react' import { MODULE } from 'src/modules' -import { mapPinService, MapPinServiceContext } from './Maps/map.service' -import { QuestionModule } from './Question' -import { ResearchModule } from './Research' - -import type { UserRole } from 'oa-shared' -import type { CSSObject } from 'theme-ui' -/** - * Import all pages for use in lazy loading - * NOTE - requires default export in page class (https://reactjs.org/docs/code-splitting.html#named-exports) - */ -const HowtoPage = lazy(() => import('./Howto/Howto')) -const SettingsPage = lazy(() => import('./UserSettings')) - -const AcademyPage = lazy(() => import('./Academy/Academy')) -const MapsPage = lazy(() => import('./Maps/Maps')) -const User = lazy(() => import('./User/user.routes')) - -const SignUpMessagePage = lazy(() => import('./SignUp/SignUpMessage')) -const SignUpPage = lazy(() => import('./SignUp/SignUp')) -const SignInPage = lazy(() => import('./SignIn/SignIn')) -const PrivacyPolicy = lazy(() => import('./policy/PrivacyPolicy')) -const TermsPolicy = lazy(() => import('./policy/TermsPolicy')) -const Unsubscribe = lazy(() => import('./Unsubscribe/Unsubscribe')) - -const Patreon = lazy(() => import('./Patreon/Patreon')) - -export const getAvailablePageList = (supportedModules: MODULE[]): IPageMeta[] => - COMMUNITY_PAGES.filter((pageItem) => - supportedModules.includes(pageItem.moduleName), - ) - -export interface IPageMeta { - moduleName: MODULE +interface IPageNavigation { + module: MODULE path: string - component: any title: string - description: string - exact?: boolean - fullPageWidth?: boolean - customStyles?: CSSObject - requiredRole?: UserRole } -const howTo = { - moduleName: MODULE.HOWTO, +const QuestionModule: IPageNavigation = { + module: MODULE.QUESTION, + path: '/questions', + title: 'Questions', +} + +const ResearchModule: IPageNavigation = { + module: MODULE.RESEARCH, + path: '/research', + title: 'Research', +} + +const howTo: IPageNavigation = { + module: MODULE.HOWTO, path: '/how-to', - component: , title: 'How-tos', - description: 'Welcome to how-to', } -const settings = { - moduleName: MODULE.USER, +const settings: IPageNavigation = { + module: MODULE.CORE, path: '/settings', - component: , title: 'Settings', - description: 'Settings', } -const user = { - moduleName: MODULE.USER, - path: '/u', - component: , - title: 'Profile', - description: 'Profile', -} -const academy = { - moduleName: MODULE.ACADEMY, +const academy: IPageNavigation = { + module: MODULE.ACADEMY, path: '/academy', - component: , title: 'Academy', - description: 'Demo external page embed', - customStyles: { - flex: 1, - }, - fullPageWidth: true, } -const maps = { - moduleName: MODULE.MAP, +const maps: IPageNavigation = { + module: MODULE.MAP, path: '/map', - component: ( - - - - ), title: 'Map', - description: 'Welcome to the Map', - customStyles: { - position: 'relative', - margin: '0', - padding: '0', - width: '100vw', - }, - fullPageWidth: true, -} - -const signup = { - moduleName: MODULE.USER, - path: '/sign-up', - exact: true, - component: , - title: 'Sign Up', - description: '', } -const signin = { - moduleName: MODULE.USER, - path: '/sign-in', - exact: true, - component: , - title: 'Sign In', - description: '', -} - -const signupmessage = { - moduleName: MODULE.USER, - path: '/sign-up-message', - exact: true, - component: , - title: 'Sign Up Message', - description: '', -} - -const privacyPolicy = { - moduleName: MODULE.CORE, - path: '/privacy', - exact: true, - component: , - title: 'Privacy Policy', - description: '', -} -const termsPolicy = { - moduleName: MODULE.CORE, - path: '/terms', - exact: true, - component: , - title: 'Terms of Use', - description: '', -} - -const unsubscribe = { - moduleName: MODULE.CORE, - path: '/unsubscribe', - component: , - title: 'Unsubscribe', - description: '', -} - -const patreon = { - moduleName: MODULE.CORE, - path: '/patreon', - component: , - title: 'Patreon', - description: '', +export const getAvailablePageList = ( + supportedModules: MODULE[], +): IPageNavigation[] => { + return COMMUNITY_PAGES.filter((pageItem) => + supportedModules.includes(pageItem.module), + ) } -export const COMMUNITY_PAGES: IPageMeta[] = [ +export const COMMUNITY_PAGES: IPageNavigation[] = [ howTo, maps, academy, ResearchModule, QuestionModule, ] + /** Additional pages to show in signed-in profile dropdown */ -export const COMMUNITY_PAGES_PROFILE: IPageMeta[] = [settings] -export const POLICY_PAGES: IPageMeta[] = [privacyPolicy, termsPolicy] -export const NO_HEADER_PAGES: IPageMeta[] = [ - user, - signup, - signupmessage, - signin, - ResearchModule, // CC 2021-06-24 - Temporary - make research module accessible to all in production but hide from nav - unsubscribe, - QuestionModule, - patreon, -] +export const COMMUNITY_PAGES_PROFILE: IPageNavigation[] = [settings] diff --git a/src/pages/Patreon/Patreon.tsx b/src/pages/Patreon/Patreon.tsx index fbf4f2a886..828d5a076c 100644 --- a/src/pages/Patreon/Patreon.tsx +++ b/src/pages/Patreon/Patreon.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { useSearchParams } from 'react-router-dom' +import { useSearchParams } from '@remix-run/react' import { Loader } from 'oa-components' import { logger } from 'src/logger' import { functions } from 'src/utils/firebase' diff --git a/src/pages/Question/Content/Common/FormFields/QuestionCategory.field.tsx b/src/pages/Question/Content/Common/FormFields/QuestionCategory.field.tsx index 3b90cc8f37..2d28d0ff11 100644 --- a/src/pages/Question/Content/Common/FormFields/QuestionCategory.field.tsx +++ b/src/pages/Question/Content/Common/FormFields/QuestionCategory.field.tsx @@ -28,7 +28,7 @@ export const QuestionCategoryField = () => { } initCategories() - }, categories) + }, []) return ( diff --git a/src/pages/Question/Content/Common/QuestionForm.tsx b/src/pages/Question/Content/Common/QuestionForm.tsx index 23714219b8..7cabea36c2 100644 --- a/src/pages/Question/Content/Common/QuestionForm.tsx +++ b/src/pages/Question/Content/Common/QuestionForm.tsx @@ -1,5 +1,5 @@ import { Form } from 'react-final-form' -import { useNavigate } from 'react-router-dom' +import { useNavigate } from '@remix-run/react' import { Button, ElWithBeforeIcon } from 'oa-components' import { IModerationStatus } from 'oa-shared' import IconHeaderHowto from 'src/assets/images/header-section/howto-header-icon.svg' diff --git a/src/pages/Question/QuestionEdit.tsx b/src/pages/Question/QuestionEdit.tsx index ee8a9d9e6e..af7f72ad64 100644 --- a/src/pages/Question/QuestionEdit.tsx +++ b/src/pages/Question/QuestionEdit.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { useNavigate, useParams } from 'react-router-dom' +import { useNavigate, useParams } from '@remix-run/react' import { toJS } from 'mobx' import { Loader } from 'oa-components' import { UserRole } from 'oa-shared' diff --git a/src/pages/Question/QuestionFilterHeader.tsx b/src/pages/Question/QuestionFilterHeader.tsx index 798326293c..3e47a461c2 100644 --- a/src/pages/Question/QuestionFilterHeader.tsx +++ b/src/pages/Question/QuestionFilterHeader.tsx @@ -1,5 +1,5 @@ import { useCallback, useEffect, useState } from 'react' -import { useSearchParams } from 'react-router-dom' +import { useSearchParams } from '@remix-run/react' import debounce from 'debounce' import { Select } from 'oa-components' import { FieldContainer } from 'src/common/Form/FieldContainer' diff --git a/src/pages/Question/QuestionListing.tsx b/src/pages/Question/QuestionListing.tsx index 532a875e42..176ada49ee 100644 --- a/src/pages/Question/QuestionListing.tsx +++ b/src/pages/Question/QuestionListing.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { Link, useSearchParams } from 'react-router-dom' +import { Link, useSearchParams } from '@remix-run/react' import { Button, Loader } from 'oa-components' import { useCommonStores } from 'src/common/hooks/useCommonStores' import { logger } from 'src/logger' @@ -125,13 +125,11 @@ export const QuestionListing = () => { )} {questions && questions.length > 0 && ( - <> -
    - {questions.map((question, index) => ( - - ))} -
- +
    + {questions.map((question, index) => ( + + ))} +
)} {showLoadMore && ( diff --git a/src/pages/Question/QuestionPage.test.tsx b/src/pages/Question/QuestionPage.test.tsx index 094a5e5531..85977bfc84 100644 --- a/src/pages/Question/QuestionPage.test.tsx +++ b/src/pages/Question/QuestionPage.test.tsx @@ -1,13 +1,9 @@ import '@testing-library/jest-dom/vitest' -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' import { faker } from '@faker-js/faker' +import { createRoutesFromElements, Route } from '@remix-run/react' import { act, render, waitFor, within } from '@testing-library/react' import { Provider } from 'mobx-react' import { UserRole } from 'oa-shared' diff --git a/src/pages/Question/QuestionPage.tsx b/src/pages/Question/QuestionPage.tsx index 68e2a32f26..e32a5eb597 100644 --- a/src/pages/Question/QuestionPage.tsx +++ b/src/pages/Question/QuestionPage.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { Link, useNavigate, useParams } from 'react-router-dom' +import { Link, useNavigate, useParams } from '@remix-run/react' import { Category, ContentStatistics, diff --git a/src/pages/Question/index.tsx b/src/pages/Question/index.tsx index e0a3d7173b..e425dedbe0 100644 --- a/src/pages/Question/index.tsx +++ b/src/pages/Question/index.tsx @@ -1,4 +1,3 @@ -import { MODULE } from 'src/modules' import { DiscussionStore, DiscussionStoreContext, @@ -11,7 +10,7 @@ import { import { useCommonStores } from '../../common/hooks/useCommonStores' import QuestionRoutes from './question.routes' -import type { IPageMeta } from 'src/pages/PageList' +// import type { IPageMeta } from 'src/pages/PageList' export const QuestionModuleContainer = () => { const rootStore = useCommonStores() @@ -24,10 +23,9 @@ export const QuestionModuleContainer = () => { ) } -export const QuestionModule: IPageMeta = { - moduleName: MODULE.QUESTION, - path: '/questions', - component: , - title: 'Questions', - description: 'Welcome to question and answer', -} +// export const QuestionModule: IPageMeta = { +// moduleName: MODULE.QUESTION, +// path: '/questions', +// component: , +// title: 'Questions', +// } diff --git a/src/pages/Question/question.routes.test.tsx b/src/pages/Question/question.routes.test.tsx index f7cd211729..df31015168 100644 --- a/src/pages/Question/question.routes.test.tsx +++ b/src/pages/Question/question.routes.test.tsx @@ -1,13 +1,9 @@ import '@testing-library/jest-dom/vitest' -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' import { faker } from '@faker-js/faker' +import { createRoutesFromElements, Route } from '@remix-run/react' import { act, cleanup, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { Provider } from 'mobx-react' @@ -70,8 +66,8 @@ vi.mock('src/common/hooks/useCommonStores', () => ({ })) const mockedUsedNavigate = vi.fn() -vi.mock('react-router-dom', async () => ({ - ...((await vi.importActual('react-router-dom')) as any), +vi.mock('@remix-run/react', async () => ({ + ...((await vi.importActual('@remix-run/react')) as any), useNavigate: () => mockedUsedNavigate, })) diff --git a/src/pages/Question/question.routes.tsx b/src/pages/Question/question.routes.tsx index ed27c6b8cb..2b06ce23c7 100644 --- a/src/pages/Question/question.routes.tsx +++ b/src/pages/Question/question.routes.tsx @@ -1,17 +1,15 @@ import { Suspense } from 'react' -import { Route, Routes } from 'react-router-dom' +import { Routes } from '@remix-run/react' -import { AuthRoute } from '../common/AuthRoute' -import { QuestionCreate } from './QuestionCreate' -import { QuestionEdit } from './QuestionEdit' -import { QuestionListing } from './QuestionListing' -import { QuestionPage } from './QuestionPage' +// import { AuthRoute } from '../common/AuthRoute' +// import { QuestionCreate } from './QuestionCreate' +// import { QuestionEdit } from './QuestionEdit' +// import { QuestionPage } from './QuestionPage' export const questionRouteElements = ( <> - } /> - } /> - } /> */} + {/* @@ -26,7 +24,7 @@ export const questionRouteElements = ( } - /> + /> */} ) diff --git a/src/pages/Research/Content/Common/ResearchUpdate.form.test.tsx b/src/pages/Research/Content/Common/ResearchUpdate.form.test.tsx index 01edb12a4f..980adb677f 100644 --- a/src/pages/Research/Content/Common/ResearchUpdate.form.test.tsx +++ b/src/pages/Research/Content/Common/ResearchUpdate.form.test.tsx @@ -1,12 +1,8 @@ import '@testing-library/jest-dom/vitest' -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' +import { createRoutesFromElements, Route } from '@remix-run/react' import { render } from '@testing-library/react' import { FactoryResearchItemUpdate } from 'src/test/factories/ResearchItem' import { testingThemeStyles } from 'src/test/utils/themeUtils' diff --git a/src/pages/Research/Content/Common/SubmitStatus.tsx b/src/pages/Research/Content/Common/SubmitStatus.tsx index 57185467ab..f867205b60 100644 --- a/src/pages/Research/Content/Common/SubmitStatus.tsx +++ b/src/pages/Research/Content/Common/SubmitStatus.tsx @@ -1,4 +1,4 @@ -import { useNavigate } from 'react-router-dom' +import { useNavigate } from '@remix-run/react' import { observer } from 'mobx-react' import { Button, Icon, Modal } from 'oa-components' import { useResearchStore } from 'src/stores/Research/research.store' diff --git a/src/pages/Research/Content/CreateUpdate/CreateUpdate.tsx b/src/pages/Research/Content/CreateUpdate/CreateUpdate.tsx index 854914039e..7a62c0984c 100644 --- a/src/pages/Research/Content/CreateUpdate/CreateUpdate.tsx +++ b/src/pages/Research/Content/CreateUpdate/CreateUpdate.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { Navigate, useParams } from 'react-router-dom' +import { Navigate, useParams } from '@remix-run/react' import { observer } from 'mobx-react' import { Loader } from 'oa-components' import { useResearchStore } from 'src/stores/Research/research.store' diff --git a/src/pages/Research/Content/EditResearch/index.tsx b/src/pages/Research/Content/EditResearch/index.tsx index 85552d7adb..1383eeb1e3 100644 --- a/src/pages/Research/Content/EditResearch/index.tsx +++ b/src/pages/Research/Content/EditResearch/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useNavigate, useParams } from 'react-router-dom' +import { useNavigate, useParams } from '@remix-run/react' import { toJS } from 'mobx' import { observer } from 'mobx-react' import { BlockedRoute, Loader } from 'oa-components' diff --git a/src/pages/Research/Content/EditUpdate/index.tsx b/src/pages/Research/Content/EditUpdate/index.tsx index f6bf45326a..29284dcfd5 100644 --- a/src/pages/Research/Content/EditUpdate/index.tsx +++ b/src/pages/Research/Content/EditUpdate/index.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from 'react' -import { useNavigate, useParams } from 'react-router-dom' +import { useNavigate, useParams } from '@remix-run/react' import { toJS } from 'mobx' import { observer } from 'mobx-react' import { BlockedRoute, Loader } from 'oa-components' diff --git a/src/pages/Research/Content/ResearchArticle.test.tsx b/src/pages/Research/Content/ResearchArticle.test.tsx index c8949fc4d3..55968e15ca 100644 --- a/src/pages/Research/Content/ResearchArticle.test.tsx +++ b/src/pages/Research/Content/ResearchArticle.test.tsx @@ -1,13 +1,9 @@ import '@testing-library/jest-dom/vitest' -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' import { faker } from '@faker-js/faker' +import { createRoutesFromElements, Route } from '@remix-run/react' import { act, render, waitFor, within } from '@testing-library/react' import { Provider } from 'mobx-react' import { ResearchUpdateStatus, UserRole } from 'oa-shared' diff --git a/src/pages/Research/Content/ResearchArticle.tsx b/src/pages/Research/Content/ResearchArticle.tsx index ca396d4ea9..aa30bb6f0a 100644 --- a/src/pages/Research/Content/ResearchArticle.tsx +++ b/src/pages/Research/Content/ResearchArticle.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from 'react' -import { Link, useLocation, useParams } from 'react-router-dom' +import { Link, useLocation, useParams } from '@remix-run/react' import { observer } from 'mobx-react' import { ArticleCallToAction, diff --git a/src/pages/Research/Content/ResearchDescription.tsx b/src/pages/Research/Content/ResearchDescription.tsx index b1a57558f3..7753ca9f0f 100644 --- a/src/pages/Research/Content/ResearchDescription.tsx +++ b/src/pages/Research/Content/ResearchDescription.tsx @@ -1,5 +1,5 @@ import { Fragment, useEffect, useState } from 'react' -import { Link, useNavigate } from 'react-router-dom' +import { Link, useNavigate } from '@remix-run/react' import { Button, Category, diff --git a/src/pages/Research/Content/ResearchFilterHeader.tsx b/src/pages/Research/Content/ResearchFilterHeader.tsx index cb7ea7dcfd..b49f8de1a1 100644 --- a/src/pages/Research/Content/ResearchFilterHeader.tsx +++ b/src/pages/Research/Content/ResearchFilterHeader.tsx @@ -1,5 +1,5 @@ import { useCallback, useEffect, useState } from 'react' -import { useSearchParams } from 'react-router-dom' +import { useSearchParams } from '@remix-run/react' import debounce from 'debounce' import { Select } from 'oa-components' import { ResearchStatus } from 'oa-shared' diff --git a/src/pages/Research/Content/ResearchList.tsx b/src/pages/Research/Content/ResearchList.tsx index cec8e60fb2..559746ace3 100644 --- a/src/pages/Research/Content/ResearchList.tsx +++ b/src/pages/Research/Content/ResearchList.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react' -import { Link, useSearchParams } from 'react-router-dom' import { useTheme } from '@emotion/react' +import { Link, useSearchParams } from '@remix-run/react' import { observer } from 'mobx-react' import { Button, Loader } from 'oa-components' import { AuthWrapper } from 'src/common/AuthWrapper' diff --git a/src/pages/Research/Content/ResearchUpdate.tsx b/src/pages/Research/Content/ResearchUpdate.tsx index c76d0a0e90..d0f8a10395 100644 --- a/src/pages/Research/Content/ResearchUpdate.tsx +++ b/src/pages/Research/Content/ResearchUpdate.tsx @@ -1,5 +1,5 @@ -import { Link, useNavigate } from 'react-router-dom' import styled from '@emotion/styled' +import { Link, useNavigate } from '@remix-run/react' import { Button, DownloadCounter, diff --git a/src/pages/Research/index.tsx b/src/pages/Research/index.tsx deleted file mode 100644 index 62911453a7..0000000000 --- a/src/pages/Research/index.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { useCommonStores } from 'src/common/hooks/useCommonStores' -import { MODULE } from 'src/modules' -import { - ResearchStore, - ResearchStoreContext, -} from 'src/stores/Research/research.store' - -import ResearchRoutes from './research.routes' - -import type { IPageMeta } from 'src/pages/PageList' - -/** - * Wraps the research module routing elements with the research module provider - */ -const ResearchModuleContainer = () => { - const rootStore = useCommonStores() - return ( - - - - ) -} - -/** - * Default export format used for integrating with the platform - * @description The research module enables users to share ongoing updates for - * experimental projects - */ -export const ResearchModule: IPageMeta = { - moduleName: MODULE.RESEARCH, - path: '/research', - component: , - title: 'Research', - description: 'Welcome to research', -} diff --git a/src/pages/Research/research.routes.test.tsx b/src/pages/Research/research.routes.test.tsx index a3a530b56d..4cbc4c823f 100644 --- a/src/pages/Research/research.routes.test.tsx +++ b/src/pages/Research/research.routes.test.tsx @@ -1,14 +1,10 @@ import '@testing-library/jest-dom/vitest' import { Suspense } from 'react' -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' import { faker } from '@faker-js/faker' +import { createRoutesFromElements, Route } from '@remix-run/react' import { act, cleanup, render, waitFor } from '@testing-library/react' import { Provider } from 'mobx-react' import { UserRole } from 'oa-shared' @@ -62,8 +58,8 @@ vi.mock('src/common/hooks/useCommonStores', () => ({ })) const mockedUsedNavigate = vi.fn() -vi.mock('react-router-dom', async () => ({ - ...((await vi.importActual('react-router-dom')) as any), +vi.mock('@remix-run/react', async () => ({ + ...((await vi.importActual('@remix-run/react')) as any), useNavigate: () => mockedUsedNavigate, })) diff --git a/src/pages/Research/research.routes.tsx b/src/pages/Research/research.routes.tsx index 2b4af31437..72c94bd9fa 100644 --- a/src/pages/Research/research.routes.tsx +++ b/src/pages/Research/research.routes.tsx @@ -1,35 +1,31 @@ -import { lazy, Suspense } from 'react' -import { Route, Routes } from 'react-router-dom' -import { isPreciousPlastic } from 'src/config/config' +import { Suspense } from 'react' +import { Routes } from '@remix-run/react' -import { AuthRoute } from '../common/AuthRoute' -import { RESEARCH_EDITOR_ROLES } from './constants' +// const CreateResearch = lazy(() => import('./Content/CreateResearch')) +// const CreateUpdate = lazy(() => import('./Content/CreateUpdate/CreateUpdate')) +// const ResearchItemEditor = lazy(() => import('./Content/EditResearch')) +// const UpdateItemEditor = lazy(() => import('./Content/EditUpdate')) +// const ResearchArticle = lazy(() => import('./Content/ResearchArticle')) +// const ResearchList = lazy(() => import('./Content/ResearchList')) -const CreateResearch = lazy(() => import('./Content/CreateResearch')) -const CreateUpdate = lazy(() => import('./Content/CreateUpdate/CreateUpdate')) -const ResearchItemEditor = lazy(() => import('./Content/EditResearch')) -const UpdateItemEditor = lazy(() => import('./Content/EditUpdate')) -const ResearchArticle = lazy(() => import('./Content/ResearchArticle')) -const ResearchList = lazy(() => import('./Content/ResearchList')) +// const getRandomInt = (max: number) => { +// return Math.floor(Math.random() * max) +// } -const getRandomInt = (max: number) => { - return Math.floor(Math.random() * max) -} - -const roles = isPreciousPlastic() ? [] : RESEARCH_EDITOR_ROLES +// const roles = isPreciousPlastic() ? [] : RESEARCH_EDITOR_ROLES export const researchRouteElements = ( <> - } /> - } /> */} + {/* } - /> - */} + {/* @@ -44,20 +40,20 @@ export const researchRouteElements = ( } - /> - */} + {/* } - /> - */} + {/* } - /> + /> */} ) diff --git a/src/pages/SignIn/SignIn.tsx b/src/pages/SignIn/SignIn.tsx index 8a2fc8b3c1..921d4000d0 100644 --- a/src/pages/SignIn/SignIn.tsx +++ b/src/pages/SignIn/SignIn.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react' import { Field, Form } from 'react-final-form' -import { Link, useNavigate } from 'react-router-dom' +import { Link, useNavigate } from '@remix-run/react' import { observer } from 'mobx-react' import { Button, FieldInput, HeroBanner, TextNotification } from 'oa-components' import { getFriendlyMessage } from 'oa-shared' diff --git a/src/pages/SignUp/SignUp.tsx b/src/pages/SignUp/SignUp.tsx index 42bb8563e4..5736e40284 100644 --- a/src/pages/SignUp/SignUp.tsx +++ b/src/pages/SignUp/SignUp.tsx @@ -1,6 +1,6 @@ import { useState } from 'react' import { Field, Form } from 'react-final-form' -import { Link, Navigate, useNavigate } from 'react-router-dom' +import { Link, Navigate, useNavigate } from '@remix-run/react' import { observer } from 'mobx-react' import { Button, ExternalLink, FieldInput, HeroBanner } from 'oa-components' import { FRIENDLY_MESSAGES } from 'oa-shared' diff --git a/src/pages/SignUp/SignUpMessage.tsx b/src/pages/SignUp/SignUpMessage.tsx index 9f2561d801..4ac45af0d0 100644 --- a/src/pages/SignUp/SignUpMessage.tsx +++ b/src/pages/SignUp/SignUpMessage.tsx @@ -1,4 +1,4 @@ -import { Link } from 'react-router-dom' +import { Link } from '@remix-run/react' import { Button, HeroBanner } from 'oa-components' import { Card, Flex, Heading, Text } from 'theme-ui' diff --git a/src/pages/Unsubscribe/Unsubscribe.tsx b/src/pages/Unsubscribe/Unsubscribe.tsx index 913309a24e..c7d1be22ab 100644 --- a/src/pages/Unsubscribe/Unsubscribe.tsx +++ b/src/pages/Unsubscribe/Unsubscribe.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { Route, Routes, useParams } from 'react-router-dom' +import { Route, Routes, useParams } from '@remix-run/react' import { observer } from 'mobx-react' import { useCommonStores } from 'src/common/hooks/useCommonStores' import { logger } from 'src/logger' diff --git a/src/pages/User/contact/UserContactNotLoggedIn.tsx b/src/pages/User/contact/UserContactNotLoggedIn.tsx index ad76d47ba6..5f24fd9341 100644 --- a/src/pages/User/contact/UserContactNotLoggedIn.tsx +++ b/src/pages/User/contact/UserContactNotLoggedIn.tsx @@ -1,4 +1,4 @@ -import { Link } from 'react-router-dom' +import { Link } from '@remix-run/react' import { Button } from 'oa-components' import { Alert, Flex, Text } from 'theme-ui' diff --git a/src/pages/User/content/UserCreatedDocumentsItem.tsx b/src/pages/User/content/UserCreatedDocumentsItem.tsx index a23d441205..1cd7e4b4cc 100644 --- a/src/pages/User/content/UserCreatedDocumentsItem.tsx +++ b/src/pages/User/content/UserCreatedDocumentsItem.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Link } from 'react-router-dom' +import { Link } from '@remix-run/react' import { Icon } from 'oa-components' import { Flex, Heading, Text } from 'theme-ui' diff --git a/src/pages/User/content/UserProfile.tsx b/src/pages/User/content/UserProfile.tsx index f7bbe4e0b2..3511b062c3 100644 --- a/src/pages/User/content/UserProfile.tsx +++ b/src/pages/User/content/UserProfile.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { useParams } from 'react-router-dom' +import { useParams } from '@remix-run/react' import { observer } from 'mobx-react-lite' import { Loader } from 'oa-components' import { useCommonStores } from 'src/common/hooks/useCommonStores' diff --git a/src/pages/User/user.routes.test.tsx b/src/pages/User/user.routes.test.tsx index 30705d78e8..d5dfec7bed 100644 --- a/src/pages/User/user.routes.test.tsx +++ b/src/pages/User/user.routes.test.tsx @@ -1,11 +1,8 @@ import '@testing-library/jest-dom/vitest' -import { - createMemoryRouter, - createRoutesFromElements, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' +import { createRoutesFromElements } from '@remix-run/react' import { act, render, waitFor } from '@testing-library/react' import { Provider } from 'mobx-react' import { useCommonStores } from 'src/common/hooks/useCommonStores' diff --git a/src/pages/User/user.routes.tsx b/src/pages/User/user.routes.tsx index 5f43f408f5..9e1fe01dc9 100644 --- a/src/pages/User/user.routes.tsx +++ b/src/pages/User/user.routes.tsx @@ -1,4 +1,4 @@ -import { Route, Routes } from 'react-router-dom' +import { Route, Routes } from '@remix-run/react' import { UserRole } from 'oa-shared' import { AuthRoute } from '../common/AuthRoute' diff --git a/src/pages/UserSettings/content/formSections/Impact/Impact.section.tsx b/src/pages/UserSettings/content/formSections/Impact/Impact.section.tsx index 31042ad38f..6749356b3a 100644 --- a/src/pages/UserSettings/content/formSections/Impact/Impact.section.tsx +++ b/src/pages/UserSettings/content/formSections/Impact/Impact.section.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react' -import { useLocation } from 'react-router-dom' +import { useLocation } from '@remix-run/react' import IconArrowDown from 'src/assets/icons/icon-arrow-down.svg' import IconArrowUp from 'src/assets/icons/icon-arrow-up.svg' import { IMPACT_YEARS } from 'src/pages/User/impact/constants' diff --git a/src/pages/UserSettings/content/formSections/Impact/ImpactYear.section.tsx b/src/pages/UserSettings/content/formSections/Impact/ImpactYear.section.tsx index 8753e32b23..348551ae6e 100644 --- a/src/pages/UserSettings/content/formSections/Impact/ImpactYear.section.tsx +++ b/src/pages/UserSettings/content/formSections/Impact/ImpactYear.section.tsx @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from 'react' import { Form } from 'react-final-form' -import { useLocation } from 'react-router-dom' +import { useLocation } from '@remix-run/react' import { observer } from 'mobx-react' import { useCommonStores } from 'src/common/hooks/useCommonStores' import { UserContactError } from 'src/pages/User/contact' diff --git a/src/pages/UserSettings/content/formSections/UserInfos.section.tsx b/src/pages/UserSettings/content/formSections/UserInfos.section.tsx index b996e41e14..e1bddb5998 100644 --- a/src/pages/UserSettings/content/formSections/UserInfos.section.tsx +++ b/src/pages/UserSettings/content/formSections/UserInfos.section.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { Field } from 'react-final-form' import { FieldArray } from 'react-final-form-arrays' -import { countries } from 'countries-list' +import countriesList from 'countries-list' import { Button, FieldInput } from 'oa-components' import { ImageInputField } from 'src/common/Form/ImageInput.field' import { SelectField } from 'src/common/Form/Select.field' @@ -151,10 +151,12 @@ export const UserInfosSection = (props: IProps) => { {(field) => ( ({ - label: countries[country].name, - value: country, - }))} + options={Object.keys(countriesList.countries).map( + (country) => ({ + label: countriesList.countries[country].name, + value: country, + }), + )} placeholder="Country" {...field} /> diff --git a/src/pages/UserSettings/content/formSections/UserProfile.test.tsx b/src/pages/UserSettings/content/formSections/UserProfile.test.tsx index 4ce2267dca..eab4596a40 100644 --- a/src/pages/UserSettings/content/formSections/UserProfile.test.tsx +++ b/src/pages/UserSettings/content/formSections/UserProfile.test.tsx @@ -1,12 +1,8 @@ import '@testing-library/jest-dom/vitest' -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { ThemeProvider } from '@emotion/react' +import { createRoutesFromElements, Route } from '@remix-run/react' import { act, render, waitFor } from '@testing-library/react' import { Provider } from 'mobx-react' import { IModerationStatus } from 'oa-shared' diff --git a/src/pages/common/AuthRoute.tsx b/src/pages/common/AuthRoute.tsx index 193b564818..10518c8e1b 100644 --- a/src/pages/common/AuthRoute.tsx +++ b/src/pages/common/AuthRoute.tsx @@ -1,4 +1,4 @@ -import { Navigate } from 'react-router-dom' +import { Navigate } from '@remix-run/react' import { observer } from 'mobx-react' import { BlockedRoute } from 'oa-components' import { AuthWrapper } from 'src/common/AuthWrapper' diff --git a/src/pages/common/DevSiteHeader/DevSiteHeader.tsx b/src/pages/common/DevSiteHeader/DevSiteHeader.tsx index 7c7fb0cce3..89e4528981 100644 --- a/src/pages/common/DevSiteHeader/DevSiteHeader.tsx +++ b/src/pages/common/DevSiteHeader/DevSiteHeader.tsx @@ -2,7 +2,8 @@ import { observer } from 'mobx-react-lite' import { Select } from 'oa-components' import { UserRole } from 'oa-shared' import { useCommonStores } from 'src/common/hooks/useCommonStores' -import { DEV_SITE_ROLE, SITE, VERSION } from 'src/config/config' +import { SITE, VERSION } from 'src/config/config' +import { getDevSiteRole } from 'src/config/devSiteConfig' import { Box, Flex, Text } from 'theme-ui' /** @@ -12,6 +13,7 @@ import { Box, Flex, Text } from 'theme-ui' const DevSiteHeader = observer(() => { const { themeStore } = useCommonStores().stores const theme = themeStore.currentTheme.styles + return ( <> {showDevSiteHeader() && ( @@ -45,7 +47,7 @@ const DevSiteHeader = observer(() => { options={siteRoles} placeholder="Role" defaultValue={ - siteRoles.find((s) => s.value === DEV_SITE_ROLE) || + siteRoles.find((s) => s.value === getDevSiteRole()) || siteRoles[0] } onChange={(s: any) => setSiteRole(s.value)} @@ -115,7 +117,7 @@ const siteRoles: { value: UserRole | null; label: string }[] = [ const setSite = async (site: string) => { await clearCache(false) localStorage.setItem('devSiteVariant', site) - localStorage.setItem('devSiteRole', DEV_SITE_ROLE) + localStorage.setItem('devSiteRole', getDevSiteRole()) window.location.reload() } diff --git a/src/pages/common/GlobalSiteFooter/GlobalSiteFooter.tsx b/src/pages/common/GlobalSiteFooter/GlobalSiteFooter.tsx index d8def10126..a4a24fe9bb 100644 --- a/src/pages/common/GlobalSiteFooter/GlobalSiteFooter.tsx +++ b/src/pages/common/GlobalSiteFooter/GlobalSiteFooter.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { useLocation } from 'react-router-dom' +import { useLocation } from '@remix-run/react' import { SiteFooter } from 'oa-components' const isFooterVisible = (path) => { @@ -11,7 +11,7 @@ const isFooterVisible = (path) => { const GlobalSiteFooter = () => { const location = useLocation() const [showFooter, setShowFooter] = useState( - isFooterVisible(window.location.pathname), + isFooterVisible(location.pathname), ) useEffect( diff --git a/src/pages/common/Header/Menu/Logo/Logo.tsx b/src/pages/common/Header/Menu/Logo/Logo.tsx index 13487c621c..1cdeabcced 100644 --- a/src/pages/common/Header/Menu/Logo/Logo.tsx +++ b/src/pages/common/Header/Menu/Logo/Logo.tsx @@ -1,4 +1,4 @@ -import { Link } from 'react-router-dom' +import { Link } from '@remix-run/react' import { observer } from 'mobx-react' import { useCommonStores } from 'src/common/hooks/useCommonStores' import { VERSION } from 'src/config/config' diff --git a/src/pages/common/Header/Menu/MenuDesktop.tsx b/src/pages/common/Header/Menu/MenuDesktop.tsx index 452dd57046..20df6e269f 100644 --- a/src/pages/common/Header/Menu/MenuDesktop.tsx +++ b/src/pages/common/Header/Menu/MenuDesktop.tsx @@ -1,7 +1,6 @@ -import { NavLink } from 'react-router-dom' import styled from '@emotion/styled' +import { NavLink } from '@remix-run/react' import MenuCurrent from 'src/assets/images/menu-current.svg' -import { AuthWrapper } from 'src/common/AuthWrapper' import { getSupportedModules } from 'src/modules' import { getAvailablePageList } from 'src/pages/PageList' import { Flex } from 'theme-ui' @@ -39,22 +38,13 @@ const MenuLink = styled(NavLink)` export const MenuDesktop = () => ( - {getAvailablePageList(getSupportedModules()).map((page) => { - const link = ( - - - {page.title} - - - ) - return page.requiredRole ? ( - - {link} - - ) : ( - link - ) - })} + {getAvailablePageList(getSupportedModules()).map((page) => ( + + + {page.title} + + + ))} ) diff --git a/src/pages/common/Header/Menu/MenuMobile/MenuMobileLink.tsx b/src/pages/common/Header/Menu/MenuMobile/MenuMobileLink.tsx index dacb193212..7c628c58ff 100644 --- a/src/pages/common/Header/Menu/MenuMobile/MenuMobileLink.tsx +++ b/src/pages/common/Header/Menu/MenuMobile/MenuMobileLink.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { NavLink } from 'react-router-dom' import styled from '@emotion/styled' +import { NavLink } from '@remix-run/react' import MenuCurrent from 'src/assets/images/menu-current.svg' import { Box } from 'theme-ui' diff --git a/src/pages/common/Header/Menu/Profile/Profile.tsx b/src/pages/common/Header/Menu/Profile/Profile.tsx index 7b7e52f741..9a9ad0ffc7 100644 --- a/src/pages/common/Header/Menu/Profile/Profile.tsx +++ b/src/pages/common/Header/Menu/Profile/Profile.tsx @@ -1,5 +1,6 @@ import React, { useState } from 'react' import Foco from 'react-foco' +import { useNavigate } from '@remix-run/react' import { observer } from 'mobx-react' import { MemberBadge } from 'oa-components' import { useCommonStores } from 'src/common/hooks/useCommonStores' @@ -23,6 +24,7 @@ interface IProps { const Profile = observer((props: IProps) => { const { userStore } = useCommonStores().stores + const navigate = useNavigate() const [state, setState] = useState({ showProfileModal: false, isLoading: true, @@ -59,7 +61,7 @@ const Profile = observer((props: IProps) => { mt: 1, }} > - + {COMMUNITY_PAGES_PROFILE.map((page) => ( { userStore.logout()} + onClick={async () => { + await userStore.logout() + navigate('/') + }} /> ) : ( diff --git a/src/pages/common/Header/Menu/Profile/ProfileButtonItem.tsx b/src/pages/common/Header/Menu/Profile/ProfileButtonItem.tsx index c1f273f4c1..2612e8f9c3 100644 --- a/src/pages/common/Header/Menu/Profile/ProfileButtonItem.tsx +++ b/src/pages/common/Header/Menu/Profile/ProfileButtonItem.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { Link } from 'react-router-dom' +import { Link } from '@remix-run/react' import { Button } from 'oa-components' import { MobileMenuContext } from '../../MobileMenuContext' diff --git a/src/pages/common/Header/Menu/ProfileModal/ProfileModal.tsx b/src/pages/common/Header/Menu/ProfileModal/ProfileModal.tsx index 40edf28b29..c2e3f7b0dd 100644 --- a/src/pages/common/Header/Menu/ProfileModal/ProfileModal.tsx +++ b/src/pages/common/Header/Menu/ProfileModal/ProfileModal.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { NavLink } from 'react-router-dom' import styled from '@emotion/styled' +import { NavLink } from '@remix-run/react' import { observer } from 'mobx-react' import { preciousPlasticTheme } from 'oa-themes' import { useCommonStores } from 'src/common/hooks/useCommonStores' diff --git a/src/pages/common/Header/getFormattedNotifications.test.tsx b/src/pages/common/Header/getFormattedNotifications.test.tsx index 51327fa984..3980b0a22f 100644 --- a/src/pages/common/Header/getFormattedNotifications.test.tsx +++ b/src/pages/common/Header/getFormattedNotifications.test.tsx @@ -1,11 +1,7 @@ import '@testing-library/jest-dom/vitest' -import { - createMemoryRouter, - createRoutesFromElements, - Route, - RouterProvider, -} from 'react-router-dom' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' +import { createRoutesFromElements, Route } from '@remix-run/react' import { render } from '@testing-library/react' import { NotificationTypes } from 'oa-shared' import { FactoryNotification } from 'src/test/factories/Notification' diff --git a/src/pages/common/Layout/Main.tsx b/src/pages/common/Layout/Main.tsx index ed53375c22..722a39b507 100644 --- a/src/pages/common/Layout/Main.tsx +++ b/src/pages/common/Layout/Main.tsx @@ -25,23 +25,19 @@ const Main = (props: IProps) => { {props.children} diff --git a/src/pages/index.tsx b/src/pages/index.tsx deleted file mode 100644 index 048014d6c2..0000000000 --- a/src/pages/index.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import React, { Suspense } from 'react' -import { - createBrowserRouter, - createRoutesFromElements, - Navigate, - Outlet, - Route, - RouterProvider, -} from 'react-router-dom' -import { Analytics } from 'src/common/Analytics' -import { getSupportedModules, isModuleSupported, MODULE } from 'src/modules' -import Main from 'src/pages/common/Layout/Main' -import { SeoTagsUpdateComponent } from 'src/utils/seo' -import { Flex } from 'theme-ui' - -import { ScrollToTop } from '../common/ScrollToTop' -import { StickyButton } from './common/StickyButton' -import { NotFoundPage } from './NotFound/NotFound' -import { - COMMUNITY_PAGES_PROFILE, - getAvailablePageList, - NO_HEADER_PAGES, - POLICY_PAGES, -} from './PageList' -import { QuestionModuleContainer } from './Question' - -export const Pages = () => { - // any, - // { - // singlePageMode: boolean - // displayPageComponent?: any - // supportedRoutes?: IPageMeta[] - // } - // > { - // we are rendering different pages and navigation dependent on whether the user has navigated directly to view the - // entire site, or just one page of it via subdomains. This is so we can effectively integrate just parts of this - // platform into other sites. The first case is direct nav - const menuItems = [ - ...getAvailablePageList(getSupportedModules()), - ...COMMUNITY_PAGES_PROFILE, - ...NO_HEADER_PAGES, - ...POLICY_PAGES, - ] - - const routeElements = [ - ...menuItems.map((page) => ( - - -
- <>{page.component} -
- - } - /> - )), - } />, - } />, - ] - if (isModuleSupported(MODULE.QUESTION)) { - routeElements.push( - - -
- -
- - } - />, - ) - } - - const router = createBrowserRouter( - createRoutesFromElements([ - } - > - - - - - - } - key="index" - > - {routeElements} - , - ]), - ) - - return ( - - - - ) -} diff --git a/src/root.tsx b/src/root.tsx new file mode 100644 index 0000000000..b10153cd89 --- /dev/null +++ b/src/root.tsx @@ -0,0 +1,73 @@ +import { useContext, useEffect } from 'react' +import { withEmotionCache } from '@emotion/react' +import { + Links, + Meta, + Outlet, + // Scripts, + ScrollRestoration, +} from '@remix-run/react' + +import { ClientStyleContext, ServerStyleContext } from './styles/context' + +interface DocumentProps { + children: React.ReactNode +} + +const Document = withEmotionCache( + ({ children }: DocumentProps, emotionCache) => { + const serverStyleData = useContext(ServerStyleContext) + const clientStyleData = useContext(ClientStyleContext) + + // Only executed on client + useEffect(() => { + // re-link sheet container + emotionCache.sheet.container = document.head + // re-inject tags + const tags = emotionCache.sheet.tags + emotionCache.sheet.flush() + tags.forEach((tag) => { + ;(emotionCache.sheet as any)._insertTag(tag) + }) + // reset cache to reapply global styles + clientStyleData?.reset() + }, []) + + return ( + + + + + + + + + {serverStyleData?.map(({ key, ids, css }) => ( +