Skip to content

Commit

Permalink
feat(billing): unify deployment modals
Browse files Browse the repository at this point in the history
refs #628
  • Loading branch information
jzsfkzm committed Feb 9, 2025
1 parent 64202f7 commit 0721038
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,15 @@ import { UAKT_DENOM } from "@src/config/denom.config";
import { usePricing } from "@src/context/PricingProvider";
import { useSettings } from "@src/context/SettingsProvider";
import { useWallet } from "@src/context/WalletProvider";
import { useUser } from "@src/hooks/useUser";
import { useDenomData, useWalletBalance } from "@src/hooks/useWalletBalance";
import { useGranteeGrants } from "@src/queries/useGrantsQuery";
import { ServiceType } from "@src/types";
import { AnalyticsCategory, AnalyticsEvents } from "@src/types/analytics";
import { denomToUdenom, udenomToDenom } from "@src/utils/mathHelpers";
import { coinToUDenom } from "@src/utils/priceUtils";
import { UrlService } from "@src/utils/urlUtils";
import { LeaseSpecDetail } from "../shared/LeaseSpecDetail";
import { LinkTo } from "../shared/LinkTo";
import { GranteeDepositMenuItem } from "./GranteeDepositMenuItem";

Expand All @@ -45,6 +49,8 @@ export type DeploymentDepositModalProps = {
onDeploymentDeposit: (deposit: number, depositorAddress: string) => void;
handleCancel: () => void;
children?: ReactNode;
title?: string;
services?: ServiceType[];
};

const formSchema = z
Expand Down Expand Up @@ -73,7 +79,9 @@ export const DeploymentDepositModal: React.FunctionComponent<DeploymentDepositMo
onDeploymentDeposit,
disableMin,
denom,
infoText = null
title = "Deployment Deposit",
infoText = null,
services = []
}) => {
const formRef = useRef<HTMLFormElement>(null);
const { settings } = useSettings();
Expand All @@ -96,6 +104,15 @@ export const DeploymentDepositModal: React.FunctionComponent<DeploymentDepositMo
const { handleSubmit, control, watch, setValue, clearErrors, unregister } = form;
const { amount, useDepositor, depositorAddress } = watch();
const validGrants = granteeGrants?.filter(x => compareAsc(new Date(), new Date(x.expiration)) !== 1 && x.authorization.spend_limit.denom === denom) || [];
const user = useUser();

const goToSignIn = () => {
window.location.href = UrlService.login();
};

const goToCheckout = () => {
window.location.href = "/api/proxy/v1/checkout";
};

useEffect(() => {
if (depositData && amount === 0 && !disableMin) {
Expand Down Expand Up @@ -225,10 +242,29 @@ export const DeploymentDepositModal: React.FunctionComponent<DeploymentDepositMo
}
]}
onClose={onClose}
maxWidth="xs"
enableCloseOnBackdropClick
title="Deployment Deposit"
title={title}
>
{services.length > 0 && (
<div className="mb-3 max-h-[300px] overflow-scroll">
{services.map(service => {
return (
<Alert key={service.title} className="mb-1">
<div className="mb-2 text-sm">
<span className="font-bold">{service.title}</span>:{service.image}
</div>
<div className="flex items-center space-x-4 whitespace-nowrap">
<LeaseSpecDetail type="cpu" className="flex-shrink-0" value={service.profile?.cpu as number} />
{service.profile?.hasGpu && <LeaseSpecDetail type="gpu" className="flex-shrink-0" value={service.profile?.gpu as number} />}
<LeaseSpecDetail type="ram" className="flex-shrink-0" value={`${service.profile?.ram} ${service.profile?.ramUnit}`} />
<LeaseSpecDetail type="storage" className="flex-shrink-0" value={`${service.profile?.storage} ${service.profile?.storageUnit}`} />
</div>
</Alert>
);
})}
</div>
)}

<Form {...form}>
<form onSubmit={handleSubmit(onSubmit)} ref={formRef}>
{infoText}
Expand Down Expand Up @@ -259,6 +295,17 @@ export const DeploymentDepositModal: React.FunctionComponent<DeploymentDepositMo
);
}}
/>
<div className="mt-1 flex justify-end text-xs">
{user?.userId ? (
<LinkTo onClick={() => goToCheckout()} className="text-primary">
Buy more credits
</LinkTo>
) : (
<LinkTo onClick={() => goToSignIn()} className="text-primary">
Sign in to buy more credits
</LinkTo>
)}
</div>
</div>

{isCustodial && (
Expand Down
26 changes: 16 additions & 10 deletions apps/deploy-web/src/components/new-deployment/ManifestEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import { useCertificate } from "@src/context/CertificateProvider";
import { useChainParam } from "@src/context/ChainParamProvider";
import { useSdlBuilder } from "@src/context/SdlBuilderProvider/SdlBuilderProvider";
import { useWallet } from "@src/context/WalletProvider";
import { useManagedDeploymentConfirm } from "@src/hooks/useManagedDeploymentConfirm";
import { useManagedWalletDenom } from "@src/hooks/useManagedWalletDenom";
import { useDenomData } from "@src/hooks/useWalletBalance";
import { useWhen } from "@src/hooks/useWhen";
import { useDepositParams } from "@src/queries/useSettings";
import sdlStore from "@src/store/sdlStore";
Expand Down Expand Up @@ -67,6 +67,8 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({
const [selectedSdlEditMode, setSelectedSdlEditMode] = useAtom(sdlStore.selectedSdlEditMode);
const [isRepoInputValid, setIsRepoInputValid] = useState(false);
const [sdlDenom, setSdlDenom] = useState("uakt");
const depositData = useDenomData(sdlDenom);

const { settings } = useSettings();
const { address, signAndBroadcastTx, isManaged, isTrialing } = useWallet();
const router = useRouter();
Expand All @@ -83,8 +85,8 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({
const defaultDeposit = depositParams || browserEnvConfig.NEXT_PUBLIC_DEFAULT_INITIAL_DEPOSIT;
const wallet = useWallet();
const managedDenom = useManagedWalletDenom();
const { createDeploymentConfirm } = useManagedDeploymentConfirm();
const { enqueueSnackbar } = useSnackbar();
const services = importSimpleSdl(editedManifest as string);

useWhen(
wallet.isManaged && sdlDenom === "uakt" && editedManifest,
Expand Down Expand Up @@ -192,18 +194,12 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({
}

if (isManaged) {
const services = importSimpleSdl(editedManifest as string);

if (!services) {
setParsingError("Error while parsing SDL file");
return;
}

const isConfirmed = await createDeploymentConfirm(services);

if (isConfirmed) {
await handleCreateClick(defaultDeposit, browserEnvConfig.NEXT_PUBLIC_MASTER_WALLET_ADDRESS);
}
setIsDepositingDeployment(true);
} else {
setIsCheckingPrerequisites(true);
}
Expand Down Expand Up @@ -429,14 +425,24 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({
handleCancel={() => setIsDepositingDeployment(false)}
onDeploymentDeposit={onDeploymentDeposit}
denom={sdlDenom}
title="Confirm deployment creation?"
infoText={
<Alert className="mb-4 text-xs" variant="default">
To create a deployment, you need to have at least <b>{minDeposit.akt} AKT</b> or <b>{minDeposit.usdc} USDC</b> in an escrow account.{" "}
{isManaged ? (
<>
To create a deployment, you need to have at least <b>${depositData?.min}</b> in an escrow account.{" "}
</>
) : (
<>
To create a deployment, you need to have at least <b>{minDeposit.akt} AKT</b> or <b>{minDeposit.usdc} USDC</b> in an escrow account.{" "}
</>
)}
<LinkTo onClick={ev => handleDocClick(ev, "https://akash.network/docs/other-resources/payments/")}>
<strong>Learn more.</strong>
</LinkTo>
</Alert>
}
services={services}
/>
)}
{isCheckingPrerequisites && <PrerequisiteList onClose={() => setIsCheckingPrerequisites(false)} onContinue={onPrerequisiteContinue} />}
Expand Down
24 changes: 14 additions & 10 deletions apps/deploy-web/src/components/sdl/RentGpusForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import { useCertificate } from "@src/context/CertificateProvider";
import { useChainParam } from "@src/context/ChainParamProvider";
import { useSettings } from "@src/context/SettingsProvider";
import { useWallet } from "@src/context/WalletProvider";
import { useManagedDeploymentConfirm } from "@src/hooks/useManagedDeploymentConfirm";
import { useManagedWalletDenom } from "@src/hooks/useManagedWalletDenom";
import { useDenomData } from "@src/hooks/useWalletBalance";
import { useWhen } from "@src/hooks/useWhen";
import { useGpuModels } from "@src/queries/useGpuQuery";
import { useDepositParams } from "@src/queries/useSettings";
Expand Down Expand Up @@ -77,10 +77,10 @@ export const RentGpusForm: React.FunctionComponent = () => {
const [sdlDenom, setSdlDenom] = useState("uakt");
const { minDeposit } = useChainParam();
const router = useRouter();
const { createDeploymentConfirm } = useManagedDeploymentConfirm();
const managedDenom = useManagedWalletDenom();
const { data: depositParams } = useDepositParams();
const defaultDeposit = depositParams || browserEnvConfig.NEXT_PUBLIC_DEFAULT_INITIAL_DEPOSIT;
const depositData = useDenomData(sdlDenom);

useWhen(isManaged && sdlDenom === "uakt", () => {
setSdlDenom(managedDenom);
Expand Down Expand Up @@ -207,13 +207,7 @@ export const RentGpusForm: React.FunctionComponent = () => {
setRentGpuSdl(data);

if (isManaged) {
const isConfirmed = await createDeploymentConfirm(rentGpuSdl?.services as ServiceType[]);

if (!isConfirmed) {
return;
}

await handleCreateClick(defaultDeposit, browserEnvConfig.NEXT_PUBLIC_MASTER_WALLET_ADDRESS);
setIsDepositingDeployment(true);
} else {
setIsCheckingPrerequisites(true);
}
Expand Down Expand Up @@ -298,13 +292,23 @@ export const RentGpusForm: React.FunctionComponent = () => {
infoText={
<Alert className="mb-4" variant="default">
<p className="text-sm text-muted-foreground">
To create a deployment, you need to have at least <b>{minDeposit.akt} AKT</b> or <b>{minDeposit.usdc} USDC</b> in an escrow account.{" "}
{isManaged ? (
<>
To create a deployment, you need to have at least <b>${depositData?.min}</b> in an escrow account.{" "}
</>
) : (
<>
To create a deployment, you need to have at least <b>{minDeposit.akt} AKT</b> or <b>{minDeposit.usdc} USDC</b> in an escrow account.{" "}
</>
)}
<LinkTo onClick={ev => handleDocClick(ev, "https://akash.network/docs/getting-started/intro-to-akash/bids-and-leases/#escrow-accounts")}>
<strong>Learn more.</strong>
</LinkTo>
</p>
</Alert>
}
title="Confirm deployment creation?"
services={rentGpuSdl?.services}
/>
)}
{isCheckingPrerequisites && <PrerequisiteList onClose={() => setIsCheckingPrerequisites(false)} onContinue={onPrerequisiteContinue} />}
Expand Down
74 changes: 1 addition & 73 deletions apps/deploy-web/src/hooks/useManagedDeploymentConfirm.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { FormattedNumber } from "react-intl";
import { Alert, AlertDescription, AlertTitle } from "@akashnetwork/ui/components";
import { usePopup } from "@akashnetwork/ui/context";

import { LeaseSpecDetail } from "@src/components/shared/LeaseSpecDetail";
import { useChainParam } from "@src/context/ChainParamProvider";
import { useWallet } from "@src/context/WalletProvider";
import { ServiceType } from "@src/types";
import { useWalletBalance } from "./useWalletBalance";

export const useManagedDeploymentConfirm = () => {
const { minDeposit } = useChainParam();
const { balance: walletBalance } = useWalletBalance();
const { isManaged } = useWallet();
const { confirm } = usePopup();

Expand All @@ -36,69 +28,5 @@ export const useManagedDeploymentConfirm = () => {
return true;
};

const createDeploymentConfirm = async (services: ServiceType[]) => {
if (isManaged) {
const hasEnoughForDeposit = (walletBalance?.totalDeploymentGrantsUSD || 0) >= minDeposit.usdc;

const isConfirmed = await confirm({
title: "Confirm deployment creation?",
message: (
<div className="space-y-2">
{!hasEnoughForDeposit && (
<Alert variant="destructive" className="text-primary">
<AlertTitle className="font-bold">Insufficient funds</AlertTitle>
<AlertDescription>
<p>
You need more than{" "}
<FormattedNumber
value={minDeposit.usdc}
// eslint-disable-next-line react/style-prop-object
style="currency"
currency="USD"
/>{" "}
available to create a deployment.
</p>
<p>
Current available balance:{" "}
<span className="font-bold">
<FormattedNumber
value={walletBalance?.totalDeploymentGrantsUSD || 0}
// eslint-disable-next-line react/style-prop-object
style="currency"
currency="USD"
/>
</span>
</p>
</AlertDescription>
</Alert>
)}

{services.map(service => {
return (
<Alert key={service.image}>
<div className="mb-2 text-sm">
<span className="font-bold">{service.title}</span>:{service.image}
</div>
<div className="flex items-center space-x-4 whitespace-nowrap">
<LeaseSpecDetail type="cpu" className="flex-shrink-0" value={service.profile?.cpu as number} />
{service.profile?.hasGpu && <LeaseSpecDetail type="gpu" className="flex-shrink-0" value={service.profile?.gpu as number} />}
<LeaseSpecDetail type="ram" className="flex-shrink-0" value={`${service.profile?.ram} ${service.profile?.ramUnit}`} />
<LeaseSpecDetail type="storage" className="flex-shrink-0" value={`${service.profile?.storage} ${service.profile?.storageUnit}`} />
</div>
</Alert>
);
})}
</div>
)
});

if (!isConfirmed) {
return false;
}
}

return true;
};

return { closeDeploymentConfirm, createDeploymentConfirm };
return { closeDeploymentConfirm };
};

0 comments on commit 0721038

Please sign in to comment.