Skip to content

Commit

Permalink
Merge pull request #716 from rishabhsharma1997/redux/middleware
Browse files Browse the repository at this point in the history
Redux/middleware
  • Loading branch information
aabidsofi19 authored Aug 14, 2024
2 parents 52bfc6f + e60f0a4 commit 8eed0c2
Show file tree
Hide file tree
Showing 8 changed files with 1,507 additions and 573 deletions.
1,925 changes: 1,355 additions & 570 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@types/jest": "^29.5.11",
"@types/react": "^18.2.45",
"@types/react-dom": "^18.2.18",
"@types/react-redux": "^7.1.33",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
"commitizen": "^4.3.0",
Expand All @@ -67,10 +68,13 @@
"prettier-plugin-organize-imports": "^3.2.3",
"react-error-boundary": "^4.0.12",
"react-markdown": "^8.0.7",
"react-redux": "^8.1.1",
"redux": "^5.0.1",
"rehype-raw": "^6.1.1",
"remark-gfm": "^3.0.1",
"ts-jest": "^29.1.1",
"tsup": "^8.0.1",
"@types/lodash": "^4.17.7",
"tsup": "^8.2.4",
"typescript": "^5.3.3"
},
"peerDependencies": {
Expand All @@ -79,12 +83,16 @@
"@mui/material": "^5.15.11",
"@types/mui-datatables": "*",
"@xstate/react": "^4.1.1",
"lodash": "^4.17.21",
"mui-datatables": "*",
"react": ">=17",
"react-dom": ">=17",
"xstate": "^5.13.0"
},
"peerDependenciesMeta": {
"lodash": {
"optional": true
},
"@emotion/react": {
"optional": true
},
Expand Down
2 changes: 1 addition & 1 deletion src/custom/Stepper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ interface CustomizedStepperPropsI {
stepLabels: string[];
children: React.ReactNode;
icons: React.ComponentType<IconProps>[];
ContentWrapper?: React.ComponentType;
ContentWrapper?: React.ComponentType<{ children: React.ReactNode }>;
}

interface UseStepperI {
Expand Down
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export * from './base';
export * from './colors';
export * from './custom';
export * from './icons';
export * from './redux-persist';
export * from './schemas';
export * from './theme';
43 changes: 43 additions & 0 deletions src/redux-persist/PersistedStateProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { ThunkDispatch } from '@reduxjs/toolkit';
import { FC, ReactNode, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { Dispatch } from 'redux';
import { RehydrateStateAction } from './initReduxPersist';

interface PersistedStateProviderProps {
children: ReactNode;
loadPersistedState: () => (dispatch: Dispatch<RehydrateStateAction>) => void;
}

export const PersistedStateProvider: FC<PersistedStateProviderProps> = ({
children,
loadPersistedState
}) => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);

const dispatch = useDispatch<ThunkDispatch<any, unknown, RehydrateStateAction>>();

useEffect(() => {
if (!loading) {
return;
}
try {
dispatch(loadPersistedState());
} catch (e) {
setError(e as Error);
}
setLoading(false);
}, [loading, dispatch, loadPersistedState]);

if (error) {
console.error('Error Loading Persisted State', error);
}

if (loading) {
return null;
}

return <>{children}</>;
};
2 changes: 2 additions & 0 deletions src/redux-persist/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './PersistedStateProvider';
export * from './initReduxPersist';
95 changes: 95 additions & 0 deletions src/redux-persist/initReduxPersist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import _ from 'lodash';
import { Dispatch, Store } from 'redux';

const INVALID_REDUCER_PATH = Symbol('INVALID_REDUCER_PATH');
const REHYDRATE_STATE_ACTION = 'REHYDRATE_STATE_ACTION';

export interface RehydrateStateAction {
type: typeof REHYDRATE_STATE_ACTION;
payload: {
reducerPath: string;
inflatedState: unknown;
};
}

type Action = RehydrateStateAction | { type: string; [key: string]: unknown };

interface ActionsToPersist {
[actionType: string]: string[];
}

const rehydrateState = (reducerPath: string, inflatedState: unknown): RehydrateStateAction => ({
type: REHYDRATE_STATE_ACTION,
payload: {
reducerPath,
inflatedState
}
});

const rehydrateStateReducer = (state: unknown, action: Action): unknown => {
if (action.type === REHYDRATE_STATE_ACTION) {
const appState = _.cloneDeep(state);
_.set(
appState as object,
(action.payload as RehydrateStateAction['payload']).reducerPath.split('/'),
(action.payload as RehydrateStateAction['payload']).inflatedState
);
return appState;
}
return state;
};

export const initReduxPersist = (actionsToPersist: ActionsToPersist) => {
const createPersistEnhancedReducer =
(reducer: (state: unknown, action: Action) => unknown) =>
(state: unknown, action: Action): unknown => {
const newState = rehydrateStateReducer(state, action);
return reducer(newState, action);
};

const persistMiddleware =
(store: Store) =>
(next: (action: Action) => unknown) =>
(action: Action): unknown => {
const result = next(action);

const reducersToPersist = actionsToPersist[action.type];

if (reducersToPersist) {
const appState = store.getState();
reducersToPersist.forEach((reducerPath) => {
const path = reducerPath.split('/');
const stateToPersist = _.get(appState, path, INVALID_REDUCER_PATH);

if (stateToPersist === INVALID_REDUCER_PATH) {
throw new Error(`Reducer Path to Persist Is Invalid: ${reducerPath}`);
}

localStorage.setItem(reducerPath, JSON.stringify(stateToPersist));
});
}
return result;
};

const loadPersistedState = () => (dispatch: Dispatch<RehydrateStateAction>) => {
Object.values(actionsToPersist).forEach((reducerPaths) => {
reducerPaths.forEach((path) => {
let inflatedState = localStorage.getItem(path);
try {
if (inflatedState) {
inflatedState = JSON.parse(inflatedState);
dispatch(rehydrateState(path, inflatedState));
}
} catch (e) {
console.error(`Error rehydrating state for reducer ${path}`, inflatedState);
}
});
});
};

return {
persistMiddleware,
createPersistEnhancedReducer,
loadPersistedState
};
};
2 changes: 1 addition & 1 deletion tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { defineConfig } from 'tsup';
const env = process.env.NODE_ENV;

export default defineConfig({
outdir: 'dist',
outDir: 'dist',
entry: ['src/index.tsx'],
bundle: env === 'production',
clean: true,
Expand Down

0 comments on commit 8eed0c2

Please sign in to comment.