mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
fork refine
This commit is contained in:
149
packages/core/src/hooks/useLoadingOvertime/index.spec.tsx
Normal file
149
packages/core/src/hooks/useLoadingOvertime/index.spec.tsx
Normal 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);
|
||||
});
|
||||
});
|
||||
114
packages/core/src/hooks/useLoadingOvertime/index.ts
Normal file
114
packages/core/src/hooks/useLoadingOvertime/index.ts
Normal 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,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user