Skip to content

fix: fixes types for useUser hook#2492

Merged
stalniy merged 1 commit intomainfrom
fix/types-for-user
Jan 14, 2026
Merged

fix: fixes types for useUser hook#2492
stalniy merged 1 commit intomainfrom
fix/types-for-user

Conversation

@stalniy
Copy link
Contributor

@stalniy stalniy commented Jan 14, 2026

Why

bug

Summary by CodeRabbit

  • Refactor
    • Replaced the render-prop auth wrapper with a hook + guard pattern across user pages.
    • Page exports now use the guard wrapper to enforce registration checks.
    • User form components updated to receive explicit user props.
    • User hooks updated to allow undefined user state for safer handling.
    • Minor query logic tightened to only run when a username exists.

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

@stalniy stalniy requested a review from a team as a code owner January 14, 2026 10:57
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 14, 2026

📝 Walkthrough

Walkthrough

Removed the render-prop RequiredUserContainer, updated hooks to allow user being undefined, and migrated pages/components to use the Guard HOC and useUser/useIsRegisteredUser patterns instead of the removed wrapper.

Changes

Cohort / File(s) Summary
Component Removal
apps/deploy-web/src/components/user/RequiredUserContainer.tsx
Deleted render-prop authentication wrapper and its public types (RequiredUserConsumer, RequiredUserContainerProps).
Component Type Updates
apps/deploy-web/src/components/user/UserSettingsForm.tsx
Switched export type from RequiredUserConsumer to FC<{ user: CustomUserProfile }>; adjusted imports to include CustomUserProfile and FC.
Hook Type Updates
apps/deploy-web/src/hooks/useCustomUser.ts, apps/deploy-web/src/hooks/useUser.ts
Changed returned user type to `CustomUserProfile
Page Authentication Refactoring
apps/deploy-web/src/pages/user/api-keys/index.tsx, apps/deploy-web/src/pages/user/settings/index.tsx
Replaced RequiredUserContainer usage with Guard(..., useIsRegisteredUser); pages now use useUser and return null if no user; default exports wrapped with Guard.
Query Key / Guarding Adjustment
apps/deploy-web/src/queries/useTemplateQuery.tsx
Tightened guard logic to use user?.username for condition and user.username for cache key to avoid mixed optional access.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • ygrishajev

Poem

🐰 I hopped through code both bright and keen,
Removed a wrapper once routine.
Guard now guides the auth-bound trail,
Hooks grow flexible—no more frail.
Tiny rabbit cheers the clean! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: updating type definitions for the useUser hook to allow undefined user values, which is the central focus across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
apps/deploy-web/src/components/user/UserSettingsForm.tsx (1)

61-70: Consider removing unnecessary null checks for consistency.

Since user is now typed as non-nullable CustomUserProfile, the following are no longer necessary:

  • if (user) guard on line 62
  • if (user && ...) guard on line 73
  • Optional chaining user?.username on line 99 (while line 100 correctly uses user.username)

These are harmless but create inconsistency—line 99 uses user?.username while line 100 uses user.username.

♻️ Suggested cleanup
   useEffect(() => {
-    if (user) {
-      setValue("username", user.username || "");
-      setValue("subscribedToNewsletter", user.subscribedToNewsletter);
-      setValue("bio", user.bio);
-      setValue("youtubeUsername", user.youtubeUsername);
-      setValue("twitterUsername", user.twitterUsername);
-      setValue("githubUsername", user.githubUsername);
-    }
-  }, [user?.username, user?.subscribedToNewsletter, user?.bio, user?.youtubeUsername, user?.twitterUsername, user?.githubUsername]);
+    setValue("username", user.username || "");
+    setValue("subscribedToNewsletter", user.subscribedToNewsletter);
+    setValue("bio", user.bio);
+    setValue("youtubeUsername", user.youtubeUsername);
+    setValue("twitterUsername", user.twitterUsername);
+    setValue("githubUsername", user.githubUsername);
+  }, [user.username, user.subscribedToNewsletter, user.bio, user.youtubeUsername, user.twitterUsername, user.githubUsername, setValue]);

   useEffect(() => {
-    if (user && username && username.length >= 3 && username.length <= 40 && username !== user.username) {
+    if (username && username.length >= 3 && username.length <= 40 && username !== user.username) {
       // ...
     }
-  }, [user?.username, username]);
+  }, [user.username, username, consoleApiHttpClient]);
-      <NextSeo title={user?.username} />
+      <NextSeo title={user.username} />

Also applies to: 72-86, 99-100


📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a71e2af and e97cad5.

📒 Files selected for processing (7)
  • apps/deploy-web/src/components/user/RequiredUserContainer.tsx
  • apps/deploy-web/src/components/user/UserSettingsForm.tsx
  • apps/deploy-web/src/hooks/useCustomUser.ts
  • apps/deploy-web/src/hooks/useUser.ts
  • apps/deploy-web/src/pages/user/api-keys/index.tsx
  • apps/deploy-web/src/pages/user/settings/index.tsx
  • apps/deploy-web/src/queries/useTemplateQuery.tsx
💤 Files with no reviewable changes (1)
  • apps/deploy-web/src/components/user/RequiredUserContainer.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/deploy-web/src/pages/user/api-keys/index.tsx
  • apps/deploy-web/src/hooks/useUser.ts
  • apps/deploy-web/src/pages/user/settings/index.tsx
  • apps/deploy-web/src/queries/useTemplateQuery.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{ts,tsx,js}: Never use type any or cast to type any. Always define the proper TypeScript types.
Never use deprecated methods from libraries.
Don't add unnecessary comments to the code.

Files:

  • apps/deploy-web/src/hooks/useCustomUser.ts
  • apps/deploy-web/src/components/user/UserSettingsForm.tsx
🧠 Learnings (2)
📚 Learning: 2025-06-05T21:07:51.985Z
Learnt from: baktun14
Repo: akash-network/console PR: 1432
File: apps/deploy-web/src/components/deployments/DeploymentAlerts/DeploymentCloseAlert.tsx:38-38
Timestamp: 2025-06-05T21:07:51.985Z
Learning: The ContactPointSelect component in apps/deploy-web/src/components/alerts/ContactPointSelectForm/ContactPointSelect.tsx uses the useFormContext hook internally to connect to React Hook Form, so it doesn't need to be wrapped in a FormField component.

Applied to files:

  • apps/deploy-web/src/components/user/UserSettingsForm.tsx
📚 Learning: 2025-06-19T16:00:05.428Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 1512
File: apps/deploy-web/src/components/deployments/DeploymentBalanceAlert/DeploymentBalanceAlert.tsx:47-68
Timestamp: 2025-06-19T16:00:05.428Z
Learning: In React Hook Form setups with zod validation, child components using useFormContext() can rely on parent form validation rather than implementing local input validation. Invalid inputs like NaN from parseFloat() are handled by the parent schema validation, eliminating the need for additional local validation in child components.

Applied to files:

  • apps/deploy-web/src/components/user/UserSettingsForm.tsx
🧬 Code graph analysis (2)
apps/deploy-web/src/hooks/useCustomUser.ts (1)
apps/deploy-web/src/types/user.ts (1)
  • CustomUserProfile (19-19)
apps/deploy-web/src/components/user/UserSettingsForm.tsx (1)
apps/deploy-web/src/types/user.ts (1)
  • CustomUserProfile (19-19)
⏰ 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). (3)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
apps/deploy-web/src/components/user/UserSettingsForm.tsx (1)

1-1: LGTM! Type improvements are well-structured.

The migration from the render-prop pattern (RequiredUserContainer) to an explicit FC with typed props improves type safety and aligns with the Guard-based composition pattern used in the rest of the PR.

Also applies to: 15-15, 31-31

apps/deploy-web/src/hooks/useCustomUser.ts (2)

6-11: LGTM! The updated type correctly reflects the nullable user state.

Adding | undefined to the user field accurately represents that the user can be undefined when not authenticated. This improves type safety and forces consumers to handle the undefined case explicitly.


18-25: LGTM! Removing the type assertion improves type honesty.

The removal of the explicit cast to CustomUserProfile aligns with the coding guidelines to avoid unnecessary type assertions. The conditional handling of completeUser correctly propagates undefined when no user is present.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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

@codecov
Copy link

codecov bot commented Jan 14, 2026

Codecov Report

❌ Patch coverage is 7.14286% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.71%. Comparing base (8be90a2) to head (e97cad5).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
apps/deploy-web/src/pages/user/settings/index.tsx 0.00% 6 Missing ⚠️
apps/deploy-web/src/pages/user/api-keys/index.tsx 0.00% 5 Missing ⚠️
...eploy-web/src/components/user/UserSettingsForm.tsx 0.00% 1 Missing ⚠️
apps/deploy-web/src/queries/useTemplateQuery.tsx 50.00% 1 Missing ⚠️

❌ Your patch status has failed because the patch coverage (7.14%) is below the target coverage (50.00%). You can increase the patch coverage or adjust the target coverage.
❌ Your project status has failed because the head coverage (79.59%) is below the target coverage (80.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2492      +/-   ##
==========================================
- Coverage   51.00%   50.71%   -0.29%     
==========================================
  Files        1065     1054      -11     
  Lines       29459    29103     -356     
  Branches     6549     6506      -43     
==========================================
- Hits        15026    14761     -265     
+ Misses      14213    14122      -91     
  Partials      220      220              
Flag Coverage Δ *Carryforward flag
api 79.59% <ø> (ø) Carriedforward from 8be90a2
deploy-web 31.44% <7.14%> (+<0.01%) ⬆️
log-collector ?
notifications 87.94% <ø> (ø) Carriedforward from 8be90a2
provider-console 81.48% <ø> (ø) Carriedforward from 8be90a2
provider-proxy 84.35% <ø> (ø) Carriedforward from 8be90a2

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
apps/deploy-web/src/hooks/useCustomUser.ts 100.00% <ø> (ø)
apps/deploy-web/src/hooks/useUser.ts 100.00% <ø> (ø)
...eploy-web/src/components/user/UserSettingsForm.tsx 0.00% <0.00%> (ø)
apps/deploy-web/src/queries/useTemplateQuery.tsx 97.29% <50.00%> (ø)
apps/deploy-web/src/pages/user/api-keys/index.tsx 0.00% <0.00%> (ø)
apps/deploy-web/src/pages/user/settings/index.tsx 0.00% <0.00%> (ø)

... and 11 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@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

Caution

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

⚠️ Outside diff range comments (1)
apps/deploy-web/src/queries/useTemplateQuery.tsx (1)

13-13: Remove any from UseQueryOptions generics (coding guideline).

UseQueryOptions<..., any, ...> on lines 13 and 22 violates the "never use any" rule. The third generic parameter (TData) should match the actual return type used in the corresponding useQuery call, which is ITemplate[] and Partial<ITemplate>[] respectively.

Proposed fix (replace `any` with concrete types)
-export function useUserTemplates(username: string, options?: Omit<UseQueryOptions<ITemplate[], Error, any, QueryKey>, "queryKey" | "queryFn">) {
+export function useUserTemplates(
+  username: string,
+  options?: Omit<UseQueryOptions<ITemplate[], Error, ITemplate[], QueryKey>, "queryKey" | "queryFn">
+) {
   const { consoleApiHttpClient } = useServices();
   return useQuery<ITemplate[], Error>({
     queryKey: QueryKeys.getUserTemplatesKey(username),
     queryFn: () => consoleApiHttpClient.get<ITemplate[]>(`/user/templates/${username}`).then(response => response.data),
     ...options
   });
 }

-export function useUserFavoriteTemplates(options?: Omit<UseQueryOptions<Partial<ITemplate>[], Error, any, QueryKey>, "queryKey" | "queryFn">) {
+export function useUserFavoriteTemplates(
+  options?: Omit<UseQueryOptions<Partial<ITemplate>[], Error, Partial<ITemplate>[], QueryKey>, "queryKey" | "queryFn">
+) {
   const { user } = useCustomUser();
   const { consoleApiHttpClient } = useServices();
   return useQuery<Partial<ITemplate>[], Error>({
     queryKey: QueryKeys.getUserFavoriteTemplatesKey(user?.sub || ""),
     queryFn: () => consoleApiHttpClient.get<Partial<ITemplate>[]>(`/user/favoriteTemplates`).then(response => response.data),
     ...options
   });
 }
🤖 Fix all issues with AI agents
In `@apps/deploy-web/src/pages/user/api-keys/index.tsx`:
- Around line 9-16: The delete flow currently passes a possibly empty string
into useDeleteApiKey via useDeleteApiKey(apiKeyToDelete?.id ?? "", ...), which
can cause deleteApiKey() to be invoked with an empty id; change the flow to
avoid wiring an empty id and to defensively guard the action: initialize
useDeleteApiKey with undefined/null when there is no id (e.g.,
useDeleteApiKey(apiKeyToDelete?.id ?? undefined, ...) or delay calling the hook
until id exists), and before invoking deleteApiKey() add a runtime check that
ensures the id is truthy (e.g., if (!apiKeyToDelete?.id) return) so
deleteApiKey() is never called with an empty string; update the handlers where
deleteApiKey() is called (references: useDeleteApiKey, apiKeyToDelete?.id,
deleteApiKey) accordingly.
🧹 Nitpick comments (2)
apps/deploy-web/src/pages/user/settings/index.tsx (1)

1-13: Guard-wrapped page is fine; if (!user) return null should be unreachable when canVisit is true.

Given Guard(UserSettingsPage, useIsRegisteredUser) and canVisit: !!user?.userId, the null-return path should not happen; consider replacing with an explicit fallback (or remove it) if you want to avoid silent blank renders in edge cases.

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

31-31: Inconsistent null checks for user prop.

The prop type declares user: CustomUserProfile as required (non-nullable), but the component still contains defensive checks like if (user) on line 62 and optional chaining user?.username in the dependency array on line 70. Meanwhile, lines 100 and 105 access user.username and user.email directly without guards.

If the Guard pattern ensures user is always defined when this component renders, consider removing the redundant null checks for consistency:

♻️ Suggested cleanup
   useEffect(() => {
-    if (user) {
-      setValue("username", user.username || "");
-      setValue("subscribedToNewsletter", user.subscribedToNewsletter);
-      setValue("bio", user.bio);
-      setValue("youtubeUsername", user.youtubeUsername);
-      setValue("twitterUsername", user.twitterUsername);
-      setValue("githubUsername", user.githubUsername);
-    }
-  }, [user?.username, user?.subscribedToNewsletter, user?.bio, user?.youtubeUsername, user?.twitterUsername, user?.githubUsername]);
+    setValue("username", user.username || "");
+    setValue("subscribedToNewsletter", user.subscribedToNewsletter);
+    setValue("bio", user.bio);
+    setValue("youtubeUsername", user.youtubeUsername);
+    setValue("twitterUsername", user.twitterUsername);
+    setValue("githubUsername", user.githubUsername);
+  }, [user.username, user.subscribedToNewsletter, user.bio, user.youtubeUsername, user.twitterUsername, user.githubUsername, setValue]);

Note: The same applies to lines 73 and 86 where user is checked or accessed with optional chaining.

Also applies to: 61-70

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f8926d and a71e2af.

📒 Files selected for processing (7)
  • apps/deploy-web/src/components/user/RequiredUserContainer.tsx
  • apps/deploy-web/src/components/user/UserSettingsForm.tsx
  • apps/deploy-web/src/hooks/useCustomUser.ts
  • apps/deploy-web/src/hooks/useUser.ts
  • apps/deploy-web/src/pages/user/api-keys/index.tsx
  • apps/deploy-web/src/pages/user/settings/index.tsx
  • apps/deploy-web/src/queries/useTemplateQuery.tsx
💤 Files with no reviewable changes (1)
  • apps/deploy-web/src/components/user/RequiredUserContainer.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{ts,tsx,js}: Never use type any or cast to type any. Always define the proper TypeScript types.
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/hooks/useCustomUser.ts
  • apps/deploy-web/src/components/user/UserSettingsForm.tsx
  • apps/deploy-web/src/queries/useTemplateQuery.tsx
  • apps/deploy-web/src/pages/user/api-keys/index.tsx
  • apps/deploy-web/src/pages/user/settings/index.tsx
🧠 Learnings (4)
📚 Learning: 2025-06-05T21:07:51.985Z
Learnt from: baktun14
Repo: akash-network/console PR: 1432
File: apps/deploy-web/src/components/deployments/DeploymentAlerts/DeploymentCloseAlert.tsx:38-38
Timestamp: 2025-06-05T21:07:51.985Z
Learning: The ContactPointSelect component in apps/deploy-web/src/components/alerts/ContactPointSelectForm/ContactPointSelect.tsx uses the useFormContext hook internally to connect to React Hook Form, so it doesn't need to be wrapped in a FormField component.

Applied to files:

  • apps/deploy-web/src/components/user/UserSettingsForm.tsx
📚 Learning: 2025-06-19T16:00:05.428Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 1512
File: apps/deploy-web/src/components/deployments/DeploymentBalanceAlert/DeploymentBalanceAlert.tsx:47-68
Timestamp: 2025-06-19T16:00:05.428Z
Learning: In React Hook Form setups with zod validation, child components using useFormContext() can rely on parent form validation rather than implementing local input validation. Invalid inputs like NaN from parseFloat() are handled by the parent schema validation, eliminating the need for additional local validation in child components.

Applied to files:

  • apps/deploy-web/src/components/user/UserSettingsForm.tsx
📚 Learning: 2025-09-10T08:40:53.104Z
Learnt from: stalniy
Repo: akash-network/console PR: 1892
File: apps/deploy-web/src/components/new-deployment/BidCountdownTimer.tsx:20-31
Timestamp: 2025-09-10T08:40:53.104Z
Learning: In TanStack Query v5, the onSuccess and onError callbacks were removed from useQuery options. Instead, use useEffect with the data as a dependency to handle side effects when query data changes.

Applied to files:

  • apps/deploy-web/src/queries/useTemplateQuery.tsx
📚 Learning: 2025-11-25T17:45:49.180Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/query-by-in-tests.mdc:0-0
Timestamp: 2025-11-25T17:45:49.180Z
Learning: Applies to {apps/deploy-web,apps/provider-console}/**/*.spec.tsx : Use `queryBy` methods instead of `getBy` methods in test expectations

Applied to files:

  • apps/deploy-web/src/queries/useTemplateQuery.tsx
🧬 Code graph analysis (4)
apps/deploy-web/src/hooks/useCustomUser.ts (1)
apps/deploy-web/src/types/user.ts (1)
  • CustomUserProfile (19-19)
apps/deploy-web/src/components/user/UserSettingsForm.tsx (1)
apps/deploy-web/src/types/user.ts (1)
  • CustomUserProfile (19-19)
apps/deploy-web/src/pages/user/api-keys/index.tsx (2)
apps/deploy-web/src/hoc/guard/guard.hoc.tsx (1)
  • Guard (9-29)
apps/deploy-web/src/hooks/useUser.ts (1)
  • useIsRegisteredUser (22-29)
apps/deploy-web/src/pages/user/settings/index.tsx (2)
apps/deploy-web/src/hooks/useUser.ts (1)
  • useUser (6-20)
apps/deploy-web/src/components/user/UserSettingsForm.tsx (1)
  • UserSettingsForm (31-199)
⏰ 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). (3)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (6)
apps/deploy-web/src/hooks/useUser.ts (1)

6-10: Widened user + optional chaining in canVisit is consistent with guarded pages.

The CustomUserProfile | undefined return type and !!user?.userId check match the new Guard-based gating pattern.

Also applies to: 22-28

apps/deploy-web/src/queries/useTemplateQuery.tsx (1)

76-85: Good: guard cache update behind user?.username and avoid optional key parts.

This prevents getUserTemplatesKey() from receiving an empty/undefined username and makes the cache update conditional on a valid key.

apps/deploy-web/src/pages/user/settings/index.tsx (1)

15-18: GSSP route annotation looks consistent with other guarded pages.

Adding route: "/user/settings" is a clean way to preserve guard context.

apps/deploy-web/src/pages/user/api-keys/index.tsx (1)

40-52: Passing combined isLoading + deletion props into ApiKeyList is a clear improvement.

Layout isLoading={isLoading} plus isDeleting / apiKeyToDelete plumbing makes the UI state easier to reason about.

apps/deploy-web/src/components/user/UserSettingsForm.tsx (2)

1-1: LGTM!

Using import type for the FC type is the correct approach for type-only imports.


15-15: LGTM!

Type-only imports for CustomUserProfile and UserSettings are appropriate and both types are used in the component.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@stalniy stalniy force-pushed the fix/types-for-user branch from a71e2af to e97cad5 Compare January 14, 2026 13:13
@stalniy stalniy enabled auto-merge (squash) January 14, 2026 13:13
@stalniy stalniy disabled auto-merge January 14, 2026 13:36
@stalniy stalniy merged commit 3c5f19d into main Jan 14, 2026
63 of 65 checks passed
@stalniy stalniy deleted the fix/types-for-user branch January 14, 2026 13:36
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.

2 participants

Comments