Skip to content

Commit 197c893

Browse files
committed
Dashboard: Published Contract page UI improvements, Fix audit link
1 parent cf401be commit 197c893

File tree

17 files changed

+291
-321
lines changed

17 files changed

+291
-321
lines changed

apps/dashboard/src/@/components/blocks/TokenSelector.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import { SelectWithSearch } from "@/components/blocks/select-with-search";
1111
import { Badge } from "@/components/ui/badge";
1212
import { useAllChainsData } from "@/hooks/chains/allChains";
1313
import { useTokensData } from "@/hooks/tokens";
14-
import { replaceIpfsUrl } from "@/lib/sdk";
1514
import { cn } from "@/lib/utils";
1615
import { fallbackChainIcon } from "@/utils/chain-icons";
16+
import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler";
1717
import { Spinner } from "../ui/Spinner/Spinner";
1818

1919
type Option = { label: string; value: string };
@@ -122,7 +122,10 @@ export function TokenSelector(props: {
122122
return option.label;
123123
}
124124
const resolvedSrc = token.iconUri
125-
? replaceIpfsUrl(token.iconUri, props.client)
125+
? resolveSchemeWithErrorHandler({
126+
client: props.client,
127+
uri: token.iconUri,
128+
})
126129
: fallbackChainIcon;
127130

128131
return (

apps/dashboard/src/@/components/contract-components/contract-deploy-form/platform-fee-fieldset.tsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import Link from "next/link";
21
import type { ThirdwebClient } from "thirdweb";
32
import { BasisPointsInput } from "@/components/blocks/BasisPointsInput";
43
import { FormFieldSetup } from "@/components/blocks/FormFieldSetup";
54
import { SolidityInput } from "@/components/solidity-inputs";
5+
import { UnderlineLink } from "@/components/ui/UnderlineLink";
66
import { Fieldset } from "./common";
77
import type { CustomContractDeploymentForm } from "./custom-contract";
88

@@ -78,30 +78,28 @@ export const PlatformFeeFieldset: React.FC<PlatformFeeFieldsetProps> = ({
7878
</FormFieldSetup>
7979
</>
8080
) : isMarketplace ? (
81-
<p className="mb-3 pt-4 text-muted-foreground text-sm italic">
81+
<p className="text-muted-foreground text-sm leading-relaxed">
8282
A 2.5% platform fee is deducted from each sale to support ongoing
83-
platform operations and improvements.{" "}
84-
<Link
85-
className="text-blue-500 underline"
83+
platform operations and improvements. <br />
84+
<UnderlineLink
8685
href={"https://thirdweb.com/pricing"}
8786
rel="noopener noreferrer"
8887
target="_blank"
8988
>
9089
See fee breakdown on pricing page.
91-
</Link>
90+
</UnderlineLink>
9291
</p>
9392
) : (
94-
<p className="mb-3 pt-4 text-muted-foreground text-sm italic">
93+
<p className="text-muted-foreground text-sm leading-relaxed">
9594
A 2.5% platform fee is deducted from each primary sale price to
96-
support ongoing platform operations and improvements.{" "}
97-
<Link
98-
className="text-blue-500 underline"
95+
support ongoing platform operations and improvements. <br />
96+
<UnderlineLink
9997
href={"https://thirdweb.com/pricing"}
10098
rel="noopener noreferrer"
10199
target="_blank"
102100
>
103101
See fee breakdown on pricing page.
104-
</Link>
102+
</UnderlineLink>
105103
</p>
106104
)}
107105
</div>
Lines changed: 56 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
"use client";
22

3-
import { ExternalLinkIcon } from "lucide-react";
3+
import { Edit3Icon } from "lucide-react";
44
import Link from "next/link";
55
import { type ThirdwebClient, ZERO_ADDRESS } from "thirdweb";
66
import {
77
AccountAddress,
88
AccountAvatar,
9-
AccountBlobbie,
109
AccountName,
1110
AccountProvider,
1211
} from "thirdweb/react";
@@ -15,77 +14,69 @@ import { useEns } from "@/hooks/contract-hooks";
1514
import { replaceDeployerAddress } from "@/lib/publisher-utils";
1615
import { shortenIfAddress } from "@/utils/usedapp-external";
1716

18-
interface PublisherHeaderProps {
19-
wallet: string;
20-
client: ThirdwebClient;
21-
}
22-
export const PublisherHeader: React.FC<PublisherHeaderProps> = ({
17+
export function PublisherLink({
2318
wallet,
2419
client,
25-
}) => {
20+
}: {
21+
wallet: string;
22+
client: ThirdwebClient;
23+
}) {
2624
const ensQuery = useEns({
2725
addressOrEnsName: wallet,
2826
client,
2927
});
3028

3129
return (
32-
<div>
33-
<h4 className="font-medium text-base mb-3">Published by</h4>
34-
<AccountProvider
35-
// passing zero address during loading time to prevent the component from crashing
36-
address={ensQuery.data?.address || ZERO_ADDRESS}
37-
client={client}
38-
>
39-
<div className="flex items-center gap-3 relative">
40-
<div className="translate-y-0.5">
41-
<AccountAvatar
42-
className="size-[34px] rounded-full border border-border border-solid object-cover"
43-
fallbackComponent={
44-
<AccountBlobbie className="size-[34px] rounded-full" />
45-
}
46-
loadingComponent={
47-
<Skeleton className="size-[34px] rounded-full" />
48-
}
49-
/>
50-
</div>
51-
52-
<div className="space-y-1">
53-
<Link
54-
className="hover:underline leading-none before:absolute before:inset-0"
55-
href={replaceDeployerAddress(
56-
`/${ensQuery.data?.ensName || wallet}`,
57-
)}
58-
rel="noopener noreferrer"
59-
target="_blank"
60-
>
61-
<AccountName
62-
className="text-base leading-none font-medium"
63-
fallbackComponent={
64-
// When social profile API support other TLDs as well - we can remove this condition
65-
ensQuery.data?.ensName ? (
66-
<span className="text-base leading-none font-medium">
67-
{ensQuery.data?.ensName}
68-
</span>
69-
) : (
70-
<AccountAddress
71-
formatFn={(addr) =>
72-
shortenIfAddress(replaceDeployerAddress(addr))
73-
}
74-
/>
75-
)
76-
}
77-
formatFn={(name) => replaceDeployerAddress(name)}
78-
loadingComponent={<Skeleton className="h-6 w-40" />}
79-
/>
80-
</Link>
30+
<AccountProvider
31+
// passing zero address during loading time to prevent the component from crashing
32+
address={ensQuery.data?.address || ZERO_ADDRESS}
33+
client={client}
34+
>
35+
<div className="flex items-center gap-2.5 relative">
36+
<div>
37+
<AccountAvatar
38+
className="size-[34px] rounded-full border border-border border-solid object-cover"
39+
fallbackComponent={
40+
<div className="size-[34px] rounded-full flex items-center justify-center border bg-card">
41+
<Edit3Icon className="size-3.5 text-muted-foreground" />
42+
</div>
43+
}
44+
loadingComponent={<Skeleton className="size-[34px] rounded-full" />}
45+
/>
46+
</div>
8147

82-
<span className="text-sm text-muted-foreground flex items-center gap-1.5 leading-none">
83-
View all published contracts{" "}
84-
<ExternalLinkIcon className="size-3 text-muted-foreground" />
85-
</span>
48+
<Link
49+
className="hover:underline before:absolute before:inset-0 space-y-1.5"
50+
href={replaceDeployerAddress(`/${ensQuery.data?.ensName || wallet}`)}
51+
rel="noopener noreferrer"
52+
target="_blank"
53+
>
54+
<div className="text-sm font-medium text-foreground leading-none">
55+
Published by
8656
</div>
87-
</div>
88-
</AccountProvider>
89-
</div>
57+
58+
<AccountName
59+
className="text-sm text-foreground leading-none"
60+
fallbackComponent={
61+
// When social profile API support other TLDs as well - we can remove this condition
62+
ensQuery.data?.ensName ? (
63+
<span className="text-sm text-muted-foreground leading-none">
64+
{ensQuery.data?.ensName}
65+
</span>
66+
) : (
67+
<AccountAddress
68+
className="text-sm text-foreground leading-none"
69+
formatFn={(addr) =>
70+
shortenIfAddress(replaceDeployerAddress(addr))
71+
}
72+
/>
73+
)
74+
}
75+
formatFn={(name) => replaceDeployerAddress(name)}
76+
loadingComponent={<Skeleton className="h-[17px] w-40" />}
77+
/>
78+
</Link>
79+
</div>
80+
</AccountProvider>
9081
);
91-
};
82+
}

apps/dashboard/src/@/components/contract-components/shared/contract-id-image.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Image from "next/image";
55
import type { FetchDeployMetadataResult } from "thirdweb/contract";
66
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
77
import { getConfiguredThirdwebClient } from "@/constants/thirdweb.server";
8-
import { replaceIpfsUrl } from "@/lib/sdk";
8+
import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler";
99
import generalContractIcon from "../../../../../public/assets/tw-icons/general.png";
1010

1111
type ContractIdImageProps = {
@@ -29,13 +29,13 @@ export const ContractIdImage: React.FC<ContractIdImageProps> = ({
2929
className="size-8 rounded-full"
3030
src={
3131
DASHBOARD_THIRDWEB_SECRET_KEY
32-
? replaceIpfsUrl(
33-
logo,
34-
getConfiguredThirdwebClient({
32+
? resolveSchemeWithErrorHandler({
33+
client: getConfiguredThirdwebClient({
3534
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
3635
teamId: undefined,
3736
}),
38-
)
37+
uri: logo,
38+
})
3939
: logo
4040
}
4141
/>

apps/dashboard/src/@/components/contracts/code-overview.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ export function CodeOverview(props: {
657657

658658
<div className="flex flex-col gap-4">
659659
<div className="space-y-2">
660-
<h2 className="text-lg font-semibold tracking-tight">
660+
<h2 className="text-2xl font-semibold tracking-tight">
661661
{isAccountFactory
662662
? "Direct contract interaction (advanced)"
663663
: chainInfo
@@ -851,7 +851,7 @@ function AccentButton(props: {
851851
return (
852852
<Button
853853
className={cn(
854-
"text-sm justify-start h-auto py-1 px-2 text-muted-foreground",
854+
"text-sm justify-start h-auto py-1.5 px-2 text-muted-foreground font-normal font-mono",
855855
props.isActive && "text-foreground bg-accent",
856856
)}
857857
onClick={props.onClick}

apps/dashboard/src/@/components/contracts/functions/contract-function.tsx

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ function ContractFunctionInputs(props: { fn: AbiFunction | AbiEvent }) {
169169

170170
return (
171171
<div className="flex flex-col gap-1.5">
172-
<div className="flex items-center flex-wrap gap-2 border-b pb-3 mb-3">
173-
<h3 className="text-lg font-semibold">{fn.name}</h3>
172+
<div className="flex items-center flex-wrap gap-2 border-b pb-2.5 mb-3">
173+
<h3 className="text-base font-semibold">{fn.name}</h3>
174174
{isFunction && <Badge variant="success">{fn.stateMutability}</Badge>}
175175
</div>
176176

@@ -206,7 +206,9 @@ function ContractFunctionInputs(props: { fn: AbiFunction | AbiEvent }) {
206206
</Table>
207207
</TableContainer>
208208
</div>
209-
) : null}
209+
) : (
210+
<p className="text-muted-foreground text-base">No inputs required</p>
211+
)}
210212
</div>
211213
);
212214
}
@@ -287,7 +289,7 @@ export const ContractFunctionsPanel: React.FC<ContractFunctionsPanelProps> = ({
287289
const [_keywordSearch, setKeywordSearch] = useState<string>("");
288290
const [keywordSearch] = useDebounce(_keywordSearch, 150);
289291

290-
const [activeTab, setActiveTab] = useState<number>(0);
292+
const [activeTab, setActiveTab] = useState<number>(1);
291293

292294
const functionSection = (e: ExtensionFunctions) => {
293295
const filteredFunctions = keywordSearch
@@ -298,7 +300,7 @@ export const ContractFunctionsPanel: React.FC<ContractFunctionsPanelProps> = ({
298300

299301
return (
300302
<div key={e.extension} className="pb-6">
301-
<div className="flex flex-col gap-0.5">
303+
<div className="space-y-0.5">
302304
{selectedFunction &&
303305
filteredFunctions.map((fn) => (
304306
<FunctionsOrEventsListItem
@@ -314,30 +316,30 @@ export const ContractFunctionsPanel: React.FC<ContractFunctionsPanelProps> = ({
314316
};
315317

316318
return (
317-
<div className="grid grid-cols-1 lg:grid-cols-[1fr_2fr] gap-4 h-full">
319+
<div className="grid grid-cols-1 lg:grid-cols-[1fr_2fr] h-full bg-card rounded-lg border">
318320
{/* left */}
319-
<div className="bg-card rounded-lg border overflow-auto">
321+
<div className="overflow-auto border-b lg:border-b-0 lg:border-r">
320322
{(writeFunctions.length > 0 || viewFunctions.length > 0) && (
321323
<div className="flex flex-col h-full relative">
322324
<TabButtons
323325
tabContainerClassName="px-3 pt-2"
324326
tabClassName="!text-sm"
325327
tabs={[
326-
...(writeFunctions.length > 0
328+
...(viewFunctions.length > 0
327329
? [
328330
{
329-
name: "Write",
330-
onClick: () => setActiveTab(0),
331-
isActive: activeTab === 0,
331+
name: "Read",
332+
onClick: () => setActiveTab(1),
333+
isActive: activeTab === 1,
332334
},
333335
]
334336
: []),
335-
...(viewFunctions.length > 0
337+
...(writeFunctions.length > 0
336338
? [
337339
{
338-
name: "Read",
339-
onClick: () => setActiveTab(1),
340-
isActive: activeTab === 1,
340+
name: "Write",
341+
onClick: () => setActiveTab(0),
342+
isActive: activeTab === 0,
341343
},
342344
]
343345
: []),
@@ -367,8 +369,9 @@ export const ContractFunctionsPanel: React.FC<ContractFunctionsPanelProps> = ({
367369
</div>
368370
</div>
369371
)}
372+
370373
{events.length > 0 && selectedFunction && (
371-
<div className="pt-2 px-4">
374+
<div className="p-4 space-y-0.5">
372375
{events.map((fn) => (
373376
<FunctionsOrEventsListItem
374377
fn={fn}
@@ -382,7 +385,7 @@ export const ContractFunctionsPanel: React.FC<ContractFunctionsPanelProps> = ({
382385
</div>
383386

384387
{/* right */}
385-
<div className="bg-card rounded-lg border p-4 overflow-auto">
388+
<div className="overflow-auto p-4">
386389
{selectedFunction && (
387390
<ContractFunction
388391
contract={contract}
@@ -414,7 +417,7 @@ const FunctionsOrEventsListItem: React.FC<FunctionsOrEventsListItemProps> = ({
414417
return (
415418
<Button
416419
className={cn(
417-
"text-muted-foreground hover:text-foreground font-mono w-full justify-start h-auto px-2 py-1",
420+
"text-muted-foreground hover:text-foreground font-mono w-full justify-start h-auto px-2 py-1.5",
418421
isActive && "text-foreground bg-accent",
419422
)}
420423
onClick={() => {

0 commit comments

Comments
 (0)