Skip to content

Commit 4007398

Browse files
Merge branch 'master' of https://github.com/layer5io/sistent into feat/add-debounce-mechanism
Signed-off-by: Senthil Athiban <[email protected]>
2 parents a88ff1d + cf98ff7 commit 4007398

File tree

11 files changed

+1518
-585
lines changed

11 files changed

+1518
-585
lines changed

package-lock.json

Lines changed: 1349 additions & 576 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@types/lodash": "^4.17.7",
5050
"@types/react": "^18.2.45",
5151
"@types/react-dom": "^18.2.18",
52+
"@types/react-redux": "^7.1.33",
5253
"@typescript-eslint/eslint-plugin": "^6.12.0",
5354
"@typescript-eslint/parser": "^6.12.0",
5455
"commitizen": "^4.3.0",
@@ -68,10 +69,13 @@
6869
"prettier-plugin-organize-imports": "^3.2.3",
6970
"react-error-boundary": "^4.0.12",
7071
"react-markdown": "^8.0.7",
72+
"react-redux": "^8.1.1",
73+
"redux": "^5.0.1",
7174
"rehype-raw": "^6.1.1",
7275
"remark-gfm": "^3.0.1",
7376
"ts-jest": "^29.1.1",
74-
"tsup": "^8.0.1",
77+
"@types/lodash": "^4.17.7",
78+
"tsup": "^8.2.4",
7579
"typescript": "^5.3.3"
7680
},
7781
"peerDependencies": {
@@ -80,12 +84,16 @@
8084
"@mui/material": "^5.15.11",
8185
"@types/mui-datatables": "*",
8286
"@xstate/react": "^4.1.1",
87+
"lodash": "^4.17.21",
8388
"mui-datatables": "*",
8489
"react": ">=17",
8590
"react-dom": ">=17",
8691
"xstate": "^5.13.0"
8792
},
8893
"peerDependenciesMeta": {
94+
"lodash": {
95+
"optional": true
96+
},
8997
"@emotion/react": {
9098
"optional": true
9199
},

src/custom/CatalogCard/style.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export const DesignInnerCard = styled('div')(({ theme }) => ({
6666
height: '100%',
6767
textAlign: 'center',
6868
transition: 'transform 0.6s',
69+
background: theme.palette.background.default,
6970
boxShadow: `2px 2px 3px 0px ${theme.palette.background.brand?.default}`,
7071
borderRadius: '0.9375rem'
7172
}));

src/custom/Stepper/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ interface CustomizedStepperPropsI {
2424
stepLabels: string[];
2525
children: React.ReactNode;
2626
icons: React.ComponentType<IconProps>[];
27-
ContentWrapper?: React.ComponentType;
27+
ContentWrapper?: React.ComponentType<{ children: React.ReactNode }>;
2828
}
2929

3030
interface UseStepperI {

src/custom/StyledChapter/StyledChapter.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { styled } from '@mui/material';
2-
import { KEPPEL, SLATE_BLUE, TRANSPARENT_WHITE } from '../../theme';
2+
import { SLATE_BLUE, TRANSPARENT_WHITE } from '../../theme';
33

44
const StyledChapter = styled('div')(({ theme }) => ({
55
color: theme.palette.text.primary,
@@ -15,9 +15,18 @@ const StyledChapter = styled('div')(({ theme }) => ({
1515
},
1616

1717
'& a': {
18-
color: KEPPEL,
18+
color: theme.palette.background.brand?.default,
1919
textDecoration: 'none'
2020
},
21+
'& p > code': {
22+
color: 'inherit',
23+
padding: '.2em .4em',
24+
margin: '0',
25+
fontSize: '85%',
26+
wordBreak: 'normal',
27+
backgroundColor: theme.palette.background.code,
28+
borderRadius: '.25rem'
29+
},
2130
'& pre': {
2231
backgroundColor: '#011627',
2332
padding: '1em',

src/custom/TOCChapter/TOCChapter.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ interface TOCProps {
99

1010
const TOC: React.FC<TOCProps> = ({ availableChapters, currentChapter, onClick }) => {
1111
const reformatTOC = (data: string): string => {
12-
let newData = data.split('-').join(' ');
13-
const firstLetter = newData.charAt(0).toUpperCase();
14-
newData = `${firstLetter}${newData.slice(1)}`;
15-
return newData;
12+
const words = data.split('-');
13+
const formattedString = words
14+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
15+
.join(' ');
16+
return formattedString;
1617
};
1718
return (
1819
<TOCWrapper>

src/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ export * from './base';
33
export * from './colors';
44
export * from './custom';
55
export * from './icons';
6+
export * from './redux-persist';
67
export * from './schemas';
78
export * from './theme';
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import { ThunkDispatch } from '@reduxjs/toolkit';
3+
import { FC, ReactNode, useEffect, useState } from 'react';
4+
import { useDispatch } from 'react-redux';
5+
import { Dispatch } from 'redux';
6+
import { RehydrateStateAction } from './initReduxPersist';
7+
8+
interface PersistedStateProviderProps {
9+
children: ReactNode;
10+
loadPersistedState: () => (dispatch: Dispatch<RehydrateStateAction>) => void;
11+
}
12+
13+
export const PersistedStateProvider: FC<PersistedStateProviderProps> = ({
14+
children,
15+
loadPersistedState
16+
}) => {
17+
const [loading, setLoading] = useState(true);
18+
const [error, setError] = useState<Error | null>(null);
19+
20+
const dispatch = useDispatch<ThunkDispatch<any, unknown, RehydrateStateAction>>();
21+
22+
useEffect(() => {
23+
if (!loading) {
24+
return;
25+
}
26+
try {
27+
dispatch(loadPersistedState());
28+
} catch (e) {
29+
setError(e as Error);
30+
}
31+
setLoading(false);
32+
}, [loading, dispatch, loadPersistedState]);
33+
34+
if (error) {
35+
console.error('Error Loading Persisted State', error);
36+
}
37+
38+
if (loading) {
39+
return null;
40+
}
41+
42+
return <>{children}</>;
43+
};

src/redux-persist/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './PersistedStateProvider';
2+
export * from './initReduxPersist';

src/redux-persist/initReduxPersist.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import _ from 'lodash';
2+
import { Dispatch, Store } from 'redux';
3+
4+
const INVALID_REDUCER_PATH = Symbol('INVALID_REDUCER_PATH');
5+
const REHYDRATE_STATE_ACTION = 'REHYDRATE_STATE_ACTION';
6+
7+
export interface RehydrateStateAction {
8+
type: typeof REHYDRATE_STATE_ACTION;
9+
payload: {
10+
reducerPath: string;
11+
inflatedState: unknown;
12+
};
13+
}
14+
15+
type Action = RehydrateStateAction | { type: string; [key: string]: unknown };
16+
17+
interface ActionsToPersist {
18+
[actionType: string]: string[];
19+
}
20+
21+
const rehydrateState = (reducerPath: string, inflatedState: unknown): RehydrateStateAction => ({
22+
type: REHYDRATE_STATE_ACTION,
23+
payload: {
24+
reducerPath,
25+
inflatedState
26+
}
27+
});
28+
29+
const rehydrateStateReducer = (state: unknown, action: Action): unknown => {
30+
if (action.type === REHYDRATE_STATE_ACTION) {
31+
const appState = _.cloneDeep(state);
32+
_.set(
33+
appState as object,
34+
(action.payload as RehydrateStateAction['payload']).reducerPath.split('/'),
35+
(action.payload as RehydrateStateAction['payload']).inflatedState
36+
);
37+
return appState;
38+
}
39+
return state;
40+
};
41+
42+
export const initReduxPersist = (actionsToPersist: ActionsToPersist) => {
43+
const createPersistEnhancedReducer =
44+
(reducer: (state: unknown, action: Action) => unknown) =>
45+
(state: unknown, action: Action): unknown => {
46+
const newState = rehydrateStateReducer(state, action);
47+
return reducer(newState, action);
48+
};
49+
50+
const persistMiddleware =
51+
(store: Store) =>
52+
(next: (action: Action) => unknown) =>
53+
(action: Action): unknown => {
54+
const result = next(action);
55+
56+
const reducersToPersist = actionsToPersist[action.type];
57+
58+
if (reducersToPersist) {
59+
const appState = store.getState();
60+
reducersToPersist.forEach((reducerPath) => {
61+
const path = reducerPath.split('/');
62+
const stateToPersist = _.get(appState, path, INVALID_REDUCER_PATH);
63+
64+
if (stateToPersist === INVALID_REDUCER_PATH) {
65+
throw new Error(`Reducer Path to Persist Is Invalid: ${reducerPath}`);
66+
}
67+
68+
localStorage.setItem(reducerPath, JSON.stringify(stateToPersist));
69+
});
70+
}
71+
return result;
72+
};
73+
74+
const loadPersistedState = () => (dispatch: Dispatch<RehydrateStateAction>) => {
75+
Object.values(actionsToPersist).forEach((reducerPaths) => {
76+
reducerPaths.forEach((path) => {
77+
let inflatedState = localStorage.getItem(path);
78+
try {
79+
if (inflatedState) {
80+
inflatedState = JSON.parse(inflatedState);
81+
dispatch(rehydrateState(path, inflatedState));
82+
}
83+
} catch (e) {
84+
console.error(`Error rehydrating state for reducer ${path}`, inflatedState);
85+
}
86+
});
87+
});
88+
};
89+
90+
return {
91+
persistMiddleware,
92+
createPersistEnhancedReducer,
93+
loadPersistedState
94+
};
95+
};

0 commit comments

Comments
 (0)