Skip to content

Staging to main #424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 54 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
96b10ee
Don't revalidate list registrations for non-existent accounts
akaia-shadowfox Jun 20, 2025
5c14397
Merge branch 'main' of github.com:PotLock/potlock-nextjs-app into sta…
akaia-shadowfox Jun 20, 2025
ccae40a
Enable basic profile configuration functionality (#418)
akaia-shadowfox Jun 25, 2025
a5c5671
Allow donations to unregistered accounts (#419)
akaia-shadowfox Jun 26, 2025
1730155
chore: Remove console.log
akaia-shadowfox Jun 26, 2025
af8bdef
fee-avoidance
Ebube111 Jun 28, 2025
2bb724d
Merge pull request #422 from PotLock/fee-avoidance
Ebube111 Jun 28, 2025
3e4fe23
v2.1.1: Add version tracking
akaia-shadowfox Jun 30, 2025
501ffb1
fix: Prevent heading lines from merging
akaia-shadowfox Jun 30, 2025
0906854
FIx initial profile image retrieval
akaia-shadowfox Jun 30, 2025
79629f7
rich text for campaign description done
Ebube111 Jul 1, 2025
54a2b0f
Merge pull request #423 from PotLock/rich-text
Ebube111 Jul 1, 2025
06517a7
Merge branch 'staging' of github.com:PotLock/potlock-nextjs-app into …
akaia-shadowfox Jul 1, 2025
0df6a74
Refactor registration / profile update flows (#327)
Jikugodwill Jul 2, 2025
f462c0f
Merge branch 'main' of github.com:PotLock/potlock-nextjs-app into sta…
akaia-shadowfox Jul 2, 2025
73d87a4
Update description length error message
akaia-shadowfox Jul 2, 2025
5aa6c42
Address Webpack warning
akaia-shadowfox Jul 7, 2025
21e8552
done with the profile changes
Ebube111 Jul 15, 2025
e65fa06
worked on review
Ebube111 Jul 16, 2025
68b5c29
Merge pull request #427 from PotLock/profile-update
Ebube111 Jul 16, 2025
e8550a8
done with logic
Ebube111 Jul 16, 2025
88bd068
done with changes and bug fixes
Ebube111 Jul 16, 2025
8f9c4d8
fixed conditional
Ebube111 Jul 16, 2025
6c73e6f
Merge pull request #428 from PotLock/campaign-profile
Ebube111 Jul 16, 2025
e7a4566
register list fix bug
Ebube111 Jul 28, 2025
2bcb17e
done with handling campaigns for self
Ebube111 Jul 28, 2025
f396adf
added unity wallet
Ebube111 Jul 28, 2025
56269b6
Merge pull request #429 from PotLock/register-list-fix
Ebube111 Jul 28, 2025
88b62d6
Merge pull request #430 from PotLock/campaign-for-self
Ebube111 Jul 28, 2025
3e5fac4
hide unity wallet
Ebube111 Jul 28, 2025
67b73e2
Merge pull request #431 from PotLock/hide-unity
Ebube111 Jul 28, 2025
2445881
done with referral-optional
Ebube111 Jul 31, 2025
9bad414
Merge pull request #432 from PotLock/referral-optional
Ebube111 Jul 31, 2025
4054f8b
done with campaign indexer changes
Ebube111 Aug 1, 2025
35ee723
switched loader to spinner
Ebube111 Aug 1, 2025
45e0701
Merge pull request #433 from PotLock/campaign-indexer
Ebube111 Aug 1, 2025
f13bd2b
fixed feature campaign toggle
Ebube111 Aug 4, 2025
f0762f9
Merge pull request #434 from PotLock/feat-fix
Ebube111 Aug 4, 2025
0921d8d
integrated intear.near
Ebube111 Aug 5, 2025
01df50e
Merge pull request #435 from PotLock/intear
Ebube111 Aug 5, 2025
99cdcd6
donations config
Ebube111 Aug 5, 2025
71cf440
Merge pull request #437 from PotLock/campaign-filter
Ebube111 Aug 5, 2025
4d6cd8d
enabled more filters and added unity wallet
Ebube111 Aug 7, 2025
77eabf4
Merge pull request #438 from PotLock/unity-wallet
Ebube111 Aug 7, 2025
d255011
done with fixes
Ebube111 Aug 8, 2025
bf9cab6
Merge pull request #439 from PotLock/fixed-end-date
Ebube111 Aug 8, 2025
97dd6b2
done with changes
Ebube111 Aug 11, 2025
1630d85
done with changes
Ebube111 Aug 11, 2025
628f8dd
Resolve merge conflict in CampaignProgressBar: keep token-aware amoun…
Ebube111 Aug 12, 2025
a370fcc
done wtih merge conflicts
Ebube111 Aug 12, 2025
00d22e1
Merge pull request #440 from PotLock/potlock-bugs
Ebube111 Aug 12, 2025
aad3207
done with fixing active status
Ebube111 Aug 14, 2025
c477ab0
fixed is active status in campaign breaking change
Ebube111 Aug 14, 2025
bdc010f
Merge pull request #446 from PotLock/active-fix
Ebube111 Aug 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@
"linktree",
"localnet",
"METAPOOL",
"Metaverse",
"Mochi",
"mpdao",
"mpdaovoting",
"Multicall",
Expand Down
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@potlock/next",
"name": "@potlock/frontend",
"description": "Decentralized funding stack for public goods",
"version": "2.1.0",
"version": "2.1.1",
"packageManager": "yarn@1.22.22",
"private": true,
"type": "module",
Expand Down Expand Up @@ -75,6 +75,10 @@
"@rematch/persist": "^2.1.2",
"@tanstack/react-table": "^8.20.5",
"@tanstack/react-virtual": "^3.11.0",
"@tiptap/core": "^2.23.0",
"@tiptap/extension-link": "^2.23.0",
"@tiptap/react": "^2.23.0",
"@tiptap/starter-kit": "^2.23.0",
Comment on lines +80 to +83
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

TipTap in Next.js: ensure client-only usage or dynamic import to avoid SSR crashes

TipTap relies on DOM APIs. If used during SSR, it can throw (window/document undefined). Verify rich text components import TipTap only on the client (e.g., "use client" + dynamic(() => import(...), { ssr: false })).

Run this quick audit:

Expected:

  • Files using @tiptap/react are client components ("use client") and/or loaded via next/dynamic with ssr: false.

🏁 Script executed:

#!/bin/bash
# Find TipTap imports
rg -n --pretty "@tiptap/(react|core|starter-kit|extension-link)"

# For files that import @tiptap/react, check client directive
for f in $(rg -l '@tiptap/react'); do
  echo "---- $f"
  sed -n '1,5p' "$f" | cat
done

# Look for dynamic import usage (Next.js)
rg -n --pretty 'from "next/dynamic"|from \'next/dynamic\'|dynamic\('

Length of output: 2173


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Searching for TipTap imports..."
rg -n --pretty "@tiptap/(react|core|starter-kit|extension-link)" || true

echo
echo "Printing src/common/ui/form/components/richtext.tsx (first 200 lines)..."
sed -n '1,200p' src/common/ui/form/components/richtext.tsx || true

echo
echo "Searching for 'use client' directives in repo..."
rg -n --hidden --no-ignore '^[[:space:]]*"use client"' || true

echo
echo "Searching for next/dynamic usage in repo..."
rg -n --pretty 'next/dynamic|dynamic\(' || true

Length of output: 15849


TipTap requires client-only rendering — mark the component as client or load it with ssr:false

Found @tiptap usage that runs DOM APIs in src/common/ui/form/components/richtext.tsx but the file has no "use client" directive and isn't dynamically imported — this will break SSR.

  • Files to fix:
    • src/common/ui/form/components/richtext.tsx — imports @tiptap/react and uses document/window (document.createElement, window.prompt).

Quick fixes (choose one):

  • Add "use client" as the first line of src/common/ui/form/components/richtext.tsx:
+ "use client";
import { useCallback, useEffect, useMemo, useRef } from "react";
import Link from "@tiptap/extension-link";
import { EditorContent, useEditor } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
  • Or import the component from its consumer with Next.js dynamic import:
const RichTextEditor = dynamic(() => import('@/common/ui/form/components/richtext'), { ssr: false })
🤖 Prompt for AI Agents
In package.json / src/common/ui/form/components/richtext.tsx around lines 80 to
83, the TipTap-based component uses DOM APIs (document/window) but is not marked
for client rendering; add "use client" as the very first line of
src/common/ui/form/components/richtext.tsx to opt the module into client-side
rendering, or alternatively stop exporting it as a normal module and have
consumers dynamically import it with ssr:false (e.g., use Next.js dynamic
import) so it never runs during SSR; ensure any document/window calls remain
unguarded only in the client module or are wrapped behind runtime checks if you
choose dynamic import.

"@uidotdev/usehooks": "^2.4.1",
"@unocss/reset": "^0.60.4",
"@web3modal/wagmi": "^5.1.10",
Expand Down Expand Up @@ -161,4 +165,4 @@
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^1.6.0"
}
}
}
8 changes: 7 additions & 1 deletion src/common/_config/production.env-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const envConfig: EnvConfig = {
[FeatureId.ProfileConfiguration]: {
id: FeatureId.ProfileConfiguration,
name: "Profile configuration",
isEnabled: false,
isEnabled: true,
},

[FeatureId.FtDonation]: {
Expand All @@ -85,5 +85,11 @@ export const envConfig: EnvConfig = {
name: "Direct native token donation",
isEnabled: true,
},

[FeatureId.Cart]: {
id: FeatureId.Cart,
name: "Cart",
isEnabled: false,
},
},
};
8 changes: 7 additions & 1 deletion src/common/_config/staging.env-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const envConfig: EnvConfig = {
[FeatureId.ProfileConfiguration]: {
id: FeatureId.ProfileConfiguration,
name: "Profile configuration",
isEnabled: false,
isEnabled: true,
},

[FeatureId.FtDonation]: {
Expand All @@ -85,6 +85,12 @@ export const envConfig: EnvConfig = {
name: "Direct native token donation",
isEnabled: true,
},

[FeatureId.Cart]: {
id: FeatureId.Cart,
name: "Cart",
isEnabled: false,
},
},
};

Expand Down
6 changes: 6 additions & 0 deletions src/common/_config/test.env-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,11 @@ export const envConfig: EnvConfig = {
name: "Direct native token donation",
isEnabled: true,
},

[FeatureId.Cart]: {
id: FeatureId.Cart,
name: "Cart",
isEnabled: false,
},
},
};
14 changes: 9 additions & 5 deletions src/common/api/coingecko/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import useSWR from "swr";

import { CONTRACT_SWR_CONFIG, NATIVE_TOKEN_ID } from "@/common/constants";
import type { WithDisabled } from "@/common/types";
import { NATIVE_TOKEN_ID } from "@/common/constants";
import type { ConditionalActivation } from "@/common/types";

import { client } from "./client";

export const useNativeTokenUsdPrice = (
{ disabled }: WithDisabled | undefined = { disabled: false },
{ enabled = true }: ConditionalActivation | undefined = { enabled: true },
) =>
useSWR(
() => (disabled ? null : ["oneNativeTokenUsdPrice", NATIVE_TOKEN_ID.toLowerCase()]),
() => (!enabled ? null : ["oneNativeTokenUsdPrice", NATIVE_TOKEN_ID.toLowerCase()]),

([_queryKeyHead, tokenId]) =>
client
Expand All @@ -18,5 +18,9 @@ export const useNativeTokenUsdPrice = (
response.data[tokenId].usd.toString(),
),

CONTRACT_SWR_CONFIG,
{
revalidateIfStale: false,
revalidateOnFocus: false,
revalidateOnReconnect: false,
},
);
6 changes: 5 additions & 1 deletion src/common/api/indexer/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@ export const useAccountListRegistrations = ({
ConditionalActivation) => {
const queryResult = generatedClient.useV1AccountsListRegistrationsRetrieve(accountId, params, {
...INDEXER_CLIENT_CONFIG,
swr: { enabled },

swr: {
enabled,
shouldRetryOnError: (err) => err.status !== 404,
},
});

return { ...queryResult, data: queryResult.data?.data };
Expand Down
21 changes: 16 additions & 5 deletions src/common/api/intear-token-indexer/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
import { ByTokenId, type WithDisabled } from "@/common/types";
import { ByTokenId, type ConditionalActivation, type LiveUpdateParams } from "@/common/types";

import * as generatedClient from "./internal/client.generated";
import { REQUEST_CONFIG } from "./internal/config";

/**
* https://prices.intear.tech/swagger-ui/#/Token%20Prices/get_get_token_price
*/
export const useTokenUsdPrice = ({ tokenId, disabled = false }: ByTokenId & WithDisabled) => {
export const useTokenUsdPrice = ({
enabled = true,
live = false,
tokenId,
}: ByTokenId & ConditionalActivation & LiveUpdateParams) => {
const queryResult = generatedClient.useGetSuperPrecisePrice(
{ token_id: tokenId },

{
...REQUEST_CONFIG,

swr: {
enabled: !disabled,
enabled,
shouldRetryOnError: (err) => err.status !== 404,
revalidateOnFocus: false,
revalidateIfStale: false,

...(live
? {}
: {
revalidateIfStale: false,
revalidateOnFocus: false,
revalidateOnMount: false,
revalidateOnReconnect: false,
}),
},
},
);
Expand Down
19 changes: 4 additions & 15 deletions src/common/api/near-social-indexer/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,19 @@ import useSWR from "swr";

import { AccountId, ByAccountId, type ConditionalActivation } from "@/common/types";

import { CLIENT_CONFIG, nearSocialIndexerClient } from "./client";
import { CLIENT_CONFIG, nearSocialClient, nearSocialIndexerClient } from "./client";

export const useFollowerAccountIds = ({
enabled = true,
accountId,
}: ByAccountId & ConditionalActivation) =>
useSWR(
["useFollowerAccountIds", "/keys"],
[`*/graph/follow/${accountId}`],

([_queryKeyHead, urlKey]) =>
(keys) =>
!enabled
? undefined
: nearSocialIndexerClient
.post(urlKey, {
keys: [`*/graph/follow/${accountId}`],
options: { values_only: true },
})
.then(
(
response: AxiosResponse<
Record<AccountId, { graph: { follow: { [key: AccountId]: boolean } } }>
>,
) => Object.keys(response.data),
),
: nearSocialClient.keys({ keys, valuesOnly: true }).then((result) => Object.keys(result)),

CLIENT_CONFIG.swr,
);
Expand Down
40 changes: 26 additions & 14 deletions src/common/blockchains/near-protocol/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import type { AccountView } from "near-api-js/lib/providers/provider";
import useSWR from "swr";
import useSWR, { type SWRResponse } from "swr";

import {
CONTRACT_SWR_CONFIG,
IS_CLIENT,
NATIVE_TOKEN_DECIMALS,
NATIVE_TOKEN_ICON_URL,
NATIVE_TOKEN_ID,
} from "@/common/constants";
import type { ByAccountId, WithDisabled } from "@/common/types";
import type { ByAccountId, ConditionalActivation, LiveUpdateParams } from "@/common/types";

import { nearRpc } from "./client";

Expand All @@ -18,9 +19,9 @@ export type NativeTokenMetadata = {
decimals: number;
};

export const useNativeTokenMetadata = ({ disabled = false }: WithDisabled) =>
export const useNativeTokenMetadata = ({ enabled = true }: ConditionalActivation) =>
useSWR(
() => (disabled ? null : ["NativeTokenMetadata", NATIVE_TOKEN_ID]),
() => (!enabled ? null : ["NativeTokenMetadata", NATIVE_TOKEN_ID]),

(_queryKeyHead) =>
new Promise<NativeTokenMetadata>((resolve) =>
Expand All @@ -35,18 +36,29 @@ export const useNativeTokenMetadata = ({ disabled = false }: WithDisabled) =>
CONTRACT_SWR_CONFIG,
);

export const useViewAccount = ({ disabled = false, ...params }: ByAccountId & WithDisabled) =>
export const useViewAccount = ({
enabled = true,
live = false,
...params
}: ByAccountId & ConditionalActivation & LiveUpdateParams): SWRResponse<AccountView, Error> =>
useSWR(
() => (disabled ? null : ["view_account", params.accountId]),
() => (!enabled || !IS_CLIENT ? null : ["view_account", params.accountId]),

([_queryKeyHead, accountId]) =>
nearRpc
.query<AccountView>({
request_type: "view_account",
account_id: accountId,
finality: "final",
})
.catch(() => undefined),
nearRpc.query<AccountView>({
request_type: "view_account",
account_id: accountId,
finality: "final",
}),

CONTRACT_SWR_CONFIG,
{
...(live
? {}
: {
revalidateIfStale: false,
revalidateOnFocus: false,
revalidateOnMount: false,
revalidateOnReconnect: false,
}),
},
);
17 changes: 15 additions & 2 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import type { SWRConfiguration } from "swr";

import { NETWORK, PLATFORM_NAME } from "./_config";
import { ChronologicalSortOrderVariant, type TokenId } from "./types";
import { version as FRAMEWORK_VERSION } from "../../package.json";

export { PLATFORM_NAME };
export { PLATFORM_NAME, FRAMEWORK_VERSION };

export const IS_CLIENT = typeof window !== "undefined";

Expand All @@ -28,6 +29,7 @@ export const APP_BOS_COUNTERPART_URL = "https://bos.potlock.org";
export const APP_METADATA: Metadata & {
title: string;
description: NonNullable<Metadata["description"]>;
other: { version: string };
manifest: NonNullable<Metadata["manifest"]>;

openGraph: {
Expand All @@ -43,6 +45,7 @@ export const APP_METADATA: Metadata & {
} = {
title: PLATFORM_NAME,
description: "Bringing public goods funding to the table, built on NEAR",
other: { version: FRAMEWORK_VERSION },
manifest: "/manifest.json",

icons: {
Expand Down Expand Up @@ -169,7 +172,7 @@ export const CONTRACT_SWR_CONFIG: SWRConfiguration = {
};

/**
* @deprecated Use `useTokenAllowlist` hooks instead
* @deprecated Use `useFungibleTokenAllowlist` hooks instead
*/
export const SUPPORTED_FTS: Record<
string,
Expand Down Expand Up @@ -197,3 +200,13 @@ export const SUPPORTED_FTS: Record<
.toFixed(decimals || 2),
},
};

console.info(`
___ ___ _____ _ ___ ___ _ __
| _ \\/ _ \\_ _| | / _ \\ / __| |/ /
| _/ (_) || | | |_| (_) | (__| ' <
|_| \\___/ |_| |____\\___/ \\___|_|\\_\\

version: ${FRAMEWORK_VERSION}

`);
33 changes: 24 additions & 9 deletions src/common/contracts/social-db/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
import useSWR from "swr";

import { IS_CLIENT } from "@/common/constants";
import type { ByAccountId, ConditionalActivation } from "@/common/types";
import type { ByAccountId, ConditionalActivation, LiveUpdateParams } from "@/common/types";

import * as contractClient from "./client";

export const useSocialProfile = ({
enabled = true,
live = false,
accountId,
}: ByAccountId & ConditionalActivation) =>
useSWR(["useSocialProfile", accountId], ([_queryKeyHead, account_id]) =>
!enabled || !IS_CLIENT
? undefined
: contractClient
.getSocialProfile({ accountId: account_id })
//* Handling `null` response
.then((response) => response ?? undefined),
}: ByAccountId & ConditionalActivation & LiveUpdateParams) =>
useSWR(
["useSocialProfile", accountId],

([_queryKeyHead, account_id]) =>
!enabled || !IS_CLIENT
? undefined
: contractClient
.getSocialProfile({ accountId: account_id })
//* Handling `null` response
.then((response) => response ?? undefined),

{
...(live
? {}
: {
revalidateIfStale: false,
revalidateOnFocus: false,
revalidateOnMount: false,
revalidateOnReconnect: false,
}),
},
);
6 changes: 3 additions & 3 deletions src/common/contracts/tokens/fungible/client.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { naxiosInstance } from "@/common/blockchains/near-protocol/client";
import { nearProtocolClient } from "@/common/blockchains/near-protocol";
import type { AccountId, ByAccountId, ByTokenId } from "@/common/types";

import type { FungibleTokenMetadata } from "./interfaces";

export const ft_metadata = ({ tokenId }: ByTokenId) =>
naxiosInstance
nearProtocolClient.naxiosInstance
.contractApi({ contractId: tokenId })
.view<{}, FungibleTokenMetadata>("ft_metadata")
.catch(() => undefined);

export const ft_balance_of = ({ accountId, tokenId }: ByAccountId & ByTokenId) =>
naxiosInstance
nearProtocolClient.naxiosInstance
.contractApi({ contractId: tokenId })
.view<{ account_id: AccountId }, string>("ft_balance_of", {
args: { account_id: accountId },
Expand Down
Loading
Loading