Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

refactor: use jotai instead of redux #68

Merged
merged 6 commits into from
Aug 27, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@
"@types/react-ga": "^2.3.0",
"@types/react-intl": "^3.0.0",
"@types/react-leaflet": "^2.5.2",
"@types/react-redux": "^7.1.16",
"@types/storybook__addon-info": "^5.2.2",
"@types/styled-components": "^5.1.7",
"@types/webpack": "^4.41.26",
Expand Down Expand Up @@ -151,7 +150,6 @@
"@emotion/styled": "^11.1.5",
"@popperjs/core": "^2.6.0",
"@reach/router": "^1.3.4",
"@reduxjs/toolkit": "^1.5.0",
"@rot1024/use-transition": "^1.0.0",
"@sentry/browser": "^6.7.1",
"@types/gapi.auth2": "^0.0.54",
Expand All @@ -164,14 +162,13 @@
"array-move": "^3.0.1",
"axios": "^0.21.1",
"cesium": "^1.84.0",
"cesium-navigation": "^1.0.0",
"core-js": "^3.8.3",
"date-fns": "^2.17.0",
"detect-browser": "^5.2.0",
"formik": "^2.2.6",
"github-markdown-css": "^4.0.0",
"graphql": "^15.5.0",
"history": "^5.0.0",
"jotai": "^1.3.1",
"leaflet": "^1.7.1",
"lodash-es": "^4.17.20",
"mini-svg-data-uri": "^1.2.3",
Expand All @@ -193,11 +190,9 @@
"react-nl2br": "^1.0.2",
"react-player": "^2.8.2",
"react-popper": "^2.2.4",
"react-redux": "^7.2.2",
"react-spinners": "^0.10.4",
"react-svg": "^14.0.7",
"react-use": "^17.1.1",
"redux-first-history": "^4.5.0",
"regenerator-runtime": "^0.13.7",
"remark-gfm": "^1.0.0",
"resium": "^1.13.1",
Expand Down
67 changes: 28 additions & 39 deletions src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import React, { Suspense } from "react";
import { Router, Redirect } from "@reach/router";
import { LocationProvider } from "@reach/router";
import { createBrowserHistory } from "history";
import { reachify } from "redux-first-history";

import { Provider as IntlProvider } from "@reearth/locale";
import { Provider as ThemeProvider, styled } from "./theme";
import { Provider as GqlProvider } from "./gql";
import { Provider as LocalStateProvider } from "./state";
import { Provider as DndProvider } from "./util/use-dnd";
import { Provider as Auth0Provider } from "./auth";
import { Provider as IntlProvider } from "@reearth/locale";

import NotFound from "@reearth/components/pages/NotFound";
import Loading from "@reearth/components/atoms/Loading";
Expand Down Expand Up @@ -38,43 +34,36 @@ if (enableWhyDidYouRender && process.env.NODE_ENV === "development") {
const EarthEditor = React.lazy(() => import("@reearth/components/pages/EarthEditor"));
const Dashboard = React.lazy(() => import("@reearth/components/pages/Dashboard"));

const history = createBrowserHistory();
const reachHistory = reachify(history);

const App: React.FC = () => {
return (
<Auth0Provider>
<LocalStateProvider>
<GqlProvider>
<ThemeProvider>
<LocationProvider history={reachHistory}>
<DndProvider>
<IntlProvider>
<Suspense fallback={<Loading />}>
<StyledRouter>
<TopPage path="/" />
<Dashboard path="/dashboard/:teamId" />
<EarthEditor path="/edit/:sceneId" />
<Preview path="/edit/:sceneId/preview" />
<Redirect from="/settings" to="/settings/account" />
<AccountSettings path="/settings/account" />
<WorkspaceList path="/settings/workspaces" />
<WorkspaceSettings path="/settings/workspace/:teamId" />
<SettingsProjectList path="/settings/workspace/:teamId/projects" />
<AssetSettings path="/settings/workspace/:teamId/asset" />
<ProjectSettings path="/settings/project/:projectId" />
<PublicSettings path="/settings/project/:projectId/public" />
<DatasetSettings path="/settings/project/:projectId/dataset" />
<PluginSettings path="/settings/project/:projectId/plugins" />
<NotFound default />
</StyledRouter>
</Suspense>
</IntlProvider>
</DndProvider>
</LocationProvider>
</ThemeProvider>
</GqlProvider>
</LocalStateProvider>
<GqlProvider>
<ThemeProvider>
<DndProvider>
<IntlProvider>
<Suspense fallback={<Loading />}>
<StyledRouter>
<TopPage path="/" />
<Dashboard path="/dashboard/:teamId" />
<EarthEditor path="/edit/:sceneId" />
<Preview path="/edit/:sceneId/preview" />
<Redirect from="/settings" to="/settings/account" />
<AccountSettings path="/settings/account" />
<WorkspaceList path="/settings/workspaces" />
<WorkspaceSettings path="/settings/workspace/:teamId" />
<SettingsProjectList path="/settings/workspace/:teamId/projects" />
<AssetSettings path="/settings/workspace/:teamId/asset" />
<ProjectSettings path="/settings/project/:projectId" />
<PublicSettings path="/settings/project/:projectId/public" />
<DatasetSettings path="/settings/project/:projectId/dataset" />
<PluginSettings path="/settings/project/:projectId/plugins" />
<NotFound default />
</StyledRouter>
</Suspense>
</IntlProvider>
</DndProvider>
</ThemeProvider>
</GqlProvider>
</Auth0Provider>
);
};
Expand Down
25 changes: 24 additions & 1 deletion src/auth/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { useEffect, useState } from "react";
export const errorKey = "reeartherror";

export default function useAuth() {
const { isAuthenticated, error, isLoading, loginWithRedirect, logout } = useAuth0();
const { isAuthenticated, error, isLoading, loginWithRedirect, logout, getAccessTokenSilently } =
useAuth0();

return {
isAuthenticated: !!window.REEARTH_E2E_ACCESS_TOKEN || (isAuthenticated && !error),
isLoading,
error: error?.message,
getAccessToken: () => getAccessTokenSilently(),
login: () => loginWithRedirect(),
logout: () =>
logout({
Expand Down Expand Up @@ -46,3 +48,24 @@ export function useCleanUrl() {

return error;
}

export function useAuthenticationRequired(): [boolean, string | undefined] {
const { isAuthenticated, isLoading, error: authError, login, logout } = useAuth();

useEffect(() => {
if (isLoading || isAuthenticated) {
return;
}

if (authError) {
logout();
return;
}

login();
}, [authError, isAuthenticated, isLoading, login, logout]);

const error = useCleanUrl();

return [isAuthenticated, error];
}
2 changes: 0 additions & 2 deletions src/auth/index.ts

This file was deleted.

14 changes: 14 additions & 0 deletions src/auth/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React, { PropsWithChildren } from "react";
import { useAuthenticationRequired } from "./hooks";

export { default as Provider } from "./provider";
export { default as useAuth, useCleanUrl, useAuthenticationRequired } from "./hooks";

export { withAuthenticationRequired } from "@auth0/auth0-react";

export function AuthenticationRequiredPage({
children,
}: PropsWithChildren<unknown>): JSX.Element | null {
const [isAuthenticated] = useAuthenticationRequired(); // TODO: show error
return isAuthenticated && children ? <>{children}</> : null;
}
75 changes: 47 additions & 28 deletions src/components/organisms/Dashboard/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import { useIntl } from "react-intl";

import { useNavigate } from "@reach/router";
import { useLocalState } from "@reearth/state";
import {
useError,
useTeam,
useProject,
useSceneId,
useSelected,
useSelectedBlock,
useCamera,
useIsCapturing,
} from "@reearth/state";
import {
useMeQuery,
useCreateTeamMutation,
Expand All @@ -22,11 +32,15 @@ import { Team } from "@reearth/components/molecules/Dashboard/types";
export type AssetNodes = NonNullable<AssetsQuery["assets"]["nodes"][number]>[];

export default (teamId?: string) => {
const [{ error, currentTeam, currentProject }, setLocalState] = useLocalState(s => ({
error: s.error,
currentTeam: s.currentTeam,
currentProject: s.currentProject,
}));
const [error, setError] = useError();
const [currentTeam, setCurrentTeam] = useTeam();
const [currentProject, setCurrentProject] = useProject();
const [, setSceneId] = useSceneId();
const [, setSelected] = useSelected();
const [, setSelectedBlock] = useSelectedBlock();
const [, setCamera] = useCamera();
const [, setIsCapturing] = useIsCapturing();

const { data, refetch } = useMeQuery();
const [modalShown, setModalShown] = useState(false);
const openModal = useCallback(() => setModalShown(true), []);
Expand All @@ -49,19 +63,19 @@ export default (teamId?: string) => {

useEffect(() => {
if (team?.id && team.id !== currentTeam?.id) {
setLocalState({ currentTeam: team });
setCurrentTeam(team);
}
}, [currentTeam, team, setLocalState]);
}, [currentTeam, team, setCurrentTeam]);

const changeTeam = useCallback(
(teamId: string) => {
const team = teams?.find(team => team.id === teamId);
if (team) {
setLocalState({ currentTeam: team });
setCurrentTeam(team);
navigate(`/dashboard/${teamId}`);
}
},
[teams, setLocalState, navigate],
[teams, setCurrentTeam, navigate],
);

const [createTeamMutation] = useCreateTeamMutation();
Expand All @@ -72,12 +86,12 @@ export default (teamId?: string) => {
refetchQueries: ["teams"],
});
if (results.data?.createTeam) {
setLocalState({ currentTeam: results.data.createTeam.team });
setCurrentTeam(results.data.createTeam.team);
navigate(`/dashboard/${results.data.createTeam.team.id}`);
}
refetch();
},
[createTeamMutation, setLocalState, refetch, navigate],
[createTeamMutation, setCurrentTeam, refetch, navigate],
);

const notificationTimeout = 5000;
Expand All @@ -89,33 +103,38 @@ export default (teamId?: string) => {
useEffect(() => {
if (!error) return;
const timerID = setTimeout(() => {
setLocalState({ error: undefined });
setError(undefined);
}, notificationTimeout);
return () => clearTimeout(timerID);
}, [error, setLocalState]);
}, [error, setError]);

const onNotificationClose = useCallback(() => {
if (error) {
setLocalState({ error: undefined });
setError(undefined);
}
}, [error, setLocalState]);
}, [error, setError]);

useEffect(() => {
// unselect project
if (currentProject) {
setLocalState({
currentProject: undefined,
sceneId: undefined,
rootLayerId: undefined,
selectedLayer: undefined,
selectedWidget: undefined,
selectedBlock: undefined,
selectedType: undefined,
camera: undefined,
isCapturing: undefined,
});
setCurrentProject(undefined);
setCurrentTeam(undefined);
setSceneId(undefined);
setSelected(undefined);
setSelectedBlock(undefined);
setCamera(undefined);
setIsCapturing(false);
}
}, [currentProject, setLocalState]);
}, [
currentProject,
setCamera,
setCurrentProject,
setCurrentTeam,
setIsCapturing,
setSceneId,
setSelected,
setSelectedBlock,
]);

const handleModalClose = useCallback(
(r?: boolean) => {
Expand Down
Loading