Skip to content

Commit 36de2f5

Browse files
authored
fix: enhance ERC-20 token modals with success feedback and fix url (#4690)
1 parent 3f6329a commit 36de2f5

4 files changed

Lines changed: 164 additions & 51 deletions

File tree

Lines changed: 94 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
import { t } from '@lingui/macro'
2-
import { Form, Input } from 'antd'
1+
import { CheckCircleIcon } from '@heroicons/react/24/outline'
2+
import { Trans, t } from '@lingui/macro'
3+
import { Button, Form, Input, Modal } from 'antd'
34
import { useForm } from 'antd/lib/form/Form'
45
import { ISSUE_ERC20_EXPLANATION } from 'components/strings'
6+
import { useRouter } from 'next/router'
57
import { useState } from 'react'
68
import { emitErrorNotification } from 'utils/notifications'
79

10+
import { useJBChainId } from 'juice-sdk-react'
811
import { useIssueErc20TokenTx } from 'hooks/useIssueErc20TokenTx'
912
import { IssueErc20TokenTxArgs } from '../buttons/IssueErc20TokenButton'
13+
import { useV4V5Version } from 'packages/v4v5/contexts/V4V5VersionProvider'
1014
import TransactionModal from './TransactionModal'
1115

1216
export function IssueErc20TokenModal({
@@ -18,8 +22,14 @@ export function IssueErc20TokenModal({
1822
onClose: VoidFunction
1923
onConfirmed?: VoidFunction
2024
}) {
25+
const router = useRouter()
26+
const chainId = useJBChainId()
27+
const { version } = useV4V5Version()
28+
const { jbUrn } = router.query
29+
2130
const [transactionPending, setTransactionPending] = useState<boolean>()
2231
const [loading, setLoading] = useState<boolean>()
32+
const [erc20SuccessModalOpen, setErc20SuccessModalOpen] = useState<boolean>(false)
2333
const [form] = useForm<IssueErc20TokenTxArgs>()
2434

2535
const issueErc20TokenTx = useIssueErc20TokenTx()
@@ -45,8 +55,7 @@ export function IssueErc20TokenModal({
4555
onConfirmed: () => {
4656
setTransactionPending(false)
4757
setLoading(false)
48-
onClose()
49-
onConfirmed?.()
58+
setErc20SuccessModalOpen(true) // Show success modal instead of closing
5059
},
5160
onError: (e: Error) => {
5261
setTransactionPending(false)
@@ -66,40 +75,87 @@ export function IssueErc20TokenModal({
6675
}
6776
}
6877

78+
const checkIconWithBackground = (
79+
<div className="flex h-20 w-20 items-center justify-center rounded-full bg-melon-100 dark:bg-melon-950">
80+
<div className="flex h-[60px] w-[60px] items-center justify-center rounded-full bg-melon-200 dark:bg-melon-900">
81+
<CheckCircleIcon className="h-10 w-10 text-melon-700 dark:text-melon-500" />
82+
</div>
83+
</div>
84+
)
85+
6986
return (
70-
<TransactionModal
71-
open={open}
72-
title={t`Create ERC-20 token`}
73-
okText={t`Create token`}
74-
cancelText={t`Later`}
75-
connectWalletText={t`Connect wallet to create`}
76-
onOk={executeErc20IssueTokenTx}
77-
onCancel={() => onClose()}
78-
confirmLoading={loading}
79-
transactionPending={transactionPending}
80-
>
81-
<p>{ISSUE_ERC20_EXPLANATION}</p>
82-
<Form form={form} layout="vertical">
83-
<Form.Item
84-
name="name"
85-
label={t`Token name`}
86-
rules={[{ required: true, message: t`Token name is required` }]}
87-
>
88-
<Input placeholder={t`Project Token`} />
89-
</Form.Item>
90-
<Form.Item
91-
name="symbol"
92-
label={t`Token ticker`}
93-
rules={[{ required: true, message: t`Token ticker is required` }]}
94-
>
95-
<Input
96-
placeholder="PRJ"
97-
onChange={e =>
98-
form.setFieldsValue({ symbol: e.target.value.toUpperCase() })
99-
}
100-
/>
101-
</Form.Item>
102-
</Form>
103-
</TransactionModal>
87+
<>
88+
<TransactionModal
89+
open={open}
90+
title={t`Create ERC-20 token`}
91+
okText={t`Create token`}
92+
cancelText={t`Later`}
93+
connectWalletText={t`Connect wallet to create`}
94+
onOk={executeErc20IssueTokenTx}
95+
onCancel={() => onClose()}
96+
confirmLoading={loading}
97+
transactionPending={transactionPending}
98+
>
99+
<p>{ISSUE_ERC20_EXPLANATION}</p>
100+
<Form form={form} layout="vertical">
101+
<Form.Item
102+
name="name"
103+
label={t`Token name`}
104+
rules={[{ required: true, message: t`Token name is required` }]}
105+
>
106+
<Input placeholder={t`Project Token`} />
107+
</Form.Item>
108+
<Form.Item
109+
name="symbol"
110+
label={t`Token ticker`}
111+
rules={[{ required: true, message: t`Token ticker is required` }]}
112+
>
113+
<Input
114+
placeholder="PRJ"
115+
onChange={e =>
116+
form.setFieldsValue({ symbol: e.target.value.toUpperCase() })
117+
}
118+
/>
119+
</Form.Item>
120+
</Form>
121+
</TransactionModal>
122+
123+
<Modal
124+
open={erc20SuccessModalOpen}
125+
onCancel={() => {
126+
setErc20SuccessModalOpen(false)
127+
onClose()
128+
onConfirmed?.()
129+
}}
130+
footer={null}
131+
>
132+
<div className="flex w-full flex-col items-center gap-4 pt-2 text-center">
133+
{checkIconWithBackground}
134+
<div className="w-80 pt-1 text-2xl font-medium">
135+
<Trans>Congrats! Your ERC-20 token has been created</Trans>
136+
</div>
137+
<div className="text-secondary pb-6">
138+
<Trans>
139+
Token holders can now claim their tokens as ERC-20.
140+
</Trans>
141+
</div>
142+
<Button
143+
type="primary"
144+
className="w-[185px] h-12"
145+
onClick={() => {
146+
setErc20SuccessModalOpen(false)
147+
onClose()
148+
149+
// Navigate to project tokens tab instead of calling onConfirmed (which causes reload)
150+
if (jbUrn && chainId) {
151+
router.push(`/v${version}/${jbUrn}?tabid=tokens`)
152+
}
153+
}}
154+
>
155+
<Trans>Back to project</Trans>
156+
</Button>
157+
</div>
158+
</Modal>
159+
</>
104160
)
105161
}

src/locales/messages.pot

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,9 @@ msgstr ""
10011001
msgid "Using crowdfunding platforms for films has been around for a while, but Juicebox adds an extra layer of transparency to the process, allowing fans to see where funds are going. Unlike traditional models where money is controlled behind the scenes, StudioDAO members source, vote, fund, and distribute movies transparently using the treasury while creators retain 100% of their creative control and ownership. With the entertainment market currently valued at two trillion dollars, StudioDAO founder Kenny Miller can see a “clear scenario for a decentralized studio to do one billion dollars of production 2-3 years from now.” To learn more about Kenny's vision for StudioDAO, listen to episode 9 of the Juicecast: <0>https://podcast.juicebox.money</0>."
10021002
msgstr ""
10031003

1004+
msgid "Congrats! Your ERC-20 token has been created"
1005+
msgstr ""
1006+
10041007
msgid "Changes will take effect in your next cycle as long as it starts after your edit deadline."
10051008
msgstr ""
10061009

@@ -1196,6 +1199,9 @@ msgstr ""
11961199
msgid "The project owner can mint any amount of project tokens at any time."
11971200
msgstr ""
11981201

1202+
msgid "Token holders can now claim their tokens as ERC-20."
1203+
msgstr ""
1204+
11991205
msgid "This cycle doesn't reserve any tokens."
12001206
msgstr ""
12011207

src/packages/v4v5/views/V4V5ProjectDashboard/hooks/useProjectPageQueries.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,14 @@ export const useProjectPageQueries = () => {
4949

5050
const setProjectPageTab = useCallback(
5151
(tabId: string) => {
52+
const { tabid, payReceipt } = router.query
5253
router.replace(
5354
{
54-
pathname: router.pathname,
55-
query: { ...router.query, tabid: tabId },
55+
pathname: router.asPath.split('?')[0], // Use actual path instead of pattern to prevent encoding
56+
query: {
57+
...(payReceipt && { payReceipt }), // Only include if it exists
58+
tabid: tabId,
59+
},
5660
},
5761
undefined,
5862
{ shallow: true },
@@ -63,12 +67,13 @@ export const useProjectPageQueries = () => {
6367

6468
const setProjectPayReceipt = useCallback(
6569
(payReceipt: ProjectPayReceipt | undefined) => {
70+
const { tabid } = router.query
6671
router.replace(
6772
{
68-
pathname: router.pathname,
73+
pathname: router.asPath.split('?')[0], // Use actual path instead of pattern to prevent encoding
6974
query: {
70-
...router.query,
71-
payReceipt: payReceipt ? JSON.stringify(payReceipt) : undefined,
75+
...(tabid && { tabid }), // Only include if it exists
76+
...(payReceipt && { payReceipt: JSON.stringify(payReceipt) }),
7277
},
7378
},
7479
undefined,

src/packages/v4v5/views/V4V5ProjectSettings/CreateErc20TokenSettingsPage.tsx

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import { Button, Form, Input } from 'antd'
1+
import { CheckCircleIcon } from '@heroicons/react/24/outline'
2+
import { Button, Form, Input, Modal } from 'antd'
23
import { JBChainId, createSalt, jbControllerAbi } from 'juice-sdk-core'
3-
import { RelayrPostBundleResponse, useGetRelayrTxBundle, useJBContractContext, useSendRelayrTx, useSuckers } from 'juice-sdk-react'
4+
import { RelayrPostBundleResponse, useGetRelayrTxBundle, useJBChainId, useJBContractContext, useJBProjectId, useSendRelayrTx, useSuckers } from 'juice-sdk-react'
45
import { Trans, t } from '@lingui/macro'
6+
import { useRouter } from 'next/router'
57
import { mainnet, sepolia } from 'viem/chains'
68
import { useEffect, useMemo, useState } from 'react'
79

@@ -18,13 +20,21 @@ import { emitErrorNotification } from 'utils/notifications'
1820
import { useDeployOmnichainErc20 } from 'packages/v4v5/hooks/useDeployOmnichainErc20'
1921
import { useProjectHasErc20Token } from 'packages/v4v5/hooks/useProjectHasErc20Token'
2022
import { useV4V5IssueErc20TokenTx } from 'packages/v4v5/hooks/useV4V5IssueErc20TokenTx'
23+
import { useV4V5Version } from 'packages/v4v5/contexts/V4V5VersionProvider'
2124
import { useV4V5WalletHasPermission } from 'packages/v4v5/hooks/useV4V5WalletHasPermission'
2225

2326
export function CreateErc20TokenSettingsPage() {
2427
const [form] = Form.useForm<IssueErc20TokenTxArgs>()
2528
const [confirmLoading, setConfirmLoading] = useState<boolean>()
2629
const [transactionModalOpen, setTransactionModalOpen] =
2730
useState<boolean>(false)
31+
const [successModalOpen, setSuccessModalOpen] = useState<boolean>(false)
32+
33+
const router = useRouter()
34+
const chainId = useJBChainId()
35+
const { projectId } = useJBProjectId(chainId)
36+
const { version } = useV4V5Version()
37+
2838
const issueErc20TokenTx = useV4V5IssueErc20TokenTx()
2939
const projectHasErc20Token = useProjectHasErc20Token()
3040
const hasIssueTicketsPermission = useV4V5WalletHasPermission(
@@ -126,10 +136,10 @@ export function CreateErc20TokenSettingsPage() {
126136

127137
useEffect(() => {
128138
if (relayrBundle.isComplete) {
129-
// close modal on complete then reload
139+
// close modal on complete then show success
130140
setConfirmLoading(false)
131141
setTransactionModalOpen(false)
132-
window.location.reload()
142+
setSuccessModalOpen(true)
133143
}
134144
}, [relayrBundle.isComplete])
135145

@@ -153,10 +163,7 @@ export function CreateErc20TokenSettingsPage() {
153163
onTransactionConfirmed: () => {
154164
setConfirmLoading(false)
155165
setTransactionModalOpen(false)
156-
setConfirmLoading(false)
157-
setTimeout(() => {
158-
window.location.reload()
159-
}, 1000)
166+
setSuccessModalOpen(true)
160167
},
161168
onTransactionError: (e: Error) => {
162169
setConfirmLoading(false)
@@ -275,6 +282,45 @@ export function CreateErc20TokenSettingsPage() {
275282
relayrResponse={relayrBundle.response}
276283
centered
277284
/>
285+
286+
<Modal
287+
open={successModalOpen}
288+
onCancel={() => {
289+
setSuccessModalOpen(false)
290+
if (projectId && chainId) {
291+
router.push(`/v${version}/${router.query.jbUrn}?tabid=tokens`)
292+
}
293+
}}
294+
footer={null}
295+
>
296+
<div className="flex w-full flex-col items-center gap-4 pt-2 text-center">
297+
<div className="flex h-20 w-20 items-center justify-center rounded-full bg-melon-100 dark:bg-melon-950">
298+
<div className="flex h-[60px] w-[60px] items-center justify-center rounded-full bg-melon-200 dark:bg-melon-900">
299+
<CheckCircleIcon className="h-10 w-10 text-melon-700 dark:text-melon-500" />
300+
</div>
301+
</div>
302+
<div className="w-80 pt-1 text-2xl font-medium">
303+
<Trans>Congrats! Your ERC-20 token has been created</Trans>
304+
</div>
305+
<div className="text-secondary pb-6">
306+
<Trans>
307+
Token holders can now claim their tokens as ERC-20.
308+
</Trans>
309+
</div>
310+
<Button
311+
type="primary"
312+
className="w-[185px] h-12"
313+
onClick={() => {
314+
setSuccessModalOpen(false)
315+
if (projectId && chainId) {
316+
router.push(`/v${version}/${router.query.jbUrn}?tabid=tokens`)
317+
}
318+
}}
319+
>
320+
<Trans>Back to project</Trans>
321+
</Button>
322+
</div>
323+
</Modal>
278324
</>
279325
)
280326
}

0 commit comments

Comments
 (0)