Skip to content

Fix/UI#553

Merged
Agilulfo1820 merged 24 commits into
mainfrom
fix/ui
Dec 12, 2025
Merged

Fix/UI#553
Agilulfo1820 merged 24 commits into
mainfrom
fix/ui

Conversation

@Agilulfo1820

@Agilulfo1820 Agilulfo1820 commented Dec 12, 2025

Copy link
Copy Markdown
Member

Description

refactor settings + fix ui bugs

Summary by CodeRabbit

  • New Features

    • Consolidated Settings view and a unified Connection card; directional animations for smoother modal transitions.
  • Bug Fixes & Improvements

    • Removed several legacy account sub-screens to simplify navigation; unified back-navigation to Settings and updated disconnect flow/defaults.
    • Swap/Send UI improvements: quick-fill balance, address normalization, expanded slippage options, and clearer quote/loading states.
  • Style

    • Refined modal/theme visuals: stronger backdrop blur, updated button styles, larger dialog height.
  • Localization

    • Added six new translation keys.

✏️ Tip: You can customize this high-level summary in your review settings.

Closes #284

@coderabbitai

coderabbitai Bot commented Dec 12, 2025

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

Walkthrough

Removes 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

Cohort / File(s) Summary
Settings consolidation
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx, packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/index.ts
Adds a new consolidated SettingsContent component and re-exports it; removes separate General/Appearance modules from KitSettings exports.
Removed account screens
packages/vechain-kit/src/components/AccountModal/Contents/Account/AccessAndSecurityContent.tsx, packages/vechain-kit/src/components/AccountModal/Contents/Account/EmbeddedWalletContent.tsx, packages/vechain-kit/src/components/AccountModal/Contents/Account/SettingsContent.tsx, packages/vechain-kit/src/components/AccountModal/Contents/Account/index.ts
Deletes Access & Security, Embedded Wallet, and legacy Account Settings components and their re-exports.
Connection details consolidation
packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/ConnectionCard.tsx, packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/*, packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/ConnectionDetailsContent.tsx, packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/index.ts
Adds ConnectionCard consolidating connection info; removes CrossAppConnectionCard, DappKitConnectionCard, PrivyConnectionCard, and NetworkInfo; ConnectionDetailsContent now renders ConnectionCard + WalletSecuredBy.
AccountModal animations & types
packages/vechain-kit/src/components/AccountModal/AccountModal.tsx, packages/vechain-kit/src/components/AccountModal/Types/Types.ts, packages/vechain-kit/src/components/AccountModal/Contents/DisconnectConfirmation/index.ts, packages/vechain-kit/src/components/AccountModal/Contents/index.ts, packages/vechain-kit/src/components/AccountModal/utils/*
Wraps modal content with AnimatePresence/motion, adds getContentKey and animation variants/transition, prunes several AccountModalContentTypes, and re-exports DisconnectConfirmContent from a new location.
Hook & modal exports removed
packages/vechain-kit/src/hooks/modals/useAccessAndSecurityModal.tsx, packages/vechain-kit/src/hooks/modals/index.ts
Removes useAccessAndSecurityModal hook/provider and its re-export.
Navigation target updates
packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/*, packages/vechain-kit/src/components/AccountModal/Contents/Ecosystem/ExploreEcosystemContent.tsx, packages/vechain-kit/src/components/AccountModal/Contents/UpgradeSmartAccount/UpgradeSmartAccountContent.tsx
Changes multiple back/onClick handlers to navigate to 'settings'; UpgradeSmartAccountContent default initialContent now 'settings'.
Profile & customization UI
packages/vechain-kit/src/components/ProfileCard/ProfileCard.tsx, packages/vechain-kit/src/components/AccountModal/Contents/Profile/ProfileContent.tsx, packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx
ProfileCard reworked from Card to VStack (removes style prop); CustomizationContent simplifies avatar/upload and form layout; ProfileContent styling adjusted.
Theme / sticky header / modal tokens
examples/homepage/src/app/providers/VechainKitProviderWrapper.tsx, packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx, packages/vechain-kit/src/theme/tokens.ts, packages/vechain-kit/src/theme/modal.ts
Computes and passes a theme object to provider, pins network to 'main', increases sticky header blur (12→20px) and modal maxHeight (550→600px), and adjusts primary button token colors/rounded.
Homepage & translations
examples/homepage/src/app/components/features/FeaturesToTry/FeaturesToTry.tsx, packages/vechain-kit/src/languages/en.json
Removes Access & Security feature block from example and appends several new translation keys to en.json.
Swap / Send UI & appearance tweaks
packages/vechain-kit/src/components/AccountModal/Contents/SendToken/SendTokenContent.tsx, packages/vechain-kit/src/components/AccountModal/Contents/Swap/SwapTokenContent.tsx, packages/vechain-kit/src/components/common/AddressDisplayCard.tsx
Send: adds balance display, set-max behavior, and layout tweaks. Swap: refactors advanced/slippage UI, adds dark-mode styling, disables back/close during pending, and updates labels. AddressDisplayCard: increased borderRadius to 2xl.
Avatar & xApp metadata changes
packages/vechain-kit/src/hooks/api/vetDomains/useGetAvatarOfAddress.ts, packages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx
Avatar lookup adds cross-app avatar fallback via localStorage before Picasso; useXAppMetadata reads metadataURI from contract.read result index and adds query enabling.
Animation & content-key utilities
packages/vechain-kit/src/components/AccountModal/utils/animationVariants.ts, packages/vechain-kit/src/components/AccountModal/utils/getContentKey.ts
Adds directional animation variants, transition config, and getContentKey hashing utility for stable animation keys.
Index / import path updates
various .../index.ts and import updates (e.g., DisconnectConfirmContent paths)
Updates exports and import paths to reflect moved/removed files and new DisconnectConfirmation location.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing extra attention:
    • ConnectionCard: confirm it covers edge cases and preserves prior data rows (timestamps, network, versions).
    • SettingsContent: conditional rendering for Privy/social login, logout flow, and navigation handlers.
    • Types: ensure all consumers tolerate removed AccountModalContentTypes members.
    • Modal animation/keying: verify stable keys, back/forward direction handling, and no remount glitches.
    • useGetAvatarOfAddress & useXAppMetadata: validate fallback ordering, localStorage mapping, and contract.read indexing robustness.

Possibly related PRs

  • Fix/UI #553 — Overlapping UI/settings refactor; appears to implement similar removals/consolidations and animation changes.
  • feat: added style options #552 — Related changes to theme/tokens and modal/button styling adjustments.

Suggested reviewers

  • victorkl400
  • mikeredmond

Poem

🐰 I nudged the panes and made them glide,

One card for connections, old doors tied,
Settings gathered snug, animations sing,
Blurs and tokens polished — a lighter spring,
A happy hop for UI on the wire!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 2 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Fix/UI' is vague and generic, using a broad categorical term that fails to convey the specific nature or scope of changes within the changeset. Replace 'Fix/UI' with a more descriptive title that highlights the primary change, such as 'Refactor settings modal and consolidate connection card components' or similar.
Description check ❓ Inconclusive The description mentions refactoring settings and fixing UI bugs but lacks sufficient detail about what was refactored, which bugs were fixed, and the extent of changes across multiple files. Expand the description to explain the key refactoring changes (e.g., consolidation of settings components, removal of deprecated modals) and specific UI bugs addressed.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 53ace92 and de3b294.

📒 Files selected for processing (1)
  • packages/vechain-kit/src/theme/tokens.ts (4 hunks)

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 against vbdApps being undefined before calling .filter().
useMostVotedAppsInRound(...) can plausibly return undefined while 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 bumped defaultBlur.stickyHeader to blur(20px), but the actual default theme tokens still say blur(12px) for effects.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 enabled property, which means it will attempt to execute even when xAppId is 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 with useCallback
The fallback onClick handlers 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 guarding IntersectionObserver for non-supporting environments.
If IntersectionObserver is unavailable, this will throw in useEffect. 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: ?? undefined is 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 single react-icons/lu import
You import from react-icons/lu twice; 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 awaiting disconnect() before calling onLogoutSuccess()

The disconnect() function from useWallet returns Promise<void> and asynchronously cleans up wallet connection state and triggers state updates. Calling onLogoutSuccess() 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 (app and baseURI) are executed sequentially, but they're independent and could be parallelized for better performance. The coding guidelines recommend using executeMultipleClausesCall for 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

📥 Commits

Reviewing files that changed from the base of the PR and between 9f592ef and 8580f43.

📒 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, use useThor instead of useConnex for contract interactions
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
For multiple parallel contract calls, use the executeMultipleClausesCall utility wrapped in a useQuery hook with the pattern: define query key function, use executeMultipleClausesCall in queryFn mapping items to clause objects, and transform results
For transaction building and sending, use the useBuildTransaction hook 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 the enabled property to prevent unnecessary contract calls, checking for all required parameters: enabled: !!requiredParam && !!otherRequiredParam
Use the select option 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: use getCallClauseQueryKeyWithArgs for contract calls with arguments and getCallClauseQueryKey for calls without arguments to ensure proper caching and invalidation
Use TypeScript as const assertions for method names and as 0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions

Files:

  • packages/vechain-kit/src/theme/tokens.ts
  • packages/vechain-kit/src/components/AccountModal/Contents/index.ts
  • packages/vechain-kit/src/components/LegalDocumentsModal/LegalDocumentsModal.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/DisconnectConfirmation/index.ts
  • packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/index.ts
  • packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/ChangeCurrencyContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/UpgradeSmartAccount/UpgradeSmartAccountContent.tsx
  • examples/homepage/src/app/providers/VechainKitProviderWrapper.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/WalletSecuredBy.tsx
  • examples/homepage/src/app/components/features/FeaturesToTry/FeaturesToTry.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/LanguageSettingsContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/index.ts
  • packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/ConnectionDetailsContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Types/Types.ts
  • packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/GasTokenSettingsContent.tsx
  • packages/vechain-kit/src/components/ProfileCard/ProfileCard.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/ConnectionCard.tsx
  • packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Ecosystem/ExploreEcosystemContent.tsx
  • packages/vechain-kit/src/components/AccountModal/AccountModal.tsx
  • packages/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.tsx
  • examples/homepage/src/app/providers/VechainKitProviderWrapper.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/Components/index.ts
  • packages/vechain-kit/src/components/AccountModal/Contents/ConnectionDetails/ConnectionDetailsContent.tsx
  • packages/vechain-kit/src/components/common/StickyHeaderContainer.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Ecosystem/ExploreEcosystemContent.tsx
  • packages/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: Defaulting initialContent to 'settings' is the right navigation fallback—just ensure the type/key matches the new flow.
Given initialContent is used as the back/close destination in several places, please double-check that 'settings' is a valid AccountModalContentTypes value (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 in isolatedView and routing back to 'settings' matches the PR’s navigation consolidation.

Also applies to: 208-212


238-242: Search icon update is fine.
Using useToken(...) and passing it to LuSearch keeps 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: Hardcoding network.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 of DisconnectConfirmation looks 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 verify AccountModalContentTypes and 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 for DisconnectConfirmContent

packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/index.ts (1)

4-4: Exporting SettingsContent from KitSettings matches 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
The failed-operation branch returning the component directly keeps behavior the same and reads cleaner.


186-187: Back target update aligns with removed settings sub-flows
Routing PrivyLinkedAccounts back to 'settings' looks consistent with the removed “access-and-security” content state.


30-30: Verify DisconnectConfirmContent export from ./Contents/DisconnectConfirmation

Confirm that DisconnectConfirmContent is exported from the target module to prevent runtime import errors.

packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx (2)

64-69: useUpgradeRequired usage looks consistent with v2 useThor guideline
Nice: the hook-level enabled guard (per useUpgradeRequired) should prevent unnecessary calls when addresses are empty. Based on learnings, this also aligns with “use useThor instead of useConnex”.

Also applies to: 170-193


195-231: Verify gating for "Access and security" section — isConnectedWithSocialLogin may be overly restrictive

Security-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 isConnectedWithSocialLogin or if it should be available to all Privy-connected users. If isConnectedWithSocialLogin is 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 exports

Since this index now only re-exports ConnectionCard, any existing imports of CrossAppConnectionCard, DappKitConnectionCard, or PrivyConnectionCard will 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 removed

Ensure that the old ../Contents/Account/DisconnectConfirmContent import path has no remaining references in the codebase and that all callers use the new ../Contents/DisconnectConfirmation/DisconnectConfirmContent path 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 accessing appDetails[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's useCallClause hook pattern with appropriate data transformation.

Comment thread packages/vechain-kit/src/components/ProfileCard/ProfileCard.tsx
Comment thread packages/vechain-kit/src/components/ProfileCard/ProfileCard.tsx
Comment thread packages/vechain-kit/src/hooks/api/wallet/useXAppMetadata.tsx
Comment thread packages/vechain-kit/src/languages/en.json
@github-actions

github-actions Bot commented Dec 12, 2025

Copy link
Copy Markdown
Contributor

Size Change: -2 B (0%)

Total Size: 5.43 MB

Filename Size Change
packages/vechain-kit/dist/index-CbP7_u7N.d.cts 0 B -143 kB (removed) 🏆
packages/vechain-kit/dist/index-CbP7_u7N.d.cts.map 0 B -41.3 kB (removed) 🏆
packages/vechain-kit/dist/index-u3CPquCV.d.cts 0 B -5.63 kB (removed) 🏆
packages/vechain-kit/dist/index-u3CPquCV.d.cts.map 0 B -2.99 kB (removed) 🏆
packages/vechain-kit/dist/index-whAsM_JL.d.mts 0 B -143 kB (removed) 🏆
packages/vechain-kit/dist/index-whAsM_JL.d.mts.map 0 B -41.3 kB (removed) 🏆
packages/vechain-kit/dist/index-CN45XRFd.d.cts 143 kB +143 kB (new file) 🆕
packages/vechain-kit/dist/index-CN45XRFd.d.cts.map 41.3 kB +41.3 kB (new file) 🆕
packages/vechain-kit/dist/index-DSMUkHcK.d.cts 5.63 kB +5.63 kB (new file) 🆕
packages/vechain-kit/dist/index-DSMUkHcK.d.cts.map 2.99 kB +2.99 kB (new file) 🆕
packages/vechain-kit/dist/index-DTfV6jAG.d.mts 143 kB +143 kB (new file) 🆕
packages/vechain-kit/dist/index-DTfV6jAG.d.mts.map 41.3 kB +41.3 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size
packages/vechain-kit/dist/assets 4.1 kB
packages/vechain-kit/dist/assets-aAdDxPJu.mjs 50.1 kB
packages/vechain-kit/dist/assets-aAdDxPJu.mjs.map 70.2 kB
packages/vechain-kit/dist/assets-DXVXPy3w.cjs 54.8 kB
packages/vechain-kit/dist/assets-DXVXPy3w.cjs.map 71.6 kB
packages/vechain-kit/dist/assets/index.cjs 716 B
packages/vechain-kit/dist/assets/index.d.cts 973 B
packages/vechain-kit/dist/assets/index.d.mts 973 B
packages/vechain-kit/dist/assets/index.mjs 718 B
packages/vechain-kit/dist/index-Bs6t5GxR.d.mts 5.63 kB
packages/vechain-kit/dist/index-Bs6t5GxR.d.mts.map 2.99 kB
packages/vechain-kit/dist/index.cjs 573 kB
packages/vechain-kit/dist/index.cjs.map 1.75 MB
packages/vechain-kit/dist/index.d.cts 19.8 kB
packages/vechain-kit/dist/index.d.mts 19.8 kB
packages/vechain-kit/dist/index.mjs 541 kB
packages/vechain-kit/dist/index.mjs.map 1.7 MB
packages/vechain-kit/dist/utils 4.1 kB
packages/vechain-kit/dist/utils-Bl-JeVTg.cjs 26.2 kB
packages/vechain-kit/dist/utils-Bl-JeVTg.cjs.map 63 kB
packages/vechain-kit/dist/utils-DAs6kMGs.mjs 21.1 kB
packages/vechain-kit/dist/utils-DAs6kMGs.mjs.map 62.7 kB
packages/vechain-kit/dist/utils/index.cjs 1.91 kB
packages/vechain-kit/dist/utils/index.d.cts 2.94 kB
packages/vechain-kit/dist/utils/index.d.mts 2.94 kB
packages/vechain-kit/dist/utils/index.mjs 1.93 kB

compressed-size-action

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

getChangedValues is redefined on every render, so including it in the dependency array breaks memoization—hasChanges recalculates every render, defeating the purpose of useMemo.

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 coverInputRef and 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 onClick handler has significant duplication between branches. Extracting the common initialContentSource would 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8580f43 and 57ab098.

📒 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, use useThor instead of useConnex for contract interactions
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
For multiple parallel contract calls, use the executeMultipleClausesCall utility wrapped in a useQuery hook with the pattern: define query key function, use executeMultipleClausesCall in queryFn mapping items to clause objects, and transform results
For transaction building and sending, use the useBuildTransaction hook 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 the enabled property to prevent unnecessary contract calls, checking for all required parameters: enabled: !!requiredParam && !!otherRequiredParam
Use the select option 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: use getCallClauseQueryKeyWithArgs for contract calls with arguments and getCallClauseQueryKey for calls without arguments to ensure proper caching and invalidation
Use TypeScript as const assertions for method names and as 0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions

Files:

  • packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/SettingsContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/KitSettings/LanguageSettingsContent.tsx
  • packages/vechain-kit/src/theme/tokens.ts
  • packages/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 if network.type dependency is necessary.

The effect depends on network.type but 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.type is 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 useColorModeValue import 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 renderLanguageButton effectively:

  • Computes isSelected once 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 useColorModeValue import is correctly added, maintaining consistency with the LanguageSettingsContent implementation.


37-40: LGTM! Consistent color mode styling.

The selectedBg uses identical rgba values as LanguageSettingsContent, ensuring a uniform selected item appearance across settings screens.


47-69: LGTM! Consistent refactoring pattern.

The renderCurrencyButton follows the same clean refactoring pattern as LanguageSettingsContent:

  • Single isSelected computation
  • 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 SettingsContentProps type 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 upgradeRequired and 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 onDisconnect and onBack callbacks
  • Handles the complete logout flow through handleLogout

65-69: The useUpgradeRequired hook already safely handles empty strings—no changes needed.

The hook uses conditional query enabling (enabled: !!thor && !!accountAddress && !!ownerAddress && !!network.type at 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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, so isValid / error state can lag until the next edit; also consider shouldDirty for UX consistency.

 const handleSetMaxAmount = () => {
     if (selectedToken) {
-        setValue('amount', selectedToken.balance);
+        setValue('amount', selectedToken.balance, {
+            shouldValidate: true,
+            shouldDirty: true,
+        });
     }
 };

504-519: Guard ens_normalize() — it can throw during typing

If 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 only address.
Without that, switching networks can serve a cached avatar resolved on a different network. Additionally, all call sites of getAvatarOfAddressQueryKey need to be updated to pass network.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, and CustomizationSummaryContent.tsx to pass network.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 become Infinity) for large/high-precision balances. Prefer formatting without converting to JS number (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 accessibility

This is effectively an action (“set max”), but it’s not keyboard-focusable by default. Prefer a Chakra Button (variant="link") or add as="button" + type="button" + focus styles + key handling.

packages/vechain-kit/src/components/AccountModal/Contents/Swap/SwapTokenContent.tsx (5)

215-222: Incomplete dependency in useMemo.

The dependency array includes from?.decimals but the memo also uses from for the conditional check. This can lead to stale closures if from changes but from?.decimals remains 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 arbitrary setTimeout for refetch.

The 100ms delay before refetchGasEstimation() appears to be a workaround. If the intent is to ensure state updates are applied before refetching, consider using useEffect to react to selectedGasToken changes 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 in useCallback.

The handleSwapError callback references fromToken, toToken, and amount in 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: Harden getCrossAppAvatar: normalize app name + consider honoring timestamp to 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 checking error.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

📥 Commits

Reviewing files that changed from the base of the PR and between 57ab098 and 00a30a4.

📒 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, use useThor instead of useConnex for contract interactions
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
For multiple parallel contract calls, use the executeMultipleClausesCall utility wrapped in a useQuery hook with the pattern: define query key function, use executeMultipleClausesCall in queryFn mapping items to clause objects, and transform results
For transaction building and sending, use the useBuildTransaction hook 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 the enabled property to prevent unnecessary contract calls, checking for all required parameters: enabled: !!requiredParam && !!otherRequiredParam
Use the select option 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: use getCallClauseQueryKeyWithArgs for contract calls with arguments and getCallClauseQueryKey for calls without arguments to ensure proper caching and invalidation
Use TypeScript as const assertions for method names and as 0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions

Files:

  • packages/vechain-kit/src/theme/modal.ts
  • packages/vechain-kit/src/components/common/AddressDisplayCard.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/SendToken/SendTokenContent.tsx
  • packages/vechain-kit/src/hooks/api/vetDomains/useGetAvatarOfAddress.ts
  • packages/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: Verify borderRadius="2xl" is supported by the project theme (loading state).
If the app overrides Chakra radii tokens, ensure 2xl is defined (otherwise it can silently fall back / look wrong).


118-190: Consistent radius across loaded + loading states (nice).
Both branches now use borderRadius="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 isTransactionPending or isWaitingForWalletConfirmation is 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 isLoadingQuote is 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 like send-token-summary → successful-operation should animate forward, not backward.

Consider checking currKey patterns 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 imported transition constant.

The inline transition duplicates the values from the imported transition constant. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 00a30a4 and 639cc60.

📒 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, use useThor instead of useConnex for contract interactions
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
For multiple parallel contract calls, use the executeMultipleClausesCall utility wrapped in a useQuery hook with the pattern: define query key function, use executeMultipleClausesCall in queryFn mapping items to clause objects, and transform results
For transaction building and sending, use the useBuildTransaction hook 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 the enabled property to prevent unnecessary contract calls, checking for all required parameters: enabled: !!requiredParam && !!otherRequiredParam
Use the select option 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: use getCallClauseQueryKeyWithArgs for contract calls with arguments and getCallClauseQueryKey for calls without arguments to ensure proper caching and invalidation
Use TypeScript as const assertions for method names and as 0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions

Files:

  • packages/vechain-kit/src/components/AccountModal/utils/getContentKey.ts
  • packages/vechain-kit/src/components/AccountModal/utils/animationVariants.ts
  • packages/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.stringify omits function properties (like setCurrentContent), 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 AnimatePresence with mode="wait" ensures proper sequencing of exit/enter animations, and the key prop correctly triggers re-animation when content changes.


214-219: Navigation path updated correctly.

The onBack callback now navigates to 'settings' instead of the removed 'access-and-security' content type, aligning with the settings consolidation in this PR.

Comment thread packages/vechain-kit/src/components/AccountModal/AccountModal.tsx Outdated
Comment thread packages/vechain-kit/src/components/AccountModal/AccountModal.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 in derivePrimaryButtonStyles causes invisible buttons

When modalBgColor and textColor are provided without explicit primaryButton config, the derived branch (lines 378–385) returns color: 'white' hardcoded. This conflicts with light mode defaults where bg: 'white' and color: 'blackAlpha.900', resulting in white text on white background.

Additionally, the derived branch omits rounded, hoverBg, and backdropFilter properties 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 in useEffect but read during render).
This is the same timing issue previously flagged: directionRef.current is 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 as Variants / Transition (and export a Direction union) so future edits can’t drift from what motion.div expects.

+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.stickyHeader looks unused / misleading

getGlassEffectSettings() returns a single blur string (Line 465) and uses defaultBlur.modal when glass is disabled (Line 479), so changing defaultBlur.stickyHeader (Line 474) appears to have no effect and can confuse future edits. Either remove the per-surface defaultBlur shape, 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

📥 Commits

Reviewing files that changed from the base of the PR and between 639cc60 and 38518f9.

📒 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, use useThor instead of useConnex for contract interactions
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
For multiple parallel contract calls, use the executeMultipleClausesCall utility wrapped in a useQuery hook with the pattern: define query key function, use executeMultipleClausesCall in queryFn mapping items to clause objects, and transform results
For transaction building and sending, use the useBuildTransaction hook 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 the enabled property to prevent unnecessary contract calls, checking for all required parameters: enabled: !!requiredParam && !!otherRequiredParam
Use the select option 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: use getCallClauseQueryKeyWithArgs for contract calls with arguments and getCallClauseQueryKey for calls without arguments to ensure proper caching and invalidation
Use TypeScript as const assertions for method names and as 0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions

Files:

  • packages/vechain-kit/src/components/AccountModal/utils/animationVariants.ts
  • packages/vechain-kit/src/theme/tokens.ts
  • packages/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 to settings looks consistent with the new consolidation.


39-41: The getContentKey function is correctly implemented with no undefined variable issues. The variable is properly named propsStr (line 14) and consistently used in the loop on lines 17-18. The function receives valid AccountModalContentTypes objects 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 accessible

The primary button with bg: '#272A2E' and color: 'white' has strong WCAG AAA-compliant contrast (approximately 16:1). Hover behavior is explicitly handled in the button component: when hoverBg is not defined (as in this case), the implementation applies opacity: 0.8 as a fallback, providing clear visual feedback. No assumptions or derivations are needed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 coverInputRef and 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 (compute direction, but pass directionRef.current).

You compute direction synchronously (Line 70-93) but the animation reads directionRef.current (Line 275), which is only updated in an effect (Line 96-99). That can still yield the wrong enter/exit direction immediately after currentContent changes.

Suggested fix: use the computed direction for 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 directionRef entirely 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 with position="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

📥 Commits

Reviewing files that changed from the base of the PR and between 38518f9 and 53ace92.

📒 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, use useThor instead of useConnex for contract interactions
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
For multiple parallel contract calls, use the executeMultipleClausesCall utility wrapped in a useQuery hook with the pattern: define query key function, use executeMultipleClausesCall in queryFn mapping items to clause objects, and transform results
For transaction building and sending, use the useBuildTransaction hook 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 the enabled property to prevent unnecessary contract calls, checking for all required parameters: enabled: !!requiredParam && !!otherRequiredParam
Use the select option 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: use getCallClauseQueryKeyWithArgs for contract calls with arguments and getCallClauseQueryKey for calls without arguments to ensure proper caching and invalidation
Use TypeScript as const assertions for method names and as 0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions

Files:

  • packages/vechain-kit/src/components/AccountModal/Contents/Profile/Customization/CustomizationContent.tsx
  • packages/vechain-kit/src/components/AccountModal/AccountModal.tsx
  • packages/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 via contentVariants / 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.

Comment on lines +69 to +93
// 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';
})();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

@Agilulfo1820 Agilulfo1820 merged commit bde8c43 into main Dec 12, 2025
7 of 8 checks passed
@Agilulfo1820 Agilulfo1820 deleted the fix/ui branch December 12, 2025 15:38
@github-actions

Copy link
Copy Markdown
Contributor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

💡 [REQUEST] - Improve modal content transition/animation

1 participant