refactor: monorepo setup with lerna (#243)

This commit is contained in:
Daniel Lautzenheiser
2022-12-15 13:44:49 -05:00
committed by GitHub
parent dac29fbf3c
commit 504d95c34f
706 changed files with 16571 additions and 142 deletions

View File

@ -0,0 +1,11 @@
import { useDispatch, useSelector } from 'react-redux';
import type { RootState } from './index';
import type { TypedUseSelectorHook } from 'react-redux';
import type { AnyAction, ThunkDispatch } from '@reduxjs/toolkit';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type AppDispatch = ThunkDispatch<RootState, any, AnyAction>;
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

View File

@ -0,0 +1,17 @@
import { configureStore } from '@reduxjs/toolkit';
import createRootReducer from '../reducers/combinedReducer';
import { waitUntilAction } from './middleware/waitUntilAction';
const store = configureStore({
reducer: createRootReducer(),
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
immutableCheck: false,
serializableCheck: false,
}).concat(waitUntilAction),
});
export { store };
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

View File

@ -0,0 +1,64 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// Based on wait-service by Mozilla:
// https://github.com/mozilla/gecko-dev/blob/main/devtools/client/shared/redux/middleware/wait-service.js
/**
* A middleware that provides the ability for actions to install a
* function to be run once when a specific condition is met by an
* action coming through the system. Think of it as a thunk that
* blocks until the condition is met.
*/
import type { AnyAction, Dispatch, Middleware, MiddlewareAPI } from '@reduxjs/toolkit';
export const WAIT_UNTIL_ACTION = 'WAIT_UNTIL_ACTION';
export interface WaitActionArgs {
predicate: (action: AnyAction) => boolean;
run: (dispatch: Dispatch, getState: () => any, action: AnyAction) => void;
}
interface WaitAction extends WaitActionArgs {
type: typeof WAIT_UNTIL_ACTION;
}
// eslint-disable-next-line func-style
export const waitUntilAction: Middleware<{}, any, Dispatch> = ({
dispatch,
getState,
}: MiddlewareAPI<Dispatch, any>) => {
let pending: WaitAction[] = [];
function checkPending(action: AnyAction): void {
const readyRequests = [];
const stillPending = [];
// Find the pending requests whose predicates are satisfied with
// this action. Wait to run the requests until after we update the
// pending queue because the request handler may synchronously
// dispatch again and run this service (that use case is
// completely valid).
for (const request of pending) {
if (request.predicate(action)) {
readyRequests.push(request);
} else {
stillPending.push(request);
}
}
pending = stillPending;
for (const request of readyRequests) {
request.run(dispatch, getState, action);
}
}
return (next: Dispatch<AnyAction>) =>
(action: AnyAction): null | AnyAction => {
if (action.type === WAIT_UNTIL_ACTION) {
pending.push(action as WaitAction);
return null;
}
const result = next(action);
checkPending(action);
return result;
};
};

View File

@ -0,0 +1,51 @@
import { createSlice } from '@reduxjs/toolkit';
import { v4 as uuid } from 'uuid';
import type { PayloadAction } from '@reduxjs/toolkit';
import type { RootState } from '..';
type MessageType = 'error' | 'warning' | 'info' | 'success';
export interface SnackbarMessage {
id: string;
type: MessageType;
message:
| string
| {
key: string;
options?: Record<string, unknown>;
};
}
// Define a type for the slice state
export interface SnackbarState {
messages: SnackbarMessage[];
}
// Define the initial state using that type
const initialState: SnackbarState = {
messages: [],
};
export const SnackbarSlice = createSlice({
name: 'snackbar',
// `createSlice` will infer the state type from the `initialState` argument
initialState,
reducers: {
addSnackbar: (state, action: PayloadAction<Omit<SnackbarMessage, 'id'>>) => {
state.messages.push({
id: uuid(),
...action.payload,
});
},
removeSnackbarById: (state, action: PayloadAction<string>) => {
state.messages = state.messages.filter(message => message.id !== action.payload);
},
},
});
export const { addSnackbar, removeSnackbarById } = SnackbarSlice.actions;
export const selectSnackbars = (state: RootState) => state.snackbar.messages;
export default SnackbarSlice.reducer;