Skip to content

Commit

Permalink
Merge pull request #190 from SFTtech/milo/remove-recoil
Browse files Browse the repository at this point in the history
refactor(frontend): remove recoil from web
  • Loading branch information
mikonse authored Jan 4, 2024
2 parents c1735ac + a29a5e7 commit 56604a1
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as React from "react";
import { selectIsAuthenticated } from "@abrechnung/redux";
import { Link as RouterLink, Navigate, Outlet, useLocation, useParams } from "react-router-dom";
import { selectAuthSlice, useAppSelector } from "@/store";
import { useRecoilValue } from "recoil";
import { ListItemLink } from "@/components/style/ListItemLink";
import { SidebarGroupList } from "@/app/authenticated-layout/SidebarGroupList";
import {
Expand Down Expand Up @@ -40,13 +39,13 @@ import {
Paid,
People,
} from "@mui/icons-material";
import { config } from "@/state/config";
import { useTheme } from "@mui/material/styles";
import { Banner } from "@/components/style/Banner";
import { Loading } from "@/components/style/Loading";
import styles from "./AuthenticatedLayout.module.css";
import { LanguageSelect } from "@/components/LanguageSelect";
import { useTranslation } from "react-i18next";
import { useConfig } from "@/core/config";

const drawerWidth = 240;
const AUTH_FALLBACK = "/login";
Expand All @@ -60,7 +59,7 @@ export const AuthenticatedLayout: React.FC = () => {
const [anchorEl, setAnchorEl] = React.useState(null);
const theme: Theme = useTheme();
const dotsMenuOpen = Boolean(anchorEl);
const cfg = useRecoilValue(config);
const cfg = useConfig();
const isLargeScreen = useMediaQuery(theme.breakpoints.up("sm"));

const [mobileOpen, setMobileOpen] = React.useState(true);
Expand Down
7 changes: 2 additions & 5 deletions frontend/apps/web/src/components/style/Banner.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from "react";
import { Alert, AlertTitle } from "@mui/material";
import { useRecoilValue } from "recoil";
import { config } from "@/state/config";
import { useConfig } from "@/core/config";

export const Banner: React.FC = () => {
const cfg = useRecoilValue(config);
const cfg = useConfig();
if (cfg.error) {
return (
<Alert sx={{ borderRadius: 0 }} color="error">
Expand All @@ -23,5 +22,3 @@ export const Banner: React.FC = () => {
</>
);
};

export default Banner;
92 changes: 92 additions & 0 deletions frontend/apps/web/src/core/config.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import * as React from "react";
import { z } from "zod";
import { environment } from "@/environments/environment";
import { AlertColor } from "@mui/material/Alert/Alert";
import Loading from "@/components/style/Loading";
import { Alert, AlertTitle } from "@mui/material";

const configSchema = z.object({
imprintURL: z.string().optional().nullable(),
sourceCodeURL: z.string().optional(),
issueTrackerURL: z.string().optional().nullable(),
messages: z
.array(
z.object({
type: z.union([z.literal("info"), z.literal("error"), z.literal("warning"), z.literal("success")]),
title: z.string().default(null).nullable(),
body: z.string(),
})
)
.optional(),
error: z.string().optional(),
});

export interface StatusMessage {
type: AlertColor;
title: string | null;
body: string;
}

export type Config = z.infer<typeof configSchema>;

const ConfigContext = React.createContext<Config>(null as Config);

export type ConfigProviderProps = {
children: React.ReactNode;
};

type ConfigState =
| {
state: "loaded";
config: Config;
}
| {
state: "loading";
}
| {
state: "error";
error: string;
};

const invalidConfigurationMessage = "This frontend is configured incorrectly, please contact your server administrator";

export const ConfigProvider: React.FC<ConfigProviderProps> = ({ children }) => {
const [state, setState] = React.useState<ConfigState>({ state: "loading" });

React.useEffect(() => {
const fetcher = async () => {
try {
const path = environment.production ? "/config.json" : "/assets/config.json";
const resp = await fetch(path, { headers: { "Content-Type": "application/json" } });
const data = await resp.json();
const parsed = configSchema.safeParse(data);
if (parsed.success) {
setState({ state: "loaded", config: parsed.data });
} else {
setState({ state: "error", error: invalidConfigurationMessage });
}
} catch (e) {
setState({ state: "error", error: invalidConfigurationMessage });
}
};
fetcher();
}, []);

if (state.state === "loading") {
return <Loading />;
}

if (state.state === "error") {
return (
<Alert severity="error">
<AlertTitle>Error loading config: {state.error}</AlertTitle>
</Alert>
);
}

return <ConfigContext.Provider value={state.config}>{children}</ConfigContext.Provider>;
};

export const useConfig = () => {
return React.useContext(ConfigContext);
};
18 changes: 9 additions & 9 deletions frontend/apps/web/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import React from "react";
import * as ReactDOM from "react-dom/client";
import { Provider } from "react-redux";
import { RecoilRoot } from "recoil";
import { PersistGate } from "redux-persist/integration/react";
import { App } from "./app/app";
import { Loading } from "./components/style/Loading";
import "./i18n";
import { persistor, store } from "./store";
import { ConfigProvider } from "./core/config";

const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
<React.StrictMode>
<RecoilRoot>
<Provider store={store}>
<PersistGate loading={<Loading />} persistor={persistor}>
<React.Suspense fallback={<Loading />}>
<Provider store={store}>
<PersistGate loading={<Loading />} persistor={persistor}>
<React.Suspense fallback={<Loading />}>
<ConfigProvider>
<App />
</React.Suspense>
</PersistGate>
</Provider>
</RecoilRoot>
</ConfigProvider>
</React.Suspense>
</PersistGate>
</Provider>
</React.StrictMode>
);
57 changes: 0 additions & 57 deletions frontend/apps/web/src/state/config.ts

This file was deleted.

25 changes: 0 additions & 25 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
"react-router-dom": "6.21.1",
"react-toastify": "^9.1.3",
"recharts": "^2.10.3",
"recoil": "^0.7.7",
"redux-persist": "^6.0.0",
"redux-persist-filesystem-storage": "^4.2.0",
"regenerator-runtime": "0.14.1",
Expand Down

0 comments on commit 56604a1

Please sign in to comment.