saleor-dashboard/src/new-apps/hooks/useActiveAppsInstallations.ts

176 lines
5.2 KiB
TypeScript

import { useApolloClient } from "@apollo/client";
import { EXTENSION_LIST_QUERY } from "@dashboard/apps/queries";
import {
AppInstallationFragment,
AppsInstallationsQuery,
JobStatusEnum,
useAppDeleteFailedInstallationMutation,
useAppRetryInstallMutation,
} from "@dashboard/graphql";
import useLocalStorage from "@dashboard/hooks/useLocalStorage";
import { useEffect, useRef } from "react";
interface UseActiveAppsInstallations {
appsInProgressData: AppsInstallationsQuery | undefined;
appsInProgressRefetch: () => void;
appsRefetch: () => void;
removeInProgressAppNotify: () => void;
installedAppNotify: (name: string) => void;
onInstallSuccess: () => void;
onInstallError: (installation: AppInstallationFragment) => void;
onRemoveInProgressAppSuccess: () => void;
}
function useActiveAppsInstallations({
appsInProgressData,
appsInProgressRefetch,
appsRefetch,
installedAppNotify,
removeInProgressAppNotify,
onInstallSuccess,
onInstallError,
onRemoveInProgressAppSuccess,
}: UseActiveAppsInstallations) {
const client = useApolloClient();
const [activeInstallations, setActiveInstallations] = useLocalStorage<
Array<Record<"id" | "name", string>>
>("activeInstallations", []);
const intervalId = useRef<null | number>(null);
const refetchExtensionList = () => {
client.refetchQueries({
include: [EXTENSION_LIST_QUERY],
});
};
const removeInstallation = (id: string) =>
setActiveInstallations(installations =>
installations.filter(item => item.id !== id),
);
const [retryInstallApp, retryInstallAppOpts] = useAppRetryInstallMutation({
onCompleted: data => {
if (!data?.appRetryInstall?.errors?.length) {
const appInstallation = data.appRetryInstall?.appInstallation;
if (appInstallation) {
setActiveInstallations(installations => [
...installations,
{
id: appInstallation.id,
name: appInstallation.appName,
},
]);
}
}
},
});
const handleAppInstallRetry = (id: string) =>
retryInstallApp({ variables: { id } });
const [deleteInProgressApp, deleteInProgressAppOpts] =
useAppDeleteFailedInstallationMutation({
onCompleted: data => {
if (!data?.appDeleteFailedInstallation?.errors?.length) {
removeInProgressAppNotify();
appsInProgressRefetch();
onRemoveInProgressAppSuccess();
}
},
});
const handleRemoveInProgress = (id: string) =>
deleteInProgressApp({
variables: {
id,
},
});
/**
* Check if there has occured by any reason untracked installation with status PENDING and add it to activeInstallations.
*/
useEffect(
() =>
appsInProgressData?.appsInstallations?.forEach(app => {
if (app.status === JobStatusEnum.PENDING) {
const item = activeInstallations.find(
installation => installation.id === app.id,
);
if (!item) {
setActiveInstallations(installations => [
...installations,
{
id: app.id,
name: app.appName,
},
]);
}
}
}),
[appsInProgressData],
);
/**
* Fetch active installations to make its status in localStorage up to date.
*/
useEffect(() => {
if (activeInstallations.length && !!appsInProgressData) {
if (!intervalId.current) {
intervalId.current = window.setInterval(() => {
appsInProgressRefetch();
appsRefetch();
}, 2000);
}
}
if (!activeInstallations.length && intervalId.current) {
clearInterval(intervalId.current);
intervalId.current = null;
}
return () => {
if (intervalId.current) {
clearInterval(intervalId.current);
intervalId.current = null;
}
};
}, [activeInstallations.length, appsInProgressData]);
/**
* Do what is needed and call chaange handlers when installation status changes.
*/
useEffect(() => {
const appsInProgress = appsInProgressData?.appsInstallations || [];
if (activeInstallations.length && !!appsInProgressData) {
let newAppInstalled = false;
activeInstallations.forEach(installation => {
const item = appsInProgress?.find(app => app.id === installation.id);
if (!item) {
removeInstallation(installation.id);
installedAppNotify(installation.name);
appsInProgressRefetch();
appsRefetch();
newAppInstalled = true;
} else if (item.status === JobStatusEnum.SUCCESS) {
removeInstallation(installation.id);
installedAppNotify(item.appName);
onInstallSuccess();
newAppInstalled = true;
} else if (item.status === JobStatusEnum.FAILED) {
removeInstallation(installation.id);
onInstallError(item);
}
});
if (newAppInstalled) {
refetchExtensionList();
}
}
}, [activeInstallations.length, appsInProgressData]);
return {
handleAppInstallRetry,
handleRemoveInProgress,
retryInstallAppOpts,
deleteInProgressAppOpts,
};
}
export default useActiveAppsInstallations;