@kwiz/fluentui
Version:
KWIZ common controls for FluentUI
85 lines • 5.17 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { jsx as _jsx } from "react/jsx-runtime";
import { CommonLogger, debounce, firstIndexOf, firstOrNull, isNotEmptyString, isNullOrEmptyString, isNumber, promiseOnce } from "@kwiz/common";
import { isValidElement, useCallback, useMemo, useRef } from "react";
import { Loading } from "../controls/loading";
import { PleaseWait } from "../controls/please-wait";
import { useStateEX } from "./hooks";
const logger = new CommonLogger("useReloadTracker");
/** a simple reload marker, can be used as a dependency, and called as a function */
export function useReloadTracker(props) {
const [reloadKey, setReload, reloadKeyRef] = useStateEX({ global: 1 });
const promises = useRef([]);
let counter = useRef(1);
const reload = useCallback(debounce((scope) => {
const rk = Object.assign({}, reloadKeyRef.current);
if (scope === "global" || isNullOrEmptyString(scope)) {
//if global - notify all listeners
Object.keys(rk).forEach(s => {
rk[s] = (isNumber(rk[s]) ? rk[s] : 0) + 1;
});
logger.debug('Reload all scopes');
}
else {
//notify only listeners for my scope + global listeners
rk[scope] = (isNumber(rk[scope]) ? rk[scope] : 0) + 1;
rk.global++;
logger.debug(`Reload ${scope}: ${rk[scope]}, and global: ${rk.global}`);
}
setReload(rk);
}, 100), []);
const [isLoading, setLoading, isLoadingRef] = useStateEX({ type: "idle" }, { skipUpdateIfSame: true });
//this does not have dependencies, never changes, so unsafe to use state. use stateRef objects.
const queue = useCallback((promise, info) => __awaiter(this, void 0, void 0, function* () {
const type = (info === null || info === void 0 ? void 0 : info.type) || "optional";
if (isLoadingRef.current.type !== "required") //if its required - do not update this back to optional
setLoading({ type, label: info.label });
const myId = counter.current++;
promises.current.push({ id: myId, type, label: info === null || info === void 0 ? void 0 : info.label });
try {
return yield (isNotEmptyString(info.cacheKey)
? (() => {
const cache_reloadKey = isNotEmptyString(info.cacheScope) ? `${info.cacheScope}:${reloadKeyRef.current[info.cacheScope] || 0}` : `global:${reloadKeyRef.current.global}`;
const promiseOnceCacheKey = `${cache_reloadKey}|${info.cacheKey}`;
logger.log(promiseOnceCacheKey);
return promiseOnce(promiseOnceCacheKey, promise);
})()
: promise());
}
finally {
//remove this promise
const myIndex = firstIndexOf(promises.current, p => p.id === myId);
promises.current.splice(myIndex, 1);
//if no more promises - set loading to false
if (promises.current.length === 0)
setLoading({ type: "idle" });
//else, if it is state required and no more required promiese - drop it to optional
else {
//drop the label/type to the next promise in queue, prioritize required ones.
const nextPromise = firstOrNull(promises.current, p_1 => p_1.type === "required") || promises.current[0];
setLoading({ type: nextPromise.type, label: nextPromise.label });
}
}
}), []);
const reloadElement = useMemo(() => {
return (isLoading === null || isLoading === void 0 ? void 0 : isLoading.type) === "required"
? isValidElement(props === null || props === void 0 ? void 0 : props.requiredElement) ? props.requiredElement
: _jsx(Loading, Object.assign({ fullsize: true, label: isLoading.label }, props === null || props === void 0 ? void 0 : props.requiredElement))
: (isLoading === null || isLoading === void 0 ? void 0 : isLoading.type) === "optional"
? isValidElement(props === null || props === void 0 ? void 0 : props.optionalElement) ? props.optionalElement
: _jsx(PleaseWait, Object.assign({ label: isLoading.label }, props === null || props === void 0 ? void 0 : props.optionalElement))
: undefined;
}, [isLoading.type, isLoading.label]);
return {
reloadKey, reload, isLoading, queue, reloadElement
};
}
//# sourceMappingURL=use-reload-tracker.js.map