@adland/react 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
# @adland/react
|
|
2
2
|
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 447cc7b: add profile & token type
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [447cc7b]
|
|
12
|
+
- @adland/data@0.12.0
|
|
13
|
+
|
|
3
14
|
## 0.8.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
|
6
17
|
|
|
7
18
|
- df8ba42: handle errors from api for no ad
|
|
19
|
+
- d6712f4: fix wrong api url ad path
|
|
8
20
|
|
|
9
21
|
## 0.7.2
|
|
10
22
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adland/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@types/react-dom": "^18.3.1",
|
|
34
34
|
"lucide-react": "0.561.0",
|
|
35
35
|
"tsup": "^8.0.1",
|
|
36
|
-
"@adland/data": "0.
|
|
36
|
+
"@adland/data": "0.12.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@typescript-eslint/eslint-plugin": "^7.13.1",
|
package/src/components/Ad.tsx
CHANGED
|
@@ -8,6 +8,8 @@ import BasicAdBody from "./BasicAdBody";
|
|
|
8
8
|
import LinkAdContent from "./content/LinkAdContent";
|
|
9
9
|
import MiniappAdContent from "./content/MiniappAdContent";
|
|
10
10
|
import CastAdContent from "./content/CastAdContent";
|
|
11
|
+
import TokenAdContent from "./content/TokenAdContent";
|
|
12
|
+
import FarcasterProfileAdContent from "./content/FarcasterProfileAdContent";
|
|
11
13
|
import { AdDataQueryError, AdProps } from "../types";
|
|
12
14
|
import { getBaseUrl } from "../utils";
|
|
13
15
|
import { adlandApiUrl } from "../utils/constants";
|
|
@@ -38,18 +40,17 @@ export function Ad({
|
|
|
38
40
|
} = useFetch<AdData>(
|
|
39
41
|
`ad-data-${owner}-${slotId}`,
|
|
40
42
|
async () => {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
43
|
+
const url = `${adlandApiUrl}/ad/owner/${owner.toLowerCase()}/slot/${slotId}`;
|
|
44
|
+
|
|
45
|
+
const res = await fetch(url, {
|
|
46
|
+
method: "GET",
|
|
47
|
+
headers: {
|
|
48
|
+
"Content-Type": "application/json",
|
|
48
49
|
},
|
|
49
|
-
);
|
|
50
|
+
});
|
|
50
51
|
|
|
51
52
|
if (!res.ok) {
|
|
52
|
-
throw new Error(AdDataQueryError.
|
|
53
|
+
throw new Error(AdDataQueryError.ERROR);
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
const data = await res.json();
|
|
@@ -148,6 +149,9 @@ export function Ad({
|
|
|
148
149
|
/>
|
|
149
150
|
);
|
|
150
151
|
}
|
|
152
|
+
if (error.message === AdDataQueryError.ERROR) {
|
|
153
|
+
return <ErrorAdContent error={error} />;
|
|
154
|
+
}
|
|
151
155
|
}
|
|
152
156
|
return <ErrorAdContent error={error} />;
|
|
153
157
|
}
|
|
@@ -159,6 +163,12 @@ export function Ad({
|
|
|
159
163
|
{adData.type === "cast" && <CastAdContent data={adData} />}
|
|
160
164
|
|
|
161
165
|
{adData.type === "miniapp" && <MiniappAdContent data={adData} />}
|
|
166
|
+
|
|
167
|
+
{adData.type === "token" && <TokenAdContent data={adData} />}
|
|
168
|
+
|
|
169
|
+
{adData.type === "farcasterProfile" && (
|
|
170
|
+
<FarcasterProfileAdContent data={adData} />
|
|
171
|
+
)}
|
|
162
172
|
</>
|
|
163
173
|
);
|
|
164
174
|
} else {
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { FarcasterProfileAd } from "@adland/data";
|
|
2
|
+
import sdk from "@farcaster/miniapp-sdk";
|
|
3
|
+
import BasicAdBody from "../BasicAdBody";
|
|
4
|
+
import { adCardIcon } from "../../utils/constants";
|
|
5
|
+
|
|
6
|
+
// Farcaster Profile Ad Component
|
|
7
|
+
const FarcasterProfileAdContent = ({ data }: { data: FarcasterProfileAd }) => {
|
|
8
|
+
const Icon = adCardIcon["farcasterProfile"];
|
|
9
|
+
const { data: profileData, metadata: profileMetadata } = data;
|
|
10
|
+
const fid = profileData.fid;
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<BasicAdBody
|
|
14
|
+
name={"PROFILE"}
|
|
15
|
+
onClick={() => {
|
|
16
|
+
sdk.actions.viewProfile({ fid: parseInt(fid) });
|
|
17
|
+
}}
|
|
18
|
+
>
|
|
19
|
+
<div className="flex flex-row items-center gap-2 flex-1 min-w-0">
|
|
20
|
+
{profileMetadata?.pfpUrl ? (
|
|
21
|
+
<img
|
|
22
|
+
src={profileMetadata.pfpUrl}
|
|
23
|
+
alt={profileMetadata.username || "Profile picture"}
|
|
24
|
+
className="w-10 h-10 md:w-12 md:h-12 rounded-full object-cover flex-shrink-0"
|
|
25
|
+
/>
|
|
26
|
+
) : (
|
|
27
|
+
<Icon className="w-5 h-5 md:w-7 md:h-7 flex-shrink-0" />
|
|
28
|
+
)}
|
|
29
|
+
<div className="flex flex-col gap-1 min-w-0 flex-1">
|
|
30
|
+
{!Boolean(profileMetadata) && (
|
|
31
|
+
<div className="flex flex-row items-center gap-2">
|
|
32
|
+
<Icon className="w-5 h-5 md:w-7 md:h-7 flex-shrink-0" />
|
|
33
|
+
<p className="font-bold text-primary">PROFILE</p>
|
|
34
|
+
</div>
|
|
35
|
+
)}
|
|
36
|
+
<div className="flex flex-row items-center gap-1">
|
|
37
|
+
{profileMetadata?.username ? (
|
|
38
|
+
<p className="text-sm font-bold text-primary truncate">
|
|
39
|
+
{profileMetadata.username}
|
|
40
|
+
</p>
|
|
41
|
+
) : (
|
|
42
|
+
<p className="text-sm font-bold text-primary">FID: {fid}</p>
|
|
43
|
+
)}
|
|
44
|
+
{profileMetadata?.pro && (
|
|
45
|
+
<span className="text-xs bg-primary text-primary-foreground px-1 rounded">
|
|
46
|
+
PRO
|
|
47
|
+
</span>
|
|
48
|
+
)}
|
|
49
|
+
</div>
|
|
50
|
+
{profileMetadata?.bio ? (
|
|
51
|
+
<p className="text-xs text-muted-foreground/80 line-clamp-1">
|
|
52
|
+
{profileMetadata.bio}
|
|
53
|
+
</p>
|
|
54
|
+
) : (
|
|
55
|
+
(profileMetadata?.followers !== undefined ||
|
|
56
|
+
profileMetadata?.following !== undefined) && (
|
|
57
|
+
<p className="text-xs text-muted-foreground/80">
|
|
58
|
+
{profileMetadata.followers !== undefined && (
|
|
59
|
+
<span>
|
|
60
|
+
{profileMetadata.followers.toLocaleString()} followers
|
|
61
|
+
</span>
|
|
62
|
+
)}
|
|
63
|
+
{profileMetadata.followers !== undefined &&
|
|
64
|
+
profileMetadata.following !== undefined &&
|
|
65
|
+
" • "}
|
|
66
|
+
{profileMetadata.following !== undefined && (
|
|
67
|
+
<span>
|
|
68
|
+
{profileMetadata.following.toLocaleString()} following
|
|
69
|
+
</span>
|
|
70
|
+
)}
|
|
71
|
+
</p>
|
|
72
|
+
)
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</BasicAdBody>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default FarcasterProfileAdContent;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { TokenAd } from "@adland/data";
|
|
2
|
+
import sdk from "@farcaster/miniapp-sdk";
|
|
3
|
+
import BasicAdBody from "../BasicAdBody";
|
|
4
|
+
import { adCardIcon } from "../../utils/constants";
|
|
5
|
+
|
|
6
|
+
// Token Ad Component
|
|
7
|
+
const TokenAdContent = ({ data }: { data: TokenAd }) => {
|
|
8
|
+
const Icon = adCardIcon["token"];
|
|
9
|
+
const { data: tokenData, metadata: tokenMetadata } = data;
|
|
10
|
+
|
|
11
|
+
// Build block explorer URL based on chainId
|
|
12
|
+
const getTokenUrl = () => {
|
|
13
|
+
const address = tokenData.address;
|
|
14
|
+
const chainId = tokenData.chainId;
|
|
15
|
+
|
|
16
|
+
// Common block explorers by chainId
|
|
17
|
+
const explorers: Record<number, string> = {
|
|
18
|
+
1: "https://etherscan.io/token/",
|
|
19
|
+
8453: "https://basescan.org/token/",
|
|
20
|
+
42161: "https://arbiscan.io/token/",
|
|
21
|
+
10: "https://optimistic.etherscan.io/token/",
|
|
22
|
+
137: "https://polygonscan.com/token/",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const baseUrl = explorers[chainId];
|
|
26
|
+
if (baseUrl) {
|
|
27
|
+
return `${baseUrl}${address}`;
|
|
28
|
+
}
|
|
29
|
+
// Fallback to Etherscan if chain not recognized
|
|
30
|
+
return `https://etherscan.io/token/${address}`;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<BasicAdBody
|
|
35
|
+
name={"TOKEN"}
|
|
36
|
+
onClick={() => {
|
|
37
|
+
sdk.actions.viewToken({ token: tokenData.address });
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
<div className="flex flex-row items-center gap-2 flex-1 min-w-0">
|
|
41
|
+
{tokenMetadata?.logoURI ? (
|
|
42
|
+
<img
|
|
43
|
+
src={tokenMetadata.logoURI}
|
|
44
|
+
alt={tokenMetadata.name || "Token logo"}
|
|
45
|
+
className="w-10 h-10 md:w-12 md:h-12 rounded object-cover flex-shrink-0"
|
|
46
|
+
/>
|
|
47
|
+
) : (
|
|
48
|
+
<Icon className="w-5 h-5 md:w-7 md:h-7 flex-shrink-0" />
|
|
49
|
+
)}
|
|
50
|
+
<div className="flex flex-col gap-1 min-w-0 flex-1">
|
|
51
|
+
{!Boolean(tokenMetadata) && (
|
|
52
|
+
<div className="flex flex-row items-center gap-2">
|
|
53
|
+
<Icon className="w-5 h-5 md:w-7 md:h-7 flex-shrink-0" />
|
|
54
|
+
<p className="font-bold text-primary">TOKEN</p>
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
{tokenMetadata?.symbol ? (
|
|
58
|
+
<p className="text-sm font-bold text-primary truncate">
|
|
59
|
+
{tokenMetadata.symbol.toUpperCase()}
|
|
60
|
+
</p>
|
|
61
|
+
) : (
|
|
62
|
+
<p className="text-sm font-bold text-primary">TOKEN</p>
|
|
63
|
+
)}
|
|
64
|
+
{tokenMetadata?.name ? (
|
|
65
|
+
<p className="text-xs text-muted-foreground/80 line-clamp-1">
|
|
66
|
+
{tokenMetadata.name}
|
|
67
|
+
</p>
|
|
68
|
+
) : (
|
|
69
|
+
<p className="text-xs text-muted-foreground/80 line-clamp-1">
|
|
70
|
+
{tokenData.address.slice(0, 6)}...{tokenData.address.slice(-4)}
|
|
71
|
+
</p>
|
|
72
|
+
)}
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</BasicAdBody>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export default TokenAdContent;
|
package/src/types.ts
CHANGED
package/src/utils/constants.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { AdType } from "@adland/data";
|
|
2
2
|
import { ForwardRefExoticComponent, RefAttributes } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Link,
|
|
5
|
+
MessageCircle,
|
|
6
|
+
LayoutGrid,
|
|
7
|
+
LucideProps,
|
|
8
|
+
Coins,
|
|
9
|
+
User,
|
|
10
|
+
} from "lucide-react";
|
|
4
11
|
|
|
5
12
|
export const adCardIcon: Record<
|
|
6
13
|
AdType,
|
|
@@ -11,6 +18,8 @@ export const adCardIcon: Record<
|
|
|
11
18
|
link: Link,
|
|
12
19
|
cast: MessageCircle,
|
|
13
20
|
miniapp: LayoutGrid,
|
|
21
|
+
token: Coins,
|
|
22
|
+
farcasterProfile: User,
|
|
14
23
|
};
|
|
15
24
|
|
|
16
25
|
export const adlandApiUrl =
|