Skip to content

chore(walletui): update dependencies - #1564

Merged
sdbondi merged 4 commits into
tari-project:developmentfrom
NovaT82:wallet-ui
Sep 2, 2025
Merged

chore(walletui): update dependencies#1564
sdbondi merged 4 commits into
tari-project:developmentfrom
NovaT82:wallet-ui

Conversation

@NovaT82

@NovaT82 NovaT82 commented Sep 2, 2025

Copy link
Copy Markdown
Contributor

Description

Update wallet ui dependencies
Updated React Query syntax throughout the site, as there were breaking changes going from v4 to v5
Added alias imports

Motivation and Context

How Has This Been Tested?

Manually

What process can a PR reviewer use to test or verify this change?

Breaking Changes

x

  • None
  • Requires data directory to be deleted
  • Other - Please specify

Summary by CodeRabbit

  • New Features
    • Enhanced “Claim Testnet NFTs” flow: streamlined action triggers and automatic refresh of NFT lists after claiming.
  • Improvements
    • Consistent loading states: various actions now use “pending” for spinners/disabled buttons (e.g., submitting manifests, onboarding, refreshing balances).
    • UI polish: developer tools panel repositioned for better visibility in development.
  • Refactor
    • Adopted path aliases across the app for cleaner, more maintainable imports; no functional changes.
  • Chores
    • Upgraded frontend dependencies (React, React Query, MUI, WalletConnect, and others) for performance, stability, and compatibility.

@coderabbitai

coderabbitai Bot commented Sep 2, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

The PR introduces TypeScript/Vite path aliases, updates React Query usage to v5-style APIs, adjusts related UI code (isLoading→isPending), and bumps frontend dependencies. It also adds a concrete NFT faucet action in ClaimNftsButton, tweaks WebAuthn typing, updates tsconfig moduleResolution to Bundler, and configures aliases in Vite.

Changes

Cohort / File(s) Summary
Dependency bumps
applications/tari_walletd/web_ui/package.json
Version updates across React, MUI, React Query, WalletConnect, and tooling; no app code changes.
Path alias adoption
applications/tari_walletd/web_ui/src/**/* (many), e.g., @/App, @components/*, @routes/*, @api/*, @store/*, @utils/*, @theme/*, @hooks/*
Switched relative imports to TS/Vite alias imports across components, routes, hooks, store, utils, and theme; no behavior changes.
React Query v5-style API updates
@api/hooks/useAccounts.ts, useKeys.tsx, useNfts.tsx, useTemplate.tsx, useTemplatesAuthored.tsx, useTokens.tsx, useTransactions.tsx, useAuth.tsx, useWebauthn.tsx
useMutation now uses object form with mutationFn; invalidateQueries uses object {queryKey}; several onError callbacks removed; placeholderData added for transactions; public shift from isLoading→isPending in some hooks; useAccountsList gains default for enabled.
Config for aliases/resolution
applications/tari_walletd/web_ui/tsconfig.json, tsconfig.node.json, vite.config.ts
moduleResolution: Node→Bundler; baseUrl and paths added; Vite resolve.alias added for @, @components, @routes, @utils, @assets, @hooks, @api, @store, @theme.
UI adjustments tied to React Query changes
src/main.tsx, src/routes/Manifest/Manifest.tsx, src/routes/Onboarding/Onboarding.tsx, src/routes/AssetVault/Components/MyAssets.tsx
Devtools position bottom-right→bottom; components now consume isPending instead of isLoading where applicable; button disabled state wired to isPending.
NFT faucet action
src/routes/AssetVault/NFTs/components/ClaimNftsButton.tsx
Adds onClaimTestnetNfts calling faucet mint (fixed payload), invalidates NFT queries via predicate; early return if no account.
WebAuthn typing
src/routes/WebauthnRegistration/Components/Registration.tsx
Broadens createCredential challenge type to BufferSource; replaces ts-ignore with casted access for challenge.
Misc type/import tweaks
src/routes/AccountDetails/AccountDetails.tsx, src/routes/AssetVault/Components/Assets.tsx, src/hooks/useTimeAgo.ts, src/utils/json_rpc.ts, src/utils/helpers.tsx, src/theme/tokens.ts, src/store/authStore.ts, and others
Minor type imports/casts (e.g., ApiError) and alias-based import updates; no logic changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as ClaimNftsButton
  participant Store as accountStore
  participant API as claimTestnetFaucetNfts (json_rpc)
  participant Backend as Walletd API
  participant QC as queryClient

  User->>UI: Click "Claim Testnet NFTs"
  UI->>Store: Read current account
  alt No account
    UI-->>User: Render nothing
  else Account present
    UI->>API: claimTestnetFaucetNfts({account, numberToMint:5, mutableData, maxFee})
    API->>Backend: POST mint request
    Backend-->>API: Response (success/error)
    API-->>UI: Promise resolved/rejected
    opt On success
      UI->>QC: invalidateQueries(predicate: NFTs keys)
      QC-->>UI: Trigger refetch of NFT lists
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

CR-too_long, P-acks_required, P-reviews_required

Suggested reviewers

  • sdbondi

Poem

A rabbit bounced through alias lanes,
Sniffed out queries—now pending trains.
Buttons mint NFTs with glee,
Caches hop, invalidation spree.
WebAuthn’s challenge? Nibbled neat.
New paths mapped—so tidy, sweet.
Thump-thump: this merge feels fleet! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (31)
applications/tari_walletd/web_ui/package.json (1)

6-11: Add packageManager field and enforce pnpm usage. In applications/tari_walletd/web_ui/package.json (and other workspace packages at lines 45–52), add a top-level

"packageManager": "pnpm@<your-pnpm-version>"

so Corepack and IDEs pick pnpm automatically, and update CI and local scripts to run pnpm install instead of npm install. (stackoverflow.com, truecoderguru.com)

applications/tari_walletd/web_ui/src/utils/helpers.tsx (1)

307-309: Bug: timezone detection regex appends a second “Z”.

Strings already ending with “Z” don’t match the current regex and get “ZZ”, yielding Invalid Date in some browsers.

Apply this diff:

-  if (!/[Z+\-]\d{2}:?\d{2}$/.test(formatted)) {
+  // Accepts ...Z or ...+hh:mm / +hhmm
+  if (!/(Z|[+\-]\d{2}:?\d{2})$/.test(formatted)) {
     formatted += "Z";
   }
applications/tari_walletd/web_ui/src/Components/JsonTooltip.tsx (1)

26-35: Fix crash risk on invalid/missing JSON and correct prop types.

jsonText is typed as string but checked against null, and JSON.parse isn’t guarded. Also, children should be ReactNode, not string.

-export default function JsonTooltip({ jsonText, children }: { jsonText: string; children: string }) {
-  if (jsonText === null) {
-    return <>No data</>;
-  }
-  return (
-    <div className="tooltip">
-      {children}
-      <span className="tooltiptext json">{renderJson(JSON.parse(jsonText))}</span>
-    </div>
-  );
-}
+export default function JsonTooltip({
+  jsonText,
+  children,
+}: {
+  jsonText?: string | null;
+  children: React.ReactNode;
+}) {
+  if (!jsonText) {
+    return <>No data</>;
+  }
+  let parsed: unknown;
+  try {
+    parsed = JSON.parse(jsonText);
+  } catch {
+    return <>Invalid JSON</>;
+  }
+  return (
+    <div className="tooltip">
+      {children}
+      <span className="tooltiptext json">{renderJson(parsed as any)}</span>
+    </div>
+  );
+}
applications/tari_walletd/web_ui/src/routes/AssetVault/Components/SelectAccount.tsx (1)

44-44: Fix selection when comparing addresses and remove non-null assertion.

Currently you compare objects (info.account.address === account?.address) which may fail; use substateIdToString consistently and avoid account!.

   const theme = useTheme();
+
+  const selectedValue =
+    account &&
+    dataAccountsList?.accounts?.some(
+      (info: AccountInfo) =>
+        substateIdToString(info.account.address) === substateIdToString(account.address),
+    )
+      ? substateIdToString(account.address)
+      : "addAccount";
@@
-          value={
-            dataAccountsList?.accounts.some((info: AccountInfo) => info.account.address === account?.address)
-              ? substateIdToString(account!.address)
-              : "addAccount"
-          }
+          value={selectedValue}

Also applies to: 70-77

applications/tari_walletd/web_ui/src/routes/Transactions/Events.tsx (1)

52-59: Type guard before passing to CopyAddress

value may be non-string; guard to prevent prop type issues.

-  if (key === "resource" || key === "resource_address") {
+  if ((key === "resource" || key === "resource_address") && typeof value === "string") {
     return (
       <Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
         <Typography variant="body2" color="text.secondary">Resource:</Typography>
         <CopyAddress address={value} />
       </Box>
     );
   }
applications/tari_walletd/web_ui/src/routes/AssetVault/NFTs/steps/FormStep.tsx (1)

95-109: Duplicate id between InputLabel and Select; use labelId

Current code assigns the same id to both elements. Fix for a11y and DOM validity.

-            <InputLabel id="select-payer-account">Account (to pay fees)</InputLabel>
+            <InputLabel id="select-payer-account-label">Account (to pay fees)</InputLabel>
             <Select
-              id="select-payer-account"
+              id="select-payer-account"
+              labelId="select-payer-account-label"
               name="payerAccount"
               disabled={disabled}
               displayEmpty
               value={
                 transferFormState.payerAccount ||
                 substateIdToString(accounts.find((a) => a.account.is_default)?.account.address) ||
                 ""
               }
applications/tari_walletd/web_ui/src/routes/Auth/Auth.tsx (1)

35-39: Move setAuthToken calls into an effect; don’t set state during render.

setAuthToken() inside render paths (“none”/“webauthn”) can cause render loops. Do the updates in an effect and keep render pure.

@@
   useEffect(() => {
     if (!authMethodsIsError && authMethod) {
       setCurrAuthMethod(authMethod.method);
     }
 
     if (authMethodsError) {
       console.error(authMethodsError);
     }
-  }, [authMethod, authMethodsIsError]);
+  }, [authMethod, authMethodsIsError, authMethodsError]);
+
+  // Apply auth token side-effects outside of render
+  useEffect(() => {
+    if (currAuthMethod === "none") {
+      setAuthToken(AUTH_TOKEN_FOR_NONE_AUTH);
+    }
+    if (currAuthMethod === "webauthn" && authToken === AUTH_TOKEN_FOR_NONE_AUTH) {
+      setAuthToken("");
+    }
+  }, [currAuthMethod, authToken, setAuthToken]);
@@
   if (currAuthMethod === "none") {
     console.log("no auth");
-    setAuthToken(AUTH_TOKEN_FOR_NONE_AUTH);
     return <Navigate replace to={redirect} />;
   }
@@
   if (currAuthMethod === "webauthn") {
-    if (authToken === AUTH_TOKEN_FOR_NONE_AUTH) {
-      setAuthToken("");
-    }
     return <Navigate replace to={"/auth/webauthn?redirect=" + redirect} />;
   }

Also applies to: 41-46, 25-33

applications/tari_walletd/web_ui/src/routes/Transactions/TransactionDetails.tsx (1)

53-54: React Query v5: use isPending (not isLoading).

In v5, isLoading was split/repurposed; recommended gate is isPending. Update selector and usages for correct initial-state handling.

-  const { data, isLoading, isError, error } = useTransactionDetails(transactionId);
+  const { data, isPending, isError, error } = useTransactionDetails(transactionId);
@@
-    if (isLoading) {
+    if (isPending) {
       return <Loading />;
     }
@@
-      <Fade in={!isLoading}>
+      <Fade in={!isPending}>

References: TanStack Query v5 migration guide and queries docs. (tanstack.com)

Also applies to: 92-99, 136-136

applications/tari_walletd/web_ui/src/utils/json_rpc.ts (1)

164-165: Bug: outerAddress ignored after first resolution.

When outerAddress is set, code returns DEFAULT_WALLET_ADDRESS instead of reusing outerAddress. This can regress to localhost even after discovering a remote address.

-  const getAddress = !outerAddress ? getClientAddress() : Promise.resolve(DEFAULT_WALLET_ADDRESS);
+  const getAddress = !outerAddress ? getClientAddress() : Promise.resolve(outerAddress!);
...
-  const getAddress = !outerAddress ? getClientAddress() : Promise.resolve(DEFAULT_WALLET_ADDRESS);
+  const getAddress = !outerAddress ? getClientAddress() : Promise.resolve(outerAddress!)

Also applies to: 187-189

applications/tari_walletd/web_ui/src/routes/Transactions/Instructions.tsx (1)

35-41: RowData receives an unused second param; keys become "undefined-*" and may collide.

React only passes a single props object to function components, so index here is always undefined. Remove the second param and the inner TableRow keys (the parent already keys ), or pass index via props.

-function RowData({ title, data }: { title: string; data: Instruction }, index: number) {
+function RowData({ title, data }: { title: string; data: Instruction }) {
   const [open, setOpen] = useState(false);
   const theme = useTheme();
   return (
     <>
-      <TableRow key={`${index}-1`}>
+      <TableRow>
         <DataTableCell sx={{ borderTop: 1, borderTopColor: "divider", borderBottom: "none" }}>{title}</DataTableCell>
         <DataTableCell
           width={90}
           sx={{ borderTop: 1, borderTopColor: "divider", borderBottom: "none", textAlign: "center" }}
         >
 ...
-      <TableRow key={`${index}-2`}>
+      <TableRow>

Also applies to: 57-58

applications/tari_walletd/web_ui/src/routes/AssetVault/Components/TransferNft.tsx (3)

271-279: Bug: Effect depends on undefined open and default payer-account condition inverted.

open isn’t in scope in this component (should be props.open), and you only set the default payer account when it’s already non-empty.

-  useEffect(() => {
-    if (transferFormState.payerAccount != "") {
-      setTransferFormState({
-        ...transferFormState,
-        payerAccount: substateIdToString(account.address),
-      });
-    }
-  }, [open]);
+  useEffect(() => {
+    if (transferFormState.payerAccount == "") {
+      setTransferFormState({
+        ...transferFormState,
+        payerAccount: substateIdToString(account.address),
+      });
+    }
+  }, [props.open]);

142-151: Unbounded refetch on every render.

refetchNfts() is invoked at render-time, causing continuous fetching/re-renders. Move it into an effect keyed by dialog open state.

-  refetchNfts().catch(console.error);
+  useEffect(() => {
+    if (props.open) {
+      refetchNfts().catch(console.error);
+    }
+  }, [props.open, refetchNfts]);

310-318: Type the Select change event correctly for single-select.

The payer account Select isn’t multiple, so use SelectChangeEvent<string> to avoid incorrect runtime guards.

-  const handlePayerAccountChange = (event: SelectChangeEvent<string[]>) => {
-    if (typeof event.target.value != "string") {
-      return;
-    }
+  const handlePayerAccountChange = (event: SelectChangeEvent<string>) => {
     const payerAccountSelected = {
       ComponentAddress: event.target.value,
     };
applications/tari_walletd/web_ui/src/routes/AssetVault/Components/PublishTemplate.tsx (1)

200-207: Fix account selection/value handling and maxFee typing

Current Select value can be an object or account name (not address), which breaks MUI equality checks and produces wrong fee_account. Also, maxFee is typed number but stored as string. Align on address strings and parse numbers.

@@
-  function setFormValue(e: React.ChangeEvent<HTMLInputElement>) {
-    setFormState({
-      ...formState,
-      [e.target.name]: e.target.value,
-    });
-    if (validity[e.target.name as keyof object] !== undefined) {
-      setValidity({
-        ...validity,
-        [e.target.name]: e.target.validity.valid,
-      });
-    }
-  }
+  function setFormValue(e: React.ChangeEvent<HTMLInputElement>) {
+    const { name, value, validity: vld } = e.target;
+    setFormState({
+      ...formState,
+      [name]:
+        name === "maxFee"
+          ? (value === "" ? null : Number(value))
+          : (value as unknown as string),
+    });
+    if ((validity as Record<string, boolean>)[name] !== undefined) {
+      setValidity({
+        ...validity,
+        [name]: vld.valid,
+      } as typeof validity);
+    }
+  }
@@
-  function setSelectFormValue(e: SelectChangeEvent<unknown>) {
+  function setSelectFormValue(e: SelectChangeEvent<string>) {
     setFormState({
       ...formState,
-      [e.target.name]: e.target.value,
+      [e.target.name]: e.target.value as string,
     });
   }
@@
-  const onSubmit = async (e: FormEvent) => {
+  const onSubmit = async (e: FormEvent) => {
     e.preventDefault();
-    if (!account) {
+    // Allow submit if either a selected account or a store account is present
+    if (!formState.account && !account) {
       return;
     }
     setDisabled(true);
     const isDryRun = !formState.maxFee;
-    publishTemplate({
+    publishTemplate({
       fee_account: { ComponentAddress: formState.account || substateIdToString(account.address) },
       binary: base64FromArrayBuffer(formState.binary!),
       max_fee: isDryRun ? 1_000_000 : Number(formState.maxFee) || 0,
       detect_inputs: true,
       dry_run: isDryRun,
     })
@@
-  useEffect(() => {
-    let account = accounts?.find((a) => a.account.is_default)?.account.name || null;
-    if (account) {
-      setFormState({ ...INITIAL_VALUES, account });
-      setValidity({ ...validity, account: true });
-    }
-  }, [accounts]);
+  useEffect(() => {
+    const addr = accounts?.find((a) => a.account.is_default)?.account.address;
+    if (addr) {
+      setFormState((s) => ({ ...s, account: substateIdToString(addr) }));
+      setValidity((v) => ({ ...v, account: true }) as typeof validity);
+    }
+  }, [accounts]);
@@
-              <InputLabel id="select-account">Account</InputLabel>
+              <InputLabel id="select-account">Account</InputLabel>
               <Select
-                id="select-account"
+                id="select-account"
+                labelId="select-account"
                 name="account"
                 disabled={disabled}
                 displayEmpty
-                value={formState.account || accounts.find((a) => a.account.is_default) || ""}
+                value={
+                  formState.account ||
+                  (accounts?.find((a) => a.account.is_default)
+                    ? substateIdToString(accounts.find((a) => a.account.is_default)!.account.address)
+                    : "")
+                }
                 onChange={setSelectFormValue}
                 variant="outlined"
               >
@@
           <TextField
             name="maxFee"
             label="Fee"
             type="number"
-            value={formState.maxFee}
+            value={formState.maxFee ?? ""}
             placeholder="Enter max fee"
             onChange={setFormValue}
             disabled={disabled}
             style={{ flexGrow: 1 }}
           />

Also applies to: 213-231, 104-115, 117-123, 124-133, 256-265

applications/tari_walletd/web_ui/src/api/hooks/useTemplatesAuthored.tsx (1)

14-18: Remove notifyOnChangeProps from all hooks and review retryOnMount under React Query v5

  • Delete the notifyOnChangeProps line from every useQuery call in:
    • useWebauthn.tsx (L14)
    • useTemplatesAuthored.tsx (L15)
    • useTemplate.tsx (L34)
    • useAccounts.ts (L258)
  • Replace any memoization needs with the select option.
  • Comment out or remove retryOnMount in each hook and verify whether it’s still required, since its semantics have changed in v5.

Example diff for useTemplatesAuthored.tsx:

   return useQuery({
     queryKey: ["templates_list_authored", request],
     queryFn: () => templatesListAuthored(request),
-    refetchInterval: false,
-    notifyOnChangeProps: ["data", "error"],
-    retryOnMount: false,
+    refetchInterval: false,
+    // notifyOnChangeProps removed in v5
+    // retryOnMount: false, // verify necessity under v5 semantics
     retry: false,
   });

Use this command to locate all instances before applying changes:

rg -n 'notifyOnChangeProps|retryOnMount' -g '*.ts' -g '*.tsx'
applications/tari_walletd/web_ui/src/routes/AccountDetails/AccountDetails.tsx (1)

171-177: Bug: “Public key” column renders the account address instead of the public key.

User-facing data is incorrect.

-                  <DataTableCell>
-                    {accountsData?.public_key && <CopyAddress address={accountsData?.account.address!} />}
-                  </DataTableCell>
+                  <DataTableCell>
+                    {accountsData?.public_key && <CopyAddress address={accountsData.public_key!} />}
+                  </DataTableCell>
applications/tari_walletd/web_ui/src/routes/WebauthnRegistration/Components/Registration.tsx (1)

88-99: Decode challenge as base64url and add a guard (Buffer may be unnecessary in browsers).

The challenge from WebAuthn servers is commonly base64url-encoded. Using Buffer.from(..., "base64") can fail on '-'/'_' and relies on polyfills. Prefer a base64url→Uint8Array helper and guard for missing challenge.

-      const challenge = Buffer.from((startRegisterResponse.public_key as any).challenge, "base64");
+      const pk = startRegisterResponse.public_key as any;
+      const challengeB64url = pk?.challenge;
+      if (typeof challengeB64url !== "string" || challengeB64url.length === 0) {
+        throw new Error("Failed to start registration: missing challenge");
+      }
+      const challenge = base64urlToUint8Array(challengeB64url);

Add once in this module (or a shared util):

function base64urlToUint8Array(input: string): Uint8Array {
  const b64 = input.replace(/-/g, "+").replace(/_/g, "/").replace(/=/g, "");
  const bin = atob(b64);
  const bytes = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
  return bytes;
}
applications/tari_walletd/web_ui/src/routes/AssetVault/NFTs/components/SendNft.tsx (1)

151-155: Do not call refetch during render. Move to an effect.

Calling refetchNfts() unconditionally in render can cause repeated fetches and render loops. Trigger refetch on account changes instead.

-  // Only refetch NFTs when account is available
-  if (account) {
-    refetchNfts().catch(console.error);
-  }
+  // Only refetch NFTs when account becomes available or changes
+  useEffect(() => {
+    if (account) {
+      refetchNfts().catch(console.error);
+    }
+  }, [account, refetchNfts]);
applications/tari_walletd/web_ui/src/api/hooks/useNfts.tsx (1)

31-39: Page-through with consistent page size for better performance.

Subsequent requests use limit: 1. Use the same limit for all pages and break when the last page has < limit items.

-      while (nfts.nfts.length > 0) {
+      while (nfts.nfts.length > 0) {
         offset += limit;
-        nfts = await nftList({
+        nfts = await nftList({
           account: request.account,
-          limit: 1,
+          limit,
           offset: offset,
         });
         result = result.concat(nfts.nfts);
+        if (nfts.nfts.length < limit) break;
       }
applications/tari_walletd/web_ui/src/Components/ConnectorLink/ConnectorLink.tsx (1)

57-66: Fix connector-link regex and hard JSON.parse to avoid crashes on valid links.

  • ([^\\]*) excludes backslashes, not slashes; names with “/” fail.
  • Greedy (.*) can over-capture.
  • JSON.parse can throw, leaving the dialog open in a bad state.

Apply safer parsing and error handling:

-  const setLink = (value: string) => {
-    const re = /tari:\/\/([^\\]*)\/([a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+)\/(.*)\/(.*)/i;
-    let groups;
-    if ((groups = re.exec(value))) {
-      setName(decodeURIComponent(groups[1]));
-      setSignalingServerJWT(groups[2]);
-      setPermissions(JSON.parse(groups[3]).map((permission: any) => parse(permission)));
-      setOptionalPermissions(JSON.parse(groups[4]).map((permission: any) => parse(permission)));
-    }
-    _setLink(value);
-  };
+  const setLink = (value: string) => {
+    const re = /^tari:\/\/([^/]+)\/([A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+)\/([^/]+)\/([^/]+)/i;
+    const groups = re.exec(value);
+    if (groups) {
+      try {
+        setName(decodeURIComponent(groups[1]));
+        setSignalingServerJWT(groups[2]);
+        const required = JSON.parse(groups[3]);
+        const optional = JSON.parse(groups[4]);
+        setPermissions(required.map((p: any) => parse(p)));
+        setOptionalPermissions(optional.map((p: any) => parse(p)));
+        setLinkDetected(true);
+      } catch (e) {
+        console.error("Invalid connector link JSON:", e);
+        setLinkDetected(false);
+      }
+    }
+    _setLink(value);
+  };
applications/tari_walletd/web_ui/src/api/hooks/useTransactions.tsx (1)

37-44: Bug: transaction_details queryKey must include hash

Without hashing in the key, different transactions will share cache entries.

   return useQuery({
-    queryKey: ["transaction_details"],
+    queryKey: ["transaction_details", hash],
     queryFn: () => {
       return transactionsGet({ transaction_id: hash });
     },
   });
applications/tari_walletd/web_ui/src/api/hooks/useAccounts.ts (3)

104-156: Fix fee fallback, prefer const, and invalidate balances/transactions using variables in onSettled

  • Use ?? for max_fee to avoid overriding 0.
  • Use const for request objects.
  • Invalidate related queries after transfer: accounts, transactions, balances for the source account (via onSettled variables).

Apply:

   return useMutation({
     mutationFn: (params: TransferParams) => {
-      const account = { ComponentAddress: params.account };
-      const max_fee = params.max_fee || DEFAULT_MAX_FEE;
+      const account = { ComponentAddress: params.account };
+      const max_fee = params.max_fee ?? DEFAULT_MAX_FEE;
       if (params.resourceType === "Confidential") {
-        let transferRequest = {
+        const transferRequest = {
           account,
           amount: params.amount,
           resource_address: params.resource_address,
           destination_public_key: params.destination_public_key,
           max_fee,
           proof_from_badge_resource: params.badge,
           input_selection: params.input_selection,
           output_to_revealed: params.output_to_revealed,
           dry_run: params.dry_run,
         };
         return accountsConfidentialTransfer(transferRequest);
       } else if (params.resourceType === "Stealth") {
-        let transferRequest = {
+        const transferRequest = {
           owner_account: account,
           input_selection: params.input_selection,
           resource_address: params.resource_address,
           destination_public_key: params.destination_public_key,
           max_fee,
           blinded_output_amount: params.output_to_revealed ? 0 : params.amount,
           revealed_output_amount: params.output_to_revealed ? params.amount : 0,
           dry_run: params.dry_run,
         };
         return accountsStealthTransfer(transferRequest);
       } else {
         // Fungible and NFTs
-        let transferRequest = {
+        const transferRequest = {
           account,
           amount: params.amount,
           resource_address: params.resource_address,
           destination_public_key: params.destination_public_key,
           max_fee,
           proof_from_badge_resource: params.badge,
           input_selection: params.input_selection,
           output_to_revealed: params.output_to_revealed,
           dry_run: params.dry_run,
         };
         return accountsTransfer(transferRequest);
       }
     },
-    onError: (error: ApiError) => {
-      error;
-    },
-    onSettled: () => {
-      queryClient.invalidateQueries({ queryKey: ["accounts"] });
-    },
+    onError: (_error: ApiError) => {},
+    onSettled: (_data, _error, vars) => {
+      queryClient.invalidateQueries({ queryKey: ["accounts"] });
+      queryClient.invalidateQueries({ queryKey: ["transactions"] });
+      if (vars?.account) {
+        queryClient.invalidateQueries({ queryKey: ["accounts_balances_" + vars.account] });
+      }
+    },
   });

218-224: Query key must include pagination parameters

The query function depends on offset and limit; include them in the key to avoid cache collisions and stale data. (tanstack.dev)

Apply:

   return useQuery({
-    queryKey: ["accounts"],
+    queryKey: ["accounts", offset, limit],
     queryFn: () => accountsList({ offset, limit }),
     enabled,
   });

277-282: Include parameters in validator_fees query key

Different inputs should produce distinct cache entries; otherwise you’ll serve wrong data across calls. (tanstack.dev)

Apply:

 export const useValidatorFees = (accountOrKeyIndex: AccountOrKeyIndex, shardGroup = null) => {
   return useQuery({
-    queryKey: ["validator_fees"],
+    queryKey: ["validator_fees", accountOrKeyIndex, shardGroup],
     queryFn: () => validatorsGetFees({ account_or_key: accountOrKeyIndex, shard_group: shardGroup }),
   });
 };
applications/tari_walletd/web_ui/src/App.tsx (2)

139-155: Remove ts-ignore; type GuardedRoute and encode redirect param

Improve typing and avoid constructing an unencoded query param.

-interface GuardedRouteProps {
-  component: React.ComponentType<any>;
-  redirect?: string;
-  isAuthenticated: boolean;
-
-  [key: string]: any;
-}
-
-// @ts-ignore
-const GuardedRoute = ({
-  component: Component,
-  redirect = "/",
-  isAuthenticated = false,
-  ...rest
-}: GuardedRouteProps) => {
-  return isAuthenticated ? <Component {...rest} /> : <Navigate replace to={"/auth?redirect=" + redirect} />;
-};
+interface GuardedRouteProps<P extends Record<string, unknown> = Record<string, unknown>> {
+  component: React.ComponentType<P>;
+  redirect?: string;
+  isAuthenticated: boolean;
+  [key: string]: unknown;
+}
+const GuardedRoute = <P extends Record<string, unknown>>({
+  component: Component,
+  redirect = "/",
+  isAuthenticated = false,
+  ...rest
+}: GuardedRouteProps<P>) => {
+  return isAuthenticated ? (
+    <Component {...(rest as P)} />
+  ) : (
+    <Navigate replace to={`/auth?redirect=${encodeURIComponent(redirect)}`} />
+  );
+};

179-193: Include authMethodsError in the effect’s dependency array or explicitly disable the lint rule

The useEffect at applications/tari_walletd/web_ui/src/App.tsx lines 179–193 reads authMethodsError but only lists [authMethod, authMethodsIsError] in its deps. Add authMethodsError to the array or precede the effect with a // eslint-disable-next-line react-hooks/exhaustive-deps comment if this omission is intentional.

applications/tari_walletd/web_ui/src/Components/WalletConnectLink/WalletConnectLink.tsx (5)

195-201: Manual “Connect” path never pairs the wallet (broken flow)

Typing a link and pressing Connect advances to page 2 without creating/pairing the wallet, leaving proposal undefined.

-  const handleConnect = () => {
-    linkRef.current && setLink(linkRef.current.value);
-    setPage(page + 1);
-  };
+  const handleConnect = async () => {
+    if (linkRef.current) {
+      setLink(linkRef.current.value.trim());
+    }
+    await handleConnectWithLink();
+  };

266-268: Fix events array syntax; it currently creates a single malformed string

This likely breaks WalletConnect event subscriptions.

-            events: ['chainChanged", "accountsChanged'],
+            events: ["chainChanged", "accountsChanged"],

253-265: Include tari_getAccountByAddress in supported methods

executeMethod supports it but it’s missing here; keep these in sync to avoid proposal rejection.

             methods: [
               "tari_getSubstate",
               "tari_getDefaultAccount",
+              "tari_getAccountByAddress",
               "tari_getAccountBalances",
               "tari_submitTransaction",
               "tari_getTransactionResult",
               "tari_getTemplate",
               "tari_createKey",
               "tari_viewConfidentialVaultBalance",
               "tari_createFreeTestCoins",
               "tari_listSubstates",
               "tari_getNftsList",
             ],

157-160: Default branch should throw to fail fast

Returning undefined on unsupported methods hides errors and returns a 200 with empty result.

-      default:
-        setError(`Unsupported method ${method}`);
+      default:
+        const msg = `Unsupported method ${method}`;
+        setError(msg);
+        throw new Error(msg);

63-64: Remove hardcoded WalletConnect projectId fallback

Shipping a shared fallback can leak usage to a public ID and bypasses your “feature disabled when not set” guard below.

-const projectId: string = import.meta.env.VITE_WALLET_CONNECT_PROJECT_ID || "78f3485d08b9640a087cbcea000e1f8b";
+const projectId: string | undefined = import.meta.env.VITE_WALLET_CONNECT_PROJECT_ID;

Comment on lines +34 to +35
"react": "^19.1.1",
"react-dom": "^19.1.1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Align React types with React 19 (likely TS errors if left at 18.x).

You’re on react/react-dom 19.1.1 but still using @types/react* 18.x, which often causes duplicate/conflicting types and broken refs/JSX typings in TS. Update both to 19.x to match React 19. (npmjs.com, react.dev)

Apply this diff:

-    "@types/react": "^18.3.24",
-    "@types/react-dom": "^18.3.7",
+    "@types/react": "^19.1.1",
+    "@types/react-dom": "^19.1.1",

Also applies to: 46-47

🤖 Prompt for AI Agents
In applications/tari_walletd/web_ui/package.json around lines 34-35 and also
lines 46-47, the project uses react and react-dom 19.1.1 but still has @types
packages pinned to 18.x causing TypeScript type conflicts; update the @types
packages to match React 19 (bump @types/react and @types/react-dom to the
corresponding 19.x versions, and any other React-related @types (e.g.,
@types/react-test-renderer) to 19.x if present) in package.json and run your
package manager (npm/yarn/pnpm) to install the matching types so JSX/refs
typings align with React 19.

Comment on lines +40 to 41
"zustand": "^5.0.8",
"zustand-persist": "^0.4.0"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Reassess ‘zustand-persist’ with Zustand v5.

Zustand v5 includes behavioral changes in persist and drops older patterns. The third‑party “zustand-persist” package is effectively unmaintained (last release years ago), so compatibility is uncertain. Prefer the official persist from zustand/middleware (or purpose‑built alternatives) to avoid subtle hydration bugs. (github.com, socket.dev, security.snyk.io)

If you’re ready to switch, I can propose a minimal diff replacing “zustand-persist” with persist from zustand/middleware and createJSONStorage. Want me to draft it?


Replace zustand-persist with official persist middleware
In applications/tari_walletd/web_ui/package.json remove "zustand-persist" (v0.4.0, last published 4 years ago) to avoid compatibility issues (npmjs.com) and refactor persistence to use:

import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

This leverages the built-in v5 persist middleware and storage helpers (zustand.docs.pmnd.rs). Let me know if you’d like a minimal diff.

🤖 Prompt for AI Agents
In applications/tari_walletd/web_ui/package.json around lines 40-41, remove the
"zustand-persist": "^0.4.0" dependency and replace persistence usage with the
official zustand v5 middleware: refactor any store files to import persist and
createJSONStorage from 'zustand/middleware' and wrap create with persist (using
createJSONStorage for custom storage when needed), update imports/usages
accordingly, and run npm/yarn install to update lockfile; ensure no lingering
references to "zustand-persist" remain in code or package.json.

Comment on lines +55 to 63
return useMutation({
mutationFn: (params: ClaimBurnRequest) => accountsClaimBurn(params),
onError: (error: ApiError) => {
error;
},
onSettled: () => {
queryClient.invalidateQueries(["accounts"]);
queryClient.invalidateQueries({ queryKey: ["accounts"] });
},
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Drop no-op onError and also invalidate transactions after ClaimBurn

  • onError just references the variable; make it a no-op param or remove it.
  • Claiming burns will also affect the transactions list; invalidate it too.

Apply:

   return useMutation({
     mutationFn: (params: ClaimBurnRequest) => accountsClaimBurn(params),
-    onError: (error: ApiError) => {
-      error;
-    },
+    onError: (_error: ApiError) => {},
     onSettled: () => {
       queryClient.invalidateQueries({ queryKey: ["accounts"] });
+      queryClient.invalidateQueries({ queryKey: ["transactions"] });
     },
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return useMutation({
mutationFn: (params: ClaimBurnRequest) => accountsClaimBurn(params),
onError: (error: ApiError) => {
error;
},
onSettled: () => {
queryClient.invalidateQueries(["accounts"]);
queryClient.invalidateQueries({ queryKey: ["accounts"] });
},
});
return useMutation({
mutationFn: (params: ClaimBurnRequest) => accountsClaimBurn(params),
onError: (_error: ApiError) => {},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["accounts"] });
queryClient.invalidateQueries({ queryKey: ["transactions"] });
},
});
🤖 Prompt for AI Agents
In applications/tari_walletd/web_ui/src/api/hooks/useAccounts.ts around lines 55
to 63, the mutation's onError handler is a no-op that only references the error
variable and should be removed or replaced with an explicit no-op param, and the
onSettled invalidation should also include the transactions query because
ClaimBurn affects both accounts and transactions; update onError to either be
removed or written as onError: (_: ApiError) => {}, and change the
invalidateQueries call to invalidate both ["accounts"] and ["transactions"] (or
call invalidateQueries twice) so both caches are refreshed after the mutation.

Comment on lines +73 to 88
return useMutation({
mutationFn: async (req: AccountsCreateMutate) => {
return await accountsCreate({
account_name: req.accountName || "",
is_default: req.isDefault || null,
key_id: req.keyId || null,
});
},
{
onError: (error: ApiError) => {
error;
},
onSettled: () => {
queryClient.invalidateQueries(["accounts"]);
},
onError: (error: ApiError) => {
error;
},
);
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["accounts"] });
},
});
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use nullish coalescing for booleans/numbers; remove no-op onError

Using || will coerce false/0 to null unintentionally. Prefer ?? to preserve explicit false/0. Also, make onError a no-op.

Apply:

   return useMutation({
     mutationFn: async (req: AccountsCreateMutate) => {
       return await accountsCreate({
-        account_name: req.accountName || "",
-        is_default: req.isDefault || null,
-        key_id: req.keyId || null,
+        account_name: req.accountName ?? "",
+        is_default: req.isDefault ?? null,
+        key_id: req.keyId ?? null,
       });
     },
-    onError: (error: ApiError) => {
-      error;
-    },
+    onError: (_error: ApiError) => {},
     onSettled: () => {
       queryClient.invalidateQueries({ queryKey: ["accounts"] });
     },
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return useMutation({
mutationFn: async (req: AccountsCreateMutate) => {
return await accountsCreate({
account_name: req.accountName || "",
is_default: req.isDefault || null,
key_id: req.keyId || null,
});
},
{
onError: (error: ApiError) => {
error;
},
onSettled: () => {
queryClient.invalidateQueries(["accounts"]);
},
onError: (error: ApiError) => {
error;
},
);
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["accounts"] });
},
});
};
return useMutation({
mutationFn: async (req: AccountsCreateMutate) => {
return await accountsCreate({
account_name: req.accountName ?? "",
is_default: req.isDefault ?? null,
key_id: req.keyId ?? null,
});
},
onError: (_error: ApiError) => {},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["accounts"] });
},
});
};
🤖 Prompt for AI Agents
In applications/tari_walletd/web_ui/src/api/hooks/useAccounts.ts around lines
73-88, the mutation currently uses || which coerces false/0 to null and includes
a pointless onError handler; change the ternary defaults to use nullish
coalescing (??) for is_default and key_id so falsy but valid values like false
or 0 are preserved (keep account_name default "" as-is), and remove the no-op
onError block entirely (or omit onError from the useMutation options).

Comment on lines 47 to 53
return useQuery({
queryKey: ["transactions", req.status],
queryFn: () => transactionsGetAll(req),
onError: (error: ApiError) => {
error;
},
refetchInterval: 5000,
keepPreviousData: true,
placeholderData: (previousData) => previousData,
});
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Key queries by full request, not just status

Prevents cache collisions across pages/filters. Keeping placeholderData is good to emulate keepPreviousData.

   return useQuery({
-    queryKey: ["transactions", req.status],
+    queryKey: ["transactions", req],
     queryFn: () => transactionsGetAll(req),
     refetchInterval: 5000,
     placeholderData: (previousData) => previousData,
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return useQuery({
queryKey: ["transactions", req.status],
queryFn: () => transactionsGetAll(req),
onError: (error: ApiError) => {
error;
},
refetchInterval: 5000,
keepPreviousData: true,
placeholderData: (previousData) => previousData,
});
};
return useQuery({
queryKey: ["transactions", req],
queryFn: () => transactionsGetAll(req),
refetchInterval: 5000,
placeholderData: (previousData) => previousData,
});
};
🤖 Prompt for AI Agents
In applications/tari_walletd/web_ui/src/api/hooks/useTransactions.tsx around
lines 47 to 53, the queryKey currently only uses req.status which can cause
cache collisions across different pages/filters; change the queryKey to uniquely
represent the full request (e.g. include all relevant fields or a stable
serialization like JSON.stringify(req) or a tuple of req.page, req.status,
req.filters, etc.) so each distinct request has its own cache entry, and keep
the existing placeholderData to emulate keepPreviousData behavior.

Comment on lines +23 to +24
import Loading from "@components/Loading";
import Error from "@components/Error";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Rename imported Error to avoid shadowing the global Error

Biome flags this as an error. Rename the import and usage to prevent confusion and lint failures.

-import Loading from "@components/Loading";
-import Error from "@components/Error";
+import Loading from "@components/Loading";
+import ErrorView from "@components/Error";
@@
-  if (isError) {
-    return <Error message={errorMessage} />;
-  }
+  if (isError) {
+    return <ErrorView message={errorMessage} />;
+  }

Also applies to: 37-39

🧰 Tools
🪛 Biome (2.1.2)

[error] 24-24: Do not shadow the global "Error" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🤖 Prompt for AI Agents
In applications/tari_walletd/web_ui/src/Components/FetchStatusCheck.tsx around
lines 23-24 (and similarly at lines 37-39), the import named Error shadows the
global Error and triggers a lint/biome error; rename the import to a
non-conflicting identifier (e.g., ErrorComponent or FetchError), update all
usages in this file to that new name (including JSX and any references), and
ensure the import path remains the same so functionality is unchanged.

import Loading from "../../Components/Loading";
import Error from "../../Components/Error";
import Loading from "@components/Loading";
import Error from "@components/Error";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Rename imported Error to avoid shadowing the global Error.

Biome flags this (noShadowRestrictedNames). Rename the import and make message extraction safe.

-import Error from "@components/Error";
+import ErrorView from "@components/Error";
@@
-      return <Error message={error.message} />;
+      return <ErrorView message={error instanceof Error ? error.message : String(error)} />;

Also applies to: 97-99

🧰 Tools
🪛 Biome (2.1.2)

[error] 44-44: Do not shadow the global "Error" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🤖 Prompt for AI Agents
In
applications/tari_walletd/web_ui/src/routes/Transactions/TransactionDetails.tsx
around lines 44 and 97-99, the import "Error" shadows the global Error and
message extraction is unsafe; rename the import (e.g., ErrorComponent or
ErrorAlert) and update all usages accordingly, and when extracting the message
from an error value use a safe expression or type guard (for example use
optional chaining and fallback like error?.message ?? String(error) or check
typeof) before passing to the component so no runtime exceptions occur.

import AddIcon from "@mui/icons-material/Add";
import Fade from "@mui/material/Fade";
import { Form } from "react-router-dom";
import Button from "@mui/material/Button/Button";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix MUI Button import path.

@mui/material/Button/Button is incorrect and brittle. Use the public entrypoint.

-import Button from "@mui/material/Button/Button";
+import Button from "@mui/material/Button";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import Button from "@mui/material/Button/Button";
import Button from "@mui/material/Button";
🤖 Prompt for AI Agents
In applications/tari_walletd/web_ui/src/routes/Wallet/Components/Keys.tsx around
line 35, the import uses the internal path "@mui/material/Button/Button" which
is brittle and incorrect; replace it with the public entrypoint
"@mui/material/Button" to import Button from the library's supported API
surface.

import { create } from "zustand";
import { persist } from "zustand/middleware";
import { AUTH_TOKEN_FOR_NONE_AUTH } from "../routes/Auth/Auth";
import { AUTH_TOKEN_FOR_NONE_AUTH } from "@routes/Auth/Auth";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Avoid store → route dependency; extract shared constant to break potential cycles.

Importing from @routes/Auth/Auth inside the store can create circular deps if that route imports the store. Move AUTH_TOKEN_FOR_NONE_AUTH to a shared module (e.g., @constants/auth) or define/export it here, and have the route import from there.

Check for a cycle and single source of truth:

Proposed change after extracting the constant:

-import { AUTH_TOKEN_FOR_NONE_AUTH } from "@routes/Auth/Auth";
+import { AUTH_TOKEN_FOR_NONE_AUTH } from "@constants/auth";

🏁 Script executed:

#!/bin/bash
rg -n 'AUTH_TOKEN_FOR_NONE_AUTH'
rg -n 'from "@store/authStore"' applications/tari_walletd/web_ui/src/routes/Auth/Auth.tsx

Length of output: 1621


Extract AUTH_TOKEN_FOR_NONE_AUTH to a shared module
A circular dependency exists: authStore.tsAuth.tsxauthStore.ts. Move AUTH_TOKEN_FOR_NONE_AUTH into a new src/constants/auth.ts, then update all imports in:

  • applications/tari_walletd/web_ui/src/routes/Auth/Auth.tsx
  • applications/tari_walletd/web_ui/src/store/authStore.ts
  • applications/tari_walletd/web_ui/src/App.tsx
  • applications/tari_walletd/web_ui/src/utils/json_rpc.ts
- import { AUTH_TOKEN_FOR_NONE_AUTH } from "@routes/Auth/Auth";
+ import { AUTH_TOKEN_FOR_NONE_AUTH } from "@constants/auth";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { AUTH_TOKEN_FOR_NONE_AUTH } from "@routes/Auth/Auth";
import { AUTH_TOKEN_FOR_NONE_AUTH } from "@constants/auth";
🤖 Prompt for AI Agents
In applications/tari_walletd/web_ui/src/store/authStore.ts around line 6, the
import of AUTH_TOKEN_FOR_NONE_AUTH from @routes/Auth/Auth creates a circular
dependency via Auth.tsx; extract the constant into a new file
applications/tari_walletd/web_ui/src/constants/auth.ts exporting
AUTH_TOKEN_FOR_NONE_AUTH, then replace the current import in this file to import
from src/constants/auth.ts and update the same import in
applications/tari_walletd/web_ui/src/routes/Auth/Auth.tsx,
applications/tari_walletd/web_ui/src/App.tsx, and
applications/tari_walletd/web_ui/src/utils/json_rpc.ts so all four files import
the constant from the new shared module, run a typecheck/build to ensure no
remaining circular imports.

@sdbondi
sdbondi added this pull request to the merge queue Sep 2, 2025
@github-actions

github-actions Bot commented Sep 2, 2025

Copy link
Copy Markdown

Test Results (CI)

419 tests   413 ✅  1h 23m 4s ⏱️
 69 suites    0 💤
  2 files      6 ❌

For more details on these failures, see this check.

Results for commit 764c95f.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Sep 2, 2025
@sdbondi
sdbondi merged commit 123734b into tari-project:development Sep 2, 2025
12 of 13 checks passed
@NovaT82
NovaT82 deleted the wallet-ui branch September 5, 2025 07:08
@coderabbitai coderabbitai Bot mentioned this pull request Sep 26, 2025
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants