fork refine

This commit is contained in:
Stefan Pejcic
2024-02-05 10:23:04 +01:00
parent 3fffde9a8f
commit 8496a83edb
3634 changed files with 715528 additions and 2 deletions

View File

@@ -0,0 +1,149 @@
import { act } from "react-dom/test-utils";
import { renderHook } from "@testing-library/react";
import { TestWrapper, mockRouterBindings } from "@test";
import { defaultRefineOptions } from "@contexts/refine";
import { useLoadingOvertime } from "./";
describe("useLoadingOvertime Hook", () => {
jest.useFakeTimers();
it("should elapsedTime undefined when isLoading false", () => {
const { result } = renderHook(
() =>
useLoadingOvertime({
isLoading: false,
}),
{
wrapper: TestWrapper({}),
},
);
const { elapsedTime } = result.current;
expect(elapsedTime).toBeUndefined();
});
it("should elapsedTime undefined when interval not start", () => {
const { result } = renderHook(
() =>
useLoadingOvertime({
isLoading: true,
}),
{
wrapper: TestWrapper({}),
},
);
act(() => {
// default 1000
jest.advanceTimersByTime(999);
});
const { elapsedTime } = result.current;
// should be undefined
expect(elapsedTime).toBeUndefined();
});
it("should elapsedTime 2000 when interval 3000", () => {
const { result } = renderHook(
() =>
useLoadingOvertime({
isLoading: true,
}),
{
wrapper: TestWrapper({}),
},
);
act(() => {
// default 1000
jest.advanceTimersByTime(2000);
});
const { elapsedTime } = result.current;
expect(elapsedTime).toBe(2000);
});
it("should override global interval and onInverval", () => {
const onInterval = jest.fn();
const onIntervalGlobal = jest.fn();
const { result } = renderHook(
() =>
useLoadingOvertime({
isLoading: true,
interval: 1000,
onInterval,
}),
{
wrapper: TestWrapper({
refineProvider: {
hasDashboard: false,
...defaultRefineOptions,
options: {
...defaultRefineOptions,
overtime: {
interval: 5000,
onInterval: onIntervalGlobal,
},
},
},
}),
},
);
act(() => {
jest.advanceTimersByTime(2000);
});
const { elapsedTime } = result.current;
expect(elapsedTime).toBe(2000);
expect(onInterval).toBeCalledTimes(1);
// should not be called global interval
expect(onIntervalGlobal).toBeCalledTimes(0);
});
it("should run global interval and onInterval", () => {
const onInterval = jest.fn();
const { result } = renderHook(
() =>
useLoadingOvertime({
isLoading: true,
}),
{
wrapper: TestWrapper({
resources: [
{
name: "posts",
},
],
refineProvider: {
hasDashboard: false,
...defaultRefineOptions,
options: {
...defaultRefineOptions,
overtime: {
interval: 500,
onInterval,
},
},
},
routerProvider: mockRouterBindings({
resource: {
name: "posts",
},
}),
}),
},
);
act(() => {
jest.advanceTimersByTime(1000);
});
const { elapsedTime } = result.current;
expect(elapsedTime).toBe(1000);
expect(onInterval).toBeCalledTimes(1);
expect(onInterval).toBeCalledWith(1000);
});
});

View File

@@ -0,0 +1,114 @@
import { useEffect, useState } from "react";
import { useRefineContext } from "..";
export type UseLoadingOvertimeRefineContext = Omit<
UseLoadingOvertimeCoreProps,
"isLoading" | "interval"
> &
Required<Pick<UseLoadingOvertimeCoreProps, "interval">>;
export type UseLoadingOvertimeOptionsProps = {
overtimeOptions?: UseLoadingOvertimeCoreOptions;
};
export type UseLoadingOvertimeReturnType = {
overtime: {
elapsedTime?: number;
};
};
type UseLoadingOvertimeCoreOptions = Omit<
UseLoadingOvertimeCoreProps,
"isLoading"
>;
type UseLoadingOvertimeCoreReturnType = {
elapsedTime?: number;
};
export type UseLoadingOvertimeCoreProps = {
/**
* The loading state. If true, the elapsed time will be calculated.
*/
isLoading: boolean;
/**
* The interval in milliseconds. If the loading time exceeds this time, the `onInterval` callback will be called.
* If not specified, the `interval` value from the `overtime` option of the `RefineProvider` will be used.
*
* @default: 1000 (1 second)
*/
interval?: number;
/**
* The callback function that will be called when the loading time exceeds the specified time.
* If not specified, the `onInterval` value from the `overtime` option of the `RefineProvider` will be used.
*
* @param elapsedInterval The elapsed time in milliseconds.
*/
onInterval?: (elapsedInterval: number) => void;
};
/**
* if you need to do something when the loading time exceeds the specified time, refine provides the `useLoadingOvertime` hook.
* It returns the elapsed time in milliseconds.
*
* @example
* const { elapsedTime } = useLoadingOvertime({
* isLoading,
* interval: 1000,
* onInterval(elapsedInterval) {
* console.log("loading overtime", elapsedInterval);
* },
* });
*/
export const useLoadingOvertime = ({
isLoading,
interval: intervalProp,
onInterval: onIntervalProp,
}: UseLoadingOvertimeCoreProps): UseLoadingOvertimeCoreReturnType => {
const [elapsedTime, setElapsedTime] = useState<number | undefined>(
undefined,
);
// get overtime options from refine context
const { options } = useRefineContext();
const { overtime } = options;
// pick props or refine context options
const interval = intervalProp ?? overtime.interval;
const onInterval = onIntervalProp ?? overtime?.onInterval;
useEffect(() => {
let intervalFn: ReturnType<typeof setInterval>;
if (isLoading) {
intervalFn = setInterval(() => {
// increase elapsed time
setElapsedTime((prevElapsedTime) => {
if (prevElapsedTime === undefined) {
return interval;
}
return prevElapsedTime + interval;
});
}, interval);
}
return () => {
clearInterval(intervalFn);
// reset elapsed time
setElapsedTime(undefined);
};
}, [isLoading, interval]);
useEffect(() => {
// call onInterval callback
if (onInterval && elapsedTime) {
onInterval(elapsedTime);
}
}, [elapsedTime]);
return {
elapsedTime,
};
};