From 96b10eefbdeda91e0a8e87cc8c95e8e6b8c948f5 Mon Sep 17 00:00:00 2001 From: Carina Akaia Date: Fri, 20 Jun 2025 06:19:51 +0000 Subject: [PATCH 01/21] Don't revalidate list registrations for non-existent accounts --- src/common/api/indexer/hooks.ts | 6 +++++- src/pages/register.tsx | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/common/api/indexer/hooks.ts b/src/common/api/indexer/hooks.ts index 0f6a4eb8..fc5ebe80 100644 --- a/src/common/api/indexer/hooks.ts +++ b/src/common/api/indexer/hooks.ts @@ -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 }; diff --git a/src/pages/register.tsx b/src/pages/register.tsx index 6b2f633f..7da7f46b 100644 --- a/src/pages/register.tsx +++ b/src/pages/register.tsx @@ -20,6 +20,7 @@ export default function RegisterPage() { const { isLoading: isAccountListRegistrationDataLoading, data: listRegistrations, + error: listRegistrationsError, mutate: refetchListRegistrations, } = indexer.useAccountListRegistrations({ enabled: viewer.isSignedIn, @@ -86,7 +87,9 @@ export default function RegisterPage() { {viewer.hasWalletReady && viewer.isSignedIn ? ( <> - {listRegistrations === undefined ? ( + {listRegistrations === undefined && + listRegistrationsError === undefined && + isAccountListRegistrationDataLoading ? ( {"Checking Account"} From ccae40a9ec5d129d562b566c9d70bf19fbe35df4 Mon Sep 17 00:00:00 2001 From: Carina Date: Wed, 25 Jun 2025 16:32:18 +0400 Subject: [PATCH 02/21] Enable basic profile configuration functionality (#418) --- .vscode/settings.json | 2 + src/common/_config/production.env-config.ts | 2 +- src/common/_config/staging.env-config.ts | 2 +- src/common/api/near-social-indexer/hooks.ts | 19 +- src/common/blockchains/near-protocol/hooks.ts | 25 +- src/common/constants.ts | 2 +- .../contracts/tokens/fungible/client.ts | 6 +- src/common/contracts/tokens/fungible/hooks.ts | 30 +- src/common/contracts/tokens/index.ts | 1 + .../contracts/tokens/non-fungible/client.ts | 30 ++ .../contracts/tokens/non-fungible/hooks.ts | 24 ++ .../contracts/tokens/non-fungible/index.ts | 7 + .../tokens/non-fungible/interfaces.ts | 119 ++++++ src/common/lib/object.ts | 8 + src/common/lib/string.ts | 27 +- src/common/services/images.ts | 121 ------ src/common/services/pinata/hooks.ts | 8 +- src/common/types.ts | 8 + src/common/ui/form/components/text.tsx | 12 +- .../components/molecules/multi-select.tsx | 16 +- src/common/ui/layout/svg/CameraIcon.tsx | 12 - src/common/ui/layout/svg/camera.tsx | 29 -- .../account/components/AccountFollowStats.tsx | 24 +- .../account/components/profile-images.tsx | 31 +- src/entities/_shared/account/constants.ts | 19 +- .../_shared/account/hooks/social-image.ts | 53 +++ .../_shared/account/hooks/social-profile.ts | 37 +- src/entities/_shared/account/index.ts | 2 + src/entities/_shared/account/types.ts | 2 +- .../_shared/account/utils/linktree.ts | 13 + src/entities/_shared/index.ts | 2 - .../_shared/token/components/balance.tsx | 5 +- .../_shared/token/components/icons.tsx | 4 +- .../_shared/token/components/selector.tsx | 6 +- .../token/components/value-summary.tsx | 4 +- .../_shared/token/hooks/_deprecated.ts | 4 +- .../token/hooks/{data.ts => fungible.ts} | 19 +- src/entities/_shared/token/index.ts | 2 +- .../campaign/components/CampaignBanner.tsx | 44 ++- .../components/CampaignDonorsTable.tsx | 4 +- .../components/CampaignProgressBar.tsx | 4 +- .../campaign/components/CampaignSettings.tsx | 4 +- src/entities/campaign/components/editor.tsx | 4 +- src/entities/campaign/hooks/forms.ts | 4 +- src/entities/list/components/AccountCard.tsx | 4 +- src/entities/list/components/ListAccounts.tsx | 2 +- src/entities/list/components/ListCard.tsx | 6 +- src/entities/list/components/ListDetails.tsx | 4 +- src/entities/list/hooks/registrations.ts | 5 +- src/entities/post/components/PostEditor.tsx | 6 +- src/entities/pot/components/PotCard.tsx | 6 +- .../pot/components/PotDonationEntry.tsx | 4 +- .../pot/components/PotDonationStats.tsx | 6 +- .../voting-round/components/WinnerRow.tsx | 4 +- src/entities/voting-round/hooks/results.ts | 4 +- .../voting-round/hooks/voter-profile.ts | 4 +- src/entities/voting-round/model/types.ts | 2 +- .../components/campaign-success-share.tsx | 3 +- .../group-allocation-recipients.tsx | 5 +- .../components/group-allocation-success.tsx | 4 +- .../donation/components/group-allocation.tsx | 9 +- .../single-recipient-allocation.tsx | 4 +- .../single-recipient-success-share.tsx | 2 +- .../components/single-recipient-success.tsx | 4 +- .../donation/components/user-entrypoints.tsx | 15 +- src/features/donation/hooks/form.ts | 4 +- .../models/effects/campaign-ft-donation.ts | 20 +- .../models/effects/direct-ft-donation.ts | 16 +- .../pot-application/hooks/clearance.ts | 4 +- .../components/AddFundingSourceModal.tsx | 27 +- .../components/contract-modal.tsx | 17 +- .../components/contracts-section.tsx | 32 +- .../components/dao-progress.tsx | 2 +- .../components/editor-elements.tsx} | 84 +---- .../components/editor.tsx} | 142 +++---- .../components/funding-sources.tsx | 13 +- .../components/image-upload.tsx | 140 +++++++ .../components/linktree-section.tsx | 92 +++++ .../components/repositories-section.tsx | 29 +- .../components/styles.ts | 0 .../hooks/forms.ts | 70 ++-- src/features/profile-configuration/index.ts | 1 + .../models/deprecated.ts | 101 +++++ .../models/effects.ts | 64 ++-- .../models/schemas.ts | 24 +- .../profile-configuration/models/types.ts | 7 + src/features/profile-configuration/types.ts | 1 + .../utils/normalization.ts | 41 +++ .../utils/validateEVMAddress.ts | 0 .../profile-setup/components/image-upload.tsx | 158 -------- .../components/linktree-section.tsx | 105 ------ src/features/profile-setup/index.ts | 1 - .../profile-setup/models/deprecated.ts | 345 ------------------ src/features/profile-setup/models/types.ts | 7 - src/features/profile-setup/types.ts | 1 - .../profile-setup/utils/normalization.ts | 29 -- .../components/payout-manager.tsx | 4 +- .../profile/_deprecated/DonationItem.tsx | 6 +- src/layout/profile/components/summary.tsx | 55 +-- src/layout/profile/components/team.tsx | 97 ++--- src/pages/pot/[potId]/applications.tsx | 2 +- src/pages/pot/[potId]/payouts.tsx | 4 +- src/pages/profile/[accountId]/edit.tsx | 4 +- src/pages/profile/[accountId]/home.tsx | 2 +- src/pages/register.tsx | 4 +- 105 files changed, 1265 insertions(+), 1394 deletions(-) create mode 100644 src/common/contracts/tokens/non-fungible/client.ts create mode 100644 src/common/contracts/tokens/non-fungible/hooks.ts create mode 100644 src/common/contracts/tokens/non-fungible/index.ts create mode 100644 src/common/contracts/tokens/non-fungible/interfaces.ts delete mode 100644 src/common/services/images.ts delete mode 100644 src/common/ui/layout/svg/CameraIcon.tsx delete mode 100644 src/common/ui/layout/svg/camera.tsx create mode 100644 src/entities/_shared/account/hooks/social-image.ts create mode 100644 src/entities/_shared/account/utils/linktree.ts delete mode 100644 src/entities/_shared/index.ts rename src/entities/_shared/token/hooks/{data.ts => fungible.ts} (89%) rename src/features/{profile-setup => profile-configuration}/components/AddFundingSourceModal.tsx (89%) rename src/features/{profile-setup => profile-configuration}/components/contract-modal.tsx (88%) rename src/features/{profile-setup => profile-configuration}/components/contracts-section.tsx (86%) rename src/features/{profile-setup => profile-configuration}/components/dao-progress.tsx (95%) rename src/features/{profile-setup/components/form-elements.tsx => profile-configuration/components/editor-elements.tsx} (67%) rename src/features/{profile-setup/components/form.tsx => profile-configuration/components/editor.tsx} (67%) rename src/features/{profile-setup => profile-configuration}/components/funding-sources.tsx (91%) create mode 100644 src/features/profile-configuration/components/image-upload.tsx create mode 100644 src/features/profile-configuration/components/linktree-section.tsx rename src/features/{profile-setup => profile-configuration}/components/repositories-section.tsx (69%) rename src/features/{profile-setup => profile-configuration}/components/styles.ts (100%) rename src/features/{profile-setup => profile-configuration}/hooks/forms.ts (72%) create mode 100644 src/features/profile-configuration/index.ts create mode 100644 src/features/profile-configuration/models/deprecated.ts rename src/features/{profile-setup => profile-configuration}/models/effects.ts (78%) rename src/features/{profile-setup => profile-configuration}/models/schemas.ts (80%) create mode 100644 src/features/profile-configuration/models/types.ts create mode 100644 src/features/profile-configuration/types.ts create mode 100644 src/features/profile-configuration/utils/normalization.ts rename src/features/{profile-setup => profile-configuration}/utils/validateEVMAddress.ts (100%) delete mode 100644 src/features/profile-setup/components/image-upload.tsx delete mode 100644 src/features/profile-setup/components/linktree-section.tsx delete mode 100644 src/features/profile-setup/index.ts delete mode 100644 src/features/profile-setup/models/deprecated.ts delete mode 100644 src/features/profile-setup/models/types.ts delete mode 100644 src/features/profile-setup/types.ts delete mode 100644 src/features/profile-setup/utils/normalization.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index bdd87c43..eac2aee6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -81,6 +81,8 @@ "linktree", "localnet", "METAPOOL", + "Metaverse", + "Mochi", "mpdao", "mpdaovoting", "Multicall", diff --git a/src/common/_config/production.env-config.ts b/src/common/_config/production.env-config.ts index a2e52fc2..07b7f2eb 100644 --- a/src/common/_config/production.env-config.ts +++ b/src/common/_config/production.env-config.ts @@ -65,7 +65,7 @@ export const envConfig: EnvConfig = { [FeatureId.ProfileConfiguration]: { id: FeatureId.ProfileConfiguration, name: "Profile configuration", - isEnabled: false, + isEnabled: true, }, [FeatureId.FtDonation]: { diff --git a/src/common/_config/staging.env-config.ts b/src/common/_config/staging.env-config.ts index 9a9d8e03..9d5876a3 100644 --- a/src/common/_config/staging.env-config.ts +++ b/src/common/_config/staging.env-config.ts @@ -65,7 +65,7 @@ export const envConfig: EnvConfig = { [FeatureId.ProfileConfiguration]: { id: FeatureId.ProfileConfiguration, name: "Profile configuration", - isEnabled: false, + isEnabled: true, }, [FeatureId.FtDonation]: { diff --git a/src/common/api/near-social-indexer/hooks.ts b/src/common/api/near-social-indexer/hooks.ts index fb67df0a..b6159dd9 100644 --- a/src/common/api/near-social-indexer/hooks.ts +++ b/src/common/api/near-social-indexer/hooks.ts @@ -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 - >, - ) => Object.keys(response.data), - ), + : nearSocialClient.keys({ keys, valuesOnly: true }).then((result) => Object.keys(result)), CLIENT_CONFIG.swr, ); diff --git a/src/common/blockchains/near-protocol/hooks.ts b/src/common/blockchains/near-protocol/hooks.ts index 6c3f0596..8040fc11 100644 --- a/src/common/blockchains/near-protocol/hooks.ts +++ b/src/common/blockchains/near-protocol/hooks.ts @@ -3,11 +3,12 @@ import useSWR 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"; @@ -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((resolve) => @@ -35,9 +36,13 @@ 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) => useSWR( - () => (disabled ? null : ["view_account", params.accountId]), + () => (!enabled || !IS_CLIENT ? null : ["view_account", params.accountId]), ([_queryKeyHead, accountId]) => nearRpc @@ -48,5 +53,13 @@ export const useViewAccount = ({ disabled = false, ...params }: ByAccountId & Wi }) .catch(() => undefined), - CONTRACT_SWR_CONFIG, + { + ...(live + ? {} + : { + revalidateIfStale: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + }), + }, ); diff --git a/src/common/constants.ts b/src/common/constants.ts index 48c82807..f28540b4 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -169,7 +169,7 @@ export const CONTRACT_SWR_CONFIG: SWRConfiguration = { }; /** - * @deprecated Use `useTokenAllowlist` hooks instead + * @deprecated Use `useFungibleTokenAllowlist` hooks instead */ export const SUPPORTED_FTS: Record< string, diff --git a/src/common/contracts/tokens/fungible/client.ts b/src/common/contracts/tokens/fungible/client.ts index c665382c..d1d2d5ab 100644 --- a/src/common/contracts/tokens/fungible/client.ts +++ b/src/common/contracts/tokens/fungible/client.ts @@ -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 }, diff --git a/src/common/contracts/tokens/fungible/hooks.ts b/src/common/contracts/tokens/fungible/hooks.ts index bf36d544..658497ff 100644 --- a/src/common/contracts/tokens/fungible/hooks.ts +++ b/src/common/contracts/tokens/fungible/hooks.ts @@ -1,28 +1,40 @@ import useSWR from "swr"; import { CONTRACT_SWR_CONFIG, IS_CLIENT } from "@/common/constants"; -import type { ByAccountId, ByTokenId, WithDisabled } from "@/common/types"; +import type { + ByAccountId, + ByTokenId, + ConditionalActivation, + LiveUpdateParams, +} from "@/common/types"; import * as ftContractClient from "./client"; -// TODO: Use conventional `enabled` instead of `disabled` -export const useFtMetadata = ({ disabled = false, ...params }: ByTokenId & WithDisabled) => +export const useFtMetadata = ({ enabled = true, ...params }: ByTokenId & ConditionalActivation) => useSWR( - () => (disabled || !IS_CLIENT ? null : ["ft_metadata", params.tokenId]), + () => (!enabled || !IS_CLIENT ? null : ["ft_metadata", params.tokenId]), ([_queryKeyHead, tokenId]) => ftContractClient.ft_metadata({ tokenId }).catch(() => undefined), CONTRACT_SWR_CONFIG, ); -// TODO: Use conventional `enabled` instead of `disabled` export const useFtBalanceOf = ({ - disabled = false, + enabled = true, + live = false, ...params -}: ByAccountId & ByTokenId & WithDisabled) => +}: ByAccountId & ByTokenId & ConditionalActivation & LiveUpdateParams) => useSWR( - () => (disabled || !IS_CLIENT ? null : ["ft_balance_of", params.accountId, params.tokenId]), + () => (!enabled || !IS_CLIENT ? null : ["ft_balance_of", params.accountId, params.tokenId]), ([_queryKeyHead, accountId, tokenId]) => ftContractClient.ft_balance_of({ accountId, tokenId }).catch(() => undefined), - CONTRACT_SWR_CONFIG, + { + ...(live + ? {} + : { + revalidateIfStale: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + }), + }, ); diff --git a/src/common/contracts/tokens/index.ts b/src/common/contracts/tokens/index.ts index 1eb3515a..86c6e6d6 100644 --- a/src/common/contracts/tokens/index.ts +++ b/src/common/contracts/tokens/index.ts @@ -1 +1,2 @@ export * from "./fungible"; +export * from "./non-fungible"; diff --git a/src/common/contracts/tokens/non-fungible/client.ts b/src/common/contracts/tokens/non-fungible/client.ts new file mode 100644 index 00000000..5157b521 --- /dev/null +++ b/src/common/contracts/tokens/non-fungible/client.ts @@ -0,0 +1,30 @@ +import { nearProtocolClient } from "@/common/blockchains/near-protocol"; +import type { ByContractAccountId } from "@/common/types"; + +import type { + NonFungibleToken, + NonFungibleTokenContractMetadata, + NonFungibleTokenLookupParams, +} from "./interfaces"; + +export type NftTokenArgs = { + token_id: string; +}; + +/** + * Returns NFT by token id from the given contract, if it exists. + */ +export const nft_token = ({ contractAccountId, tokenId }: NonFungibleTokenLookupParams) => + nearProtocolClient.naxiosInstance + .contractApi({ contractId: contractAccountId }) + .view("nft_token", { args: { token_id: tokenId } }) + .catch(() => undefined); + +/** + * Returns NFT contract metadata. + */ +export const nft_metadata = ({ contractAccountId }: ByContractAccountId) => + nearProtocolClient.naxiosInstance + .contractApi({ contractId: contractAccountId }) + .view<{}, NonFungibleTokenContractMetadata>("nft_metadata") + .catch(() => undefined); diff --git a/src/common/contracts/tokens/non-fungible/hooks.ts b/src/common/contracts/tokens/non-fungible/hooks.ts new file mode 100644 index 00000000..ed576125 --- /dev/null +++ b/src/common/contracts/tokens/non-fungible/hooks.ts @@ -0,0 +1,24 @@ +import useSWR from "swr"; + +import { CONTRACT_SWR_CONFIG, IS_CLIENT } from "@/common/constants"; +import type { ConditionalActivation } from "@/common/types"; + +import * as nftContractClient from "./client"; +import type { NonFungibleTokenLookupParams } from "./interfaces"; + +export const useToken = ({ + enabled = true, + contractAccountId, + tokenId, +}: NonFungibleTokenLookupParams & ConditionalActivation) => + useSWR( + () => + !enabled || !IS_CLIENT ? null : ["nftContractClient.nft_token", contractAccountId, tokenId], + + ([_queryKeyHead, account_id, token_id]) => + nftContractClient + .nft_token({ contractAccountId: account_id, tokenId: token_id }) + .catch(() => undefined), + + CONTRACT_SWR_CONFIG, + ); diff --git a/src/common/contracts/tokens/non-fungible/index.ts b/src/common/contracts/tokens/non-fungible/index.ts new file mode 100644 index 00000000..b8c61283 --- /dev/null +++ b/src/common/contracts/tokens/non-fungible/index.ts @@ -0,0 +1,7 @@ +import * as nftContractClient from "./client"; +import * as nftContractHooks from "./hooks"; + +export type * from "./hooks"; +export * from "./interfaces"; + +export { nftContractClient, nftContractHooks }; diff --git a/src/common/contracts/tokens/non-fungible/interfaces.ts b/src/common/contracts/tokens/non-fungible/interfaces.ts new file mode 100644 index 00000000..b001075d --- /dev/null +++ b/src/common/contracts/tokens/non-fungible/interfaces.ts @@ -0,0 +1,119 @@ +import type { AccountId } from "@/common/types"; + +/** + * https://nomicon.io/Standards/Tokens/NonFungibleToken/Metadata#interface + */ +export type NonFungibleTokenMetadata = { + /** + * e.g. "Arch Nemesis: Mail Carrier" or "Parcel #5055" + */ + title: string | null; + + /** + * Free-form description + */ + description: string | null; + + /** + * A URI pointing to the associated media, preferably to decentralized, content-addressed storage + */ + media: string | null; + + /** + * Base64-encoded sha256 hash of content referenced by the `media` field + */ + media_hash: string | null; + + /** + * Number of copies of this set of metadata in existence when token was minted + */ + copies: number | null; + + /** + * When token was issued or minted, Unix epoch in milliseconds + */ + issued_at: number | null; + + /** + * When token expires, Unix epoch in milliseconds + */ + expires_at: number | null; + + /** + * When token starts being valid, Unix epoch in milliseconds + */ + starts_at: number | null; + + /** + * When token was last updated, Unix epoch in milliseconds + */ + updated_at: number | null; + + /** + * Anything extra the NFT wants to store on-chain. Can be stringified JSON + */ + extra: string | null; + + /** + * URL to an off-chain JSON file with more info + */ + reference: string | null; + + /** + * Base64-encoded sha256 hash of JSON from reference field + */ + reference_hash: string | null; +}; + +/** + * https://nomicon.io/Standards/Tokens/NonFungibleToken/Metadata#interface + */ +export type NonFungibleTokenContractMetadata = { + /** + * Essentially a version like "nft-2.0.0", + * replacing "2.0.0" with the implemented version of NEP-177 + */ + spec: string; + + /** + * e.g. "Mochi Rising — Digital Edition" or "Metaverse 3" + */ + name: string; + + /** + * e.g. "MOCHI" + */ + symbol: string; + + /** + * Data URL + */ + icon: string | null; + + /** + * Centralized gateway known to have reliable access to decentralized storage assets + * referenced by `reference` or `media` URLs + */ + base_uri: string | null; + + /** + * URL to a JSON file with more info + */ + reference: string | null; + + /** + * Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included. + */ + reference_hash: string | null; +}; + +export type NonFungibleToken = { + token_id: string; + owner_id: AccountId; + metadata: NonFungibleTokenMetadata; +}; + +export type NonFungibleTokenLookupParams = { + contractAccountId: AccountId; + tokenId: NonFungibleToken["token_id"]; +}; diff --git a/src/common/lib/object.ts b/src/common/lib/object.ts index 711040ae..db51c763 100644 --- a/src/common/lib/object.ts +++ b/src/common/lib/object.ts @@ -1,3 +1,5 @@ +import { mapValues } from "remeda"; + type DeepPartial = T extends object ? { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; @@ -44,3 +46,9 @@ export const deepObjectDiff = >( return findDiff(objOriginal, objUpdated, diff); }; + +export const nullifyEmptyStrings = mapValues((value: string | unknown) => { + if (typeof value === "string" && value.length === 0) { + return null; + } else return value; +}); diff --git a/src/common/lib/string.ts b/src/common/lib/string.ts index 0e9fe952..6c398a27 100644 --- a/src/common/lib/string.ts +++ b/src/common/lib/string.ts @@ -1,22 +1,15 @@ -export const extractFromUrl = (url: string, pattern: RegExp) => { - if (url) { - if (url.startsWith("/")) { - url = url.slice(1, url.length); - } - - // Execute the regular expression on the URL - const match = url.match(pattern); - // If a match is found, return the extracted repository path; otherwise, return null - return match ? match[1] : url; +export const truncate = (value: string, maxLength: number) => { + if (value?.length ?? 0 <= maxLength) { + return value; + } else { + return value.substring(0, maxLength - 3) + "..."; } }; -export const truncate = (input: string, maxLength: number) => { - if (!input) return ""; - - if (input.length <= maxLength) { - return input; +export const isValidHttpUrl = (value: string) => { + try { + return Boolean(new URL(value)); + } catch (_) { + return false; } - - return input.substring(0, maxLength - 3) + "..."; }; diff --git a/src/common/services/images.ts b/src/common/services/images.ts deleted file mode 100644 index ae609c00..00000000 --- a/src/common/services/images.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { naxiosInstance } from "@/common/blockchains/near-protocol/client"; -import { Image, socialDbContractClient } from "@/common/contracts/social-db"; - -type Props = { - accountId?: string; - image?: Image | string; - type?: "backgroundImage" | "image"; - fallbackurl?: string; -}; - -type TokenResponse = { - metadata: { - reference: string; - media: string; - }; -}; - -type TokenInput = { - token_id: string; -}; - -type MetadateRes = { - base_uri: string; -}; - -/** - * Check account profile and get its avatar|background image provided by URL | IPFS | NFT - * @param - * @returns - */ -export const getImage = async ({ accountId, image, type, fallbackurl }: Props) => { - let socialImage: any = image; - - try { - if (!socialImage && accountId) { - const profile = await socialDbContractClient.getSocialProfile({ accountId }); - if (!profile) return console.error("error fetching social profile"); - - socialImage = profile[type || "image"]; - } - - if (socialImage?.nft) { - const { tokenId, contractId } = socialImage.nft; - - const contractApi = naxiosInstance.contractApi({ - contractId: contractId, - }); - - const tokenMetadata = ( - await contractApi.view("nft_token", { - args: { - token_id: tokenId, - }, - }) - ).metadata; - - const nftMetadata = await contractApi.view("nft_metadata", { - args: { - token_id: tokenId, - }, - }); - - const tokenMedia = tokenMetadata.media || ""; - - let imageUrl = null; - - if (nftMetadata && tokenMetadata) { - imageUrl = - tokenMedia.startsWith("https://") || - tokenMedia.startsWith("http://") || - tokenMedia.startsWith("data:image") - ? tokenMedia - : nftMetadata.base_uri - ? `${nftMetadata.base_uri}/${tokenMedia}` - : tokenMedia.startsWith("Qm") || tokenMedia.startsWith("ba") - ? `https://ipfs.near.social/ipfs/${tokenMedia}` - : tokenMedia; - - if (!tokenMedia && tokenMetadata.reference) { - if ( - nftMetadata.base_uri === "https://arweave.net" && - !tokenMetadata.reference.startsWith("https://") - ) { - const data = await fetch(`${nftMetadata.base_uri}/${tokenMetadata.reference}`); - const res = await data.json(); - - imageUrl = res.body?.media; - } else if ( - tokenMetadata.reference.startsWith("https://") || - tokenMetadata.reference.startsWith("http://") - ) { - const data = await fetch(tokenMetadata.reference); - const res = await data.json(); - - imageUrl = JSON.parse(res.body).media; - } else if (tokenMetadata.reference.startsWith("ar://")) { - const data = await fetch( - `${"https://arweave.net"}/${tokenMetadata.reference.split("//")[1]}`, - ); - - const res = await data.json(); - - imageUrl = JSON.parse(res.body).media; - } - } - } - - return imageUrl; - } else if (socialImage?.ipfs_cid) { - return `https://ipfs.near.social/ipfs/${socialImage.ipfs_cid}`; - } else { - return (fallbackurl ?? type === "image") - ? "/assets/images/profile-image.png" - : "/assets/images/profile-banner.png"; - } - } catch (err) { - return (fallbackurl ?? type === "image") - ? "/assets/images/profile-image.png" - : "/assets/images/profile-banner.png"; - } -}; diff --git a/src/common/services/pinata/hooks.ts b/src/common/services/pinata/hooks.ts index 086cbc50..c4e33dc0 100644 --- a/src/common/services/pinata/hooks.ts +++ b/src/common/services/pinata/hooks.ts @@ -46,15 +46,15 @@ export const useFileUpload = ({ onSuccess }: UseFileUploadParams | undefined = { ); const handleFileInputChange = useCallback( - (e: React.ChangeEvent) => { - upload(e.target?.files?.[0]); - }, - + (e: React.ChangeEvent) => upload(e.target.files?.[0]), [upload], ); + const handleFileBufferChange = useCallback((files?: File[]) => upload(files?.[0]), [upload]); + return { handleFileInputChange, + handleFileBufferChange, isPending, data: data ?? undefined, error: error ?? undefined, diff --git a/src/common/types.ts b/src/common/types.ts index c024c081..82be8bad 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -43,6 +43,10 @@ export interface ByAccountId { accountId: AccountId; } +export type ByContractAccountId = { + contractAccountId: AccountId; +}; + export type ContractConfig = ByAccountId & {}; export type EnvConfig = { @@ -87,6 +91,10 @@ export interface ConditionalActivation { enabled?: boolean; } +export type LiveUpdateParams = { + live?: boolean; +}; + export type ContractMetadata = { latestSourceCodeCommitHash: null | string; }; diff --git a/src/common/ui/form/components/text.tsx b/src/common/ui/form/components/text.tsx index ef865733..13c1f540 100644 --- a/src/common/ui/form/components/text.tsx +++ b/src/common/ui/form/components/text.tsx @@ -22,6 +22,7 @@ export type TextFieldProps = Omit, " classNames?: { root?: string; fieldRoot?: string; + inputExtension?: string; input?: string; }; }; @@ -58,7 +59,6 @@ export const TextField = forwardRef(
{label && {label}} - {required && *}
@@ -87,10 +87,10 @@ export const TextField = forwardRef( () => inputExtension ? (
{typeof inputExtension === "string" ? ( {inputExtension} @@ -100,7 +100,7 @@ export const TextField = forwardRef(
) : null, - [inputExtension], + [classNames?.inputExtension, inputExtension], ); const appendixElement = useMemo( diff --git a/src/common/ui/layout/components/molecules/multi-select.tsx b/src/common/ui/layout/components/molecules/multi-select.tsx index e2ab19d0..c089e224 100644 --- a/src/common/ui/layout/components/molecules/multi-select.tsx +++ b/src/common/ui/layout/components/molecules/multi-select.tsx @@ -65,7 +65,8 @@ const MultiSelector = ({ onValueChange([...value, val]); } }, - [value], + + [onValueChange, value], ); // TODO : change from else if use to switch case statement @@ -114,7 +115,8 @@ const MultiSelector = ({ } } }, - [value, inputValue, activeIndex, loop], + + [value, dir, activeIndex, loop, inputValue.length, onValueChange], ); return ( @@ -132,7 +134,7 @@ const MultiSelector = ({ > @@ -155,8 +157,7 @@ const MultiSelectorTrigger = forwardRef diff --git a/src/common/ui/layout/svg/CameraIcon.tsx b/src/common/ui/layout/svg/CameraIcon.tsx deleted file mode 100644 index 248da3ee..00000000 --- a/src/common/ui/layout/svg/CameraIcon.tsx +++ /dev/null @@ -1,12 +0,0 @@ -const CameraIcon = (props: React.SVGProps) => { - return ( - - - - ); -}; - -export default CameraIcon; diff --git a/src/common/ui/layout/svg/camera.tsx b/src/common/ui/layout/svg/camera.tsx deleted file mode 100644 index 0dfe5b7d..00000000 --- a/src/common/ui/layout/svg/camera.tsx +++ /dev/null @@ -1,29 +0,0 @@ -const CameraSvg = ({ height }: { height?: number }) => ( - - - - - - - - -); - -export default CameraSvg; diff --git a/src/entities/_shared/account/components/AccountFollowStats.tsx b/src/entities/_shared/account/components/AccountFollowStats.tsx index 769b4e0b..198e8d0c 100644 --- a/src/entities/_shared/account/components/AccountFollowStats.tsx +++ b/src/entities/_shared/account/components/AccountFollowStats.tsx @@ -1,3 +1,5 @@ +import { useMemo } from "react"; + import Link from "next/link"; import { nearSocialIndexerHooks } from "@/common/api/near-social-indexer"; @@ -6,27 +8,31 @@ import { ByAccountId } from "@/common/types"; export type AccountFollowStatsProps = ByAccountId & {}; export const AccountFollowStats: React.FC = ({ accountId }) => { - const { data: followerAccountIds } = nearSocialIndexerHooks.useFollowerAccountIds({ + const { data: followerAccountIds = [] } = nearSocialIndexerHooks.useFollowerAccountIds({ accountId, }); - const { data: followedAccountIds } = nearSocialIndexerHooks.useFollowedAccountIds({ + const { data: followedAccountIds = [] } = nearSocialIndexerHooks.useFollowedAccountIds({ accountId, }); - // TODO: Links should lead to the corresponding Near Social profile pages + const followPageUrl = useMemo( + () => `https://near.social/mob.near/widget/FollowPage?accountId=${accountId}`, + [accountId], + ); + return (
- {followerAccountIds && ( - - {followerAccountIds?.length} + {followerAccountIds.length > 0 && ( + + {followerAccountIds.length} {"Followers"} )} - {followedAccountIds && ( - - {followedAccountIds?.length} + {followedAccountIds.length > 0 && ( + + {followedAccountIds.length} {"Following"} )} diff --git a/src/entities/_shared/account/components/profile-images.tsx b/src/entities/_shared/account/components/profile-images.tsx index c06fcf6b..07e1bd5a 100644 --- a/src/entities/_shared/account/components/profile-images.tsx +++ b/src/entities/_shared/account/components/profile-images.tsx @@ -1,5 +1,3 @@ -import { useMemo } from "react"; - import { LazyLoadImage, LazyLoadImageProps } from "react-lazy-load-image-component"; import { ByAccountId } from "@/common/types"; @@ -17,13 +15,18 @@ export const AccountProfilePicture: React.FC = ({ accountId, className, }) => { - const { isLoading, avatarSrc } = useAccountSocialProfile({ accountId }); + const { isLoading, avatar } = useAccountSocialProfile({ accountId }); return isLoading ? ( ) : ( - + ); }; @@ -33,25 +36,18 @@ export type AccountProfileCoverProps = ByAccountId & className?: string; }; +const contentClassName = + "h-full w-full object-cover transition-transform duration-500 ease-in-out hover:scale-110"; + export const AccountProfileCover: React.FC = ({ accountId, height, className, }) => { - const { isLoading: isProfileDataLoading, backgroundSrc: src } = useAccountSocialProfile({ + const { isLoading: isProfileDataLoading, cover } = useAccountSocialProfile({ accountId, }); - const contentClassName = useMemo( - () => - cn( - "h-full w-full object-cover", - "transition-transform duration-500 ease-in-out hover:scale-110", - ), - - [], - ); - return isProfileDataLoading ? ( ) : ( @@ -59,9 +55,10 @@ export const AccountProfileCover: React.FC = ({ diff --git a/src/entities/_shared/account/constants.ts b/src/entities/_shared/account/constants.ts index 4201761a..9d3b15f0 100644 --- a/src/entities/_shared/account/constants.ts +++ b/src/entities/_shared/account/constants.ts @@ -1,4 +1,3 @@ -import { IMAGES_ASSET_ENDPOINT_URL } from "@/common/constants"; import { RegistrationStatus } from "@/common/contracts/core/lists"; import { @@ -8,9 +7,17 @@ import { type AccountProfileLinktreeKey, } from "./types"; -export const ACCOUNT_PROFILE_IMAGE_PLACEHOLDER_SRC = `${IMAGES_ASSET_ENDPOINT_URL}/profile-image.jpg`; +export const ACCOUNT_PROFILE_DESCRIPTION_MAX_LENGTH = 1500; -export const ACCOUNT_PROFILE_COVER_IMAGE_PLACEHOLDER_SRC = `${IMAGES_ASSET_ENDPOINT_URL}/profile-banner.png`; +// export const ACCOUNT_PROFILE_IMAGE_PLACEHOLDER_SRC = `${IMAGES_ASSET_ENDPOINT_URL}/profile-image.jpg`; + +export const ACCOUNT_PROFILE_IMAGE_PLACEHOLDER_SRC = + "https://potlock.mypinata.cloud/ipfs/bafkreidmfead5arjheqrsvarqfqhofwwlguw2kb5rlhgcmvdd4d7wkh43u"; + +// export const ACCOUNT_PROFILE_COVER_IMAGE_PLACEHOLDER_SRC = `${IMAGES_ASSET_ENDPOINT_URL}/profile-banner.png`; + +export const ACCOUNT_PROFILE_COVER_IMAGE_PLACEHOLDER_SRC = + "https://potlock.mypinata.cloud/ipfs/bafkreidcescdtqwteqtqtoluujf6z52cbmphjrd6bghxa6667n4djkznqa"; export const ACCOUNT_PROFILE_LINKTREE_KEYS: AccountProfileLinktreeKey[] = [ "github", @@ -21,9 +28,9 @@ export const ACCOUNT_PROFILE_LINKTREE_KEYS: AccountProfileLinktreeKey[] = [ export const ACCOUNT_PROFILE_URL_PATTERNS: Record = { github: /^(?:https?:\/\/)?(?:www\.)?github\.com\/([^/]+(?:\/[^/]+)?)\/?$/, - twitter: /^(?:https?:\/\/)?(?:www\.)?x\.com\/([^/]+(?:\/[^/]+)?)\/?$/, - telegram: /^(?:https?:\/\/)?(?:www\.)?t\.com\/([^/]+(?:\/[^/]+)?)\/?$/, - website: /^(?:https?:\/\/)\/?$/, + twitter: /^(?:https?:\/\/)?(?:www\.)?(?:x\.com|twitter\.com)\/([^/]+(?:\/[^/]+)?)\/?$/, + telegram: /^(?:https?:\/\/)?(?:www\.)?t\.me\/([^/]+(?:\/[^/]+)?)\/?$/, + website: /^(?:https?:\/\/)?([^/]+)$/, }; export const ACCOUNT_CATEGORY_VARIANTS: AccountCategoryVariant[] = [ diff --git a/src/entities/_shared/account/hooks/social-image.ts b/src/entities/_shared/account/hooks/social-image.ts new file mode 100644 index 00000000..cdd0c8e3 --- /dev/null +++ b/src/entities/_shared/account/hooks/social-image.ts @@ -0,0 +1,53 @@ +import { useMemo } from "react"; + +import { isNonNullish } from "remeda"; + +import { NOOP_STRING } from "@/common/constants"; +import type { NEARSocialUserProfile } from "@/common/contracts/social-db"; +import { nftContractHooks } from "@/common/contracts/tokens"; +import { isValidHttpUrl } from "@/common/lib"; + +export type UseAccountSocialImageParams = { + data?: NEARSocialUserProfile["image"]; + fallbackUrl: string; +}; + +export const useAccountSocialImageSrc = ({ data, fallbackUrl }: UseAccountSocialImageParams) => { + const nftParams = useMemo( + () => + data !== undefined && typeof data !== "string" && "nft" in data ? (data.nft ?? null) : null, + + [data], + ); + + const { data: nft } = nftContractHooks.useToken({ + enabled: nftParams !== null, + contractAccountId: nftParams?.contractId ?? NOOP_STRING, + tokenId: nftParams?.tokenId ?? NOOP_STRING, + }); + + const nftMediaSrc = useMemo(() => { + if (isNonNullish(nft?.metadata.media)) { + return isValidHttpUrl(nft.metadata.media) + ? nft.metadata.media + : `https://ipfs.near.social/ipfs/${nft.metadata.media}`; + } else return null; + }, [nft]); + + const rawImageSrc = useMemo(() => { + if (typeof data !== "string") { + return ( + data?.url ?? (data?.ipfs_cid ? `https://ipfs.near.social/ipfs/${data?.ipfs_cid}` : null) + ); + } else return data; + }, [data]); + + return useMemo( + () => ({ + url: nftMediaSrc ?? rawImageSrc ?? fallbackUrl, + isNft: nftMediaSrc !== null, + }), + + [fallbackUrl, nftMediaSrc, rawImageSrc], + ); +}; diff --git a/src/entities/_shared/account/hooks/social-profile.ts b/src/entities/_shared/account/hooks/social-profile.ts index c5c09a23..8491e8d5 100644 --- a/src/entities/_shared/account/hooks/social-profile.ts +++ b/src/entities/_shared/account/hooks/social-profile.ts @@ -1,5 +1,3 @@ -import { useMemo } from "react"; - import { socialDbContractHooks } from "@/common/contracts/social-db"; import type { ByAccountId, ConditionalActivation } from "@/common/types"; @@ -7,6 +5,7 @@ import { ACCOUNT_PROFILE_COVER_IMAGE_PLACEHOLDER_SRC, ACCOUNT_PROFILE_IMAGE_PLACEHOLDER_SRC, } from "../constants"; +import { useAccountSocialImageSrc } from "./social-image"; export const useAccountSocialProfile = ({ accountId, @@ -20,36 +19,22 @@ export const useAccountSocialProfile = ({ error, } = socialDbContractHooks.useSocialProfile({ enabled, accountId }); - const avatarSrc = useMemo( - () => - (typeof data?.image === "string" - ? data?.image - : (data?.image?.url ?? - (data?.image?.ipfs_cid - ? `https://ipfs.near.social/ipfs/${data?.image?.ipfs_cid}` - : null))) ?? ACCOUNT_PROFILE_IMAGE_PLACEHOLDER_SRC, - - [data?.image], - ); - - const backgroundSrc = useMemo( - () => - (typeof data?.backgroundImage === "string" - ? data?.backgroundImage - : (data?.backgroundImage?.url ?? - (data?.backgroundImage?.ipfs_cid - ? `https://ipfs.near.social/ipfs/${data?.backgroundImage?.ipfs_cid}` - : null))) ?? ACCOUNT_PROFILE_COVER_IMAGE_PLACEHOLDER_SRC, + const avatar = useAccountSocialImageSrc({ + data: data?.image, + fallbackUrl: ACCOUNT_PROFILE_IMAGE_PLACEHOLDER_SRC, + }); - [data?.backgroundImage], - ); + const cover = useAccountSocialImageSrc({ + data: data?.backgroundImage, + fallbackUrl: ACCOUNT_PROFILE_COVER_IMAGE_PLACEHOLDER_SRC, + }); return { isLoading, isValidating, profile: data ?? undefined, - avatarSrc, - backgroundSrc, + avatar, + cover, refetch, error, }; diff --git a/src/entities/_shared/account/index.ts b/src/entities/_shared/account/index.ts index 8887dce9..67391563 100644 --- a/src/entities/_shared/account/index.ts +++ b/src/entities/_shared/account/index.ts @@ -21,6 +21,8 @@ export * from "./hooks/social-profile"; export * from "./model/schemas"; +export * from "./utils/linktree"; + //! Only exported for backward compatibility // TODO!: Stop using the model component directly and use the `AccountGroup` integrated flow instead export * from "./components/AccountGroupEditModal"; diff --git a/src/entities/_shared/account/types.ts b/src/entities/_shared/account/types.ts index 3cd8d8c7..0af29c66 100644 --- a/src/entities/_shared/account/types.ts +++ b/src/entities/_shared/account/types.ts @@ -45,7 +45,7 @@ export type AccountListRegistrationStatus = keyof typeof RegistrationStatus; export type AccountListRegistrationStatusVariant = | AccountListRegistrationStatus /** - *? INFO: Only needed for backward compatibility: + ** INFO: Only needed for backward compatibility: */ | "All"; diff --git a/src/entities/_shared/account/utils/linktree.ts b/src/entities/_shared/account/utils/linktree.ts new file mode 100644 index 00000000..a9230a09 --- /dev/null +++ b/src/entities/_shared/account/utils/linktree.ts @@ -0,0 +1,13 @@ +import { ACCOUNT_PROFILE_URL_PATTERNS } from "../constants"; +import type { AccountProfileLinktreeKey } from "../types"; + +/** + * Returns a function that extracts a raw identifier from the specific linktree url. + */ +export const getLinktreeLeafExtractor = (key: AccountProfileLinktreeKey) => (url?: string) => { + if (typeof url === "string" && url.length > 0) { + return ACCOUNT_PROFILE_URL_PATTERNS[key].test(url) + ? ACCOUNT_PROFILE_URL_PATTERNS[key].exec(url)?.at(1) + : url; + } else return undefined; +}; diff --git a/src/entities/_shared/index.ts b/src/entities/_shared/index.ts deleted file mode 100644 index df9079ee..00000000 --- a/src/entities/_shared/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./account"; -export * from "./token"; diff --git a/src/entities/_shared/token/components/balance.tsx b/src/entities/_shared/token/components/balance.tsx index f8eb9fd9..6d3480d8 100644 --- a/src/entities/_shared/token/components/balance.tsx +++ b/src/entities/_shared/token/components/balance.tsx @@ -2,7 +2,7 @@ import { ByTokenId } from "@/common/types"; import { Skeleton } from "@/common/ui/layout/components"; import { cn } from "@/common/ui/layout/utils"; import { useWalletUserSession } from "@/common/wallet"; -import { useToken } from "@/entities/_shared/token"; +import { useFungibleToken } from "@/entities/_shared/token"; export type TokenBalanceProps = ByTokenId & { classNames?: { root?: string; amount?: string }; @@ -11,7 +11,8 @@ export type TokenBalanceProps = ByTokenId & { export const TokenBalance: React.FC = ({ tokenId, classNames }) => { const viewer = useWalletUserSession(); - const { data: token, error: tokenError } = useToken({ + const { data: token, error: tokenError } = useFungibleToken({ + live: true, balanceCheckAccountId: viewer?.accountId, tokenId, }); diff --git a/src/entities/_shared/token/components/icons.tsx b/src/entities/_shared/token/components/icons.tsx index d69b389f..7d463faf 100644 --- a/src/entities/_shared/token/components/icons.tsx +++ b/src/entities/_shared/token/components/icons.tsx @@ -5,7 +5,7 @@ import { AccountId } from "@/common/types"; import { NearIcon } from "@/common/ui/layout/svg"; import { cn } from "@/common/ui/layout/utils"; -import { useToken } from "../hooks/data"; +import { useFungibleToken } from "../hooks/fungible"; type TokenIconSize = "xs" | "sm" | "md"; @@ -29,7 +29,7 @@ export type TokenIconProps = { }; export const TokenIcon = ({ tokenId, className, size = "md" }: TokenIconProps) => { - const { data: token } = useToken({ tokenId }); + const { data: token } = useFungibleToken({ tokenId }); const { sizePx, rootClass, placeholderClass } = variants[size]; return ( diff --git a/src/entities/_shared/token/components/selector.tsx b/src/entities/_shared/token/components/selector.tsx index 0b86271c..1dfccbb9 100644 --- a/src/entities/_shared/token/components/selector.tsx +++ b/src/entities/_shared/token/components/selector.tsx @@ -12,7 +12,7 @@ import { } from "@/common/ui/form/components"; import { useWalletUserSession } from "@/common/wallet"; -import { useToken, useTokenAllowlist } from "../hooks/data"; +import { useFungibleToken, useFungibleTokenAllowlist } from "../hooks/fungible"; type TokenSelectorOptionProps = ByTokenId & { showBalance?: boolean; @@ -26,7 +26,7 @@ const TokenSelectorOption: React.FC = ({ }) => { const viewer = useWalletUserSession(); - const { data: token } = useToken({ + const { data: token } = useFungibleToken({ tokenId, balanceCheckAccountId: showBalance || skipIfZeroBalance ? viewer?.accountId : undefined, }); @@ -68,7 +68,7 @@ export const TokenSelector: React.FC = ({ hideZeroBalanceOptions = false, ...props }) => { - const { data: tokenAllowlist } = useTokenAllowlist({ + const { data: tokenAllowlist } = useFungibleTokenAllowlist({ enabled: FEATURE_REGISTRY.FtDonation.isEnabled, }); diff --git a/src/entities/_shared/token/components/value-summary.tsx b/src/entities/_shared/token/components/value-summary.tsx index 2917905f..9e4d2df2 100644 --- a/src/entities/_shared/token/components/value-summary.tsx +++ b/src/entities/_shared/token/components/value-summary.tsx @@ -5,7 +5,7 @@ import { Skeleton } from "@/common/ui/layout/components"; import { cn } from "@/common/ui/layout/utils"; import { TokenIcon } from "./icons"; -import { useToken } from "../hooks/data"; +import { useFungibleToken } from "../hooks/fungible"; export type TokenValueSummaryProps = ByTokenId & ({ amountFloat: number } | { amountIndivisible: string }) & { @@ -19,7 +19,7 @@ export const TokenValueSummary: React.FC = ({ classNames, ...props }) => { - const { data: token } = useToken({ tokenId }); + const { data: token } = useFungibleToken({ tokenId }); const amount = "amountFloat" in props diff --git a/src/entities/_shared/token/hooks/_deprecated.ts b/src/entities/_shared/token/hooks/_deprecated.ts index 6e43a231..2035b543 100644 --- a/src/entities/_shared/token/hooks/_deprecated.ts +++ b/src/entities/_shared/token/hooks/_deprecated.ts @@ -3,10 +3,10 @@ import { Big } from "big.js"; import { coingeckoHooks } from "@/common/api/coingecko"; import { formatWithCommas } from "@/common/lib"; // eslint-disable-next-line @typescript-eslint/no-unused-vars -import { useToken } from "@/entities/_shared/token"; +import { useFungibleToken } from "@/entities/_shared/token"; /** - * @deprecated Use `data.usdPrice` from {@link useToken}({ tokenId: NATIVE_TOKEN_ID }) + * @deprecated Use `data.usdPrice` from {@link useFungibleToken}({ tokenId: NATIVE_TOKEN_ID }) */ export const useNearToUsdWithFallback = (amountNear: number, abbreviate?: boolean) => { const { data: oneNearTokenUsdPrice } = coingeckoHooks.useNativeTokenUsdPrice(); diff --git a/src/entities/_shared/token/hooks/data.ts b/src/entities/_shared/token/hooks/fungible.ts similarity index 89% rename from src/entities/_shared/token/hooks/data.ts rename to src/entities/_shared/token/hooks/fungible.ts index 5b1bd663..afdbe950 100644 --- a/src/entities/_shared/token/hooks/data.ts +++ b/src/entities/_shared/token/hooks/fungible.ts @@ -9,11 +9,11 @@ import { NATIVE_TOKEN_ID, PLATFORM_LISTED_TOKEN_IDS } from "@/common/constants"; import { refExchangeContractHooks } from "@/common/contracts/ref-finance"; import { ftContractHooks } from "@/common/contracts/tokens"; import { indivisibleUnitsToBigNum, indivisibleUnitsToFloat, isAccountId } from "@/common/lib"; -import type { AccountId, ConditionalActivation } from "@/common/types"; +import type { AccountId, ConditionalActivation, LiveUpdateParams } from "@/common/types"; import { type TokenQuery, type TokenQueryResult } from "../types"; -export const useTokenAllowlist = ({ enabled = true }: ConditionalActivation) => { +export const useFungibleTokenAllowlist = ({ enabled = true }: ConditionalActivation) => { const { data: refFinanceTokenAllowlist } = refExchangeContractHooks.useWhitelistedTokens({ enabled, }); @@ -32,11 +32,12 @@ export const useTokenAllowlist = ({ enabled = true }: ConditionalActivation) => * * When `balanceCheckAccountId` is provided, the balance of the token is also retrieved. */ -export const useToken = ({ +export const useFungibleToken = ({ tokenId, balanceCheckAccountId, enabled = true, -}: TokenQuery & ConditionalActivation): TokenQueryResult => { + live = false, +}: TokenQuery & ConditionalActivation & LiveUpdateParams): TokenQueryResult => { const isValidFtContractAccountId = isAccountId(tokenId); const isValidTokenId = tokenId === NATIVE_TOKEN_ID || isValidFtContractAccountId; @@ -45,7 +46,7 @@ export const useToken = ({ data: ntMetadata, error: ntMetadataError, } = nearProtocolHooks.useNativeTokenMetadata({ - disabled: !enabled || tokenId !== NATIVE_TOKEN_ID, + enabled: enabled && tokenId === NATIVE_TOKEN_ID, }); const { @@ -61,7 +62,8 @@ export const useToken = ({ data: accountSummary, error: accountSummaryError, } = nearProtocolHooks.useViewAccount({ - disabled: !enabled || balanceCheckAccountId === undefined || tokenId !== NATIVE_TOKEN_ID, + enabled: enabled && balanceCheckAccountId !== undefined && tokenId === NATIVE_TOKEN_ID, + live, accountId: balanceCheckAccountId as AccountId, }); @@ -70,7 +72,7 @@ export const useToken = ({ data: ftMetadata, error: ftMetadataError, } = ftContractHooks.useFtMetadata({ - disabled: !enabled || !isValidFtContractAccountId, + enabled: enabled && isValidFtContractAccountId, tokenId, }); @@ -88,7 +90,8 @@ export const useToken = ({ data: ftBalance, error: ftBalanceError, } = ftContractHooks.useFtBalanceOf({ - disabled: balanceCheckAccountId === undefined || !isValidFtContractAccountId, + enabled: balanceCheckAccountId !== undefined && isValidFtContractAccountId, + live, accountId: balanceCheckAccountId as AccountId, tokenId, }); diff --git a/src/entities/_shared/token/index.ts b/src/entities/_shared/token/index.ts index a5de4ab2..e4d201b7 100644 --- a/src/entities/_shared/token/index.ts +++ b/src/entities/_shared/token/index.ts @@ -5,4 +5,4 @@ export * from "./components/icons"; export * from "./components/selector"; export * from "./components/value-summary"; -export * from "./hooks/data"; +export * from "./hooks/fungible"; diff --git a/src/entities/campaign/components/CampaignBanner.tsx b/src/entities/campaign/components/CampaignBanner.tsx index 7f894923..9bfd192e 100644 --- a/src/entities/campaign/components/CampaignBanner.tsx +++ b/src/entities/campaign/components/CampaignBanner.tsx @@ -15,8 +15,8 @@ import { Button, SocialsShare, Spinner } from "@/common/ui/layout/components"; import { BadgeIcon } from "@/common/ui/layout/svg/BadgeIcon"; import { cn } from "@/common/ui/layout/utils"; import { useWalletUserSession } from "@/common/wallet"; -import { useToken } from "@/entities/_shared"; import { AccountProfileLink } from "@/entities/_shared/account"; +import { useFungibleToken } from "@/entities/_shared/token"; import { DonateToCampaign } from "@/features/donation"; import { CampaignProgressBar } from "./CampaignProgressBar"; @@ -33,7 +33,7 @@ export const CampaignBanner: React.FC = ({ campaignId }) => error: campaignLoadingError, } = campaignsContractHooks.useCampaign({ campaignId }); - const { data: token } = useToken({ tokenId: campaign?.ft_id ?? NATIVE_TOKEN_ID }); + const { data: token } = useFungibleToken({ tokenId: campaign?.ft_id ?? NATIVE_TOKEN_ID }); const raisedAmountFloat = useMemo( () => @@ -107,28 +107,33 @@ export const CampaignBanner: React.FC = ({ campaignId }) =>

FOR

+
+
{" "}
+

ORGANIZED BY

+ {campaign?.owner === campaign?.recipient && ( -
+
OFFICIAL
@@ -136,13 +141,16 @@ export const CampaignBanner: React.FC = ({ campaignId }) =>
+

{campaign?.description}

+

- TOTAL AMOUNT RAISED + {"TOTAL AMOUNT RAISED"}

+

{`${raisedAmountFloat} ${token?.metadata.symbol ?? ""}`} @@ -169,12 +177,20 @@ export const CampaignBanner: React.FC = ({ campaignId }) => {viewer.isSignedIn && hasEscrowedDonations && (
-
+ +
+

Campaign Successful

+

The Minimum Target of the Campaign has been successfully reach and the Donations can be processed. @@ -183,6 +199,7 @@ export const CampaignBanner: React.FC = ({ campaignId }) =>

)} + {viewer.isSignedIn && isDonationRefundsProcessed && campaign?.end_ms && @@ -190,10 +207,17 @@ export const CampaignBanner: React.FC = ({ campaignId }) => raisedAmountFloat < minAmountFloat && (
-
+ +
+

Campaign Ended

diff --git a/src/entities/campaign/components/CampaignDonorsTable.tsx b/src/entities/campaign/components/CampaignDonorsTable.tsx index 8687b69e..5ff0d2cc 100644 --- a/src/entities/campaign/components/CampaignDonorsTable.tsx +++ b/src/entities/campaign/components/CampaignDonorsTable.tsx @@ -9,15 +9,15 @@ import { indivisibleUnitsToFloat, oldToRecent } from "@/common/lib"; import getTimePassed from "@/common/lib/getTimePassed"; import type { ByCampaignId } from "@/common/types"; import { DataTable } from "@/common/ui/layout/components"; -import { TokenIcon, useToken } from "@/entities/_shared"; import { AccountProfilePicture } from "@/entities/_shared/account"; +import { TokenIcon, useFungibleToken } from "@/entities/_shared/token"; import { rootPathnames } from "@/pathnames"; export type CampaignDonorsTableProps = ByCampaignId & {}; export const CampaignDonorsTable: React.FC = ({ campaignId }) => { const { data: campaign } = campaignsContractHooks.useCampaign({ campaignId }); - const { data: token } = useToken({ tokenId: campaign?.ft_id ?? NATIVE_TOKEN_ID }); + const { data: token } = useFungibleToken({ tokenId: campaign?.ft_id ?? NATIVE_TOKEN_ID }); const { data: donations } = campaignsContractHooks.useCampaignDonations({ campaignId }); const sortedDonations = useMemo(() => { diff --git a/src/entities/campaign/components/CampaignProgressBar.tsx b/src/entities/campaign/components/CampaignProgressBar.tsx index 4f656cc2..15fa1043 100644 --- a/src/entities/campaign/components/CampaignProgressBar.tsx +++ b/src/entities/campaign/components/CampaignProgressBar.tsx @@ -9,7 +9,7 @@ import { indivisibleUnitsToFloat } from "@/common/lib"; import getTimePassed from "@/common/lib/getTimePassed"; import type { ByTokenId } from "@/common/types"; import { Progress } from "@/common/ui/layout/components"; -import { TokenIcon, useToken } from "@/entities/_shared"; +import { TokenIcon, useFungibleToken } from "@/entities/_shared/token"; export type CampaignProgressBarProps = ByTokenId & { target: Campaign["target_amount"]; @@ -31,7 +31,7 @@ export const CampaignProgressBar: React.FC = ({ isStarted, startDate, }) => { - const { data: token } = useToken({ tokenId }); + const { data: token } = useFungibleToken({ tokenId }); const raisedAmountFloat = useMemo( () => (token === undefined ? 0 : indivisibleUnitsToFloat(amount, token.metadata.decimals)), diff --git a/src/entities/campaign/components/CampaignSettings.tsx b/src/entities/campaign/components/CampaignSettings.tsx index f087b8a4..54764b67 100644 --- a/src/entities/campaign/components/CampaignSettings.tsx +++ b/src/entities/campaign/components/CampaignSettings.tsx @@ -10,8 +10,8 @@ import { indivisibleUnitsToFloat } from "@/common/lib"; import type { ByCampaignId } from "@/common/types"; import { Skeleton, Spinner } from "@/common/ui/layout/components"; import { useWalletUserSession } from "@/common/wallet"; -import { TokenIcon, useToken } from "@/entities/_shared"; import { AccountProfilePicture } from "@/entities/_shared/account"; +import { TokenIcon, useFungibleToken } from "@/entities/_shared/token"; import { CampaignEditor } from "./editor"; @@ -61,7 +61,7 @@ export const CampaignSettings: React.FC = ({ campaignId } error: campaignLoadingError, } = campaignsContractHooks.useCampaign({ campaignId }); - const { data: token } = useToken({ tokenId: campaign?.ft_id ?? NATIVE_TOKEN_ID }); + const { data: token } = useFungibleToken({ tokenId: campaign?.ft_id ?? NATIVE_TOKEN_ID }); const minAmountFloat = useMemo( () => diff --git a/src/entities/campaign/components/editor.tsx b/src/entities/campaign/components/editor.tsx index 2fe198ea..927a56c6 100644 --- a/src/entities/campaign/components/editor.tsx +++ b/src/entities/campaign/components/editor.tsx @@ -14,7 +14,7 @@ import { TextAreaField, TextField } from "@/common/ui/form/components"; import { Button, Form, FormField, Switch } from "@/common/ui/layout/components"; import { cn } from "@/common/ui/layout/utils"; import { useWalletUserSession } from "@/common/wallet"; -import { TokenSelector, useToken } from "@/entities/_shared"; +import { TokenSelector, useFungibleToken } from "@/entities/_shared/token"; import { useCampaignForm } from "../hooks/forms"; @@ -49,7 +49,7 @@ export const CampaignEditor = ({ existingData, campaignId, close }: CampaignEdit "cover_image_url", ]); - const { data: token } = useToken({ + const { data: token } = useFungibleToken({ tokenId: existingData?.ft_id ?? ftId ?? NATIVE_TOKEN_ID, balanceCheckAccountId: walletUser?.accountId, }); diff --git a/src/entities/campaign/hooks/forms.ts b/src/entities/campaign/hooks/forms.ts index 9bc7a5c5..74530ec3 100644 --- a/src/entities/campaign/hooks/forms.ts +++ b/src/entities/campaign/hooks/forms.ts @@ -12,7 +12,7 @@ import type { FileUploadResult } from "@/common/services/pinata"; import { type ByCampaignId, type FromSchema, type TokenId } from "@/common/types"; import { toast } from "@/common/ui/layout/hooks"; import { useWalletUserSession } from "@/common/wallet"; -import { useToken } from "@/entities/_shared"; +import { useFungibleToken } from "@/entities/_shared/token"; import { routeSelectors } from "@/pathnames"; import { dispatch } from "@/store"; @@ -64,7 +64,7 @@ export const useCampaignForm = ({ campaignId, ftId, onUpdateSuccess }: CampaignF [values.max_amount], ); - const { isLoading: isTokenDataLoading, data: token } = useToken({ + const { isLoading: isTokenDataLoading, data: token } = useFungibleToken({ tokenId: values.ft_id ?? NATIVE_TOKEN_ID, }); diff --git a/src/entities/list/components/AccountCard.tsx b/src/entities/list/components/AccountCard.tsx index 0ac3f20a..3d8d0f4b 100644 --- a/src/entities/list/components/AccountCard.tsx +++ b/src/entities/list/components/AccountCard.tsx @@ -31,7 +31,7 @@ import { AccountHandle, AccountProfileCover, AccountProfilePicture, -} from "@/entities/_shared"; +} from "@/entities/_shared/account"; import { dispatch } from "@/store"; import { listRegistrationStatuses } from "../constants"; @@ -142,7 +142,7 @@ export const ListAccountCard = ({ />

- {truncate(profile?.description as string, 150) ?? "N/A"} + {profile?.description !== undefined ? truncate(profile.description, 150) : null}

{/* Labels NOT sure if we need this */} diff --git a/src/entities/list/components/ListAccounts.tsx b/src/entities/list/components/ListAccounts.tsx index 66c03f74..be3929ad 100644 --- a/src/entities/list/components/ListAccounts.tsx +++ b/src/entities/list/components/ListAccounts.tsx @@ -3,7 +3,7 @@ import React, { useCallback, useEffect, useMemo, useState } from "react"; import { List, ListRegistration } from "@/common/api/indexer"; import { Filter, Group, GroupType, SearchBar, SortSelect } from "@/common/ui/layout/components"; -import { ACCOUNT_LIST_REGISTRATION_STATUS_OPTIONS } from "@/entities/_shared"; +import { ACCOUNT_LIST_REGISTRATION_STATUS_OPTIONS } from "@/entities/_shared/account"; import { ListCardSkeleton } from "./ListCardSkeleton"; import { NoListItem } from "./NoListItem"; diff --git a/src/entities/list/components/ListCard.tsx b/src/entities/list/components/ListCard.tsx index 372e9ff0..f06885bc 100644 --- a/src/entities/list/components/ListCard.tsx +++ b/src/entities/list/components/ListCard.tsx @@ -44,14 +44,14 @@ export const ListCard = ({ listsContractClient.remove_upvote({ list_id: dataForList?.on_chain_id }); dispatch.listEditor.handleListToast({ - name: truncate(dataForList?.name, 15), + name: truncate(dataForList?.name ?? "", 15), type: ListFormModalType.DOWNVOTE, }); } else { listsContractClient.upvote({ list_id: dataForList?.on_chain_id }); dispatch.listEditor.handleListToast({ - name: truncate(dataForList?.name, 15), + name: truncate(dataForList?.name ?? "", 15), type: ListFormModalType.UPVOTE, }); } @@ -111,7 +111,7 @@ export const ListCard = ({ > -

{truncate(dataForList.owner?.id, 25)}

+

{truncate(dataForList.owner?.id ?? "", 25)}

diff --git a/src/entities/list/components/ListDetails.tsx b/src/entities/list/components/ListDetails.tsx index 5ff518bc..c128693c 100644 --- a/src/entities/list/components/ListDetails.tsx +++ b/src/entities/list/components/ListDetails.tsx @@ -130,7 +130,7 @@ export const ListDetails = ({ admins, listId, listDetails, savedUsers }: ListDet .catch((error) => console.error("Error upvoting:", error)); dispatch.listEditor.handleListToast({ - name: truncate(listDetails?.name, 15), + name: truncate(listDetails?.name ?? "", 15), type: ListFormModalType.DOWNVOTE, }); } else { @@ -139,7 +139,7 @@ export const ListDetails = ({ admins, listId, listDetails, savedUsers }: ListDet .catch((error) => console.error("Error upvoting:", error)); dispatch.listEditor.handleListToast({ - name: truncate(listDetails?.name, 15), + name: truncate(listDetails?.name ?? "", 15), type: ListFormModalType.UPVOTE, }); } diff --git a/src/entities/list/hooks/registrations.ts b/src/entities/list/hooks/registrations.ts index 93208656..74d00171 100644 --- a/src/entities/list/hooks/registrations.ts +++ b/src/entities/list/hooks/registrations.ts @@ -3,7 +3,10 @@ import { useCallback, useMemo, useState } from "react"; import { indexer } from "@/common/api/indexer"; import { oldToRecent } from "@/common/lib"; import { ByListId, ChronologicalSortOrder, ChronologicalSortOrderVariant } from "@/common/types"; -import { AccountCategory, type AccountListRegistrationStatusVariant } from "@/entities/_shared"; +import { + AccountCategory, + type AccountListRegistrationStatusVariant, +} from "@/entities/_shared/account"; export type ListRegistrationLookupParams = ByListId & {}; diff --git a/src/entities/post/components/PostEditor.tsx b/src/entities/post/components/PostEditor.tsx index 631984df..49876925 100644 --- a/src/entities/post/components/PostEditor.tsx +++ b/src/entities/post/components/PostEditor.tsx @@ -11,7 +11,7 @@ import { useAccountSocialProfile } from "@/entities/_shared/account"; export const PostEditor = ({ accountId }: { accountId: AccountId }) => { const viewer = useWalletUserSession(); - const { avatarSrc } = useAccountSocialProfile({ + const { avatar } = useAccountSocialProfile({ enabled: viewer.isSignedIn, accountId: viewer.accountId as AccountId, }); @@ -36,8 +36,8 @@ export const PostEditor = ({ accountId }: { accountId: AccountId }) => {
{ }; /** - * @deprecated Use {@link useToken} capabilities. + * @deprecated Use {@link useFungibleToken} capabilities. */ export const useMatchingPoolBalance = ({ pot }: { pot?: Pot }) => { - const { data: nearToken } = useToken({ tokenId: NATIVE_TOKEN_ID }); + const { data: nearToken } = useFungibleToken({ tokenId: NATIVE_TOKEN_ID }); return useMemo(() => { if (pot) { diff --git a/src/entities/pot/components/PotDonationEntry.tsx b/src/entities/pot/components/PotDonationEntry.tsx index 4e0537d5..fd364ca4 100644 --- a/src/entities/pot/components/PotDonationEntry.tsx +++ b/src/entities/pot/components/PotDonationEntry.tsx @@ -56,7 +56,7 @@ export const PotDonationEntry = ({ > Donor profile image @@ -68,7 +68,7 @@ export const PotDonationEntry = ({ Recipient profile image diff --git a/src/entities/pot/components/PotDonationStats.tsx b/src/entities/pot/components/PotDonationStats.tsx index d07a287a..57257245 100644 --- a/src/entities/pot/components/PotDonationStats.tsx +++ b/src/entities/pot/components/PotDonationStats.tsx @@ -6,7 +6,7 @@ import { Pot } from "@/common/api/indexer"; import { NATIVE_TOKEN_ID } from "@/common/constants"; import { Toggle } from "@/common/ui/layout/svg"; import { AccountHandle, AccountProfilePicture } from "@/entities/_shared/account"; -import { useToken } from "@/entities/_shared/token"; +import { useFungibleToken } from "@/entities/_shared/token"; import { rootPathnames } from "@/pathnames"; import { Container, Row } from "./styled"; @@ -24,7 +24,7 @@ const Table = ({ title: string; }) => { const [usdToggle, setUsdToggle] = useState(false); - const { data: nativeToken } = useToken({ tokenId: NATIVE_TOKEN_ID }); + const { data: nativeToken } = useFungibleToken({ tokenId: NATIVE_TOKEN_ID }); return ( @@ -78,7 +78,7 @@ type DonationProps = { }; const Donation = ({ donorId, nearAmount, index, usdToggle }: DonationProps) => { - const { data: nativeToken } = useToken({ tokenId: NATIVE_TOKEN_ID }); + const { data: nativeToken } = useFungibleToken({ tokenId: NATIVE_TOKEN_ID }); const matchedAmount = usdToggle ? (nativeToken?.usdPrice?.mul(nearAmount).toFixed(2) ?? 0) diff --git a/src/entities/voting-round/components/WinnerRow.tsx b/src/entities/voting-round/components/WinnerRow.tsx index 09d49bf6..d9241a0f 100644 --- a/src/entities/voting-round/components/WinnerRow.tsx +++ b/src/entities/voting-round/components/WinnerRow.tsx @@ -14,7 +14,7 @@ import { } from "@/common/ui/layout/components"; import { cn } from "@/common/ui/layout/utils"; import { AccountListItem } from "@/entities/_shared/account"; -import { TokenIcon, useToken } from "@/entities/_shared/token"; +import { TokenIcon, useFungibleToken } from "@/entities/_shared/token"; import type { VotingRoundWinner } from "../types"; @@ -31,7 +31,7 @@ export const VotingRoundWinnerRow: React.FC = ({ isSelected = false, onSelect, }) => { - const { data: token } = useToken({ tokenId: NATIVE_TOKEN_ID }); + const { data: token } = useFungibleToken({ tokenId: NATIVE_TOKEN_ID }); const onCheckTriggered = useCallback( (checked: CheckedState) => onSelect?.(accountId, Boolean(checked)), diff --git a/src/entities/voting-round/hooks/results.ts b/src/entities/voting-round/hooks/results.ts index 71c0f06d..7e7cb7ad 100644 --- a/src/entities/voting-round/hooks/results.ts +++ b/src/entities/voting-round/hooks/results.ts @@ -8,7 +8,7 @@ import { potContractHooks } from "@/common/contracts/core/pot"; import { type ElectionId, votingContractHooks } from "@/common/contracts/core/voting"; import { indivisibleUnitsToBigNum } from "@/common/lib"; import type { ConditionalActivation } from "@/common/types"; -import { useToken } from "@/entities/_shared"; +import { useFungibleToken } from "@/entities/_shared/token"; import { usePotFeatureFlags } from "@/entities/pot"; import { useVotingRoundResultsStore } from "../model/results"; @@ -23,7 +23,7 @@ export const useVotingRoundResults = ({ const { data: potConfig } = potContractHooks.useConfig({ enabled, potId }); const { hasPFMechanism } = usePotFeatureFlags({ potId }); - const { data: matchingPoolToken } = useToken({ + const { data: matchingPoolToken } = useFungibleToken({ enabled: potConfig !== undefined, tokenId: diff --git a/src/entities/voting-round/hooks/voter-profile.ts b/src/entities/voting-round/hooks/voter-profile.ts index 886a846b..96ba686a 100644 --- a/src/entities/voting-round/hooks/voter-profile.ts +++ b/src/entities/voting-round/hooks/voter-profile.ts @@ -7,7 +7,7 @@ import { sybilResistanceContractHooks } from "@/common/contracts/core/sybil-resi import { METAPOOL_MPDAO_VOTING_POWER_DECIMALS } from "@/common/contracts/metapool"; import { indivisibleUnitsToBigNum } from "@/common/lib"; import { ByAccountId, type ConditionalActivation, TokenId } from "@/common/types"; -import { useToken } from "@/entities/_shared/token"; +import { useFungibleToken } from "@/entities/_shared/token"; import { VoterProfile } from "../types"; @@ -34,7 +34,7 @@ export const useVoterProfile = ({ [stakingContractAccountId, voterInfo?.voter_data.staking_token_id], ); - const { data: stakingToken } = useToken({ + const { data: stakingToken } = useFungibleToken({ enabled: tokenId !== undefined, tokenId: tokenId as TokenId, }); diff --git a/src/entities/voting-round/model/types.ts b/src/entities/voting-round/model/types.ts index ed2fdda5..fbe84899 100644 --- a/src/entities/voting-round/model/types.ts +++ b/src/entities/voting-round/model/types.ts @@ -1,5 +1,5 @@ import type { AccountId } from "@/common/types"; -import type { TokenData } from "@/entities/_shared"; +import type { TokenData } from "@/entities/_shared/token"; import type { VotingRoundVoterSummary, VotingRoundWinner } from "../types"; diff --git a/src/features/donation/components/campaign-success-share.tsx b/src/features/donation/components/campaign-success-share.tsx index 124fa68a..97382741 100644 --- a/src/features/donation/components/campaign-success-share.tsx +++ b/src/features/donation/components/campaign-success-share.tsx @@ -4,7 +4,6 @@ import Link from "next/link"; import { APP_DEFAULT_PUBLIC_URL, - DEFAULT_SHARE_HASHTAGS, PLATFORM_TWITTER_ACCOUNT_ID, X_INTENT_URL_BASE, } from "@/common/constants"; @@ -13,7 +12,7 @@ import type { AccountId, CampaignId } from "@/common/types"; import { Button, Skeleton } from "@/common/ui/layout/components"; import TwitterSvg from "@/common/ui/layout/svg/twitter"; import { useWalletUserSession } from "@/common/wallet"; -import { useAccountSocialProfile } from "@/entities/_shared"; +import { useAccountSocialProfile } from "@/entities/_shared/account"; import { routeSelectors } from "@/pathnames"; export type DonationCampaignSuccessXShareButtonProps = { diff --git a/src/features/donation/components/group-allocation-recipients.tsx b/src/features/donation/components/group-allocation-recipients.tsx index c9f0230c..4811bb97 100644 --- a/src/features/donation/components/group-allocation-recipients.tsx +++ b/src/features/donation/components/group-allocation-recipients.tsx @@ -5,7 +5,8 @@ import { CheckboxField, TextField } from "@/common/ui/form/components"; import { FormField, RuntimeErrorAlert } from "@/common/ui/layout/components"; import { NearIcon } from "@/common/ui/layout/svg"; import { useWalletUserSession } from "@/common/wallet"; -import { AccountListItem, useToken } from "@/entities/_shared"; +import { AccountListItem } from "@/entities/_shared/account"; +import { useFungibleToken } from "@/entities/_shared/token"; import { useEvenGroupDonationDistribution } from "../hooks/even-distribution"; import { useManualGroupDonationAllocation } from "../hooks/manual-allocation"; @@ -24,7 +25,7 @@ export const DonationGroupAllocationRecipients: React.FC< const listId = "listId" in props ? props.listId : undefined; const [tokenId, groupAllocationStrategy] = form.watch(["tokenId", "groupAllocationStrategy"]); - const { data: token } = useToken({ + const { data: token } = useFungibleToken({ tokenId, balanceCheckAccountId: viewer?.accountId, }); diff --git a/src/features/donation/components/group-allocation-success.tsx b/src/features/donation/components/group-allocation-success.tsx index 446dce1b..8ccb3869 100644 --- a/src/features/donation/components/group-allocation-success.tsx +++ b/src/features/donation/components/group-allocation-success.tsx @@ -20,7 +20,7 @@ import { } from "@/common/ui/layout/components"; import { useWalletUserSession } from "@/common/wallet"; import { AccountProfileLink } from "@/entities/_shared/account"; -import { TokenValueSummary, useToken } from "@/entities/_shared/token"; +import { TokenValueSummary, useFungibleToken } from "@/entities/_shared/token"; import { rootPathnames } from "@/pathnames"; import { DonationHumanVerificationAlert } from "./human-verification-alert"; @@ -63,7 +63,7 @@ export const DonationGroupAllocationSuccessScreen: React.FC< [], ); - const { isLoading: isTokenLoading, data: token } = useToken({ tokenId }); + const { isLoading: isTokenLoading, data: token } = useFungibleToken({ tokenId }); type DerivedOutcome = { recipientAccountIds: AccountId[]; diff --git a/src/features/donation/components/group-allocation.tsx b/src/features/donation/components/group-allocation.tsx index 7a4c2b22..47701e12 100644 --- a/src/features/donation/components/group-allocation.tsx +++ b/src/features/donation/components/group-allocation.tsx @@ -21,7 +21,12 @@ import { Skeleton, } from "@/common/ui/layout/components"; import { useWalletUserSession } from "@/common/wallet"; -import { TokenBalance, TokenSelector, TokenValueSummary, useToken } from "@/entities/_shared/token"; +import { + TokenBalance, + TokenSelector, + TokenValueSummary, + useFungibleToken, +} from "@/entities/_shared/token"; import { DonationGroupAllocationRecipients } from "./group-allocation-recipients"; import { DonationHumanVerificationAlert } from "./human-verification-alert"; @@ -51,7 +56,7 @@ export const DonationGroupAllocation: React.FC = ( const [tokenId, groupAllocationStrategy] = form.watch(["tokenId", "groupAllocationStrategy"]); const amountError = useMemo(() => form.formState.errors.amount, [form.formState.errors.amount]); - const { data: token } = useToken({ + const { data: token } = useFungibleToken({ tokenId, balanceCheckAccountId: viewer?.accountId, }); diff --git a/src/features/donation/components/single-recipient-allocation.tsx b/src/features/donation/components/single-recipient-allocation.tsx index 6d38f1f9..fc51a898 100644 --- a/src/features/donation/components/single-recipient-allocation.tsx +++ b/src/features/donation/components/single-recipient-allocation.tsx @@ -23,7 +23,7 @@ import { Skeleton, } from "@/common/ui/layout/components"; import { useWalletUserSession } from "@/common/wallet"; -import { TokenBalance, TokenSelector, useToken } from "@/entities/_shared/token"; +import { TokenBalance, TokenSelector, useFungibleToken } from "@/entities/_shared/token"; import { DonationHumanVerificationAlert } from "./human-verification-alert"; import { DONATION_ALLOCATION_STRATEGIES } from "../constants"; @@ -46,7 +46,7 @@ export const DonationSingleRecipientAllocation: React.FC< "potAccountId", ]); - const { data: token } = useToken({ + const { data: token } = useFungibleToken({ tokenId, balanceCheckAccountId: walletUser?.accountId, }); diff --git a/src/features/donation/components/single-recipient-success-share.tsx b/src/features/donation/components/single-recipient-success-share.tsx index 45ab67bd..76ad00be 100644 --- a/src/features/donation/components/single-recipient-success-share.tsx +++ b/src/features/donation/components/single-recipient-success-share.tsx @@ -13,7 +13,7 @@ import type { AccountId } from "@/common/types"; import { Button, Skeleton } from "@/common/ui/layout/components"; import TwitterSvg from "@/common/ui/layout/svg/twitter"; import { useWalletUserSession } from "@/common/wallet"; -import { useAccountSocialProfile } from "@/entities/_shared"; +import { useAccountSocialProfile } from "@/entities/_shared/account"; import { rootPathnames } from "@/pathnames"; export type DonationSingleRecipientSuccessXShareButtonProps = { diff --git a/src/features/donation/components/single-recipient-success.tsx b/src/features/donation/components/single-recipient-success.tsx index 0a3928a1..f3875d09 100644 --- a/src/features/donation/components/single-recipient-success.tsx +++ b/src/features/donation/components/single-recipient-success.tsx @@ -18,7 +18,7 @@ import { Skeleton, } from "@/common/ui/layout/components"; import { AccountProfileLink } from "@/entities/_shared/account"; -import { TokenValueSummary, useToken } from "@/entities/_shared/token"; +import { TokenValueSummary, useFungibleToken } from "@/entities/_shared/token"; import { routeSelectors } from "@/pathnames"; import { DonationHumanVerificationAlert } from "./human-verification-alert"; @@ -89,7 +89,7 @@ export const DonationSingleRecipientSuccessScreen: React.FC< } else return NATIVE_TOKEN_ID; }, [isCampaignDonation, isDirectDonation, receipt]); - const { isLoading: isTokenLoading, data: token } = useToken({ tokenId }); + const { isLoading: isTokenLoading, data: token } = useFungibleToken({ tokenId }); const isLoading = isResultLoading || isCampaignLoading || isPotLoading || isTokenLoading; diff --git a/src/features/donation/components/user-entrypoints.tsx b/src/features/donation/components/user-entrypoints.tsx index a6f8e959..d323d4f1 100644 --- a/src/features/donation/components/user-entrypoints.tsx +++ b/src/features/donation/components/user-entrypoints.tsx @@ -1,7 +1,7 @@ import { ByPotId, indexer } from "@/common/api/indexer"; import { NOOP_STRING, PUBLIC_GOODS_REGISTRY_LIST_ID } from "@/common/constants"; import { type ByAccountId, ByCampaignId, ByListId } from "@/common/types"; -import { Button, Skeleton } from "@/common/ui/layout/components"; +import { Button, type ButtonProps, Skeleton } from "@/common/ui/layout/components"; import { cn } from "@/common/ui/layout/utils"; import { type DonationUserFlowProps, useDonationUserFlow } from "../hooks/user-flow"; @@ -38,13 +38,20 @@ export const DonateRandomly = () => { ); }; -export type DonateToAccountButtonProps = ByAccountId & {}; +export type DonateToAccountButtonProps = ByAccountId & Pick & {}; -export const DonateToAccountButton: React.FC = ({ accountId }) => { +export const DonateToAccountButton: React.FC = ({ + accountId, + variant: variantProp, +}) => { const { openDonationModal } = useDonationUserFlow({ accountId }); return ( - ); diff --git a/src/features/donation/hooks/form.ts b/src/features/donation/hooks/form.ts index b72f8684..ccd4e579 100644 --- a/src/features/donation/hooks/form.ts +++ b/src/features/donation/hooks/form.ts @@ -13,7 +13,7 @@ import type { TokenId } from "@/common/types"; import { useEnhancedForm } from "@/common/ui/form/hooks"; import { useToast } from "@/common/ui/layout/hooks"; import { useWalletUserSession } from "@/common/wallet"; -import { useToken } from "@/entities/_shared"; +import { useFungibleToken } from "@/entities/_shared/token"; import { extractMatchingPots } from "@/entities/pot"; import { dispatch } from "@/store"; @@ -131,7 +131,7 @@ export const useDonationForm = ({ cachedTokenId, ...params }: DonationFormParams values.allocationStrategy === DonationAllocationStrategyEnum.share && values.potAccountId !== undefined; - const { data: token } = useToken({ + const { data: token } = useFungibleToken({ tokenId: values.tokenId ?? NATIVE_TOKEN_ID, balanceCheckAccountId: viewer?.accountId, }); diff --git a/src/features/donation/models/effects/campaign-ft-donation.ts b/src/features/donation/models/effects/campaign-ft-donation.ts index c2f879da..bff0daea 100644 --- a/src/features/donation/models/effects/campaign-ft-donation.ts +++ b/src/features/donation/models/effects/campaign-ft-donation.ts @@ -66,7 +66,7 @@ export const campaignFtDonationMulticall = async ({ .then(({ max }) => indivisibleUnitsToBigNum(max, NATIVE_TOKEN_DECIMALS)), /** - *? Checking the FT contract storage balance of the protocol fee recipient account + ** Checking the FT contract storage balance of the protocol fee recipient account */ bypassProtocolFee ? NOOP_BALANCE_VIEW @@ -80,7 +80,7 @@ export const campaignFtDonationMulticall = async ({ ), /** - *? Checking the FT contract storage balance of the campaigns contract account + ** Checking the FT contract storage balance of the campaigns contract account */ tokenClient .view< @@ -92,7 +92,7 @@ export const campaignFtDonationMulticall = async ({ ), /** - *? Checking the FT contract storage balance of the campaign creator account + ** Checking the FT contract storage balance of the campaign creator account */ bypassCreatorFee ? NOOP_BALANCE_VIEW @@ -106,7 +106,7 @@ export const campaignFtDonationMulticall = async ({ ), /** - *? Checking the FT contract storage balance of the donation recipient account + ** Checking the FT contract storage balance of the donation recipient account */ tokenClient .view< @@ -133,7 +133,7 @@ export const campaignFtDonationMulticall = async ({ .then((_updatedDonationContractStorageBalance) => tokenClient.callMultiple([ /** - *? FT contract storage balance replenishment for the protocol fee recipient account + ** FT contract storage balance replenishment for the protocol fee recipient account */ ...(!bypassProtocolFee && protocolFeeRecipientFtStorageBalanceBig.lt(maxFtStorageBalanceBig) @@ -152,7 +152,7 @@ export const campaignFtDonationMulticall = async ({ : []), /** - *? FT contract storage balance replenishment for the referrer account + ** FT contract storage balance replenishment for the referrer account */ ...(referrerStorageBalanceBig !== null && referrerStorageBalanceBig.lt(maxFtStorageBalanceBig) @@ -171,7 +171,7 @@ export const campaignFtDonationMulticall = async ({ : []), /** - *? FT contract storage balance replenishment for the donation contract account + ** FT contract storage balance replenishment for the donation contract account */ ...(donationContractFtStorageBalanceBig.lt(maxFtStorageBalanceBig) ? [ @@ -189,7 +189,7 @@ export const campaignFtDonationMulticall = async ({ : []), /** - *? FT contract storage balance replenishment for the campaign creator account + ** FT contract storage balance replenishment for the campaign creator account */ ...(!bypassCreatorFee && creatorFtStorageBalanceBig.lt(maxFtStorageBalanceBig) ? [ @@ -207,7 +207,7 @@ export const campaignFtDonationMulticall = async ({ : []), /** - *? FT contract storage balance replenishment for the donation recipient account + ** FT contract storage balance replenishment for the donation recipient account */ ...(recipientFtStorageBalanceBig.lt(maxFtStorageBalanceBig) ? [ @@ -262,7 +262,7 @@ export const campaignFtDonationMulticall = async ({ ); /** - *? Checking for the donation receipt signature + ** Checking for the donation receipt signature */ if (decodedReceipt.includes(campaignId.toString())) { try { diff --git a/src/features/donation/models/effects/direct-ft-donation.ts b/src/features/donation/models/effects/direct-ft-donation.ts index 75cc6764..fd5a490b 100644 --- a/src/features/donation/models/effects/direct-ft-donation.ts +++ b/src/features/donation/models/effects/direct-ft-donation.ts @@ -58,7 +58,7 @@ export const directFtDonationMulticall = async ({ .then(({ max }) => indivisibleUnitsToBigNum(max, NATIVE_TOKEN_DECIMALS)), /** - *? Checking the FT contract storage balance of the protocol fee recipient account + ** Checking the FT contract storage balance of the protocol fee recipient account */ bypassProtocolFee ? NOOP_BALANCE_VIEW @@ -72,7 +72,7 @@ export const directFtDonationMulticall = async ({ ), /** - *? Checking the FT contract storage balance of the donation contract account + ** Checking the FT contract storage balance of the donation contract account */ tokenClient .view< @@ -84,7 +84,7 @@ export const directFtDonationMulticall = async ({ ), /** - *? Checking the FT contract storage balance of the donation recipient account + ** Checking the FT contract storage balance of the donation recipient account */ tokenClient .view< @@ -110,7 +110,7 @@ export const directFtDonationMulticall = async ({ .then((_updatedDonationContractStorageBalance) => tokenClient.callMultiple([ /** - *? FT contract storage balance replenishment for the protocol fee recipient account + ** FT contract storage balance replenishment for the protocol fee recipient account */ ...(!bypassProtocolFee && protocolFeeRecipientFtStorageBalanceBig.lt(maxFtStorageBalanceBig) @@ -129,7 +129,7 @@ export const directFtDonationMulticall = async ({ : []), /** - *? FT contract storage balance replenishment for the referrer account + ** FT contract storage balance replenishment for the referrer account */ ...(referrerStorageBalanceBig !== null && referrerStorageBalanceBig.lt(maxFtStorageBalanceBig) @@ -148,7 +148,7 @@ export const directFtDonationMulticall = async ({ : []), /** - *? FT contract storage balance replenishment for the donation contract account + ** FT contract storage balance replenishment for the donation contract account */ ...(donationContractFtStorageBalanceBig.lt(maxFtStorageBalanceBig) ? [ @@ -166,7 +166,7 @@ export const directFtDonationMulticall = async ({ : []), /** - *? FT contract storage balance replenishment for the donation recipient account + ** FT contract storage balance replenishment for the donation recipient account */ ...(recipientFtStorageBalanceBig.lt(maxFtStorageBalanceBig) ? [ @@ -220,7 +220,7 @@ export const directFtDonationMulticall = async ({ ); /** - *? Checking for the donation receipt signature + ** Checking for the donation receipt signature */ if (decodedReceipt.includes(recipientAccountId)) { try { diff --git a/src/features/pot-application/hooks/clearance.ts b/src/features/pot-application/hooks/clearance.ts index 17065786..bd0a89fc 100644 --- a/src/features/pot-application/hooks/clearance.ts +++ b/src/features/pot-application/hooks/clearance.ts @@ -8,7 +8,7 @@ import { METAPOOL_MPDAO_VOTING_POWER_DECIMALS } from "@/common/contracts/metapoo import { indivisibleUnitsToBigNum } from "@/common/lib"; import { type AccountId, ClearanceCheckResult } from "@/common/types"; import { useWalletUserSession } from "@/common/wallet"; -import { useToken } from "@/entities/_shared/token"; +import { useFungibleToken } from "@/entities/_shared/token"; import { POT_APPLICATION_REQUIREMENTS_MPDAO } from "../constants"; @@ -31,7 +31,7 @@ export const usePotApplicationUserClearance = ({ accountId: viewer.accountId as AccountId, }); - const { data: stakingToken } = useToken({ + const { data: stakingToken } = useFungibleToken({ balanceCheckAccountId: viewer.accountId, tokenId: staking.tokenId, }); diff --git a/src/features/profile-setup/components/AddFundingSourceModal.tsx b/src/features/profile-configuration/components/AddFundingSourceModal.tsx similarity index 89% rename from src/features/profile-setup/components/AddFundingSourceModal.tsx rename to src/features/profile-configuration/components/AddFundingSourceModal.tsx index b88d4ec0..9d37bbb5 100644 --- a/src/features/profile-setup/components/AddFundingSourceModal.tsx +++ b/src/features/profile-configuration/components/AddFundingSourceModal.tsx @@ -1,5 +1,6 @@ import { useCallback } from "react"; +import { TextAreaField } from "@/common/ui/form/components"; import { Button, Dialog, @@ -10,23 +11,20 @@ import { FormField, } from "@/common/ui/layout/components"; -import { CustomInput, CustomTextForm } from "./form-elements"; +import { CustomInput } from "./editor-elements"; import { useAddFundingSourceForm } from "../hooks/forms"; -import { AddFundingSourceInputs, type ProfileSetupInputs } from "../models/types"; +import { AddFundingSourceInputs, type ProfileConfigurationInputs } from "../models/types"; -export type ProfileSetupFundingSourceModalProps = { - data: ProfileSetupInputs["fundingSources"]; +export type ProfileConfigurationFundingSourceModalProps = { + data: ProfileConfigurationInputs["fundingSources"]; open?: boolean; onCloseClick?: () => void; editFundingIndex?: number; }; -export const ProfileSetupFundingSourceModal: React.FC = ({ - data: fundingSources = [], - open, - onCloseClick, - editFundingIndex, -}) => { +export const ProfileConfigurationFundingSourceModal: React.FC< + ProfileConfigurationFundingSourceModalProps +> = ({ data: fundingSources = [], open, onCloseClick, editFundingIndex }) => { const { form, errors } = useAddFundingSourceForm({ defaultValues: { description: "", @@ -140,12 +138,13 @@ export const ProfileSetupFundingSourceModal: React.FC ( - )} /> diff --git a/src/features/profile-setup/components/contract-modal.tsx b/src/features/profile-configuration/components/contract-modal.tsx similarity index 88% rename from src/features/profile-setup/components/contract-modal.tsx rename to src/features/profile-configuration/components/contract-modal.tsx index 8063fd44..9cc4fced 100644 --- a/src/features/profile-setup/components/contract-modal.tsx +++ b/src/features/profile-configuration/components/contract-modal.tsx @@ -13,23 +13,20 @@ import { } from "@/common/ui/layout/components"; import { AddChainSelector } from "./contracts-section"; -import { CustomInput } from "./form-elements"; -import type { ProfileSetupInputs } from "../models/types"; +import { CustomInput } from "./editor-elements"; +import type { ProfileConfigurationInputs } from "../models/types"; import validateEVMAddress from "../utils/validateEVMAddress"; -export type ProfileSetupSmartContractModalProps = { - data: ProfileSetupInputs["smartContracts"]; +export type ProfileConfigurationSmartContractModalProps = { + data: ProfileConfigurationInputs["smartContracts"]; open?: boolean; onCloseClick?: () => void; contractIndex: number; }; -export const ProfileSetupSmartContractModal: React.FC = ({ - data = [], - open, - onCloseClick, - contractIndex, -}) => { +export const ProfileConfigurationSmartContractModal: React.FC< + ProfileConfigurationSmartContractModalProps +> = ({ data = [], open, onCloseClick, contractIndex }) => { const [chain, setChain] = useState( data[contractIndex] && data[contractIndex][0] ? data[contractIndex][0] : "", ); diff --git a/src/features/profile-setup/components/contracts-section.tsx b/src/features/profile-configuration/components/contracts-section.tsx similarity index 86% rename from src/features/profile-setup/components/contracts-section.tsx rename to src/features/profile-configuration/components/contracts-section.tsx index d80e5b63..8e01a189 100644 --- a/src/features/profile-setup/components/contracts-section.tsx +++ b/src/features/profile-configuration/components/contracts-section.tsx @@ -1,4 +1,4 @@ -import { useCallback, useState } from "react"; +import { type CSSProperties, useCallback, useState } from "react"; import { validateNearAddress } from "@wpdas/naxios"; import { CircleAlert } from "lucide-react"; @@ -14,11 +14,29 @@ import { } from "@/common/ui/layout/components"; import Delete from "@/common/ui/layout/svg/Delete"; import Edit from "@/common/ui/layout/svg/Edit"; +import { cn } from "@/common/ui/layout/utils"; -import { CustomInput, Label } from "./form-elements"; -import type { ProfileSetupInputs } from "../models/types"; +import { CustomInput } from "./editor-elements"; +import type { ProfileConfigurationInputs } from "../models/types"; import validateEVMAddress from "../utils/validateEVMAddress"; +const Label = ({ + children, + className, + style, +}: { + children: React.ReactNode; + className?: string; + style?: CSSProperties; +}) => ( +

+ {children} +

+); + type AddChainSelectorProps = { onChange: (value: string) => void; defaultValue?: string; @@ -179,15 +197,15 @@ const SmartContract = ({ ); }; -export type ProfileSetupSmartContractsSectionProps = { - values: ProfileSetupInputs["smartContracts"]; +export type ProfileConfigurationSmartContractsSectionProps = { + values: ProfileConfigurationInputs["smartContracts"]; onEditClickHandler: (contractIndex: number) => void; }; -export const ProfileSetupSmartContractsSection = ({ +export const ProfileConfigurationSmartContractsSection = ({ values, onEditClickHandler, -}: ProfileSetupSmartContractsSectionProps) => { +}: ProfileConfigurationSmartContractsSectionProps) => { if (values && values.length > 0) { return ( <> diff --git a/src/features/profile-setup/components/dao-progress.tsx b/src/features/profile-configuration/components/dao-progress.tsx similarity index 95% rename from src/features/profile-setup/components/dao-progress.tsx rename to src/features/profile-configuration/components/dao-progress.tsx index 9e8388d2..4d4de6cc 100644 --- a/src/features/profile-setup/components/dao-progress.tsx +++ b/src/features/profile-configuration/components/dao-progress.tsx @@ -2,7 +2,7 @@ import Link from "next/link"; import { Button } from "@/common/ui/layout/components"; -export const ProfileSetupDaoProgress = () => { +export const ProfileConfigurationDaoProgress = () => { const { daoProjectProposal, daoAddress } = { daoProjectProposal: { id: 0 }, daoAddress: undefined, diff --git a/src/features/profile-setup/components/form-elements.tsx b/src/features/profile-configuration/components/editor-elements.tsx similarity index 67% rename from src/features/profile-setup/components/form-elements.tsx rename to src/features/profile-configuration/components/editor-elements.tsx index 0ec95f09..2c4abb80 100644 --- a/src/features/profile-setup/components/form-elements.tsx +++ b/src/features/profile-configuration/components/editor-elements.tsx @@ -1,6 +1,7 @@ -import { CSSProperties, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { + FormLabel, Input, InputProps, MultiSelector, @@ -9,7 +10,6 @@ import { MultiSelectorItem, MultiSelectorList, MultiSelectorTrigger, - Textarea, } from "@/common/ui/layout/components"; import { cn } from "@/common/ui/layout/utils"; import { ACCOUNT_CATEGORY_VARIANTS } from "@/entities/_shared/account"; @@ -39,29 +39,6 @@ export const Row = ({ children }: { children: React.ReactNode }) => (
{children}
); -export const InputContainer = ({ children }: { children: React.ReactNode }) => ( -
- {children} -
-); - -export const Label = ({ - children, - className, - style, -}: { - children: React.ReactNode; - className?: string; - style?: CSSProperties; -}) => ( -

- {children} -

-); - type CustomInputProps = { label: string; inputProps: InputProps; @@ -79,11 +56,11 @@ export const CustomInput = ({ prefix, prefixMinWidth, }: CustomInputProps) => ( - -