split widget and default App components
use router in default App for retrieving quizId from url add QuizIdContext
This commit is contained in:
parent
db541d97ef
commit
fb3d46110f
@ -27,6 +27,7 @@
|
|||||||
"notistack": "^3.0.1",
|
"notistack": "^3.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"react-router-dom": "^6.21.3",
|
||||||
"swr": "^2.2.4",
|
"swr": "^2.2.4",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"use-debounce": "^9.0.4",
|
"use-debounce": "^9.0.4",
|
||||||
|
62
src/App.tsx
62
src/App.tsx
@ -1,56 +1,24 @@
|
|||||||
import { Box, CssBaseline, ThemeProvider } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
import { LocalizationProvider } from "@mui/x-date-pickers";
|
import ContextProviders from "ContextProviders";
|
||||||
import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment";
|
import { QuizIdContext } from "contexts/QuizIdContext";
|
||||||
import { ruRU } from '@mui/x-date-pickers/locales';
|
import { useParams } from "react-router-dom";
|
||||||
import moment from "moment";
|
|
||||||
import { SnackbarProvider } from 'notistack';
|
|
||||||
import { SWRConfig } from "swr";
|
|
||||||
import { ViewPage } from "./pages/ViewPublicationPage/ViewPublicationPage";
|
import { ViewPage } from "./pages/ViewPublicationPage/ViewPublicationPage";
|
||||||
import lightTheme from "./utils/themes/light";
|
|
||||||
|
|
||||||
|
|
||||||
const defaultQuizId = "ef836ff8-35b1-4031-9acf-af5766bac2b2";
|
const defaultQuizId = "ef836ff8-35b1-4031-9acf-af5766bac2b2";
|
||||||
|
|
||||||
moment.locale("ru");
|
export default function App() {
|
||||||
const localeText = ruRU.components.MuiLocalizationProvider.defaultProps.localeText;
|
const quizId = useParams().quizId ?? defaultQuizId;
|
||||||
|
|
||||||
interface Props {
|
|
||||||
widget?: boolean;
|
|
||||||
quizId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function App({ widget = false, quizId }: Props) {
|
|
||||||
quizId ??= defaultQuizId;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SWRConfig value={{
|
<QuizIdContext.Provider value={quizId}>
|
||||||
revalidateOnFocus: false,
|
<ContextProviders>
|
||||||
shouldRetryOnError: false,
|
<Box sx={{
|
||||||
}}>
|
height: "100dvh",
|
||||||
<LocalizationProvider dateAdapter={AdapterMoment} adapterLocale="ru" localeText={localeText}>
|
}}>
|
||||||
<ThemeProvider theme={lightTheme}>
|
<ViewPage />
|
||||||
<SnackbarProvider
|
</Box>
|
||||||
preventDuplicate={true}
|
</ContextProviders>
|
||||||
style={{ backgroundColor: lightTheme.palette.brightPurple.main }}
|
</QuizIdContext.Provider>
|
||||||
>
|
|
||||||
<CssBaseline />
|
|
||||||
{widget ? (
|
|
||||||
<Box sx={{
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
}}>
|
|
||||||
<ViewPage quizId={quizId} />
|
|
||||||
</Box>
|
|
||||||
) : (
|
|
||||||
<Box sx={{
|
|
||||||
height: "100dvh",
|
|
||||||
}}>
|
|
||||||
<ViewPage quizId={quizId} />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</SnackbarProvider>
|
|
||||||
</ThemeProvider>
|
|
||||||
</LocalizationProvider>
|
|
||||||
</SWRConfig>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
38
src/ContextProviders.tsx
Normal file
38
src/ContextProviders.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { CssBaseline, ThemeProvider } from "@mui/material";
|
||||||
|
import { LocalizationProvider } from "@mui/x-date-pickers";
|
||||||
|
import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment";
|
||||||
|
import { ruRU } from '@mui/x-date-pickers/locales';
|
||||||
|
import moment from "moment";
|
||||||
|
import { SnackbarProvider } from 'notistack';
|
||||||
|
import { SWRConfig } from "swr";
|
||||||
|
import lightTheme from "./utils/themes/light";
|
||||||
|
|
||||||
|
|
||||||
|
moment.locale("ru");
|
||||||
|
const localeText = ruRU.components.MuiLocalizationProvider.defaultProps.localeText;
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ContextProviders({ children }: Props) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SWRConfig value={{
|
||||||
|
revalidateOnFocus: false,
|
||||||
|
shouldRetryOnError: false,
|
||||||
|
}}>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterMoment} adapterLocale="ru" localeText={localeText}>
|
||||||
|
<ThemeProvider theme={lightTheme}>
|
||||||
|
<SnackbarProvider
|
||||||
|
preventDuplicate={true}
|
||||||
|
style={{ backgroundColor: lightTheme.palette.brightPurple.main }}
|
||||||
|
>
|
||||||
|
<CssBaseline />
|
||||||
|
{children}
|
||||||
|
</SnackbarProvider>
|
||||||
|
</ThemeProvider>
|
||||||
|
</LocalizationProvider>
|
||||||
|
</SWRConfig>
|
||||||
|
);
|
||||||
|
}
|
25
src/WidgetApp.tsx
Normal file
25
src/WidgetApp.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Box } from "@mui/material";
|
||||||
|
import ContextProviders from "ContextProviders";
|
||||||
|
import { QuizIdContext } from "contexts/QuizIdContext";
|
||||||
|
import { ViewPage } from "./pages/ViewPublicationPage/ViewPublicationPage";
|
||||||
|
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
quizId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function WidgetApp({ quizId }: Props) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<QuizIdContext.Provider value={quizId}>
|
||||||
|
<ContextProviders>
|
||||||
|
<Box sx={{
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
}}>
|
||||||
|
<ViewPage />
|
||||||
|
</Box>
|
||||||
|
</ContextProviders>
|
||||||
|
</QuizIdContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
11
src/contexts/QuizIdContext.ts
Normal file
11
src/contexts/QuizIdContext.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { createContext, useContext } from "react";
|
||||||
|
|
||||||
|
|
||||||
|
export const QuizIdContext = createContext<string | null>(null);
|
||||||
|
|
||||||
|
export const useQuizId = () => {
|
||||||
|
const quizId = useContext(QuizIdContext);
|
||||||
|
if (quizId === null) throw new Error("quizId context is null");
|
||||||
|
|
||||||
|
return quizId;
|
||||||
|
};
|
19
src/main.tsx
19
src/main.tsx
@ -1,7 +1,24 @@
|
|||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
|
import { RouterProvider, createBrowserRouter } from "react-router-dom";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
|
||||||
|
|
||||||
|
const router = createBrowserRouter([
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <App />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ":quizId",
|
||||||
|
element: <App />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
const root = createRoot(document.getElementById("root")!);
|
const root = createRoot(document.getElementById("root")!);
|
||||||
|
|
||||||
root.render(<App />);
|
root.render(<RouterProvider router={router} />);
|
||||||
|
@ -13,13 +13,12 @@ import { Question } from "./Question";
|
|||||||
import { StartPageViewPublication } from "./StartPageViewPublication";
|
import { StartPageViewPublication } from "./StartPageViewPublication";
|
||||||
|
|
||||||
import { parseQuizData } from "@model/api/getQuizData";
|
import { parseQuizData } from "@model/api/getQuizData";
|
||||||
|
import { useQuizId } from "contexts/QuizIdContext";
|
||||||
import { replaceSpacesToEmptyLines } from "./tools/replaceSpacesToEmptyLines";
|
import { replaceSpacesToEmptyLines } from "./tools/replaceSpacesToEmptyLines";
|
||||||
|
|
||||||
type Props = {
|
|
||||||
quizId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ViewPage = ({ quizId }: Props) => {
|
export const ViewPage = () => {
|
||||||
|
const quizId = useQuizId();
|
||||||
const { isLoading, error } = useSWR(["quizData", quizId], params => getQuizData(params[1]), {
|
const { isLoading, error } = useSWR(["quizData", quizId], params => getQuizData(params[1]), {
|
||||||
onSuccess: setQuizData,
|
onSuccess: setQuizData,
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import WidgetApp from "./WidgetApp";
|
||||||
import { Root, createRoot } from "react-dom/client";
|
import { Root, createRoot } from "react-dom/client";
|
||||||
import App from "./App";
|
|
||||||
|
|
||||||
|
|
||||||
let root: Root | undefined = undefined;
|
let root: Root | undefined = undefined;
|
||||||
@ -14,7 +14,7 @@ const widget = {
|
|||||||
|
|
||||||
root = createRoot(element);
|
root = createRoot(element);
|
||||||
|
|
||||||
root.render(<App widget quizId={quizId} />);
|
root.render(<WidgetApp quizId={quizId} />);
|
||||||
},
|
},
|
||||||
unmount() {
|
unmount() {
|
||||||
if (root) root.unmount();
|
if (root) root.unmount();
|
||||||
|
20
yarn.lock
20
yarn.lock
@ -737,6 +737,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
|
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
|
||||||
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
||||||
|
|
||||||
|
"@remix-run/router@1.14.2":
|
||||||
|
version "1.14.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.14.2.tgz#4d58f59908d9197ba3179310077f25c88e49ed17"
|
||||||
|
integrity sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==
|
||||||
|
|
||||||
"@rollup/rollup-android-arm-eabi@4.9.5":
|
"@rollup/rollup-android-arm-eabi@4.9.5":
|
||||||
version "4.9.5"
|
version "4.9.5"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.5.tgz#b752b6c88a14ccfcbdf3f48c577ccc3a7f0e66b9"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.5.tgz#b752b6c88a14ccfcbdf3f48c577ccc3a7f0e66b9"
|
||||||
@ -2724,6 +2729,21 @@ react-refresh@^0.14.0:
|
|||||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
|
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
|
||||||
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
|
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
|
||||||
|
|
||||||
|
react-router-dom@^6.21.3:
|
||||||
|
version "6.21.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.21.3.tgz#ef3a7956a3699c7b82c21fcb3dbc63c313ed8c5d"
|
||||||
|
integrity sha512-kNzubk7n4YHSrErzjLK72j0B5i969GsuCGazRl3G6j1zqZBLjuSlYBdVdkDOgzGdPIffUOc9nmgiadTEVoq91g==
|
||||||
|
dependencies:
|
||||||
|
"@remix-run/router" "1.14.2"
|
||||||
|
react-router "6.21.3"
|
||||||
|
|
||||||
|
react-router@6.21.3:
|
||||||
|
version "6.21.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.21.3.tgz#8086cea922c2bfebbb49c6594967418f1f167d70"
|
||||||
|
integrity sha512-a0H638ZXULv1OdkmiK6s6itNhoy33ywxmUFT/xtSoVyf9VnC7n7+VT4LjVzdIHSaF5TIh9ylUgxMXksHTgGrKg==
|
||||||
|
dependencies:
|
||||||
|
"@remix-run/router" "1.14.2"
|
||||||
|
|
||||||
react-transition-group@^4.4.5:
|
react-transition-group@^4.4.5:
|
||||||
version "4.4.5"
|
version "4.4.5"
|
||||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
|
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
|
||||||
|
Loading…
Reference in New Issue
Block a user