This commit is contained in:
Stefan Pejcic
2024-11-07 19:03:37 +01:00
parent c6df945ed5
commit 09f9f9502d
2472 changed files with 620417 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
import * as React from "react";
import { renderHook } from "@testing-library/react";
import { act } from "@test";
import { undoableQueueReducer } from ".";
describe("Notification Reducer", () => {
const notificationDispatch = jest.fn();
const providerProps = {
notifications: [
{
id: "1",
resource: "posts",
seconds: 5000,
isRunning: true,
},
],
notificationDispatch: notificationDispatch,
};
it("should render notification item with ADD action", () => {
const { result } = renderHook(() =>
React.useReducer(undoableQueueReducer, []),
);
const [, dispatch] = result.current;
act(() => {
dispatch({ type: "ADD", payload: providerProps.notifications[0] });
});
const [state] = result.current;
expect(state).toEqual([
{
id: "1",
resource: "posts",
seconds: 5000,
isRunning: true,
},
]);
});
it("remove notification item with DELETE action", async () => {
const { result } = renderHook(() =>
React.useReducer(undoableQueueReducer, providerProps.notifications),
);
const [, dispatch] = result.current;
act(() => {
dispatch({
type: "REMOVE",
payload: providerProps.notifications[0],
});
});
const [state] = result.current;
expect(state).toEqual([]);
});
it("decrease notification item by 1 second with DECREASE_NOTIFICATION_SECOND action", async () => {
const { result } = renderHook(() =>
React.useReducer(undoableQueueReducer, providerProps.notifications),
);
const [, dispatch] = result.current;
act(() => {
dispatch({
type: "DECREASE_NOTIFICATION_SECOND",
payload: {
id: providerProps.notifications[0].id,
seconds: providerProps.notifications[0].seconds,
resource: providerProps.notifications[0].resource,
},
});
});
const [state] = result.current;
expect(state[0].seconds).toEqual(
providerProps.notifications[0].seconds - 1000,
);
});
});

View File

@@ -0,0 +1,90 @@
import React, {
createContext,
useReducer,
type PropsWithChildren,
} from "react";
import isEqual from "lodash/isEqual";
import { UndoableQueue } from "../../components";
import {
ActionTypes,
type IUndoableQueue,
type IUndoableQueueContext,
} from "./types";
export const UndoableQueueContext = createContext<IUndoableQueueContext>({
notifications: [],
notificationDispatch: () => false,
});
const initialState: IUndoableQueue[] = [];
export const undoableQueueReducer = (state: IUndoableQueue[], action: any) => {
switch (action.type) {
case ActionTypes.ADD: {
const newState = state.filter((notificationItem: IUndoableQueue) => {
return !(
isEqual(notificationItem.id, action.payload.id) &&
notificationItem.resource === action.payload.resource
);
});
return [
...newState,
{
...action.payload,
isRunning: true,
},
];
}
case ActionTypes.REMOVE:
return state.filter(
(notificationItem: IUndoableQueue) =>
!(
isEqual(notificationItem.id, action.payload.id) &&
notificationItem.resource === action.payload.resource
),
);
case ActionTypes.DECREASE_NOTIFICATION_SECOND:
return state.map((notificationItem: IUndoableQueue) => {
if (
isEqual(notificationItem.id, action.payload.id) &&
notificationItem.resource === action.payload.resource
) {
return {
...notificationItem,
seconds: action.payload.seconds - 1000,
};
}
return notificationItem;
});
default:
return state;
}
};
export const UndoableQueueContextProvider: React.FC<PropsWithChildren> = ({
children,
}) => {
const [notifications, notificationDispatch] = useReducer(
undoableQueueReducer,
initialState,
);
const notificationData = { notifications, notificationDispatch };
return (
<UndoableQueueContext.Provider value={notificationData}>
{children}
{typeof window !== "undefined"
? notifications.map((notification) => (
<UndoableQueue
key={`${notification.id}-${notification.resource}-queue`}
notification={notification}
/>
))
: null}
</UndoableQueueContext.Provider>
);
};

View File

@@ -0,0 +1,22 @@
import type { BaseKey } from "../data/types";
export enum ActionTypes {
ADD = "ADD",
REMOVE = "REMOVE",
DECREASE_NOTIFICATION_SECOND = "DECREASE_NOTIFICATION_SECOND",
}
export interface IUndoableQueue {
id: BaseKey;
resource: string;
cancelMutation: () => void;
doMutation: () => void;
seconds: number;
isRunning: boolean;
isSilent: boolean;
}
export interface IUndoableQueueContext {
notifications: IUndoableQueue[];
notificationDispatch: React.Dispatch<any>;
}