139 lines
3.8 KiB
TypeScript
139 lines
3.8 KiB
TypeScript
/*
|
|
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
|
|
*
|
|
* This file is part of Campus INSAT.
|
|
*
|
|
* Campus INSAT is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Campus INSAT is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import { DependencyList, useEffect, useRef, useState } from 'react';
|
|
import { REQUEST_STATUS } from './Requests';
|
|
import { ApiRejectType } from './WebData';
|
|
|
|
export function useMountEffect(func: () => void) {
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
useEffect(func, []);
|
|
}
|
|
|
|
/**
|
|
* Effect that does not run on first render
|
|
*
|
|
* @param effect
|
|
* @param deps
|
|
*/
|
|
export function useSubsequentEffect(effect: () => void, deps?: DependencyList) {
|
|
const didMountRef = useRef(false);
|
|
useEffect(
|
|
() => {
|
|
if (didMountRef.current) {
|
|
effect();
|
|
} else {
|
|
didMountRef.current = true;
|
|
}
|
|
},
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
deps ? deps : []
|
|
);
|
|
}
|
|
|
|
export function useRequestLogic<T>(
|
|
request: () => Promise<T>,
|
|
cache?: T,
|
|
onCacheUpdate?: (newCache: T) => void,
|
|
startLoading?: boolean,
|
|
minRefreshTime?: number
|
|
) {
|
|
const [response, setResponse] = useState<{
|
|
loading: boolean;
|
|
lastRefreshDate?: Date;
|
|
status: REQUEST_STATUS;
|
|
code?: number;
|
|
data: T | undefined;
|
|
}>({
|
|
loading: startLoading !== false && cache === undefined,
|
|
lastRefreshDate: undefined,
|
|
status: REQUEST_STATUS.SUCCESS,
|
|
code: undefined,
|
|
data: undefined,
|
|
});
|
|
|
|
const refreshData = (newRequest?: () => Promise<T>) => {
|
|
let canRefresh;
|
|
if (response.lastRefreshDate && minRefreshTime) {
|
|
canRefresh =
|
|
new Date().getTime() - response.lastRefreshDate.getTime() >
|
|
minRefreshTime;
|
|
} else {
|
|
canRefresh = true;
|
|
}
|
|
if (canRefresh) {
|
|
if (!response.loading) {
|
|
setResponse((prevState) => ({
|
|
...prevState,
|
|
loading: true,
|
|
}));
|
|
}
|
|
const r = newRequest ? newRequest : request;
|
|
r()
|
|
.then((requestResponse: T) => {
|
|
setResponse({
|
|
loading: false,
|
|
lastRefreshDate: new Date(),
|
|
status: REQUEST_STATUS.SUCCESS,
|
|
code: undefined,
|
|
data: requestResponse,
|
|
});
|
|
if (onCacheUpdate) {
|
|
onCacheUpdate(requestResponse);
|
|
}
|
|
})
|
|
.catch((error: ApiRejectType | undefined) => {
|
|
if (!error) {
|
|
setResponse((prevState) => ({
|
|
loading: false,
|
|
lastRefreshDate: prevState.lastRefreshDate,
|
|
status: REQUEST_STATUS.CONNECTION_ERROR,
|
|
code: undefined,
|
|
data: prevState.data,
|
|
}));
|
|
} else {
|
|
setResponse((prevState) => ({
|
|
loading: false,
|
|
lastRefreshDate: prevState.lastRefreshDate,
|
|
status: error.status,
|
|
code: error.code,
|
|
data: prevState.data,
|
|
}));
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
const value: [
|
|
boolean,
|
|
Date | undefined,
|
|
REQUEST_STATUS,
|
|
number | undefined,
|
|
T | undefined,
|
|
(newRequest?: () => Promise<T>) => void
|
|
] = [
|
|
response.loading,
|
|
response.lastRefreshDate,
|
|
response.status,
|
|
response.code,
|
|
cache ? cache : response.data,
|
|
refreshData,
|
|
];
|
|
return value;
|
|
}
|