feat: role system
This commit is contained in:
183
src/shared/api/mobxFetch/index.ts
Normal file
183
src/shared/api/mobxFetch/index.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import { runInAction } from "mobx";
|
||||
|
||||
type mobxFetchOptions<RequestType, ResponseType, Store> = {
|
||||
store: Store;
|
||||
value?: keyof Store;
|
||||
values?: Array<keyof Store>;
|
||||
loading?: keyof Store;
|
||||
error?: keyof Store;
|
||||
fn: RequestType extends void
|
||||
? (signal?: AbortSignal) => Promise<ResponseType>
|
||||
: (request: RequestType, signal?: AbortSignal) => Promise<ResponseType>;
|
||||
|
||||
pollingInterval?: number;
|
||||
resetValue?: boolean;
|
||||
transform?: (response: ResponseType) => Partial<Record<string, any>>;
|
||||
onSuccess?: (response: ResponseType) => void;
|
||||
};
|
||||
|
||||
type FetchFunction<RequestType, ResponseType> = RequestType extends void
|
||||
? {
|
||||
(): Promise<ResponseType | null>;
|
||||
stopPolling?: () => void;
|
||||
}
|
||||
: {
|
||||
(request: RequestType): Promise<ResponseType | null>;
|
||||
stopPolling?: () => void;
|
||||
};
|
||||
|
||||
export function mobxFetch<ResponseType, Store extends Record<string, any>>(
|
||||
options: mobxFetchOptions<void, ResponseType, Store>
|
||||
): FetchFunction<void, ResponseType>;
|
||||
|
||||
export function mobxFetch<
|
||||
RequestType,
|
||||
ResponseType,
|
||||
Store extends Record<string, any>,
|
||||
>(
|
||||
options: mobxFetchOptions<RequestType, ResponseType, Store>
|
||||
): FetchFunction<RequestType, ResponseType>;
|
||||
|
||||
export function mobxFetch<
|
||||
RequestType,
|
||||
ResponseType,
|
||||
Store extends Record<string, any>,
|
||||
>(
|
||||
options: mobxFetchOptions<RequestType, ResponseType, Store>
|
||||
): FetchFunction<RequestType, ResponseType> {
|
||||
const {
|
||||
store,
|
||||
value,
|
||||
values,
|
||||
loading,
|
||||
error,
|
||||
fn,
|
||||
pollingInterval,
|
||||
resetValue,
|
||||
transform,
|
||||
onSuccess,
|
||||
} = options;
|
||||
|
||||
let abortController: AbortController | undefined;
|
||||
let pollingTimer: ReturnType<typeof setInterval> | undefined;
|
||||
let currentRequest: RequestType | undefined;
|
||||
|
||||
const stopPolling = () => {
|
||||
if (pollingTimer) {
|
||||
clearInterval(pollingTimer);
|
||||
pollingTimer = undefined;
|
||||
}
|
||||
abortController?.abort();
|
||||
};
|
||||
|
||||
const fetch = async (request?: RequestType): Promise<ResponseType | null> => {
|
||||
abortController?.abort();
|
||||
abortController = new AbortController();
|
||||
currentRequest = request as RequestType;
|
||||
|
||||
runInAction(() => {
|
||||
if (value) {
|
||||
(store[value] as any) = resetValue ? null : store[value];
|
||||
}
|
||||
|
||||
if (values) {
|
||||
values.forEach((key) => {
|
||||
(store[key] as any) = resetValue ? null : store[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (error) {
|
||||
(store[error] as any) = null;
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
(store[loading] as any) = true;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await (
|
||||
fn as (
|
||||
request?: RequestType,
|
||||
signal?: AbortSignal
|
||||
) => Promise<ResponseType>
|
||||
)(request, abortController.signal);
|
||||
|
||||
runInAction(() => {
|
||||
if (values && transform) {
|
||||
const transformed = transform(result) as Record<string, any>;
|
||||
values.forEach((key) => {
|
||||
const k = key as string;
|
||||
if (k in transformed) {
|
||||
(store[key] as any) = transformed[k];
|
||||
}
|
||||
});
|
||||
} else if (value) {
|
||||
(store[value] as any) = result as ResponseType;
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
(store[loading] as any) = false;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
(store[error] as any) = null;
|
||||
}
|
||||
});
|
||||
|
||||
if (pollingInterval && !pollingTimer) {
|
||||
pollingTimer = setInterval(() => {
|
||||
if (currentRequest !== undefined) {
|
||||
fetch(currentRequest);
|
||||
} else {
|
||||
fetch();
|
||||
}
|
||||
}, pollingInterval);
|
||||
}
|
||||
|
||||
if (onSuccess) {
|
||||
onSuccess(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (err) {
|
||||
if (!(err instanceof Error && err.name === "CanceledError")) {
|
||||
runInAction(() => {
|
||||
if (error) {
|
||||
(store[error] as any) =
|
||||
err instanceof Error ? err.message : String(err);
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
(store[loading] as any) = false;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
(store[value] as any) = null;
|
||||
}
|
||||
|
||||
if (values) {
|
||||
values.forEach((key) => {
|
||||
(store[key] as any) = null;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const fetchWithStopPolling = fetch as FetchFunction<
|
||||
RequestType,
|
||||
ResponseType
|
||||
>;
|
||||
|
||||
if (pollingInterval) {
|
||||
fetchWithStopPolling.stopPolling = stopPolling;
|
||||
}
|
||||
|
||||
return fetchWithStopPolling;
|
||||
}
|
||||
Reference in New Issue
Block a user