Skip to content

Commit 2a8f78f

Browse files
committed
feat: Delete Engine modal now programmatically deletes
1 parent 982219a commit 2a8f78f

File tree

2 files changed

+72
-51
lines changed

2 files changed

+72
-51
lines changed

apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,27 +244,26 @@ export function useEngineRemoveFromDashboard() {
244244
});
245245
}
246246

247-
export interface RemoveCloudHostedInput {
248-
instanceId: string;
247+
export interface DeleteCloudHostedInput {
248+
deploymentId: string;
249249
reason: "USING_SELF_HOSTED" | "TOO_EXPENSIVE" | "MISSING_FEATURES" | "OTHER";
250250
feedback: string;
251251
}
252252

253-
export function useEngineRemoveCloudHosted() {
253+
export function useEngineDeleteCloudHosted() {
254254
const { user } = useLoggedInUser();
255255
const queryClient = useQueryClient();
256256

257257
return useMutation({
258258
mutationFn: async ({
259-
instanceId,
259+
deploymentId,
260260
reason,
261261
feedback,
262-
}: RemoveCloudHostedInput) => {
262+
}: DeleteCloudHostedInput) => {
263263
const res = await fetch(
264-
`${THIRDWEB_API_HOST}/v1/engine/${instanceId}/remove-cloud-hosted`,
264+
`${THIRDWEB_API_HOST}/v2/engine/deployments/${deploymentId}/infrastructure`,
265265
{
266266
method: "POST",
267-
268267
headers: {
269268
"Content-Type": "application/json",
270269
},

apps/dashboard/src/components/engine/engine-instances-table.tsx

Lines changed: 66 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Spinner } from "@/components/ui/Spinner/Spinner";
22
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
33
import { Badge } from "@/components/ui/badge";
44
import { Button } from "@/components/ui/button";
5+
import { Checkbox, CheckboxWithLabel } from "@/components/ui/checkbox";
56
import {
67
Dialog,
78
DialogContent,
@@ -13,12 +14,12 @@ import { Input } from "@/components/ui/input";
1314
import { Textarea } from "@/components/ui/textarea";
1415
import { ToolTipLabel } from "@/components/ui/tooltip";
1516
import {
17+
type DeleteCloudHostedInput,
1618
type EditEngineInstanceInput,
1719
type EngineInstance,
18-
type RemoveCloudHostedInput,
20+
useEngineDeleteCloudHosted,
1921
useEngineEditInstance,
2022
type useEngineInstances,
21-
useEngineRemoveCloudHosted,
2223
useEngineRemoveFromDashboard,
2324
} from "@3rdweb-sdk/react/hooks/useEngine";
2425
import { FormControl, Radio, RadioGroup } from "@chakra-ui/react";
@@ -28,7 +29,7 @@ import { TWTable } from "components/shared/TWTable";
2829
import { useTrack } from "hooks/analytics/useTrack";
2930
import {
3031
CircleAlertIcon,
31-
SendIcon,
32+
InfoIcon,
3233
Trash2Icon,
3334
TriangleAlertIcon,
3435
} from "lucide-react";
@@ -38,6 +39,7 @@ import { useForm } from "react-hook-form";
3839
import { BiPencil } from "react-icons/bi";
3940
import { FiTrash } from "react-icons/fi";
4041
import { toast } from "sonner";
42+
import invariant from "tiny-invariant";
4143
import { FormLabel } from "tw-components";
4244

4345
interface EngineInstancesTableProps {
@@ -258,7 +260,7 @@ const EditModal = (props: {
258260

259261
<DialogFooter className="mt-10 gap-2">
260262
<Button onClick={() => onOpenChange(false)} variant="outline">
261-
Cancel
263+
Close
262264
</Button>
263265
<Button
264266
type="submit"
@@ -295,7 +297,7 @@ const RemoveModal = (props: {
295297
close={() => onOpenChange(false)}
296298
/>
297299
) : (
298-
<CancelSubscriptionModalContent
300+
<DeleteSubscriptionModalContent
299301
refetch={refetch}
300302
instance={instance}
301303
close={() => onOpenChange(false)}
@@ -318,18 +320,22 @@ function RemoveFromDashboardModalContent(props: {
318320
<>
319321
<DialogHeader>
320322
<DialogTitle className="mb-3 font-semibold text-2xl tracking-tight">
321-
Remove Engine Instance
323+
Remove Engine
322324
</DialogTitle>
323325
<DialogDescription className="text-muted-foreground">
324326
<span className="mb-2 block">
325-
Are you sure you want to remove
326-
<em className="font-semibold not-italic">"{instance.name}"</em> from
327+
Are you sure you want to remove{" "}
328+
<em className="font-semibold not-italic">{instance.name}</em> from
327329
your dashboard?
328330
</span>
329-
<span className="block">
330-
This action does not modify your Engine infrastructure. You can
331-
re-add it at any time.
332-
</span>
331+
332+
<Alert variant="info">
333+
<InfoIcon className="size-5" />
334+
<AlertTitle>
335+
This action does not modify your Engine infrastructure.
336+
</AlertTitle>
337+
<AlertDescription>You can re-add it at any time.</AlertDescription>
338+
</Alert>
333339
</DialogDescription>
334340
</DialogHeader>
335341

@@ -367,17 +373,22 @@ function RemoveFromDashboardModalContent(props: {
367373
);
368374
}
369375

370-
function CancelSubscriptionModalContent(props: {
376+
function DeleteSubscriptionModalContent(props: {
371377
refetch: () => void;
372378
instance: EngineInstance;
373379
close: () => void;
374380
}) {
375381
const { refetch, instance, close } = props;
376-
const removeCloudHosted = useEngineRemoveCloudHosted();
382+
invariant(
383+
instance.deploymentId,
384+
"Instance must have a deploymentId to be cancelled.",
385+
);
377386

378-
const form = useForm<RemoveCloudHostedInput>({
387+
const deleteCloudHosted = useEngineDeleteCloudHosted();
388+
const [ackDeletion, setAckDeletion] = useState(false);
389+
const form = useForm<DeleteCloudHostedInput>({
379390
defaultValues: {
380-
instanceId: instance.id,
391+
deploymentId: instance.deploymentId,
381392
},
382393
reValidateMode: "onChange",
383394
});
@@ -386,33 +397,25 @@ function CancelSubscriptionModalContent(props: {
386397
<div>
387398
<DialogHeader>
388399
<DialogTitle className="mb-1 font-semibold text-2xl tracking-tight">
389-
Cancel Engine Subscription
400+
Permanently Delete Engine
390401
</DialogTitle>
391-
<DialogDescription className="text-muted-foreground">
392-
Complete this form to request to cancel your Engine subscription. This
393-
may take up to 2 business days.
394-
</DialogDescription>
395402
</DialogHeader>
396403

397-
<div className="h-3" />
404+
<div className="h-4" />
398405

399-
<Alert variant="destructive">
400-
<TriangleAlertIcon className="!text-destructive-text size-5" />
401-
<AlertTitle>This action is irreversible!</AlertTitle>
402-
<AlertDescription>
403-
You will no longer be able to access this Engine's local backend
404-
wallets. <strong>Any remaining mainnet funds will be lost.</strong>
405-
</AlertDescription>
406-
</Alert>
406+
<p className="text-muted-foreground">
407+
This step will cancel your monthly subscription and immediately delete
408+
all data and infrastructure for this Engine.
409+
</p>
407410

408-
<div className="h-5" />
411+
<div className="h-4" />
409412

410413
<form
411414
onSubmit={form.handleSubmit((data) =>
412-
removeCloudHosted.mutate(data, {
415+
deleteCloudHosted.mutate(data, {
413416
onSuccess: () => {
414417
toast.success(
415-
"Submitted a request to cancel your Engine subscription. This may take up to 2 business days.",
418+
"Deleting Engine. Please check again in a few minutes.",
416419
{
417420
dismissible: true,
418421
duration: 10000,
@@ -424,16 +427,16 @@ function CancelSubscriptionModalContent(props: {
424427
},
425428
onError: () => {
426429
toast.error(
427-
"Error requesting to cancel your Engine subscription",
430+
"Error deleting Engine. Please visit https://thirdweb.com/support.",
428431
);
429432
},
430433
}),
431434
)}
432435
>
433-
{/* Form */}
436+
{/* Reason */}
434437
<FormControl isRequired>
435438
<FormLabel className="!text-base">
436-
Please share any feedback to help us improve
439+
Please share your feedback to help us improve Engine.
437440
</FormLabel>
438441
<RadioGroup>
439442
<div className="flex flex-col gap-2">
@@ -467,13 +470,32 @@ function CancelSubscriptionModalContent(props: {
467470

468471
<div className="h-2" />
469472

473+
{/* Feedback */}
470474
<Textarea
471475
className="mt-3"
472476
placeholder="Provide additional feedback"
473477
{...form.register("feedback")}
474478
/>
475479

476-
<div className="h-8" />
480+
<div className="h-4" />
481+
482+
<Alert variant="destructive">
483+
<TriangleAlertIcon className="!text-destructive-text size-5" />
484+
<AlertTitle>This action is irreversible!</AlertTitle>
485+
486+
<AlertDescription className="!pl-0 pt-2">
487+
<CheckboxWithLabel>
488+
<Checkbox
489+
checked={ackDeletion}
490+
onCheckedChange={(checked) => setAckDeletion(!!checked)}
491+
/>
492+
I understand that access to my local backend wallets and any
493+
remaining funds will be lost.
494+
</CheckboxWithLabel>
495+
</AlertDescription>
496+
</Alert>
497+
498+
<div className="h-4" />
477499

478500
<DialogFooter className="gap-2">
479501
<Button onClick={close} variant="outline">
@@ -482,15 +504,15 @@ function CancelSubscriptionModalContent(props: {
482504
<Button
483505
type="submit"
484506
variant="destructive"
485-
disabled={!form.formState.isValid}
507+
disabled={
508+
!ackDeletion ||
509+
deleteCloudHosted.isPending ||
510+
!form.formState.isValid
511+
}
486512
className="gap-2"
487513
>
488-
{removeCloudHosted.isPending ? (
489-
<Spinner className="size-4" />
490-
) : (
491-
<SendIcon className="size-4" />
492-
)}
493-
Request to cancel
514+
{deleteCloudHosted.isPending && <Spinner className="size-4" />}
515+
Yes, delete this Engine
494516
</Button>
495517
</DialogFooter>
496518
</form>

0 commit comments

Comments
 (0)