@adland/react 0.8.0 → 0.10.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,28 @@
1
1
  # @adland/react
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 466472d: add labels
8
+
9
+ ## 0.9.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 447cc7b: add profile & token type
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [447cc7b]
18
+ - @adland/data@0.12.0
19
+
3
20
  ## 0.8.0
4
21
 
5
22
  ### Minor Changes
6
23
 
7
24
  - df8ba42: handle errors from api for no ad
25
+ - d6712f4: fix wrong api url ad path
8
26
 
9
27
  ## 0.7.2
10
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adland/react",
3
- "version": "0.8.0",
3
+ "version": "0.10.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.11.0"
36
+ "@adland/data": "0.12.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@typescript-eslint/eslint-plugin": "^7.13.1",
@@ -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 res = await fetch(
42
- `${adlandApiUrl}/api/data/owner/${owner.toLowerCase()}/slot/${slotId}`,
43
- {
44
- method: "GET",
45
- headers: {
46
- "Content-Type": "application/json",
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.NO_AD);
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/index.ts CHANGED
@@ -10,4 +10,4 @@ export {
10
10
  } from "./utils/sdk";
11
11
 
12
12
  // Constants exports
13
- export { adCardIcon } from "./utils/constants";
13
+ export * from "./utils/constants";
package/src/types.ts CHANGED
@@ -23,6 +23,7 @@ export interface AdProps extends React.HTMLAttributes<HTMLDivElement> {
23
23
 
24
24
  export enum AdDataQueryError {
25
25
  NO_AD = "NO_AD",
26
+ ERROR = "ERROR",
26
27
  }
27
28
 
28
29
  export interface AdDataQueryResponse {
@@ -1,6 +1,13 @@
1
1
  import { AdType } from "@adland/data";
2
2
  import { ForwardRefExoticComponent, RefAttributes } from "react";
3
- import { Link, MessageCircle, LayoutGrid, LucideProps } from "lucide-react";
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,16 @@ export const adCardIcon: Record<
11
18
  link: Link,
12
19
  cast: MessageCircle,
13
20
  miniapp: LayoutGrid,
21
+ token: Coins,
22
+ farcasterProfile: User,
23
+ };
24
+
25
+ export const adCardLabel: Record<AdType, string> = {
26
+ link: "Link",
27
+ cast: "Cast",
28
+ miniapp: "Miniapp",
29
+ token: "Token",
30
+ farcasterProfile: "Profile",
14
31
  };
15
32
 
16
33
  export const adlandApiUrl =