Skip to content

Instantly share code, notes, and snippets.

@MuttakinHasib
Last active October 12, 2022 13:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MuttakinHasib/3c421c6e3f6690b075a1f3ed269c7eda to your computer and use it in GitHub Desktop.
Save MuttakinHasib/3c421c6e3f6690b075a1f3ed269c7eda to your computer and use it in GitHub Desktop.
RT+NRW+RP
import React, {
ComponentType,
ReactNode,
useMemo,
useState,
useEffect,
} from "react";
import type { AppProps } from "next/app";
import { GoogleOAuthProvider } from "@react-oauth/google";
import GlobalStyles from "@components/GlobalStyles";
import Layout from "@components/Layouts";
import { Hydrate, QueryClient, QueryClientProvider } from "react-query";
import { ReactQueryDevtools } from "react-query/devtools";
import { wrapper } from "@app/store";
import { MantineProvider } from "@mantine/core";
import { PersistGate } from "redux-persist/integration/react";
import { useStore } from "react-redux";
import { NextComponentType, NextPageContext } from "next";
import { Toaster } from "react-hot-toast";
import baseTheme, { applyTheme } from "themes";
import { DefaultSeo } from "next-seo";
import SEO from "next-seo.config";
import { AnimatePresence } from "framer-motion";
import * as gtag from "@lib/gtag";
import "antd/dist/antd.css";
import "../styles/globals.css";
import "cropperjs/dist/cropper.css";
interface Props extends AppProps {
Component: NextComponentType<NextPageContext, any> & {
Layout: ComponentType;
};
}
function MyApp({ Component, router, pageProps }: Props) {
const [client] = useState<QueryClient>(() => new QueryClient());
const store = useStore();
useEffect(() => {
applyTheme(baseTheme);
}, []);
useEffect(() => {
const handleRouteChange = (url: string) => {
gtag.pageview(url);
};
router.events.on("routeChangeComplete", handleRouteChange);
return () => {
router.events.off("routeChangeComplete", handleRouteChange);
};
}, [router.events]);
const page = useMemo(() => {
const PageLayout = Component.Layout || React.Fragment;
return (
<React.Fragment>
<DefaultSeo {...SEO} />
<AnimatePresence exitBeforeEnter>
<Layout>
<Toaster reverseOrder={false} toastOptions={{ duration: 5000 }} />
<PageLayout>
<GlobalStyles />
<Component {...pageProps} />
{process.env.NODE_ENV === "development" && <ReactQueryDevtools />}
</PageLayout>
</Layout>
</AnimatePresence>
</React.Fragment>
);
}, [Component, pageProps]);
return (
<QueryClientProvider {...{ client }}>
<Hydrate state={pageProps.dehydrateState}>
{/* <PersistWrapper> */}
<GoogleOAuthProvider clientId="538345234542-aulpufnocibib4g6oj554r5abro7g1dj.apps.googleusercontent.com">
<MantineProvider
withGlobalStyles
withNormalizeCSS
theme={{
/** Put your mantine theme override here */
colorScheme: "light",
}}
>
<PersistGate persistor={(store as any).__persistor} loading={null}>
{() => page}
</PersistGate>
</MantineProvider>
</GoogleOAuthProvider>
{/* </PersistWrapper> */}
</Hydrate>
</QueryClientProvider>
);
}
export default wrapper.withRedux(MyApp);
import { onboardCoupleReducer, onboardVenueReducer } from "@features/onboard";
import { userReducer } from "@features/user";
import { combineReducers } from "@reduxjs/toolkit";
export default combineReducers({
"onboard/couple": onboardCoupleReducer,
"onboard/venue": onboardVenueReducer,
user: userReducer,
});
import createWebStorage from "redux-persist/lib/storage/createWebStorage";
const createNoopStorage = () => {
return {
getItem(_key: any) {
return Promise.resolve(null);
},
setItem(_key: any, value: any) {
return Promise.resolve(value);
},
removeItem(_key: any) {
return Promise.resolve();
},
};
};
export const storage =
typeof window !== "undefined"
? createWebStorage("local")
: createNoopStorage();
import {
Action,
AnyAction,
CombinedState,
configureStore,
ThunkAction,
} from "@reduxjs/toolkit";
import { createWrapper, HYDRATE } from "next-redux-wrapper";
import rootReducers from "./reducers";
import { storage } from "./storage";
export const reducers = (
state: ReturnType<typeof rootReducers>,
action: AnyAction
) => {
if (action.type === HYDRATE) {
const nextState = {
...state, // use previous state
...action.payload, // apply delta from hydration
};
// if (state.user) {
// nextState.user = action.payload.user;
// }
// if (state["onboard/couple"]) {
// nextState["onboard/couple"] = action.payload["onboard/couple"];
// }
// if (state["onboard/venue"]) {
// nextState["onboard/venue"] = action.payload["onboard/venue"];
// }
return nextState;
} else {
return rootReducers(state, action);
}
};
const makeConfiguredStore = (reducer: CombinedState<typeof rootReducers>) =>
configureStore({
reducer,
devTools: true,
middleware: (getDefaultMiddleware) => getDefaultMiddleware(),
});
const makeStore = () => {
const isServer = typeof window === "undefined";
if (isServer) {
return makeConfiguredStore(reducers as CombinedState<typeof rootReducers>);
} else {
// we need it only on client side
const { persistStore, persistReducer } = require("redux-persist");
const persistConfig = {
key: "beweddy",
whitelist: ["onboard/couple", "onboard/venue", "user"], // make sure it does not clash with server keys
storage,
};
const persistedReducer = persistReducer(persistConfig, reducers);
const store = makeConfiguredStore(persistedReducer);
// @ts-ignore
store.__persistor = persistStore(store); // Nasty hack
return store;
}
};
export type AppStore = ReturnType<typeof makeStore>;
export type AppState = ReturnType<AppStore["getState"]>;
export type AppDispatch = AppStore["dispatch"];
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
AppState,
unknown,
Action<string>
>;
export const wrapper = createWrapper<AppStore>(makeStore);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment