mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
190 lines
5.3 KiB
TypeScript
190 lines
5.3 KiB
TypeScript
import React, { useContext, useState } from "react";
|
|
import { InjectedRouter } from "react-router";
|
|
import { useQuery } from "react-query";
|
|
import { AxiosError } from "axios";
|
|
|
|
import PATHS from "router/paths";
|
|
import { NotificationContext } from "context/notification";
|
|
import { getErrorReason } from "interfaces/errors";
|
|
import mdmAppleAPI, { IGetVppInfoResponse } from "services/entities/mdm_apple";
|
|
import { DEFAULT_USE_QUERY_OPTIONS } from "utilities/constants";
|
|
import { readableDate } from "utilities/helpers";
|
|
|
|
import MainContent from "components/MainContent";
|
|
import BackLink from "components/BackLink";
|
|
import FileUploader from "components/FileUploader";
|
|
import DataSet from "components/DataSet";
|
|
import Button from "components/buttons/Button";
|
|
import Spinner from "components/Spinner";
|
|
import DataError from "components/DataError";
|
|
|
|
import DisableVppModal from "./components/DisableVppModal";
|
|
import VppSetupSteps from "./components/VppSetupSteps";
|
|
import RenewVppTokenModal from "./components/RenewVppTokenModal";
|
|
|
|
const baseClass = "vpp-setup-page";
|
|
|
|
interface IVppSetupContentProps {
|
|
router: InjectedRouter;
|
|
}
|
|
|
|
const VPPSetupContent = ({ router }: IVppSetupContentProps) => {
|
|
const { renderFlash } = useContext(NotificationContext);
|
|
const [isUploading, setIsUploading] = useState(false);
|
|
|
|
const uploadToken = async (files: FileList | null) => {
|
|
setIsUploading(true);
|
|
|
|
const token = files?.[0];
|
|
if (!token) {
|
|
setIsUploading(false);
|
|
renderFlash("error", "No token selected.");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await mdmAppleAPI.uploadVppToken(token);
|
|
renderFlash(
|
|
"success",
|
|
"Volume Purchasing Program (VPP) integration enabled successfully."
|
|
);
|
|
router.push(PATHS.ADMIN_INTEGRATIONS_VPP);
|
|
} catch (e) {
|
|
// TODO: error messages
|
|
const msg = getErrorReason(e, { reasonIncludes: "valid token" });
|
|
if (msg) {
|
|
renderFlash("error", msg);
|
|
} else {
|
|
renderFlash("error", "Couldn't Upload. Please try again.");
|
|
}
|
|
} finally {
|
|
setIsUploading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={`${baseClass}__setup-content`}>
|
|
<p className={`${baseClass}__description`}>
|
|
Connect Fleet to your Apple Business Manager account to enable access to
|
|
purchased apps.
|
|
</p>
|
|
<VppSetupSteps extendendSteps />
|
|
<FileUploader
|
|
className={`${baseClass}__file-uploader ${
|
|
isUploading ? `${baseClass}__file-uploader--loading` : ""
|
|
}`}
|
|
accept=".vpptoken"
|
|
message="Content token (.vpptoken)"
|
|
graphicName="file-vpp"
|
|
buttonType="link"
|
|
buttonMessage={isUploading ? "Uploading..." : "Upload"}
|
|
onFileUpload={uploadToken}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface IVppDisableOrRenewContentProps {
|
|
vppInfo: IGetVppInfoResponse;
|
|
onDisable: () => void;
|
|
onRenew: () => void;
|
|
}
|
|
|
|
const VPPDisableOrRenewContent = ({
|
|
vppInfo,
|
|
onDisable,
|
|
onRenew,
|
|
}: IVppDisableOrRenewContentProps) => {
|
|
return (
|
|
<div className={`${baseClass}__disable-renew-content`}>
|
|
<div className={`${baseClass}__info`}>
|
|
<DataSet title="Organization name" value={vppInfo.org_name} />
|
|
<DataSet title="Location" value={vppInfo.location} />
|
|
<DataSet title="Renew date" value={readableDate(vppInfo.renew_date)} />
|
|
</div>
|
|
<div className={`${baseClass}__button-wrap`}>
|
|
<Button variant="inverse" onClick={onDisable}>
|
|
Disable
|
|
</Button>
|
|
<Button variant="brand" onClick={onRenew}>
|
|
Renew token
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface IVppSetupPageProps {
|
|
router: InjectedRouter;
|
|
}
|
|
|
|
const VppSetupPage = ({ router }: IVppSetupPageProps) => {
|
|
const [showDisableModal, setShowDisableModal] = useState(false);
|
|
const [showRenewModal, setShowRenewModal] = useState(false);
|
|
|
|
const {
|
|
data: vppData,
|
|
error: vppError,
|
|
isLoading,
|
|
isError,
|
|
refetch: refetchVppInfo,
|
|
} = useQuery<IGetVppInfoResponse, AxiosError>(
|
|
"vppInfo",
|
|
() => mdmAppleAPI.getVppInfo(),
|
|
{
|
|
...DEFAULT_USE_QUERY_OPTIONS,
|
|
retry: false,
|
|
}
|
|
);
|
|
|
|
const renderContent = () => {
|
|
if (isLoading) {
|
|
return <Spinner />;
|
|
}
|
|
|
|
if (isError && vppError?.status !== 404) {
|
|
return <DataError />;
|
|
}
|
|
|
|
// 404 means there is no token, se we want to show the setup steps content
|
|
if (vppError?.status === 404) {
|
|
return <VPPSetupContent router={router} />;
|
|
}
|
|
|
|
return vppData ? (
|
|
<VPPDisableOrRenewContent
|
|
vppInfo={vppData}
|
|
onDisable={() => setShowDisableModal(true)}
|
|
onRenew={() => setShowRenewModal(true)}
|
|
/>
|
|
) : null;
|
|
};
|
|
|
|
return (
|
|
<MainContent className={baseClass}>
|
|
<>
|
|
<BackLink
|
|
text="Back to automatic enrollment"
|
|
path={PATHS.ADMIN_INTEGRATIONS_VPP}
|
|
className={`${baseClass}__back-to-vpp`}
|
|
/>
|
|
<h1>Volume Purchasing Program (VPP)</h1>
|
|
<>{renderContent()}</>
|
|
</>
|
|
{showDisableModal && (
|
|
<DisableVppModal
|
|
router={router}
|
|
onExit={() => setShowDisableModal(false)}
|
|
/>
|
|
)}
|
|
{showRenewModal && (
|
|
<RenewVppTokenModal
|
|
onExit={() => setShowRenewModal(false)}
|
|
onTokenRenewed={refetchVppInfo}
|
|
/>
|
|
)}
|
|
</MainContent>
|
|
);
|
|
};
|
|
|
|
export default VppSetupPage;
|