Skip to content
Snippets Groups Projects
routine.reducer.ts 3.34 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { PayloadAction, createSlice } from '@reduxjs/toolkit';
    
    import { RoutineManager } from '@utils/routine.manager';
    
    Matthias Feyll's avatar
    Matthias Feyll committed
    import { REHYDRATE } from 'redux-persist';
    
    import { RootState } from '../../stores';
    import { startListening } from '../../stores/middleware/listener.middleware';
    import { setToken } from './user.reducer';
    
    
    
    
    interface ThunkEntityDTO {
    
        thunk: any,
    
        payload: any
    
        /**
         * Only one subscription per category is allowed. New subscription will unsubscribe and overwrite the old one
         */
        category: CATEGORIES,
    }
    
    interface ThunkEntity extends ThunkEntityDTO {
        id?: number,
    
    Matthias Feyll's avatar
    Matthias Feyll committed
        locked: boolean,
    
    Matthias Feyll's avatar
    Matthias Feyll committed
    export interface ReducerState {
    
        thunks: {[key in keyof typeof CATEGORIES]: ThunkEntity | null}
    }
    
    export enum CATEGORIES {
        TABLE,
        TAB
    }
    
    
    Matthias Feyll's avatar
    Matthias Feyll committed
    const initialState: ReducerState = {
    
        thunks: {
            TABLE: null,
            TAB: null
        }
    }
    
    
    Matthias Feyll's avatar
    Matthias Feyll committed
    const RoutineSlice = createSlice({
        name: 'routine',
    
        initialState,
        reducers: {
    
    Matthias Feyll's avatar
    Matthias Feyll committed
            addRoutine: (state, {payload}: PayloadAction<ThunkEntityDTO>) => {
    
                const newThunk: ThunkEntity = {...payload, locked: true};
                state.thunks[CATEGORIES[payload.category]] = newThunk;
            },
    
            setThunkId: (state, {payload}: PayloadAction<{id: number, category: CATEGORIES}>) => {
                let thunk = state.thunks[CATEGORIES[payload.category]];
    
                if (!thunk) {
                    // TODO
                    throw new Error('Thunk not found');
                }
                
                state.thunks[CATEGORIES[payload.category]] = {...thunk, id: payload.id, locked: false};
            },
    
    
            removeAll: (state) => {
    
                state.thunks = initialState.thunks;
            },
        },
    })
    
    
    Matthias Feyll's avatar
    Matthias Feyll committed
    export const { addRoutine } = RoutineSlice.actions
    
    Matthias Feyll's avatar
    Matthias Feyll committed
    // on logout remove all routine
    
    startListening({
    
        predicate: (action) => setToken.match(action) && action.payload === null,
    
        effect: async (_, listenerApi) => {
    
            RoutineManager.unsubscribeAll()
    
    Matthias Feyll's avatar
    Matthias Feyll committed
            listenerApi.dispatch(RoutineSlice.actions.removeAll());
    
    Matthias Feyll's avatar
    Matthias Feyll committed
    // on rehydrate add all persistet routines
    startListening({
        predicate: ({type}) => type === REHYDRATE,
        effect: async (_, listenerApi) => {
            const {routine} = listenerApi.getState() as RootState;
            for (const [_,thunk] of Object.entries<ThunkEntity>(routine.thunks)) {
                if (!thunk) {
                    return;
                }
    
                const dto: ThunkEntityDTO = thunk;
                listenerApi.dispatch(addRoutine(dto));
            }
        },
    })
    
    Matthias Feyll's avatar
    Matthias Feyll committed
    // unsubscribe old routine 
    
    startListening({
    
    Matthias Feyll's avatar
    Matthias Feyll committed
        predicate: (action) => addRoutine.match(action),
    
        effect: async (action, listenerApi) => {
    
    Matthias Feyll's avatar
    Matthias Feyll committed
            const {routine} = listenerApi.getOriginalState() as RootState;
            const lastThunk = routine.thunks[CATEGORIES[action.payload.category]];
            if (lastThunk) {
                RoutineManager.unsubscribe(lastThunk.id);
            }
    
    Matthias Feyll's avatar
    Matthias Feyll committed
    // add new routine
    
    startListening({
    
    Matthias Feyll's avatar
    Matthias Feyll committed
        predicate: (action) => addRoutine.match(action),
    
        effect: async (action, listenerApi) => {
    
            const {thunk} = action.payload as ThunkEntity;
            const subscription = await listenerApi.dispatch(thunk(action.payload.payload));
    
    Matthias Feyll's avatar
    Matthias Feyll committed
            const thunkId = await RoutineManager.add(subscription.payload);
            listenerApi.dispatch(RoutineSlice.actions.setThunkId({id: thunkId, category: action.payload.category}));
    
    Matthias Feyll's avatar
    Matthias Feyll committed
    export default RoutineSlice.reducer