Skip to content

Commit

Permalink
Store session cache (#1202)
Browse files Browse the repository at this point in the history
* Cache state

---------

Co-authored-by: sigurdgroneng <[email protected]>
  • Loading branch information
johatr and tu55eladd authored Oct 10, 2023
1 parent 43f1445 commit 4b7e2cc
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 13 deletions.
9 changes: 6 additions & 3 deletions src/Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import { Provider as ReduxProvider } from 'react-redux';

import { ER_INTERN_FLATE } from './constant';
import FeatureToggle from './moduler/feature/FeatureToggle';
import createStore from './store';
import createStore, { RootState } from './store';

interface Props {
children: React.ReactNode;
setFnrRef?: (setFnr: Dispatch<string>) => void;
fnr?: string;
preloadedState?: RootState;
}

export const ErVeilederContext = React.createContext(false);
Expand All @@ -22,7 +23,7 @@ export const useFnr = () => useContext(FnrContext);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const noOp = (_: string | undefined) => {};
const Provider = ({ children, setFnrRef, fnr: propFnr }: Props) => {
const Provider = ({ children, setFnrRef, fnr: propFnr, preloadedState }: Props) => {
const [fnr, setFnr] = useState(propFnr);
useEffect(() => {
if (setFnrRef) setFnrRef(setFnr);
Expand All @@ -33,7 +34,9 @@ const Provider = ({ children, setFnrRef, fnr: propFnr }: Props) => {
};
}, []);

const store = useMemo(createStore, [fnr]);
const store = useMemo(() => {
return createStore(preloadedState);
}, [fnr]);

return (
<FnrContext.Provider value={fnr}>
Expand Down
2 changes: 1 addition & 1 deletion src/moduler/dialog/DialogFlateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const byttTilDialogFlate = ({
dialogId: dialogId,
aktivitetId: aktivitetId,
},
})
}),
);
};

Expand Down
9 changes: 7 additions & 2 deletions src/moduler/oppfolging-status/OppfolgingStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from './oppfolging-selector';
import { hentOppfolging } from './oppfolging-slice';
import VidereSendBrukereEllerRenderChildren from './VidereSendBrukereEllerRenderChildren';
import { Status } from '../../createGenericSlice';

interface Props {
children: ReactNode;
Expand Down Expand Up @@ -48,8 +49,12 @@ const OppfolgingStatus = ({ children }: Props) => {
};

useEffect(() => {
dispatch(hentOppfolging());
dispatch(hentIdentitet());
if (avhengigheter[0] === Status.NOT_STARTED) {
dispatch(hentOppfolging());
}
if (avhengigheter[1] === Status.NOT_STARTED) {
dispatch(hentIdentitet());
}
}, []);

return (
Expand Down
37 changes: 35 additions & 2 deletions src/store.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,46 @@
import { configureStore } from '@reduxjs/toolkit';

import reducer from './reducer';
import { EnhancedStore } from '@reduxjs/toolkit/src/configureStore';

const createStore = () =>
configureStore({
let store: EnhancedStore | null = null;
const createStore = (preloadedState: any = undefined) => {
const newStore = configureStore({
reducer: reducer,
preloadedState,
});
store = newStore;
return newStore;
};

type Store = ReturnType<typeof createStore>;

const key = 'aktivitetsplan-state';
export const getPreloadedStateFromSessionStorage = (fnr: string | undefined): RootState | undefined => {
if (!fnr) return undefined;
const serializedState = sessionStorage.getItem(key);
if (serializedState) {
try {
const state: RootState = JSON.parse(serializedState);
// Only use cache if correct user
if (fnr === state.data.oppfolging?.data?.fnr) {
return JSON.parse(serializedState);
}
sessionStorage.removeItem(key);
return undefined;
} catch (e) {
console.warn(e);
return undefined;
}
}
return undefined;
};
export const saveReduxStateToSessionStorage = () => {
const state = store?.getState();
sessionStorage.setItem(key, JSON.stringify(state));
};
export const clearReduxCache = () => sessionStorage.removeItem(key);

export type RootState = ReturnType<Store['getState']>;
export type Dispatch = Store['dispatch'];

Expand Down
25 changes: 20 additions & 5 deletions src/webcomponentWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,52 @@ import modulesCss from './moduler/aktivitet/aktivitet-kort/Aktivitetskort.module
import Provider from './Provider';
import tailwindCss from './tailwind.css?inline';
import { createRoot, Root } from 'react-dom/client';
import {
clearReduxCache,
getPreloadedStateFromSessionStorage,
RootState,
saveReduxStateToSessionStorage,
} from './store';

// Clear redux-cache from session storage on page load to make sure new data is fetched
// Cache is only supposed to be used when "jumping" between apps in veilarbpersonflate
clearReduxCache();

export class DabAktivitetsplan extends HTMLElement {
setFnr?: (fnr: string) => void;
root: Root | undefined;

disconnectedCallback() {
saveReduxStateToSessionStorage();
this.root?.unmount();
}

connectedCallback() {
// Cant mount on shadowRoot, create a extra div for mounting modal
const shadowDomFirstChild = document.createElement('div');
// This will be app entry point, need to be outside modal-mount node
const appRoot = document.createElement('div');
appRoot.id = 'aktivitetsplan-root';
const shadowRoot = this.attachShadow({ mode: 'closed' });
shadowRoot.appendChild(shadowDomFirstChild);
shadowDomFirstChild.appendChild(appRoot);
shadowRoot.appendChild(appRoot);

// Load styles under this shadowDom-node, not root element
const styleElem = document.createElement('style');
styleElem.innerHTML = dsStyles + tailwindCss + lessCss + modulesCss;
shadowRoot.appendChild(styleElem);

const fnr = this.getAttribute('data-fnr') ?? undefined;
let preloadedState: RootState | undefined = undefined;
if (fnr) {
settLocalStorage(LocalStorageElement.FNR, fnr);
preloadedState = getPreloadedStateFromSessionStorage(fnr);
}
this.root = createRoot(appRoot);
this.root.render(
<Provider key={fnr} fnr={fnr} setFnrRef={(setFnr) => (this.setFnr = setFnr)}>
<Provider
preloadedState={preloadedState}
key={fnr}
fnr={fnr}
setFnrRef={(setFnr) => (this.setFnr = setFnr)}
>
<App Routes={Routes} key={'1'} />
</Provider>,
);
Expand Down

0 comments on commit 4b7e2cc

Please sign in to comment.