Fix/UI#553
Conversation
|
Caution Review failedThe pull request is closed. WalkthroughRemoves several Account modal screens and a modal hook, consolidates connection cards into a single ConnectionCard and Kit settings into a new SettingsContent, adds directional modal animations and content-keying, updates navigation targets and theme tokens, and adds avatar cross-app fallbacks and multiple UI refinements. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 2 inconclusive)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/vechain-kit/src/components/AccountModal/Contents/Ecosystem/ExploreEcosystemContent.tsx (1)
127-167: Guard againstvbdAppsbeing undefined before calling.filter().
useMostVotedAppsInRound(...)can plausibly returnundefinedwhile loading/error;vbdApps.filter(...)would crash the modal.- const filteredVbdApps = isMainnet - ? vbdApps.filter((dapp) => - dapp.app.name.toLowerCase().includes(searchQuery.toLowerCase()), - ) - : []; + const filteredVbdApps = isMainnet + ? (vbdApps ?? []).filter((dapp) => + dapp.app.name.toLowerCase().includes(searchQuery.toLowerCase()), + ) + : [];packages/vechain-kit/src/theme/tokens.ts (1)
470-475: Inconsistent sticky-header blur defaults (20px vs 12px).
You bumpeddefaultBlur.stickyHeadertoblur(20px), but the actual default theme tokens still sayblur(12px)foreffects.backdropFilter.stickyHeader, so most paths will continue to render 12px.const defaultLightTokens: ThemeTokens = { effects: { backdropFilter: { modal: 'blur(3px)', overlay: 'blur(3px)', - stickyHeader: 'blur(12px)', + stickyHeader: 'blur(20px)', }, ... const defaultDarkTokens: ThemeTokens = { effects: { backdropFilter: { modal: 'blur(3px)', overlay: 'blur(3px)', - stickyHeader: 'blur(12px)', + stickyHeader: 'blur(20px)', },Also applies to: 561-567, 654-660
packages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx (1)
72-93: Add query enablement to prevent unnecessary contract calls.The query lacks an
enabledproperty, which means it will attempt to execute even whenxAppIdis empty or invalid, potentially causing errors or wasting resources.As per coding guidelines, always conditionally enable queries by checking for all required parameters.
Apply this diff:
return useQuery({ queryKey: ['xAppMetaData', xAppId], queryFn: async () => { const address = getConfig(network.type).x2EarnAppsContractAddress; const contract = thor.contracts.load(address, abi); const appDetailsResult = await contract.read.app( xAppId as `0x${string}`, ); const appDetails = appDetailsResult[0] as unknown as unknown[]; const metadataURI = appDetails[3]?.toString() || ''; const [baseUri] = await contract.read.baseURI(); const metadata = await getXAppMetadata( `${baseUri}${metadataURI}`, network.type, ); return metadata; }, + enabled: !!xAppId, });
🧹 Nitpick comments (8)
packages/vechain-kit/src/components/ProfileCard/ProfileCard.tsx (1)
160-210: Optional: stabilize inline default handlers withuseCallback
The fallbackonClickhandlers are created each render; not a blocker, but easy to make more stable/traceable.packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx (1)
172-175: Fix useMemo dependencies to enable proper memoization.The dependency
[getChangedValues]references a non-memoized function that's redefined on every render, causing the useMemo to re-compute every time and defeating its purpose.Solution: Use actual value dependencies instead of the function reference.
-const hasChanges = useMemo(() => { - const changes = getChangedValues(); - return Object.keys(changes).length > 0; -}, [getChangedValues]); +const hasChanges = useMemo(() => { + const changes = getChangedValues(); + return Object.keys(changes).length > 0; +}, [avatarIpfsHash, initialAvatarHash, formValues.displayName, formValues.description, initialDisplayName, initialDescription]);Alternative: Wrap getChangedValues in useCallback.
-const getChangedValues = () => { +const getChangedValues = useCallback(() => { const changes: { avatarIpfsHash?: string; displayName?: string; description?: string; } = {}; if (avatarIpfsHash !== initialAvatarHash && avatarIpfsHash) changes.avatarIpfsHash = avatarIpfsHash; if (formValues.displayName !== initialDisplayName) changes.displayName = formValues.displayName; if (formValues.description !== initialDescription) changes.description = formValues.description; return changes; -}; +}, [avatarIpfsHash, initialAvatarHash, formValues.displayName, formValues.description, initialDisplayName, initialDescription]);packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx (1)
13-31: Consider guardingIntersectionObserverfor non-supporting environments.
IfIntersectionObserveris unavailable, this will throw inuseEffect. A small feature-detect fallback would make the header more robust.useEffect(() => { + if (typeof IntersectionObserver === 'undefined') { + // Best-effort fallback: behave as if content is below (enable blur) + setHasContentBelow(true); + return; + } const observer = new IntersectionObserver( ([entry]) => { setHasContentBelow(!entry.isIntersecting); }, { threshold: 0 }, );packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/ConnectionDetailsContent.tsx (1)
13-15: Nice simplification; minor cleanup:?? undefinedis redundant- const connectionCache = getConnectionCache() ?? undefined; + const connectionCache = getConnectionCache();Also applies to: 24-42
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx (3)
12-40: Prefer a singlereact-icons/luimport
You import fromreact-icons/lutwice; consider merging to one import for cleanliness.
215-221:exportWallet()should be wrapped with basic error handling / UX feedback
If export fails (popup blocked, provider error), the user currently gets no feedback.
90-93: Consider awaitingdisconnect()before callingonLogoutSuccess()The
disconnect()function fromuseWalletreturnsPromise<void>and asynchronously cleans up wallet connection state and triggers state updates. CallingonLogoutSuccess()immediately without awaiting may cause it to execute before state cleanup completes, potentially resulting in stale state or UI flicker on subsequent interactions.- const handleLogout = () => { - disconnect(); - onLogoutSuccess(); - }; + const handleLogout = async () => { + await disconnect(); + onLogoutSuccess(); + };Also applies to: 278-290
packages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx (1)
78-89: Consider parallelizing independent contract reads.The two contract reads (
appandbaseURI) are executed sequentially, but they're independent and could be parallelized for better performance. The coding guidelines recommend usingexecuteMultipleClausesCallfor multiple parallel contract calls.Consider refactoring to execute both reads in parallel:
import { executeMultipleClausesCall } from '@/utils/contract'; return useQuery({ queryKey: ['xAppMetaData', xAppId], queryFn: async () => { const address = getConfig(network.type).x2EarnAppsContractAddress; const results = await executeMultipleClausesCall( thor, [ { address, abi, method: 'app', args: [xAppId as `0x${string}`], }, { address, abi, method: 'baseURI', args: [], }, ] ); const appDetails = results[0][0] as unknown[]; const metadataURI = appDetails[3]?.toString() || ''; const baseUri = results[1][0]; return getXAppMetadata(`${baseUri}${metadataURI}`, network.type); }, enabled: !!xAppId, });This executes both contract reads in parallel, reducing total execution time.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (37)
examples/homepage/src/app/components/features/FeaturesToTry/FeaturesToTry.tsx(1 hunks)examples/homepage/src/app/providers/VechainKitProviderWrapper.tsx(2 hunks)packages/vechain-kit/src/components/AccountModal/AccountModal.tsx(3 hunks)packages/vechain-kit/src/components/AccountModal/Contents/Account/AccessAndSecurityContent.tsx(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/Account/EmbeddedWalletContent.tsx(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/Account/SettingsContent.tsx(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/Account/index.ts(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/ConnectionCard.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/CrossAppConnectionCard.tsx(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/DappKitConnectionCard.tsx(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/NetworkInfo.tsx(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/PrivyConnectionCard.tsx(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/WalletSecuredBy.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/index.ts(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/ConnectionDetailsContent.tsx(3 hunks)packages/vechain-kit/src/components/AccountModal/Contents/DisconnectConfirmation/index.ts(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/Ecosystem/ExploreEcosystemContent.tsx(3 hunks)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/AppearanceSettingsContent.tsx(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/ChangeCurrencyContent.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/GasTokenSettingsContent.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/GeneralSettingsContent.tsx(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/LanguageSettingsContent.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/index.ts(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/Profile/ProfileContent.tsx(0 hunks)packages/vechain-kit/src/components/AccountModal/Contents/UpgradeSmartAccount/UpgradeSmartAccountContent.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/index.ts(1 hunks)packages/vechain-kit/src/components/AccountModal/Types/Types.ts(1 hunks)packages/vechain-kit/src/components/LegalDocumentsModal/LegalDocumentsModal.tsx(1 hunks)packages/vechain-kit/src/components/ProfileCard/ProfileCard.tsx(1 hunks)packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx(2 hunks)packages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx(1 hunks)packages/vechain-kit/src/hooks/modals/index.ts(0 hunks)packages/vechain-kit/src/hooks/modals/useAccessAndSecurityModal.tsx(0 hunks)packages/vechain-kit/src/languages/en.json(1 hunks)packages/vechain-kit/src/theme/tokens.ts(1 hunks)
💤 Files with no reviewable changes (13)
- packages/vechain-kit/src/hooks/modals/index.ts
- packages/vechain-kit/src/components/AccountModal/Contents/Profile/ProfileContent.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/GeneralSettingsContent.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/Account/EmbeddedWalletContent.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/AppearanceSettingsContent.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/PrivyConnectionCard.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/CrossAppConnectionCard.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/DappKitConnectionCard.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/NetworkInfo.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/Account/SettingsContent.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/Account/index.ts
- packages/vechain-kit/src/hooks/modals/useAccessAndSecurityModal.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/Account/AccessAndSecurityContent.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/migration-guide-to-v2.mdc)
**/*.{ts,tsx}: In VeChain Kit Version 2, useuseThorinstead ofuseConnexfor contract interactions
For single contract read operations, use theuseCallClausehook with the pattern: import dependencies, define ABI and method as const, create query key function usinggetCallClauseQueryKeyWithArgs, and wrap with useCallClause including data transformation in the select option
For multiple parallel contract calls, use theexecuteMultipleClausesCallutility wrapped in auseQueryhook with the pattern: define query key function, useexecuteMultipleClausesCallin queryFn mapping items to clause objects, and transform results
For transaction building and sending, use theuseBuildTransactionhook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action
Always provide an arguments array for contract calls, even when no parameters are required - use an empty array for parameter-less functions to enable TypeScript type checking
Always conditionally enable queries using theenabledproperty to prevent unnecessary contract calls, checking for all required parameters:enabled: !!requiredParam && !!otherRequiredParam
Use theselectoption in useCallClause or transform data in queryFn to handle data transformation, particularly for converting BigInt values to strings and normalizing contract return data
Maintain consistent query key patterns: usegetCallClauseQueryKeyWithArgsfor contract calls with arguments andgetCallClauseQueryKeyfor calls without arguments to ensure proper caching and invalidation
Use TypeScriptas constassertions for method names andas0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions
Files:
packages/vechain-kit/src/theme/tokens.tspackages/vechain-kit/src/components/AccountModal/Contents/index.tspackages/vechain-kit/src/components/LegalDocumentsModal/LegalDocumentsModal.tsxpackages/vechain-kit/src/components/AccountModal/Contents/DisconnectConfirmation/index.tspackages/vechain-kit/src/components/AccountModal/Contents/KitSettings/index.tspackages/vechain-kit/src/components/AccountModal/Contents/KitSettings/ChangeCurrencyContent.tsxpackages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsxpackages/vechain-kit/src/components/AccountModal/Contents/UpgradeSmartAccount/UpgradeSmartAccountContent.tsxexamples/homepage/src/app/providers/VechainKitProviderWrapper.tsxpackages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/WalletSecuredBy.tsxexamples/homepage/src/app/components/features/FeaturesToTry/FeaturesToTry.tsxpackages/vechain-kit/src/components/AccountModal/Contents/KitSettings/LanguageSettingsContent.tsxpackages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/index.tspackages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/ConnectionDetailsContent.tsxpackages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsxpackages/vechain-kit/src/components/AccountModal/Types/Types.tspackages/vechain-kit/src/components/AccountModal/Contents/KitSettings/GasTokenSettingsContent.tsxpackages/vechain-kit/src/components/ProfileCard/ProfileCard.tsxpackages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/ConnectionCard.tsxpackages/vechain-kit/src/components/common/StickyHeaderContainer.tsxpackages/vechain-kit/src/components/AccountModal/Contents/Ecosystem/ExploreEcosystemContent.tsxpackages/vechain-kit/src/components/AccountModal/AccountModal.tsxpackages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx
🧠 Learnings (2)
📚 Learning: 2025-12-01T13:01:33.771Z
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : In VeChain Kit Version 2, use `useThor` instead of `useConnex` for contract interactions
Applied to files:
packages/vechain-kit/src/components/LegalDocumentsModal/LegalDocumentsModal.tsxexamples/homepage/src/app/providers/VechainKitProviderWrapper.tsxpackages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/index.tspackages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/ConnectionDetailsContent.tsxpackages/vechain-kit/src/components/common/StickyHeaderContainer.tsxpackages/vechain-kit/src/components/AccountModal/Contents/Ecosystem/ExploreEcosystemContent.tsxpackages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx
📚 Learning: 2025-12-01T13:01:33.771Z
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : For single contract read operations, use the `useCallClause` hook with the pattern: import dependencies, define ABI and method as const, create query key function using `getCallClauseQueryKeyWithArgs`, and wrap with useCallClause including data transformation in the select option
Applied to files:
packages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx
🧬 Code graph analysis (6)
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx (7)
packages/vechain-kit/src/hooks/modals/useAccountModalOptions.tsx (1)
useAccountModalOptions(3-10)packages/vechain-kit/src/providers/VeChainKitProvider.tsx (1)
useVeChainKitConfig(204-210)packages/vechain-kit/src/hooks/thor/smartAccounts/useUpgradeRequired.ts (1)
useUpgradeRequired(60-85)packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx (1)
StickyHeaderContainer(9-63)packages/vechain-kit/src/components/common/ModalBackButton.tsx (1)
ModalBackButton(8-23)packages/vechain-kit/src/components/AccountModal/Contents/Account/SettingsContent.tsx (1)
SettingsContentProps(34-239)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/GeneralSettingsContent.tsx (1)
Props(35-136)
packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/ConnectionDetailsContent.tsx (2)
packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/ConnectionCard.tsx (1)
ConnectionCard(40-231)packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/WalletSecuredBy.tsx (1)
WalletSecuredBy(8-70)
packages/vechain-kit/src/components/ProfileCard/ProfileCard.tsx (2)
packages/vechain-kit/src/components/common/AccountAvatar.tsx (1)
AccountAvatar(10-43)packages/vechain-kit/src/components/common/AddressDisplay.tsx (1)
AddressDisplay(27-177)
packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/ConnectionCard.tsx (7)
packages/vechain-kit/src/types/types.ts (1)
CrossAppConnectionCache(151-159)packages/vechain-kit/src/providers/VeChainKitProvider.tsx (1)
useVeChainKitConfig(204-210)packages/vechain-kit/src/hooks/api/privy/useFetchAppInfo.ts (1)
useFetchAppInfo(26-67)packages/vechain-kit/src/hooks/api/privy/useFetchPrivyStatus.ts (1)
useFetchPrivyStatus(19-37)packages/vechain-kit/src/hooks/thor/smartAccounts/useGetAccountVersion.ts (1)
useGetAccountVersion(27-47)packages/vechain-kit/src/config/index.ts (1)
getConfig(47-52)packages/vechain-kit/src/utils/formattingUtils.tsx (1)
humanAddress(5-9)
packages/vechain-kit/src/components/AccountModal/Contents/Ecosystem/ExploreEcosystemContent.tsx (1)
packages/vechain-kit/src/components/common/ModalBackButton.tsx (1)
ModalBackButton(8-23)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (1)
packages/vechain-kit/src/components/AccountModal/Contents/FailedOperation/FailedOperationContent.tsx (1)
FailedOperationContent(31-100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: e2e-test
- GitHub Check: Lint & Build
- GitHub Check: deploy
- GitHub Check: build-size-check
🔇 Additional comments (21)
packages/vechain-kit/src/components/AccountModal/Contents/UpgradeSmartAccount/UpgradeSmartAccountContent.tsx (1)
38-42: DefaultinginitialContentto'settings'is the right navigation fallback—just ensure the type/key matches the new flow.
GiveninitialContentis used as the back/close destination in several places, please double-check that'settings'is a validAccountModalContentTypesvalue (and the intended landing screen) after the refactor.packages/vechain-kit/src/components/AccountModal/Contents/Ecosystem/ExploreEcosystemContent.tsx (2)
109-112: Back navigation + isolated view gating look consistent with the new “settings” hub.
Hiding the back button inisolatedViewand routing back to'settings'matches the PR’s navigation consolidation.Also applies to: 208-212
238-242: Search icon update is fine.
UsinguseToken(...)and passing it toLuSearchkeeps styling centralized.packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/ChangeCurrencyContent.tsx (1)
64-69: Back navigation to'settings'aligns with removed “general-settings” flow.packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/GasTokenSettingsContent.tsx (1)
47-53: Back navigation to'settings'matches the new settings structure.packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/WalletSecuredBy.tsx (1)
14-20: Early return gating on Privy connectivity is a good simplification.examples/homepage/src/app/providers/VechainKitProviderWrapper.tsx (2)
33-57: Theme config changes look coherent with the new blur-heavy modal styling.
111-115: Hardcodingnetwork.type: 'main'may be surprising for an example app—verify intent.
If this is meant to stay configurable, consider reading from env (with a safe default).network={{ - type: 'main', + type: (process.env.NEXT_PUBLIC_VECHAIN_NETWORK as 'main' | 'test') ?? 'main', // nodeUrl: 'http://localhost:8669', }}packages/vechain-kit/src/components/AccountModal/Contents/index.ts (1)
13-13: Re-export ofDisconnectConfirmationlooks consistent with the new structure
Just double-check this is an intended public API addition for external consumers (not only internal wiring).packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/LanguageSettingsContent.tsx (1)
56-58: Back nav updated to consolidated'settings'
Please verifyAccountModalContentTypesand any persisted modal-state/deep-linking can’t still emit'general-settings'.packages/vechain-kit/src/components/AccountModal/Contents/DisconnectConfirmation/index.ts (1)
1-1: Good barrel export forDisconnectConfirmContentpackages/vechain-kit/src/components/AccountModal/Contents/KitSettings/index.ts (1)
4-4: ExportingSettingsContentfromKitSettingsmatches the consolidation
Please confirm this is aligned with your intended public API/semver expectations (removed sub-exports won’t break consumers).packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (3)
109-109: Render simplification is fine
Thefailed-operationbranch returning the component directly keeps behavior the same and reads cleaner.
186-187: Back target update aligns with removed settings sub-flows
RoutingPrivyLinkedAccountsback to'settings'looks consistent with the removed “access-and-security” content state.
30-30: VerifyDisconnectConfirmContentexport from./Contents/DisconnectConfirmationConfirm that
DisconnectConfirmContentis exported from the target module to prevent runtime import errors.packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx (2)
64-69:useUpgradeRequiredusage looks consistent with v2useThorguideline
Nice: the hook-levelenabledguard (peruseUpgradeRequired) should prevent unnecessary calls when addresses are empty. Based on learnings, this also aligns with “useuseThorinstead ofuseConnex”.Also applies to: 170-193
195-231: Verify gating for "Access and security" section —isConnectedWithSocialLoginmay be overly restrictiveSecurity-critical features like MFA enrollment, wallet backup, and linked accounts management should be available to all authenticated users. Confirm whether this section should be gated on
isConnectedWithSocialLoginor if it should be available to all Privy-connected users. IfisConnectedWithSocialLoginis too narrow, users who authenticated via other methods would be unable to access essential security controls.packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/index.ts (1)
1-1: Verify no downstream imports still reference removed card exportsSince this index now only re-exports
ConnectionCard, any existing imports ofCrossAppConnectionCard,DappKitConnectionCard, orPrivyConnectionCardwill break. Search the codebase to confirm these old exports are no longer referenced before merging this change.packages/vechain-kit/src/components/AccountModal/Types/Types.ts (2)
19-35: Verify no remaining navigation targets for removed content types
Ensure no UI still attempts to set content to'access-and-security','embedded-wallet','general-settings', or'appearance-settings'.
9-9: Verify old import path is fully removedEnsure that the old
../Contents/Account/DisconnectConfirmContentimport path has no remaining references in the codebase and that all callers use the new../Contents/DisconnectConfirmation/DisconnectConfirmContentpath consistently.packages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx (1)
82-83: Unsafe type casting and array access without validation.The double cast
as unknown as unknown[]bypasses TypeScript's type safety, and accessingappDetails[3]without bounds checking could cause runtime errors if the contract returns unexpected data. Verify the contract ABI to ensure the return type is properly typed, and if so, replace the unsafe assertion with proper type guards or use VeChain Kit v2'suseCallClausehook pattern with appropriate data transformation.
|
Size Change: -2 B (0%) Total Size: 5.43 MB
ℹ️ View Unchanged
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx (1)
172-175: Fix useMemo dependencies to enable proper memoization.
getChangedValuesis redefined on every render, so including it in the dependency array breaks memoization—hasChangesrecalculates every render, defeating the purpose ofuseMemo.Apply this diff to fix the memoization:
- const hasChanges = useMemo(() => { - const changes = getChangedValues(); - return Object.keys(changes).length > 0; - }, [getChangedValues]); + const hasChanges = useMemo(() => { + const changes = getChangedValues(); + return Object.keys(changes).length > 0; + }, [avatarIpfsHash, initialAvatarHash, formValues.displayName, initialDisplayName, formValues.description, initialDescription]);
♻️ Duplicate comments (1)
packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx (1)
233-245: Fix the upload overlay to actually cover the avatar.The upload overlay is still missing
position="absolute"and dimensions, so it won't overlay the avatar—it will render below it as a sibling. This is the same issue flagged in the previous review.Apply this diff to fix the overlay positioning:
{isUploading && ( <Box + position="absolute" + top="0" + left="0" + width="100px" + height="100px" + borderRadius="full" display="flex" alignItems="center" justifyContent="center" backgroundColor="rgba(0, 0, 0, 0.5)" - borderRadius="full" + zIndex="1" > <Text fontSize="xs" color="white"> {isUploading ? 'Uploading...' : 'Processing...'} </Text> </Box> )}
🧹 Nitpick comments (2)
packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx (2)
385-394: Remove unused cover input or complete the implementation.The
coverInputRefand its associated input exist but serve no purpose—the handler is a no-op placeholder. Either complete the cover upload feature or remove this unused code.If this is not planned for implementation, apply this diff:
- const coverInputRef = useRef<HTMLInputElement>(null);- <input - type="file" - ref={coverInputRef} - hidden - accept="image/*" - onChange={async (event) => { - /* Add cover upload handler */ - event.preventDefault(); - }} - />
256-292: Consider simplifying the navigation logic.The
onClickhandler has significant duplication between branches. Extracting the commoninitialContentSourcewould improve readability.Apply this diff to reduce duplication:
onClick={() => { + const commonInitialContentSource = { + type: 'account-customization' as const, + props: { + setCurrentContent, + }, + }; + if (account?.domain) { setCurrentContent({ type: 'choose-name-search', props: { name: '', setCurrentContent, - initialContentSource: { - type: 'account-customization', - props: { - setCurrentContent, - }, - }, + initialContentSource: commonInitialContentSource, }, }); } else { setCurrentContent({ type: 'choose-name', props: { setCurrentContent, - initialContentSource: { - type: 'account-customization', - props: { - setCurrentContent, - }, - }, + initialContentSource: commonInitialContentSource, onBack: () => - setCurrentContent({ - type: 'account-customization', - props: { - setCurrentContent, - }, - }), + setCurrentContent(commonInitialContentSource), }, }); } }}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/ChangeCurrencyContent.tsx(2 hunks)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/LanguageSettingsContent.tsx(2 hunks)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx(1 hunks)packages/vechain-kit/src/languages/en.json(1 hunks)packages/vechain-kit/src/theme/tokens.ts(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/vechain-kit/src/languages/en.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/migration-guide-to-v2.mdc)
**/*.{ts,tsx}: In VeChain Kit Version 2, useuseThorinstead ofuseConnexfor contract interactions
For single contract read operations, use theuseCallClausehook with the pattern: import dependencies, define ABI and method as const, create query key function usinggetCallClauseQueryKeyWithArgs, and wrap with useCallClause including data transformation in the select option
For multiple parallel contract calls, use theexecuteMultipleClausesCallutility wrapped in auseQueryhook with the pattern: define query key function, useexecuteMultipleClausesCallin queryFn mapping items to clause objects, and transform results
For transaction building and sending, use theuseBuildTransactionhook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action
Always provide an arguments array for contract calls, even when no parameters are required - use an empty array for parameter-less functions to enable TypeScript type checking
Always conditionally enable queries using theenabledproperty to prevent unnecessary contract calls, checking for all required parameters:enabled: !!requiredParam && !!otherRequiredParam
Use theselectoption in useCallClause or transform data in queryFn to handle data transformation, particularly for converting BigInt values to strings and normalizing contract return data
Maintain consistent query key patterns: usegetCallClauseQueryKeyWithArgsfor contract calls with arguments andgetCallClauseQueryKeyfor calls without arguments to ensure proper caching and invalidation
Use TypeScriptas constassertions for method names andas0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions
Files:
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsxpackages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsxpackages/vechain-kit/src/components/AccountModal/Contents/KitSettings/LanguageSettingsContent.tsxpackages/vechain-kit/src/theme/tokens.tspackages/vechain-kit/src/components/AccountModal/Contents/KitSettings/ChangeCurrencyContent.tsx
🧬 Code graph analysis (3)
packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx (3)
packages/vechain-kit/src/components/common/AccountAvatar.tsx (1)
AccountAvatar(10-43)packages/vechain-kit/src/components/AccountModal/Components/Alerts/DomainRequiredAlert.tsx (1)
DomainRequiredAlert(4-21)packages/vechain-kit/src/components/AccountModal/Components/ActionButton.tsx (1)
ActionButton(37-141)
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/LanguageSettingsContent.tsx (3)
packages/vechain-kit/src/components/common/ScrollToTopWrapper.tsx (1)
ScrollToTopWrapper(4-8)packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx (1)
StickyHeaderContainer(9-63)packages/vechain-kit/src/components/common/ModalBackButton.tsx (1)
ModalBackButton(8-23)
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/ChangeCurrencyContent.tsx (2)
packages/vechain-kit/src/utils/ssrUtils.ts (1)
setLocalStorageItem(23-32)packages/vechain-kit/src/types/types.ts (2)
CURRENCY(174-174)CURRENCY_SYMBOLS(176-180)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: e2e-test
- GitHub Check: Lint & Build
- GitHub Check: build-size-check
- GitHub Check: deploy
🔇 Additional comments (23)
packages/vechain-kit/src/theme/tokens.ts (3)
474-474: LGTM: Blur intensity increased for better visual effect.The default sticky header blur has been increased from 12px to 20px, providing a more pronounced glass effect when the feature is disabled or as a fallback. This aligns with the UI refinements in this PR.
549-549: LGTM: Consistent rounded button styling.Adding
rounded: 'full'creates fully rounded (pill-shaped) primary buttons in light mode, consistent with the dark theme update.
640-643: Verify the intentional theme inconsistency for primary buttons.The dark theme primary button now uses a white background with dark text (
blackAlpha.900), while the light theme primary button retains a purple background (rgb(96 66 221)) with white text. This creates a significant visual difference in primary call-to-action buttons across themes.Please confirm this design choice is intentional. Typically, primary buttons maintain similar visual weight and prominence across themes to ensure consistent user experience.
packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx (4)
88-100: Verify ifnetwork.typedependency is necessary.The effect depends on
network.typebut doesn't use it. If resetting the form on network changes is intentional, consider adding a comment to clarify. Otherwise, remove it from the dependency array.If
network.typeis not needed, apply this diff:- }, [account, network.type]); + }, [account]);
298-376: Well-structured form controls with proper validation.The Display Name and Description fields are properly implemented with
react-hook-form, validation rules, error display, and appropriate disabled states. The maxLength validations (25 for display name, 100 for description) and error messaging are clear.
105-138: Good error handling and state management in image upload.The image upload handler properly manages state transitions, creates preview URLs, handles errors with try-catch, and includes cleanup for old preview URLs. The IPFS upload integration is well-structured.
146-152: Excellent memory management practice.The cleanup effect properly revokes object URLs to prevent memory leaks. The comment explaining the purpose is helpful for maintainability.
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/LanguageSettingsContent.tsx (4)
10-10: LGTM!The
useColorModeValueimport is correctly added to support theme-aware styling for the selected language indicator.
30-33: LGTM! Color mode aware selection background.The selected background adapts appropriately to the color mode. Note the asymmetric alpha values (0.1 for light, 0.05 for dark) which may be intentional for visual balance across themes.
39-58: LGTM! Clean refactoring with improved code clarity.The refactored
renderLanguageButtoneffectively:
- Computes
isSelectedonce to avoid duplicate checks- Applies the selected background consistently
- Shows the check icon only for the selected language
66-66: LGTM! Navigation updated to consolidated settings.The back button now correctly navigates to the consolidated 'settings' content, aligning with the broader settings refactoring in this PR.
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/ChangeCurrencyContent.tsx (4)
11-11: LGTM!The
useColorModeValueimport is correctly added, maintaining consistency with the LanguageSettingsContent implementation.
37-40: LGTM! Consistent color mode styling.The
selectedBguses identical rgba values as LanguageSettingsContent, ensuring a uniform selected item appearance across settings screens.
47-69: LGTM! Consistent refactoring pattern.The
renderCurrencyButtonfollows the same clean refactoring pattern as LanguageSettingsContent:
- Single
isSelectedcomputation- Conditional background application
- Check icon displayed only when selected
76-76: LGTM! Aligned with settings consolidation.Back navigation correctly updated to 'settings', consistent with the broader refactoring.
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx (8)
1-40: LGTM! Well-organized imports.The imports are comprehensive and properly organized, supporting the consolidated settings functionality.
42-52: LGTM! Clear type definition and component signature.The
SettingsContentPropstype is well-defined with proper callback signatures for content navigation and logout handling.
102-169: LGTM! Well-structured general settings section.The general settings section is properly organized with:
- Currency selection
- Language selection
- Conditional gas token preferences (only shown for Privy connections without delegation)
- Terms and policies
The navigation logic correctly uses both string literals and object structures where appropriate.
171-194: LGTM! Smart account upgrade notification.The upgrade section is conditionally rendered based on
upgradeRequiredand includes:
- Clear call-to-action
- Visual indicator (red dot) for the upgrade notification
- Proper navigation with back navigation state
196-238: LGTM! Comprehensive access and security options.The access and security section is properly gated for social login users and provides:
- Passkey linking
- Wallet backup
- MFA management
- Login method management
All actions use the appropriate Privy hooks.
240-280: LGTM! Helpful support resources.The help section provides clear access to:
- FAQ with proper back navigation
- Connection details
- Ecosystem exploration
Navigation targets are correctly specified.
282-299: LGTM! Logout flow with confirmation.The logout button properly:
- Shows a visual divider
- Navigates to a confirmation modal with both
onDisconnectandonBackcallbacks- Handles the complete logout flow through
handleLogout
65-69: TheuseUpgradeRequiredhook already safely handles empty strings—no changes needed.The hook uses conditional query enabling (
enabled: !!thor && !!accountAddress && !!ownerAddress && !!network.typeat line 83) which prevents contract calls when addresses are empty strings. The code at lines 65-69 in SettingsContent.tsx is safe and follows VeChain Kit v2 guidelines correctly.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/vechain-kit/src/components/AccountModal/Contents/SendToken/SendTokenContent.tsx (2)
150-154: Max-fill should trigger validation/state updates (and avoid input quirks)
setValue('amount', selectedToken.balance)doesn’t request validation, soisValid/ error state can lag until the next edit; also considershouldDirtyfor UX consistency.const handleSetMaxAmount = () => { if (selectedToken) { - setValue('amount', selectedToken.balance); + setValue('amount', selectedToken.balance, { + shouldValidate: true, + shouldDirty: true, + }); } };
504-519: Guardens_normalize()— it can throw during typingIf
ens_normalize(trimmed)throws on invalid domain syntax, the input will crash onChange. Safer to try/catch and fall back to the raw value (validation can still handle errors).onChange={(e) => { const trimmed = e.target.value.trim(); // If the input contains a dot, treat it as a domain name and normalize it - const normalizedValue = - trimmed.includes('.') - ? ens_normalize(trimmed) - : trimmed; + let normalizedValue = trimmed; + if (trimmed.includes('.')) { + try { + normalizedValue = ens_normalize(trimmed); + } catch { + normalizedValue = trimmed; + } + } e.target.value = normalizedValue; setValue('toAddressOrDomain', normalizedValue, { shouldValidate: true, }); }}packages/vechain-kit/src/hooks/api/vetDomains/useGetAvatarOfAddress.ts (1)
45-50: Cache correctness: queryKey should include the network (network.type), not onlyaddress.
Without that, switching networks can serve a cached avatar resolved on a different network. Additionally, all call sites ofgetAvatarOfAddressQueryKeyneed to be updated to passnetwork.type.-export const getAvatarOfAddressQueryKey = (address?: string) => [ +export const getAvatarOfAddressQueryKey = (address?: string, networkType?: NETWORK_TYPE) => [ 'VECHAIN_KIT', 'VET_DOMAINS', 'AVATAR_OF_ADDRESS', + networkType, address, ]; export const useGetAvatarOfAddress = (address?: string) => { const { network } = useVeChainKitConfig(); return useQuery({ - queryKey: getAvatarOfAddressQueryKey(address), + queryKey: getAvatarOfAddressQueryKey(address, network.type), queryFn: async () => { ... },Also update calls in
useRefreshMetadata.ts,domainQueryUtils.ts, andCustomizationSummaryContent.tsxto passnetwork.type.
🧹 Nitpick comments (10)
packages/vechain-kit/src/theme/modal.ts (1)
14-14: LGTM - Consider testing on smaller viewports.The increased modal height from 550px to 600px aligns with the UI refinement objectives. The existing scroll behavior ensures content overflow is handled gracefully.
For improved responsiveness, consider testing this on smaller mobile viewports (e.g., iPhone SE at 667px height) to ensure the modal doesn't dominate the screen. Alternatively, using viewport-relative units like
maxHeight: '80vh'could provide better adaptability across different screen sizes.packages/vechain-kit/src/components/AccountModal/Contents/SendToken/SendTokenContent.tsx (2)
269-291: Balance formatting risks precision loss (Number overflow/rounding)
Number(selectedToken?.balance ?? 0)can lose precision (or becomeInfinity) for large/high-precision balances. Prefer formatting without converting to JSnumber(or use a project-wide “format token amount” util if you have one).Minimal local option (string-safe, no grouping):
+const format2dp = (v: string) => { + const [i, f = ''] = v.split('.'); + return `${i}.${(f + '00').slice(0, 2)}`; +}; // ... - {Number(selectedToken?.balance ?? 0).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} + {format2dp(selectedToken?.balance ?? '0')}
269-291: Clickable<Text>needs button semantics for accessibilityThis is effectively an action (“set max”), but it’s not keyboard-focusable by default. Prefer a Chakra
Button(variant="link") or addas="button"+type="button"+ focus styles + key handling.packages/vechain-kit/src/components/AccountModal/Contents/Swap/SwapTokenContent.tsx (5)
215-222: Incomplete dependency inuseMemo.The dependency array includes
from?.decimalsbut the memo also usesfromfor the conditional check. This can lead to stale closures iffromchanges butfrom?.decimalsremains the same.const amountInRaw = useMemo(() => { if (!amount || Number(amount) <= 0 || !from) return 0n; try { return parseUnits(amount, from.decimals); } catch { return 0n; } - }, [amount, from?.decimals]); + }, [amount, from]);
342-349: Consider removing arbitrarysetTimeoutfor refetch.The 100ms delay before
refetchGasEstimation()appears to be a workaround. If the intent is to ensure state updates are applied before refetching, consider usinguseEffectto react toselectedGasTokenchanges instead.const handleGasTokenChange = React.useCallback( (token: GasTokenType) => { setSelectedGasToken(token); setUserSelectedGasToken(token); - setTimeout(() => refetchGasEstimation(), 100); }, - [refetchGasEstimation], + [], ); + + // Refetch gas estimation when selected gas token changes + React.useEffect(() => { + if (selectedGasToken) { + refetchGasEstimation(); + } + }, [selectedGasToken, refetchGasEstimation]);
478-485: Unused dependencies inuseCallback.The
handleSwapErrorcallback referencesfromToken,toToken, andamountin its dependency array, but these variables are not used in the function body. This can cause unnecessary re-renders.const handleSwapError = useCallback( (error: Error | string) => { const errorMessage = typeof error === 'string' ? error : error.message; console.error('Swap failed:', errorMessage); }, - [fromToken, toToken, amount], + [], );
1099-1123: Hardcoded color values should use theme tokens.The active button state uses hardcoded
'rgb(96 66 221)'which bypasses the theme system and won't adapt if the theme changes. Consider using a semantic color token from the theme.This pattern is repeated for all three preset slippage buttons. Extract the active/inactive styling to a variable or use a theme token:
+const activeButtonBg = 'vechain-kit-accent'; // or appropriate theme token +const activeButtonColor = 'white'; + <Button ... bg={ isAutoMode - ? 'rgb(96 66 221)' + ? activeButtonBg : 'transparent' } color={ isAutoMode - ? 'white' + ? activeButtonColor : textSecondary } borderColor={ isAutoMode - ? 'rgb(96 66 221)' + ? activeButtonBg : textSecondary } ... >
1087-1265: Consider extracting slippage button into a reusable component.The three preset slippage buttons (Auto, 0.5%, 3%) share nearly identical styling logic with only the value and active condition differing. This repetition increases maintenance burden.
Consider extracting to a helper component:
const SlippageButton = ({ value, label, isActive, onClick, isDark }: { value: number; label: string; isActive: boolean; onClick: () => void; isDark: boolean; }) => ( <Button size="sm" variant="outline" onClick={onClick} flex="0 0 auto" minW="60px" borderRadius="md" fontSize="xs" bg={isActive ? 'rgb(96 66 221)' : 'transparent'} color={isActive ? 'white' : textSecondary} borderColor={isActive ? 'rgb(96 66 221)' : textSecondary} _hover={{ bg: isActive ? 'rgb(96 66 221)' : isDark ? 'whiteAlpha.300' : 'blackAlpha.300', opacity: isActive ? 0.8 : 1, }} > {label} </Button> );packages/vechain-kit/src/hooks/api/vetDomains/useGetAvatarOfAddress.ts (2)
19-43: HardengetCrossAppAvatar: normalize app name + consider honoringtimestampto avoid stale/malformed cache.
Today this is case-sensitive and will keep returning an avatar indefinitely even if the cache is ancient.-const CROSSAPP_AVATAR_MAP: Record<string, string> = { - Mugshot: +const CROSSAPP_AVATAR_MAP: Record<string, string> = { + mugshot: 'https://prod-vechainkit-docs-images-bucket.s3.eu-west-1.amazonaws.com/mugshot.png', - Greencart: + greencart: 'https://prod-vechainkit-docs-images-bucket.s3.eu-west-1.amazonaws.com/greencart.png', - Cleanify: + cleanify: 'https://prod-vechainkit-docs-images-bucket.s3.eu-west-1.amazonaws.com/cleanify.png', - EVearn: 'https://prod-vechainkit-docs-images-bucket.s3.eu-west-1.amazonaws.com/evearn.png', + evearn: 'https://prod-vechainkit-docs-images-bucket.s3.eu-west-1.amazonaws.com/evearn.png', }; const getCrossAppAvatar = (): string | null => { const cached = getLocalStorageItem(CACHE_KEY); if (!cached) return null; try { const connectionCache = JSON.parse(cached) as CrossAppConnectionCache; - const appName = connectionCache?.ecosystemApp?.name; + // Optional: ignore stale cache + // if (!connectionCache?.timestamp || Date.now() - connectionCache.timestamp > 1000 * 60 * 60 * 24) return null; + const appName = connectionCache?.ecosystemApp?.name?.trim().toLowerCase(); if (!appName) return null; return CROSSAPP_AVATAR_MAP[appName] ?? null; } catch { return null; } };
86-99: Retry cancellation detection: prefer checkingerror.name(e.g.,AbortError) over substring matching.
Substring matching can accidentally disable retries for unrelated errors that contain “abort/cancel” in the message.retry: (failureCount, error) => { // Don't retry on cancellation errors if (error instanceof Error) { - const errorMessage = error.message.toLowerCase(); + if (error.name === 'AbortError') return false; + const errorMessage = error.message.toLowerCase(); if ( errorMessage.includes('cancel') || errorMessage.includes('abort') ) { return false; } } // Retry network errors up to 2 times return failureCount < 2; },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
packages/vechain-kit/src/components/AccountModal/Contents/SendToken/SendTokenContent.tsx(2 hunks)packages/vechain-kit/src/components/AccountModal/Contents/Swap/SwapTokenContent.tsx(15 hunks)packages/vechain-kit/src/components/common/AddressDisplayCard.tsx(2 hunks)packages/vechain-kit/src/hooks/api/vetDomains/useGetAvatarOfAddress.ts(2 hunks)packages/vechain-kit/src/languages/en.json(1 hunks)packages/vechain-kit/src/theme/modal.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/vechain-kit/src/languages/en.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/migration-guide-to-v2.mdc)
**/*.{ts,tsx}: In VeChain Kit Version 2, useuseThorinstead ofuseConnexfor contract interactions
For single contract read operations, use theuseCallClausehook with the pattern: import dependencies, define ABI and method as const, create query key function usinggetCallClauseQueryKeyWithArgs, and wrap with useCallClause including data transformation in the select option
For multiple parallel contract calls, use theexecuteMultipleClausesCallutility wrapped in auseQueryhook with the pattern: define query key function, useexecuteMultipleClausesCallin queryFn mapping items to clause objects, and transform results
For transaction building and sending, use theuseBuildTransactionhook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action
Always provide an arguments array for contract calls, even when no parameters are required - use an empty array for parameter-less functions to enable TypeScript type checking
Always conditionally enable queries using theenabledproperty to prevent unnecessary contract calls, checking for all required parameters:enabled: !!requiredParam && !!otherRequiredParam
Use theselectoption in useCallClause or transform data in queryFn to handle data transformation, particularly for converting BigInt values to strings and normalizing contract return data
Maintain consistent query key patterns: usegetCallClauseQueryKeyWithArgsfor contract calls with arguments andgetCallClauseQueryKeyfor calls without arguments to ensure proper caching and invalidation
Use TypeScriptas constassertions for method names andas0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions
Files:
packages/vechain-kit/src/theme/modal.tspackages/vechain-kit/src/components/common/AddressDisplayCard.tsxpackages/vechain-kit/src/components/AccountModal/Contents/SendToken/SendTokenContent.tsxpackages/vechain-kit/src/hooks/api/vetDomains/useGetAvatarOfAddress.tspackages/vechain-kit/src/components/AccountModal/Contents/Swap/SwapTokenContent.tsx
🧠 Learnings (1)
📚 Learning: 2025-12-01T13:01:33.771Z
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : In VeChain Kit Version 2, use `useThor` instead of `useConnex` for contract interactions
Applied to files:
packages/vechain-kit/src/components/AccountModal/Contents/Swap/SwapTokenContent.tsx
🧬 Code graph analysis (1)
packages/vechain-kit/src/hooks/api/vetDomains/useGetAvatarOfAddress.ts (3)
packages/vechain-kit/src/utils/ssrUtils.ts (1)
getLocalStorageItem(8-18)packages/vechain-kit/src/types/types.ts (1)
CrossAppConnectionCache(151-159)packages/vechain-kit/src/utils/formattingUtils.tsx (1)
getPicassoImage(55-62)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: e2e-test
- GitHub Check: Lint & Build
- GitHub Check: build-size-check
- GitHub Check: deploy
🔇 Additional comments (6)
packages/vechain-kit/src/components/common/AddressDisplayCard.tsx (2)
68-115: VerifyborderRadius="2xl"is supported by the project theme (loading state).
If the app overrides Chakra radii tokens, ensure2xlis defined (otherwise it can silently fall back / look wrong).
118-190: Consistent radius across loaded + loading states (nice).
Both branches now useborderRadius="2xl", which avoids a subtle visual “jump” on load.packages/vechain-kit/src/components/AccountModal/Contents/SendToken/SendTokenContent.tsx (1)
258-295: Layout refactor looks coherent (clearer headers + separation)The new header rows for “Amount”/“To” and card separation read cleaner and should compose better with the modal styling changes in this PR.
Also applies to: 488-499
packages/vechain-kit/src/components/AccountModal/Contents/Swap/SwapTokenContent.tsx (3)
649-659: Good UX: Disabling navigation during transaction.The back and close buttons are now properly disabled when
isTransactionPendingorisWaitingForWalletConfirmationis true. This prevents accidental modal dismissal during critical transaction flows.
1348-1350: Good UX: Loading state feedback on swap button.The swap button now shows "Loading quote..." when
isLoadingQuoteis true, providing clear feedback to users about the current operation state.
1293-1329: Good practice: Reserved space prevents layout shift.Using
minH="24px"on the container ensures consistent layout regardless of whether the toggle is visible, preventing jarring shifts when the quote loads.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (2)
79-88: Direction heuristics may produce incorrect results for some navigation flows.The conditions checking
prevKey(lines 86-88) classify ANY navigation away from summary/confirm/operation pages as backward. However, flows likesend-token-summary → successful-operationshould animate forward, not backward.Consider checking
currKeypatterns instead, or use explicit navigation flow mappings:const isBackward = currKey === 'main' || (currKey === 'settings' && prevKey !== 'main') || // Check if navigating TO summary/operation (forward) vs away from them (prevKey.includes('summary') && !currKey.includes('operation')) || (prevKey.includes('confirm') && currKey !== 'main');
265-274: Consider reusing the importedtransitionconstant.The inline transition duplicates the values from the imported
transitionconstant. Reusing it improves maintainability:<motion.div layout - transition={{ - layout: { - duration: 0.2, - ease: [0.4, 0, 0.2, 1], - }, - }} + transition={{ layout: transition }} style={{ width: '100%', overflow: 'hidden' }} >
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx(7 hunks)packages/vechain-kit/src/components/AccountModal/utils/animationVariants.ts(1 hunks)packages/vechain-kit/src/components/AccountModal/utils/getContentKey.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/migration-guide-to-v2.mdc)
**/*.{ts,tsx}: In VeChain Kit Version 2, useuseThorinstead ofuseConnexfor contract interactions
For single contract read operations, use theuseCallClausehook with the pattern: import dependencies, define ABI and method as const, create query key function usinggetCallClauseQueryKeyWithArgs, and wrap with useCallClause including data transformation in the select option
For multiple parallel contract calls, use theexecuteMultipleClausesCallutility wrapped in auseQueryhook with the pattern: define query key function, useexecuteMultipleClausesCallin queryFn mapping items to clause objects, and transform results
For transaction building and sending, use theuseBuildTransactionhook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action
Always provide an arguments array for contract calls, even when no parameters are required - use an empty array for parameter-less functions to enable TypeScript type checking
Always conditionally enable queries using theenabledproperty to prevent unnecessary contract calls, checking for all required parameters:enabled: !!requiredParam && !!otherRequiredParam
Use theselectoption in useCallClause or transform data in queryFn to handle data transformation, particularly for converting BigInt values to strings and normalizing contract return data
Maintain consistent query key patterns: usegetCallClauseQueryKeyWithArgsfor contract calls with arguments andgetCallClauseQueryKeyfor calls without arguments to ensure proper caching and invalidation
Use TypeScriptas constassertions for method names andas0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions
Files:
packages/vechain-kit/src/components/AccountModal/utils/getContentKey.tspackages/vechain-kit/src/components/AccountModal/utils/animationVariants.tspackages/vechain-kit/src/components/AccountModal/AccountModal.tsx
🧬 Code graph analysis (2)
packages/vechain-kit/src/components/AccountModal/utils/getContentKey.ts (1)
packages/vechain-kit/src/components/AccountModal/Types/Types.ts (1)
AccountModalContentTypes(19-104)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (5)
packages/vechain-kit/src/components/AccountModal/Types/Types.ts (1)
AccountModalContentTypes(19-104)packages/vechain-kit/src/components/AccountModal/utils/getContentKey.ts (1)
getContentKey(8-23)packages/vechain-kit/src/components/AccountModal/Contents/FailedOperation/FailedOperationContent.tsx (1)
FailedOperationContent(31-100)packages/vechain-kit/src/components/common/BaseModal.tsx (1)
BaseModal(29-104)packages/vechain-kit/src/components/AccountModal/utils/animationVariants.ts (2)
contentVariants(2-15)transition(17-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Lint & Build
- GitHub Check: e2e-test
- GitHub Check: build-size-check
- GitHub Check: deploy
🔇 Additional comments (4)
packages/vechain-kit/src/components/AccountModal/utils/getContentKey.ts (1)
8-23: LGTM! Clean utility for stable animation keys.The implementation correctly handles both string and object content types. The djb2-style hash is appropriate for generating unique animation keys.
Note:
JSON.stringifyomits function properties (likesetCurrentContent), so objects differing only by function references will produce identical keys. This is acceptable here since the function instance should be consistent within the modal's lifecycle.packages/vechain-kit/src/components/AccountModal/utils/animationVariants.ts (1)
1-20: LGTM! Well-structured animation configuration.The direction-aware variants and Material Design easing curve provide smooth, intuitive navigation transitions.
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (2)
275-291: LGTM! Animation wrapper implementation is correct.The
AnimatePresencewithmode="wait"ensures proper sequencing of exit/enter animations, and thekeyprop correctly triggers re-animation when content changes.
214-219: Navigation path updated correctly.The
onBackcallback now navigates to'settings'instead of the removed'access-and-security'content type, aligning with the settings consolidation in this PR.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/vechain-kit/src/theme/tokens.ts (1)
354-390: Critical: hardcoded white text color inderivePrimaryButtonStylescauses invisible buttonsWhen
modalBgColorandtextColorare provided without explicitprimaryButtonconfig, the derived branch (lines 378–385) returnscolor: 'white'hardcoded. This conflicts with light mode defaults wherebg: 'white'andcolor: 'blackAlpha.900', resulting in white text on white background.Additionally, the derived branch omits
rounded,hoverBg, andbackdropFilterproperties that exist in both the custom config branch and light mode defaults.Fix by using default token values instead of hardcoding:
if (backgroundColor && textColor) { return { bg: defaultTokens.buttons.primaryButton.bg, - color: 'white', + color: defaultTokens.buttons.primaryButton.color, - border: 'none', + border: defaultTokens.buttons.primaryButton.border, + rounded: defaultTokens.buttons.primaryButton.rounded, + hoverBg: defaultTokens.buttons.primaryButton.hoverBg, + backdropFilter: defaultTokens.buttons.primaryButton.backdropFilter, }; }
♻️ Duplicate comments (1)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (1)
69-93: Animation direction can be stale (computed inuseEffectbut read during render).
This is the same timing issue previously flagged:directionRef.currentis read on Line 269, but it’s only updated after render in the effect, so the first animated transition after a content change can use the prior direction.Also applies to: 265-279
🧹 Nitpick comments (2)
packages/vechain-kit/src/components/AccountModal/utils/animationVariants.ts (1)
1-20: LGTM; consider typing variants/transition to lock the contract.
This is clean and symmetric. Optional: type it asVariants/Transition(and export aDirectionunion) so future edits can’t drift from whatmotion.divexpects.+import type { Transition, Variants } from 'framer-motion'; + +export type Direction = 'forward' | 'backward'; + -export const contentVariants = { - enter: (direction: 'forward' | 'backward') => ({ +export const contentVariants: Variants = { + enter: (direction: Direction) => ({ opacity: 0, x: direction === 'forward' ? 20 : -20, }), center: { opacity: 1, x: 0, }, - exit: (direction: 'forward' | 'backward') => ({ + exit: (direction: Direction) => ({ opacity: 0, x: direction === 'forward' ? -20 : 20, }), }; -export const transition = { +export const transition: Transition = { duration: 0.17, ease: [0.4, 0, 0.2, 1] as const, };packages/vechain-kit/src/theme/tokens.ts (1)
461-508:defaultBlur.stickyHeaderlooks unused / misleading
getGlassEffectSettings()returns a singleblurstring (Line 465) and usesdefaultBlur.modalwhen glass is disabled (Line 479), so changingdefaultBlur.stickyHeader(Line 474) appears to have no effect and can confuse future edits. Either remove the per-surfacedefaultBlurshape, or refactor the function to actually return per-surface blurs (modal/overlay/stickyHeader).Also applies to: 474-475
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
examples/homepage/src/app/providers/VechainKitProviderWrapper.tsx(2 hunks)packages/vechain-kit/src/components/AccountModal/AccountModal.tsx(7 hunks)packages/vechain-kit/src/components/AccountModal/utils/animationVariants.ts(1 hunks)packages/vechain-kit/src/theme/tokens.ts(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- examples/homepage/src/app/providers/VechainKitProviderWrapper.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/migration-guide-to-v2.mdc)
**/*.{ts,tsx}: In VeChain Kit Version 2, useuseThorinstead ofuseConnexfor contract interactions
For single contract read operations, use theuseCallClausehook with the pattern: import dependencies, define ABI and method as const, create query key function usinggetCallClauseQueryKeyWithArgs, and wrap with useCallClause including data transformation in the select option
For multiple parallel contract calls, use theexecuteMultipleClausesCallutility wrapped in auseQueryhook with the pattern: define query key function, useexecuteMultipleClausesCallin queryFn mapping items to clause objects, and transform results
For transaction building and sending, use theuseBuildTransactionhook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action
Always provide an arguments array for contract calls, even when no parameters are required - use an empty array for parameter-less functions to enable TypeScript type checking
Always conditionally enable queries using theenabledproperty to prevent unnecessary contract calls, checking for all required parameters:enabled: !!requiredParam && !!otherRequiredParam
Use theselectoption in useCallClause or transform data in queryFn to handle data transformation, particularly for converting BigInt values to strings and normalizing contract return data
Maintain consistent query key patterns: usegetCallClauseQueryKeyWithArgsfor contract calls with arguments andgetCallClauseQueryKeyfor calls without arguments to ensure proper caching and invalidation
Use TypeScriptas constassertions for method names andas0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions
Files:
packages/vechain-kit/src/components/AccountModal/utils/animationVariants.tspackages/vechain-kit/src/theme/tokens.tspackages/vechain-kit/src/components/AccountModal/AccountModal.tsx
🧬 Code graph analysis (1)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (3)
packages/vechain-kit/src/components/AccountModal/Types/Types.ts (1)
AccountModalContentTypes(19-104)packages/vechain-kit/src/components/AccountModal/utils/getContentKey.ts (1)
getContentKey(8-23)packages/vechain-kit/src/components/AccountModal/utils/animationVariants.ts (2)
contentVariants(2-15)transition(17-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: e2e-test
- GitHub Check: Lint & Build
- GitHub Check: build-size-check
- GitHub Check: deploy
🔇 Additional comments (3)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (2)
215-219: Back navigation tosettingslooks consistent with the new consolidation.
39-41: ThegetContentKeyfunction is correctly implemented with no undefined variable issues. The variable is properly namedpropsStr(line 14) and consistently used in the loop on lines 17-18. The function receives validAccountModalContentTypesobjects at all call sites (lines 76, 77, and 256) and will execute without runtime errors.packages/vechain-kit/src/theme/tokens.ts (1)
539-550: Contrast and hover states for primary button are well-defined and accessibleThe primary button with
bg: '#272A2E'andcolor: 'white'has strong WCAG AAA-compliant contrast (approximately 16:1). Hover behavior is explicitly handled in the button component: whenhoverBgis not defined (as in this case), the implementation appliesopacity: 0.8as a fallback, providing clear visual feedback. No assumptions or derivations are needed.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx (3)
88-100: Preview URL may not reset when switching accounts.Line 98 uses
setPreviewImageUrl((prev) => prev ?? account.image ?? null), which retains the previous preview if it exists. When switching between accounts, this prevents the avatar from updating to the new account's image, causing the wrong avatar to display.Apply this diff to reset the preview URL when the account changes:
- // Only set the preview URL if it hasn't been set yet - setPreviewImageUrl((prev) => prev ?? account.image ?? null); + // Reset preview URL to account's image (or null) when account changes + setPreviewImageUrl(account.image ?? null);
172-175: useMemo dependency on function reference breaks memoization.The dependency array includes
getChangedValues, which is redefined on every render. This causes the memoization to recompute unnecessarily on every render, defeating its purpose.Apply this diff to fix the memoization by depending on the actual values:
- const hasChanges = useMemo(() => { - const changes = getChangedValues(); - return Object.keys(changes).length > 0; - }, [getChangedValues]); + const hasChanges = useMemo(() => { + const changes = getChangedValues(); + return Object.keys(changes).length > 0; + }, [avatarIpfsHash, initialAvatarHash, formValues.displayName, initialDisplayName, formValues.description, initialDescription]);
390-399: Remove unused cover image input or implement the feature.The
coverInputRefand its associated file input are defined but never used. The onChange handler is a no-op with a placeholder comment. This adds unnecessary code without providing functionality.Apply this diff to remove the unused code:
- <input - type="file" - ref={coverInputRef} - hidden - accept="image/*" - onChange={async (event) => { - /* Add cover upload handler */ - event.preventDefault(); - }} - />If cover image upload is planned, consider opening an issue to track this feature implementation.
Do you want me to open a new issue to track the cover image upload feature?
♻️ Duplicate comments (1)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (1)
55-99: Direction is still potentially stale for the first animation frame (computedirection, but passdirectionRef.current).You compute
directionsynchronously (Line 70-93) but the animation readsdirectionRef.current(Line 275), which is only updated in an effect (Line 96-99). That can still yield the wrong enter/exit direction immediately aftercurrentContentchanges.Suggested fix: use the computed
directionfor the motion custom prop, and keep the ref only as “previous direction” storage.- const content = renderContent(); - const contentKey = getContentKey(currentContent); + const content = renderContent(); + const contentKey = getContentKey(currentContent); ... - custom={directionRef.current} + custom={direction}Optionally, once you do the above, you can simplify/remove
directionRefentirely unless something else needs it.
🧹 Nitpick comments (2)
packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx (1)
12-13: Nice fix for the animation glitches!The debounced IntersectionObserver with initial mount guard effectively prevents the visual glitches during content animation. The implementation is solid:
- Proper debounce pattern with timeout clearing
- Initial mount guard prevents blur on first render
- Comprehensive cleanup prevents memory leaks
- Increased default blur to 20px aligns with token changes
Consider extracting the hardcoded timing values as named constants for better maintainability:
+const OBSERVER_ATTACHMENT_DELAY_MS = 200; // Wait for modal animation to complete +const INTERSECTION_DEBOUNCE_MS = 50; // Debounce to let animations settle + export const StickyHeaderContainer = ({ children }: Props) => { // ... existing code ... useEffect(() => { const handleIntersection = ([entry]: IntersectionObserverEntry[]) => { // ... existing code ... timeoutRef.current = setTimeout(() => { // ... existing code ... - }, 50); + }, INTERSECTION_DEBOUNCE_MS); }; // ... existing code ... - const observeTimeout = setTimeout(() => { + const observeTimeout = setTimeout(() => { // ... existing code ... - }, 200); + }, OBSERVER_ATTACHMENT_DELAY_MS);This makes the timing dependencies more explicit and easier to adjust if animation durations change.
Also applies to: 18-18, 23-58
packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx (1)
233-250: Remove unnecessary transform property.Line 240's
transform="translateX(0%)"has no effect since it translates by 0%. The element is already properly positioned withposition="absolute"and explicit dimensions.Apply this diff to remove the redundant property:
{isUploading && ( <Box display="flex" alignItems="center" justifyContent="center" backgroundColor="rgba(0, 0, 0, 0.5)" position="absolute" - transform="translateX(0%)" width="100px" height="100px" borderRadius="full" zIndex={10} >
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx(7 hunks)packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/ConnectionCard.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx(1 hunks)packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx(1 hunks)packages/vechain-kit/src/components/ProfileCard/ProfileCard.tsx(1 hunks)packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx(2 hunks)packages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx
- packages/vechain-kit/src/components/ProfileCard/ProfileCard.tsx
- packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/ConnectionCard.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/migration-guide-to-v2.mdc)
**/*.{ts,tsx}: In VeChain Kit Version 2, useuseThorinstead ofuseConnexfor contract interactions
For single contract read operations, use theuseCallClausehook with the pattern: import dependencies, define ABI and method as const, create query key function usinggetCallClauseQueryKeyWithArgs, and wrap with useCallClause including data transformation in the select option
For multiple parallel contract calls, use theexecuteMultipleClausesCallutility wrapped in auseQueryhook with the pattern: define query key function, useexecuteMultipleClausesCallin queryFn mapping items to clause objects, and transform results
For transaction building and sending, use theuseBuildTransactionhook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action
Always provide an arguments array for contract calls, even when no parameters are required - use an empty array for parameter-less functions to enable TypeScript type checking
Always conditionally enable queries using theenabledproperty to prevent unnecessary contract calls, checking for all required parameters:enabled: !!requiredParam && !!otherRequiredParam
Use theselectoption in useCallClause or transform data in queryFn to handle data transformation, particularly for converting BigInt values to strings and normalizing contract return data
Maintain consistent query key patterns: usegetCallClauseQueryKeyWithArgsfor contract calls with arguments andgetCallClauseQueryKeyfor calls without arguments to ensure proper caching and invalidation
Use TypeScriptas constassertions for method names andas0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions
Files:
packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsxpackages/vechain-kit/src/components/AccountModal/AccountModal.tsxpackages/vechain-kit/src/components/common/StickyHeaderContainer.tsx
🧠 Learnings (1)
📚 Learning: 2025-12-01T13:01:33.771Z
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : In VeChain Kit Version 2, use `useThor` instead of `useConnex` for contract interactions
Applied to files:
packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx
🧬 Code graph analysis (2)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (4)
packages/vechain-kit/src/components/AccountModal/Types/Types.ts (1)
AccountModalContentTypes(19-104)packages/vechain-kit/src/components/AccountModal/utils/getContentKey.ts (1)
getContentKey(8-23)packages/vechain-kit/src/components/AccountModal/Contents/FailedOperation/FailedOperationContent.tsx (1)
FailedOperationContent(31-100)packages/vechain-kit/src/components/AccountModal/utils/animationVariants.ts (2)
contentVariants(2-15)transition(17-20)
packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx (1)
packages/vechain-kit/src/providers/VechainKitThemeProvider.tsx (1)
useVechainKitThemeConfig(190-198)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: e2e-test
- GitHub Check: build-size-check
- GitHub Check: Lint & Build
- GitHub Check: deploy
🔇 Additional comments (3)
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx (2)
271-286: AnimatePresence + keyed motion container looks good (clean separation viacontentVariants/transition).
mode="wait"+key={contentKey}+ variants/transition integration is straightforward and should make transitions predictable.
221-224: Back target change to'settings'looks consistent with the settings consolidation.Just sanity-check the intended UX flow for
PrivyLinkedAccounts(i.e., no longer returning to a removed “access-and-security” branch) and that no deep-link relies on the old target.packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx (1)
303-380: Well-structured form controls with proper validation.The refactored form controls using
FormControl,FormLabel, and integrated error handling follow Chakra UI best practices. Validation rules, disabled states, and error messages are properly implemented.
| // Track navigation direction (computed synchronously) | ||
| const direction = (() => { | ||
| if ( | ||
| previousContentRef.current === null || | ||
| previousContentRef.current === currentContent | ||
| ) { | ||
| return directionRef.current; | ||
| } | ||
| // Determine direction based on common navigation patterns | ||
| const prevKey = getContentKey(previousContentRef.current); | ||
| const currKey = getContentKey(currentContent); | ||
|
|
||
| // Common backward navigation patterns | ||
| const isBackward = | ||
| // Going back to main from any view | ||
| currKey === 'main' || | ||
| // Going back to settings from sub-settings | ||
| (currKey === 'settings' && prevKey !== 'main') || | ||
| // Going from summary/confirmation back to main content | ||
| prevKey.includes('summary') || | ||
| prevKey.includes('confirm') || | ||
| prevKey.includes('operation'); | ||
|
|
||
| return isBackward ? 'backward' : 'forward'; | ||
| })(); |
There was a problem hiding this comment.
Guard getContentKey(...) to avoid render-time crashes if props aren’t JSON-safe.
getContentKey uses JSON.stringify(content.props). If any screen props ever include a BigInt (throws), circular references (throws), or other non-serializable values, this will crash the modal render. Consider making getContentKey resilient (try/catch + safe replacer) or narrowing what goes into the key (e.g., only stable primitive identifiers per screen type).
(You’re calling it multiple times per render: Line 78-79 and Line 262.)
Also applies to: 262-262
🤖 Prompt for AI Agents
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx lines 69-93
(also called at line 262): getContentKey currently JSON.stringify(content.props)
and can throw at render time for BigInt, circular refs or non-serializable
values; update getContentKey to guard against that by wrapping the stringify in
try/catch and returning a safe fallback when serialization fails (e.g., use a
stable identifier from content.type or a hash of selected primitive props), or
implement a safeStringify replacer that handles BigInt and circular refs; ensure
callers use the protected getContentKey so render cannot crash and consider
reducing the props included in the key to only stable primitive identifiers per
screen type.
🚀 Preview environment deployed!Preview URL: https://preview.vechainkit.vechain.org/fixui |
Description
refactor settings + fix ui bugs
Summary by CodeRabbit
New Features
Bug Fixes & Improvements
Style
Localization
✏️ Tip: You can customize this high-level summary in your review settings.
Closes #284