UNPKG

bananas-commerce-admin

Version:

What's this, an admin for apes?

71 lines 3.03 kB
import React, { lazy, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Suspense } from "react"; import { useApi } from "../contexts/ApiContext"; import { useUser } from "../contexts/UserContext"; import useAsyncError from "../hooks/useAsyncError"; import { hasAccess } from "../util/has_access"; import LoadingScreen from "./LoadingScreen"; export class DataLoadFailedError extends Error { response; constructor(response, message) { super(message); this.response = response; } } export const ComponentLoader = ({ operation, ...rest }) => { const api = useApi(); const { user } = useUser(); if (typeof operation === "string") { operation = api.operations[operation]; } if (operation == null) { console.error(`[COMPONENT_LOADER] Could not find operation ${operation}`); return null; } if (operation.component?.component == null) { console.error(`[COMPONENT_LOADER] Could not find component for operation ${operation.id}`); return null; } if (!hasAccess(user, operation.component.permission, operation.component.group)) { return null; } rest.body ??= operation.component.body; // NOTE: Consider merging with the rest properties instead of // using the operation component's properties as defaults. rest.params ??= operation.component.params; rest.query ??= operation.component.query; rest.headers ??= operation.component.headers; return (React.createElement(ComponentLoaderInner, { operation: operation, ...rest })); }; const ComponentLoaderInner = ({ operation, ...rest }) => { const throwError = useAsyncError(); // TODO: Find a suitable type const [data, setData] = useState(); const initialLoad = useRef(true); const component = operation.component.component ?? (() => null); const Component = useMemo(() => lazy(async () => ({ default: await Promise.resolve(component) })), [component]); const refresh = useCallback(async () => { const response = await operation.call(rest); if (response.ok) { setData(await response.json()); } else { // TODO: Report to Sentry // TODO: Handle in the component, this will just unmount it. // Things that suddenly dissapear are bit confusing, don't you think? console.error(`[COMPONENT_LOADER] Data load failed with ${response.status} ${response.statusText}`); setData(null); } }, [operation, rest, throwError]); useEffect(() => { if (initialLoad.current) { initialLoad.current = false; } else { refresh(); } }, [rest.query, rest.params]); return (React.createElement(Suspense, { fallback: React.createElement(LoadingScreen, null) }, data == null ? null : React.createElement(Component, { data: data, refresh: refresh, ...rest }))); }; export default ComponentLoader; //# sourceMappingURL=ComponentLoader.js.map