Skip to content

Commit 1c6ed9b

Browse files
committed
[TOOL-4667] Dashboard: Various improvements in ERC20 asset creation flow (#7264)
<!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on renaming references from "Token" to "Coin" throughout the codebase, along with some improvements in error handling and component structure. ### Detailed summary - Renamed "Token" to "Coin" in various components and UI elements. - Updated the `parseError` function to be exported. - Introduced `ContractTypeCellUI` for better contract type rendering. - Modified multi-step status handling to include more structured error messages. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Enhanced multi-step status tracking with structured error messages and improved error display in step-based processes. - **Improvements** - Updated all user-facing terminology from "Token" to "Coin" across creation, distribution, and sale interfaces. - Distribution and allocation charts now reflect "Coin" terminology and dynamically display the coin symbol when available. - Improved contract table to show "Coin" for relevant contract types. - Refined event tracking to trigger only when relevant actions occur. - **Bug Fixes** - Error messages in step-based processes are now displayed more clearly with detailed information. - **Refactor** - Streamlined contract type badge rendering for consistency and maintainability. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 82035fd commit 1c6ed9b

File tree

13 files changed

+104
-83
lines changed

13 files changed

+104
-83
lines changed

apps/dashboard/src/@/components/blocks/multi-step-status/multi-step-status.stories.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,41 +22,36 @@ export const AllStates: Story = {
2222
args: {
2323
steps: [
2424
{
25-
status: "completed",
25+
status: { type: "completed" },
2626
label: "Connect Wallet",
27-
retryLabel: "Failed to connect wallet",
2827
execute: async () => {
2928
await sleep(1000);
3029
},
3130
},
3231
{
33-
status: "pending",
32+
status: { type: "pending" },
3433
label: "Sign Message",
35-
retryLabel: "Failed to sign message",
3634
execute: async () => {
3735
await sleep(1000);
3836
},
3937
},
4038
{
41-
status: "error",
39+
status: { type: "error", message: "This is an error message" },
4240
label: "Approve Transaction",
43-
retryLabel: "Transaction approval failed",
4441
execute: async () => {
4542
await sleep(1000);
4643
},
4744
},
4845
{
49-
status: "idle",
46+
status: { type: "idle" },
5047
label: "Confirm Transaction",
51-
retryLabel: "Transaction confirmation failed",
5248
execute: async () => {
5349
await sleep(1000);
5450
},
5551
},
5652
{
57-
status: "idle",
53+
status: { type: "idle" },
5854
label: "Finalize",
59-
retryLabel: "Finalization failed",
6055
execute: async () => {
6156
await sleep(1000);
6257
},

apps/dashboard/src/@/components/blocks/multi-step-status/multi-step-status.tsx

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@ import { DynamicHeight } from "../../ui/DynamicHeight";
1111
import { Spinner } from "../../ui/Spinner/Spinner";
1212

1313
export type MultiStepState = {
14-
status: "idle" | "pending" | "completed" | "error";
15-
retryLabel: string;
14+
status:
15+
| {
16+
type: "idle" | "pending" | "completed";
17+
}
18+
| {
19+
type: "error";
20+
message: string | React.ReactNode;
21+
};
1622
label: string;
1723
execute: () => Promise<void>;
1824
};
@@ -25,33 +31,35 @@ export function MultiStepStatus(props: {
2531
<div className="space-y-4">
2632
{props.steps.map((step) => (
2733
<div key={step.label} className="flex items-start space-x-3 ">
28-
{step.status === "completed" ? (
34+
{step.status.type === "completed" ? (
2935
<CircleCheckIcon className="mt-0.5 size-5 flex-shrink-0 text-green-500" />
30-
) : step.status === "pending" ? (
36+
) : step.status.type === "pending" ? (
3137
<Spinner className="mt-0.5 size-5 flex-shrink-0 text-foreground" />
32-
) : step.status === "error" ? (
38+
) : step.status.type === "error" ? (
3339
<AlertCircleIcon className="mt-0.5 size-5 flex-shrink-0 text-red-500" />
3440
) : (
3541
<CircleIcon className="mt-0.5 size-5 flex-shrink-0 text-muted-foreground/70" />
3642
)}
3743
<div className="flex-1">
3844
<p
3945
className={`font-medium ${
40-
step.status === "pending"
46+
step.status.type === "pending"
4147
? "text-foreground"
42-
: step.status === "completed"
48+
: step.status.type === "completed"
4349
? "text-green-500"
44-
: step.status === "error"
50+
: step.status.type === "error"
4551
? "text-red-500"
4652
: "text-muted-foreground/70"
4753
}`}
4854
>
4955
{step.label}
5056
</p>
5157

52-
{step.status === "error" && (
58+
{step.status.type === "error" && (
5359
<div className="mt-1 space-y-2">
54-
<p className="mb-1 text-red-500 text-sm">{step.retryLabel}</p>
60+
<p className="mb-1 text-red-500 text-sm">
61+
{step.status.message}
62+
</p>
5563
<Button
5664
variant="destructive"
5765
size="sm"

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/cards.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ export function Cards(props: {
3232
/>
3333

3434
<CardLink
35-
title="Create Token"
36-
description="Launch your own ERC-20 token"
35+
title="Create Coin"
36+
description="Launch your own ERC-20 coin"
3737
href={`/team/${props.teamSlug}/${props.projectSlug}/assets/create`}
3838
icon={CoinsIcon}
3939
trackingLabel="create-token"
@@ -76,12 +76,14 @@ function CardLink(props: {
7676
const trackEvent = useTrack();
7777

7878
function handleClick() {
79-
trackEvent({
80-
category: "assets-landing-page",
81-
action: "click",
82-
label: props.trackingLabel,
83-
});
84-
onClick?.();
79+
if (onClick) {
80+
trackEvent({
81+
category: "assets-landing-page",
82+
action: "click",
83+
label: props.trackingLabel,
84+
});
85+
onClick();
86+
}
8587
}
8688

8789
return (

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/create-token-page-impl.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ export function CreateTokenAssetPage(props: {
336336
metadata: {
337337
name:
338338
formValues.saleEnabled && salePercent > 0
339-
? "Token Sale phase"
339+
? "Coin Sale phase"
340340
: "Only Owner phase",
341341
},
342342
overrideList: [

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/create-token-page.client.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export function CreateTokenAssetPageUI(props: {
101101

102102
{step === "distribution" && (
103103
<TokenDistributionFieldset
104+
tokenSymbol={tokenInfoForm.watch("symbol")}
104105
client={props.client}
105106
form={tokenDistributionForm}
106107
accountAddress={props.accountAddress}

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/distribution/token-distribution.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,15 @@ export function TokenDistributionFieldset(props: {
2323
form: TokenDistributionForm;
2424
chainId: string;
2525
client: ThirdwebClient;
26+
tokenSymbol: string | undefined;
2627
}) {
2728
const { form } = props;
2829

2930
return (
3031
<Form {...form}>
3132
<form onSubmit={form.handleSubmit(props.onNext)}>
3233
<StepCard
33-
title="Token Distribution"
34+
title="Coin Distribution"
3435
page="distribution"
3536
prevButton={{
3637
onClick: props.onPrevious,
@@ -50,7 +51,7 @@ export function TokenDistributionFieldset(props: {
5051
<div className="relative">
5152
<Input id="supply" {...form.register("supply")} />
5253
<span className="-translate-y-1/2 absolute top-1/2 right-3 text-muted-foreground text-sm">
53-
Tokens
54+
{props.tokenSymbol || "Tokens"}
5455
</span>
5556
</div>
5657
</FormFieldSetup>
@@ -107,9 +108,6 @@ export function TokenDistributionBarChart(props: {
107108
];
108109

109110
return (
110-
<DistributionBarChart
111-
segments={tokenAllocations}
112-
title="Token Allocation"
113-
/>
111+
<DistributionBarChart segments={tokenAllocations} title="Coin Allocation" />
114112
);
115113
}

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/distribution/token-sale.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function TokenSaleSection(props: {
2626
<div>
2727
<h2 className="font-semibold text-lg">Sale</h2>
2828
<p className="text-muted-foreground text-sm">
29-
Make your token available for purchase by setting a price
29+
Make your coin available for purchase by setting a price
3030
</p>
3131
</div>
3232

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/launch/launch-token.tsx

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@ import { TransactionButton } from "components/buttons/TransactionButton";
1616
import { ChainIconClient } from "components/icons/ChainIcon";
1717
import { useTrack } from "hooks/analytics/useTrack";
1818
import { useAllChainsData } from "hooks/chains/allChains";
19-
import { ArrowRightIcon, ImageOffIcon, RocketIcon } from "lucide-react";
19+
import {
20+
ArrowRightIcon,
21+
ArrowUpFromLineIcon,
22+
ImageOffIcon,
23+
} from "lucide-react";
2024
import Link from "next/link";
2125
import { useEffect, useState } from "react";
2226
import type { ThirdwebClient } from "thirdweb";
2327
import { useActiveWallet } from "thirdweb/react";
28+
import { parseError } from "../../../../../../../../../utils/errorParser";
2429
import { StepCard } from "../create-token-card";
2530
import type { CreateTokenFunctions } from "../create-token-page.client";
2631
import { TokenDistributionBarChart } from "../distribution/token-distribution";
@@ -85,10 +90,10 @@ export function LaunchTokenStatus(props: {
8590
executeFn: (values: CreateAssetFormValues) => Promise<void>,
8691
) {
8792
return async () => {
88-
updateStatus(index, "pending");
93+
updateStatus(index, { type: "pending" });
8994
try {
9095
await executeFn(formValues);
91-
updateStatus(index, "completed");
96+
updateStatus(index, { type: "completed" });
9297
// start next one
9398
const nextStep = initialSteps[index + 1];
9499
if (nextStep) {
@@ -101,7 +106,7 @@ export function LaunchTokenStatus(props: {
101106
props.onLaunchSuccess();
102107
}
103108
} catch (error) {
104-
updateStatus(index, "error");
109+
updateStatus(index, { type: "error", message: parseError(error) });
105110
launchTracking({
106111
type: "error",
107112
errorMessage:
@@ -115,8 +120,7 @@ export function LaunchTokenStatus(props: {
115120
const initialSteps: MultiStepState[] = [
116121
{
117122
label: "Deploy contract",
118-
status: "idle",
119-
retryLabel: "Failed to deploy contract",
123+
status: { type: "idle" },
120124
execute: createSequenceExecutorFn(0, async (values) => {
121125
const result = await createTokenFunctions.deployContract(values);
122126
setContractLink(
@@ -126,26 +130,23 @@ export function LaunchTokenStatus(props: {
126130
},
127131
{
128132
label: "Set claim conditions",
129-
status: "idle",
130-
retryLabel: "Failed to set claim conditions",
133+
status: { type: "idle" },
131134
execute: createSequenceExecutorFn(
132135
1,
133136
createTokenFunctions.setClaimConditions,
134137
),
135138
},
136139
{
137140
label: "Mint tokens",
138-
status: "idle",
139-
retryLabel: "Failed to mint tokens",
141+
status: { type: "idle" },
140142
execute: createSequenceExecutorFn(2, createTokenFunctions.mintTokens),
141143
},
142144
];
143145

144146
if (formValues.airdropEnabled && formValues.airdropAddresses.length > 0) {
145147
initialSteps.push({
146148
label: "Airdrop tokens",
147-
status: "idle",
148-
retryLabel: "Failed to airdrop tokens",
149+
status: { type: "idle" },
149150
execute: createSequenceExecutorFn(
150151
3,
151152
createTokenFunctions.airdropTokens,
@@ -160,13 +161,13 @@ export function LaunchTokenStatus(props: {
160161
initialSteps[0]?.execute();
161162
}
162163

163-
const isComplete = steps.every((step) => step.status === "completed");
164-
const isPending = steps.some((step) => step.status === "pending");
164+
const isComplete = steps.every((step) => step.status.type === "completed");
165+
const isPending = steps.some((step) => step.status.type === "pending");
165166

166167
return (
167168
<StepCard
168169
page="launch"
169-
title="Launch Token"
170+
title="Launch Coin"
170171
prevButton={{
171172
onClick: props.onPrevious,
172173
}}
@@ -182,8 +183,8 @@ export function LaunchTokenStatus(props: {
182183
transactionCount={undefined}
183184
onClick={handleSubmitClick}
184185
>
185-
<RocketIcon className="size-4" />
186-
Launch Token
186+
<ArrowUpFromLineIcon className="size-4" />
187+
Launch Coin
187188
</TransactionButton>
188189
),
189190
}}
@@ -256,7 +257,7 @@ export function LaunchTokenStatus(props: {
256257
<div>
257258
<Button asChild className="gap-2">
258259
<Link href={contractLink}>
259-
View Launched Token <ArrowRightIcon className="size-4" />
260+
View Coin <ArrowRightIcon className="size-4" />
260261
</Link>
261262
</Button>
262263
</div>

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ function PageHeader(props: {
8989
</BreadcrumbItem>
9090
<BreadcrumbSeparator />
9191
<BreadcrumbItem>
92-
<BreadcrumbPage>Create Token</BreadcrumbPage>
92+
<BreadcrumbPage>Create Coin</BreadcrumbPage>
9393
</BreadcrumbItem>
9494
</BreadcrumbList>
9595
</Breadcrumb>
@@ -98,10 +98,10 @@ function PageHeader(props: {
9898
<div className="container flex max-w-5xl flex-col gap-3 py-8 lg:flex-row lg:items-center lg:justify-between">
9999
<div>
100100
<h1 className="font-semibold text-2xl tracking-tight lg:text-3xl">
101-
Create Token
101+
Create Coin
102102
</h1>
103103
<p className="text-muted-foreground">
104-
Launch an ERC-20 token for your project
104+
Launch an ERC-20 coin for your project
105105
</p>
106106
</div>
107107
</div>

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/token-info-fieldset.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function TokenInfoFieldset(props: {
3232
<form onSubmit={form.handleSubmit(props.onNext)}>
3333
<StepCard
3434
page="info"
35-
title="Token Information"
35+
title="Coin Information"
3636
prevButton={undefined}
3737
nextButton={{
3838
type: "submit",
@@ -70,7 +70,7 @@ export function TokenInfoFieldset(props: {
7070
>
7171
<Input
7272
id="name"
73-
placeholder="My Token"
73+
placeholder="My Coin"
7474
{...form.register("name")}
7575
/>
7676
</FormFieldSetup>
@@ -120,7 +120,7 @@ export function TokenInfoFieldset(props: {
120120
>
121121
<Textarea
122122
id="description"
123-
placeholder="Describe your token"
123+
placeholder="Describe your coin"
124124
className="grow"
125125
{...form.register("description")}
126126
/>

0 commit comments

Comments
 (0)