Skip to content

fix: billing usage page guard flicker #1826

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

domhhv
Copy link
Contributor

@domhhv domhhv commented Aug 20, 2025

Fixes #1822

Summary by CodeRabbit

  • New Features

    • Multi-state gating for protected pages: pages show a loading state while user/wallet checks run.
    • Composed access checks: multiple guards combine to determine access and loading state.
  • Bug Fixes

    • Reduced flicker and premature redirects during access checks.
    • More accurate access decisions, lowering unexpected 404s or blocked navigation.
  • Tests

    • Updated tests and fixtures to reflect the new loading-aware behavior.

@domhhv domhhv requested a review from a team as a code owner August 20, 2025 12:29
Copy link

coderabbitai bot commented Aug 20, 2025

Walkthrough

Guard and user/wallet hooks now return loading-aware objects ({ canVisit, isLoading }); Guard short-circuits to a Loading component when any guard is loading. useUser aggregates isLoading; related tests and fixtures updated to the new shapes.

Changes

Cohort / File(s) Summary
Guard system updates
apps/deploy-web/src/hoc/guard/guard.hoc.tsx
Guard and composeGuards now use UseCheck = () => { canVisit, isLoading }; Guard renders Loading when isLoading is true; composeGuards ANDs canVisit and ORs isLoading.
User hooks & types
apps/deploy-web/src/hooks/useUser.ts, apps/deploy-web/src/types/user.ts
useUser aggregates loading from registered and anonymous sources and returns isLoading on the user object; useIsRegisteredUser returns { canVisit, isLoading }; CustomUserProfile gains optional isLoading?: boolean.
Wallet-managed hook
apps/deploy-web/src/context/WalletProvider/WalletProvider.tsx
useIsManagedWalletUser now returns { canVisit, isLoading } mapped from useWallet's isManaged/isWalletLoading.
Tests & fixtures
apps/deploy-web/src/components/user/UserProviders/UserProviders.spec.tsx, apps/deploy-web/src/hooks/useUser.spec.tsx, apps/deploy-web/tests/seeders/user.ts
Tests updated to expect { canVisit, isLoading } shapes; seed user fixture adds isLoading: false; assertions adapted to object shape and isLoading flags.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant P as Protected Page
  participant G as Guard(Component, useCheck)
  participant H as useCheck (hook)
  participant L as Loading
  participant F as Fallback (404)
  participant C as Component

  U->>P: Navigate
  P->>G: Render
  G->>H: Invoke useCheck()
  H-->>G: { canVisit, isLoading }

  alt isLoading === true
    G->>L: Render Loading
    note right of G: Short-circuit until loading resolves
  else canVisit === true
    G->>C: Render Component
  else
    G->>F: Render Fallback
  end
Loading
sequenceDiagram
  autonumber
  participant P as Protected Page
  participant CG as composeGuards(g1, g2, ...)
  participant g1 as Guard Hook A
  participant g2 as Guard Hook B

  P->>CG: composedUseCheck()
  CG->>g1: call()
  g1-->>CG: { canVisit: a, isLoading: la }
  CG->>g2: call()
  g2-->>CG: { canVisit: b, isLoading: lb }
  CG-->>P: { canVisit: a && b, isLoading: la || lb }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Assessment against linked issues

Objective Addressed Explanation
Expose loading states in guards/hooks to prevent 404 flicker on Billing/Usage pages (#1822)
Ensure Guard short-circuits rendering while any composed hook is loading (#1822)
Update Billing/Usage pages to consume new UseCheck signatures (#1822) No changes to Billing/Usage page files are included in this diff; adoption is not visible here.

Possibly related PRs

Suggested reviewers

  • ygrishajev
  • baktun14

Poem

"I nibble at guards with patient feet,
Loading lights make my heartbeat beat,
canVisit waits while I softly hop,
No more flicker — I arrive on top.
🐇"

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 46200c1 and c41c6d4.

📒 Files selected for processing (1)
  • apps/deploy-web/src/hooks/useUser.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/deploy-web/src/hooks/useUser.ts
⏰ 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). (1)
  • GitHub Check: test-build
✨ 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 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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/deploy-web/src/hooks/useUser.ts (1)

7-17: Return type is too strong; prefer Partial to match actual runtime shape

useUser promises a full CustomUserProfile, but can return {} when no user is present. This is type-unsafe and can mislead call sites into treating fields as always defined.

Apply this diff to align the type contract with behavior:

-export const useUser = (): CustomUserProfile & { isLoading: boolean } => {
+export const useUser = (): Partial<CustomUserProfile> & { isLoading: boolean } => {

This keeps your current usage pattern (optional chaining) sound, and avoids leaking unsound “always-present” fields.

apps/deploy-web/src/hoc/guard/guard.hoc.tsx (1)

4-8: Export the UseCheck type for consumers

Exporting UseCheck allows guard hooks to explicitly annotate their return type and get compile-time alignment with Guard/composeGuards.

-type UseCheck = () => {
+export type UseCheck = () => {
   canVisit: boolean;
   isLoading: boolean;
 };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 431fa2a and 7bba022.

📒 Files selected for processing (3)
  • apps/deploy-web/src/context/WalletProvider/WalletProvider.tsx (1 hunks)
  • apps/deploy-web/src/hoc/guard/guard.hoc.tsx (2 hunks)
  • apps/deploy-web/src/hooks/useUser.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/hooks/useUser.ts
  • apps/deploy-web/src/context/WalletProvider/WalletProvider.tsx
  • apps/deploy-web/src/hoc/guard/guard.hoc.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/hooks/useUser.ts
  • apps/deploy-web/src/context/WalletProvider/WalletProvider.tsx
  • apps/deploy-web/src/hoc/guard/guard.hoc.tsx
🧬 Code Graph Analysis (2)
apps/deploy-web/src/hooks/useUser.ts (3)
apps/deploy-web/src/types/user.ts (1)
  • CustomUserProfile (19-19)
apps/deploy-web/src/hooks/useCustomUser.ts (1)
  • useCustomUser (16-26)
apps/deploy-web/src/hooks/useStoredAnonymousUser.ts (1)
  • useStoredAnonymousUser (18-49)
apps/deploy-web/src/hoc/guard/guard.hoc.tsx (1)
apps/deploy-web/src/components/layout/Layout.tsx (1)
  • Loading (151-162)
⏰ 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). (2)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (4)
apps/deploy-web/src/context/WalletProvider/WalletProvider.tsx (1)

360-363: LGTM: guard-ready hook shape is correct

useIsManagedWalletUser cleanly maps to the new guard contract and will prevent the 404 flicker by surfacing isLoading. A repository-wide search across .ts/.tsx files confirms there are no remaining boolean-style usages of useIsManagedWalletUser that need adapting.

apps/deploy-web/src/hooks/useUser.ts (1)

19-26: Normalize registered-user detection to consider both id and userId

To prevent false negatives when one of these fields is populated and the other isn’t, update useIsRegisteredUser to accept either:

– export const useIsRegisteredUser = () => {
–   const { isLoading, userId } = useUser();
–
–   return {
–     isLoading,
–     canVisit: !!userId
–   };
– };
+ export const useIsRegisteredUser = () => {
+   const { isLoading, userId, id } = useUser();
+   return {
+     isLoading,
+     canVisit: Boolean(userId ?? id)
+   };
+ };

– This aligns with checks elsewhere (e.g. user?.id in WalletProvider.tsx).
– Once the user shape is consolidated, you can remove one of these branches.

apps/deploy-web/src/hoc/guard/guard.hoc.tsx (2)

9-16: LGTM: loading gate removes 404 flicker

Rendering <Loading> during isLoading neatly fixes the transient 404 without violating hook rules.


31-44: ComposeGuards verification complete – no boolean-only guards found

• Searched for all composeGuards(…) usages and confirmed only the intended calls in

  • apps/deploy-web/src/pages/usage/index.tsx
  • apps/deploy-web/src/pages/billing/index.tsx
    • Searched across all .ts/.tsx files for any guard hooks still returning a bare boolean – none found

Composition logic is sound, hooks correctly return { canVisit, isLoading }, and there are no remaining boolean-based guards to migrate.

Copy link

@coderabbitai coderabbitai bot left a comment

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 (4)
apps/deploy-web/src/types/user.ts (1)

19-22: Consider keeping loading state out of the domain/User type

Adding isLoading onto CustomUserProfile blurs concerns (data vs. UI state) and can accidentally leak into analytics/persistence. Optional, but consider returning a wrapper result from hooks instead (e.g., { user?: CustomUserProfile; isLoading: boolean }) and keep CustomUserProfile purely user data.

Example type (outside this hunk) if you decide to refactor hooks later:

export type UseUserResult = {
  user?: CustomUserProfile;
  isLoading: boolean;
};
apps/deploy-web/src/components/user/UserProviders/UserProviders.spec.tsx (1)

21-21: Follow repo test guideline: prefer queryBy over getBy in expectations

In apps//.spec.tsx we use queryBy methods. Replace getByRole with queryByRole here.

Apply:

-    expect(screen.getByRole("status")).toBeInTheDocument();
+    expect(screen.queryByRole("status")).toBeInTheDocument();
apps/deploy-web/src/hooks/useUser.ts (2)

7-16: useMemo here is optional and adds noise

These computations are cheap and derived from stable hook outputs. You can simplify by inlining them without useMemo to reduce indirection and dependency maintenance.

Example:

-  const user = useMemo(() => registeredUser ?? anonymousUser, [registeredUser, anonymousUser]);
-  const isLoading = useMemo(() => isLoadingRegisteredUser || isLoadingAnonymousUser, [isLoadingRegisteredUser, isLoadingAnonymousUser]);
+  const user = registeredUser ?? anonymousUser;
+  const isLoading = isLoadingRegisteredUser || isLoadingAnonymousUser;

8-12: Potential double invocation of useCustomUser via nested hook usage

useUser calls useCustomUser, and useStoredAnonymousUser also calls useCustomUser internally. This duplicates subscription to Auth0’s user state and can cause extra renders. Optional: thread registered user/loading into useStoredAnonymousUser, or have useStoredAnonymousUser accept a flag/param to avoid its internal useCustomUser call when already provided.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7bba022 and 46200c1.

📒 Files selected for processing (6)
  • apps/deploy-web/src/components/user/UserProviders/UserProviders.spec.tsx (1 hunks)
  • apps/deploy-web/src/hoc/guard/guard.hoc.tsx (2 hunks)
  • apps/deploy-web/src/hooks/useUser.spec.tsx (1 hunks)
  • apps/deploy-web/src/hooks/useUser.ts (1 hunks)
  • apps/deploy-web/src/types/user.ts (1 hunks)
  • apps/deploy-web/tests/seeders/user.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/deploy-web/src/hoc/guard/guard.hoc.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/tests/seeders/user.ts
  • apps/deploy-web/src/types/user.ts
  • apps/deploy-web/src/hooks/useUser.spec.tsx
  • apps/deploy-web/src/components/user/UserProviders/UserProviders.spec.tsx
  • apps/deploy-web/src/hooks/useUser.ts
**/*.{js,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/tests/seeders/user.ts
  • apps/deploy-web/src/types/user.ts
  • apps/deploy-web/src/hooks/useUser.spec.tsx
  • apps/deploy-web/src/components/user/UserProviders/UserProviders.spec.tsx
  • apps/deploy-web/src/hooks/useUser.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/deploy-web/src/hooks/useUser.spec.tsx
  • apps/deploy-web/src/components/user/UserProviders/UserProviders.spec.tsx
apps/{deploy-web,provider-console}/**/*.spec.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/query-by-in-tests.mdc)

Use queryBy methods instead of getBy methods in test expectations in .spec.tsx files

Files:

  • apps/deploy-web/src/hooks/useUser.spec.tsx
  • apps/deploy-web/src/components/user/UserProviders/UserProviders.spec.tsx
🧠 Learnings (1)
📚 Learning: 2025-07-21T08:24:27.953Z
Learnt from: CR
PR: akash-network/console#0
File: .cursor/rules/query-by-in-tests.mdc:0-0
Timestamp: 2025-07-21T08:24:27.953Z
Learning: Applies to apps/{deploy-web,provider-console}/**/*.spec.tsx : Use `queryBy` methods instead of `getBy` methods in test expectations in `.spec.tsx` files

Applied to files:

  • apps/deploy-web/src/hooks/useUser.spec.tsx
  • apps/deploy-web/src/components/user/UserProviders/UserProviders.spec.tsx
🧬 Code Graph Analysis (3)
apps/deploy-web/src/types/user.ts (1)
apps/deploy-web/src/components/user/UserProfile.tsx (1)
  • UserProfile (20-71)
apps/deploy-web/src/hooks/useUser.spec.tsx (1)
apps/deploy-web/tests/seeders/user.ts (1)
  • buildUser (7-26)
apps/deploy-web/src/hooks/useUser.ts (2)
apps/deploy-web/src/hooks/useCustomUser.ts (1)
  • useCustomUser (16-26)
apps/deploy-web/src/hooks/useStoredAnonymousUser.ts (1)
  • useStoredAnonymousUser (18-49)
⏰ 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). (2)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (7)
apps/deploy-web/tests/seeders/user.ts (1)

23-23: LGTM: sensible default for tests

Defaulting isLoading to false in the user seeder is consistent with the updated typing and enables overriding per test.

apps/deploy-web/src/components/user/UserProviders/UserProviders.spec.tsx (1)

56-62: LGTM: updated tracking payloads match the new loading-aware shape

The test now asserts the transient loading payload and the final anonymous user payload with isLoading. This aligns with the new contract and should prevent the flicker regressions from slipping.

apps/deploy-web/src/hooks/useUser.spec.tsx (4)

15-15: LGTM: test name reflects the new canVisit contract

Clearer intent with “can visit” wording.


20-23: LGTM: expectation updated to the new return shape

Asserting { isLoading: false, canVisit: true } matches the updated API.


26-26: LGTM: negative case covered

Covers the falsy userId path appropriately.


31-34: LGTM: expectation mirrors the object result for the negative path

Matches { isLoading: false, canVisit: false } as designed.

apps/deploy-web/src/hooks/useUser.ts (1)

20-25: No boolean-style usages of useIsRegisteredUser remain – all call sites are up to date

A repository-wide search for useIsRegisteredUser( in *.ts/tsx only returned its use within apps/deploy-web/src/hooks/useUser.spec.tsx (no production code treating the hook call as a bare boolean). There are no downstream if (useIsRegisteredUser()) or const foo = useIsRegisteredUser() patterns in the app.

Since no code outside tests was broken by the change, no further updates are required.

Comment on lines 7 to +16
export const useUser = (): CustomUserProfile => {
const { user: registeredUser } = useCustomUser();
const { user: anonymousUser } = useStoredAnonymousUser();
const user = useMemo(() => registeredUser || anonymousUser, [registeredUser, anonymousUser]);
const { user: registeredUser, isLoading: isLoadingRegisteredUser } = useCustomUser();
const { user: anonymousUser, isLoading: isLoadingAnonymousUser } = useStoredAnonymousUser();
const user = useMemo(() => registeredUser || anonymousUser || {}, [registeredUser, anonymousUser]);
const isLoading = useMemo(() => isLoadingRegisteredUser || isLoadingAnonymousUser, [isLoadingRegisteredUser, isLoadingAnonymousUser]);

return user;
return {
...user,
isLoading
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Tighten return typing and avoid {} as a user fallback

Returning {} as the user can be type-unsound against CustomUserProfile (depending on required fields of Auth0’s UserProfile) and spreads UI state into a domain object. Also, nullish coalescing communicates intent better than || here.

Minimal, local change to improve type-safety without altering callers:

-export const useUser = (): CustomUserProfile => {
+export const useUser = (): Partial<CustomUserProfile> & { isLoading: boolean } => {
   const { user: registeredUser, isLoading: isLoadingRegisteredUser } = useCustomUser();
   const { user: anonymousUser, isLoading: isLoadingAnonymousUser } = useStoredAnonymousUser();
-  const user = useMemo(() => registeredUser || anonymousUser || {}, [registeredUser, anonymousUser]);
+  const user = useMemo(() => registeredUser ?? anonymousUser, [registeredUser, anonymousUser]);
   const isLoading = useMemo(() => isLoadingRegisteredUser || isLoadingAnonymousUser, [isLoadingRegisteredUser, isLoadingAnonymousUser]);
 
   return {
-    ...user,
+    ...(user ?? {}),
     isLoading
   };
 };

Notes:

  • Return type is now Partial with a guaranteed isLoading flag.
  • Avoids returning {} as a “user” while keeping the existing spread shape for consumers.
  • Uses ?? over || to avoid treating falsy-but-valid values as absent.
📝 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
export const useUser = (): CustomUserProfile => {
const { user: registeredUser } = useCustomUser();
const { user: anonymousUser } = useStoredAnonymousUser();
const user = useMemo(() => registeredUser || anonymousUser, [registeredUser, anonymousUser]);
const { user: registeredUser, isLoading: isLoadingRegisteredUser } = useCustomUser();
const { user: anonymousUser, isLoading: isLoadingAnonymousUser } = useStoredAnonymousUser();
const user = useMemo(() => registeredUser || anonymousUser || {}, [registeredUser, anonymousUser]);
const isLoading = useMemo(() => isLoadingRegisteredUser || isLoadingAnonymousUser, [isLoadingRegisteredUser, isLoadingAnonymousUser]);
return user;
return {
...user,
isLoading
};
export const useUser = (): Partial<CustomUserProfile> & { isLoading: boolean } => {
const { user: registeredUser, isLoading: isLoadingRegisteredUser } = useCustomUser();
const { user: anonymousUser, isLoading: isLoadingAnonymousUser } = useStoredAnonymousUser();
const user = useMemo(() => registeredUser ?? anonymousUser, [registeredUser, anonymousUser]);
const isLoading = useMemo(() => isLoadingRegisteredUser || isLoadingAnonymousUser, [isLoadingRegisteredUser, isLoadingAnonymousUser]);
return {
...(user ?? {}),
isLoading
};
};
🤖 Prompt for AI Agents
In apps/deploy-web/src/hooks/useUser.ts around lines 7 to 16, the function
returns {} as a user and uses || which is type-unsafe and can mix UI state into
the domain object; change the function return type to Partial<CustomUserProfile>
& { isLoading: boolean }, replace the user fallback {} with undefined (i.e.
compute user = useMemo(() => registeredUser ?? anonymousUser, [...])), use ??
instead of || for nullish coalescing, and when returning only spread the
resolved user if present (e.g. ...(user ? user : {})) alongside a guaranteed
isLoading boolean so callers keep the same shape without unsafe empty-object
fallbacks.

const { canVisit, isLoading } = useCheck();

if (isLoading) {
return <Loading text="Please wait..." />;
Copy link
Contributor

Choose a reason for hiding this comment

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

question(non-blocking): Is there a way we can customize the text in different pages?

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.

Billing usage pages flicker with 404 on first load
2 participants