Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store session cache #1202

Merged
merged 18 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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