Skip to content

[_]: feat/add mail EPs and refresh user avatar#31

Merged
xabg2 merged 3 commits intomasterfrom
feature/fetch-mails
Mar 26, 2026
Merged

[_]: feat/add mail EPs and refresh user avatar#31
xabg2 merged 3 commits intomasterfrom
feature/fetch-mails

Conversation

@xabg2
Copy link
Contributor

@xabg2 xabg2 commented Mar 26, 2026

New EPs added:

  • Refresh user's avatar
  • Get mailbox info (new messages)
  • Get mail list based on folder (inbox/draft/send/trash/etc)
  • Get mail info to preview it

Refactors:

  • Centralize errors in the same folder

@xabg2 xabg2 requested a review from larryrider March 26, 2026 14:58
@xabg2 xabg2 self-assigned this Mar 26, 2026
@xabg2 xabg2 added the enhancement New feature or request label Mar 26, 2026
Copy link

@larryrider larryrider left a comment

Choose a reason for hiding this comment

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

good job! 🚀

@coderabbitai
Copy link

coderabbitai bot commented Mar 26, 2026

Warning

Rate limit exceeded

@xabg2 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 7 minutes and 50 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 257256fd-178b-4153-a3ce-423068f5dc2c

📥 Commits

Reviewing files that changed from the base of the PR and between 93656a3 and a0afcce.

📒 Files selected for processing (2)
  • sonar-project.properties
  • src/services/sdk/sdk.service.test.ts
📝 Walkthrough

Walkthrough

Centralized error exports into src/errors, added Mail client and MailService, refactored SdkManager to separate Drive/Mail/Payments endpoints, introduced user avatar refresh flow with a thunk and service method, replaced user initialize→hydrate, updated imports/tests, and bumped @internxt/sdk plus environment/config entries.

Changes

Cohort / File(s) Summary
Configuration & Environment
\.env.example, package.json, vite.config.ts, sonar-project.properties
Added VITE_MAIL_API_URL to env example; upgraded @internxt/sdk version; added @internxt/sdk to Vite optimizeDeps.include; adjusted SonarQube coverage exclusion pattern.
Error Barrel & Shared Errors
src/errors/index.ts, src/errors/shared/index.ts, src/errors/oauth/index.ts
Added errors barrel re-exporting submodules; added UserNotFoundError; minor formatting change in OAuth error constructors.
Error Import Updates (services & tests)
src/services/config/..., src/services/navigation/..., src/services/oauth/..., src/store/queries/storage/...
src/services/config/config.service.test.ts, src/services/navigation/navigation.service.test.ts, src/services/oauth/oauth.service.test.ts, src/store/queries/storage/storage.query.test.ts
Replaced many local-relative error imports with centralized @/errors across services and tests (no behavior changes).
SDK Manager & Mail client
src/services/sdk/index.ts, src/services/sdk/mail/index.ts, src/services/sdk/mail/mail.service.test.ts
Refactored SdkManager to use driveApiUrl, added mailApiUrl and paymentsApiUrl getters; added getMail() and MailService wrapper with methods and tests.
User service, slice & thunks
src/services/user/user.service.ts, src/store/slices/user/index.ts, src/store/slices/user/thunks/index.ts, src/store/slices/user/thunks/refreshAvatarThunk/..., src/store/slices/user/thunks/refreshAvatarThunk/refreshAvatarThunk.test.ts, src/store/slices/user/userSlice.test.ts
Added refreshUserAvatar to UserService; added refreshAvatarThunk and tests; replaced initialize action/slice usage with hydrate and updated related tests.
App bootstrap / entry
src/App.tsx, src/main.tsx
App startup now dispatches hydrate pattern and chains avatar refresh thunk; JSX nesting adjusted in main entry (no render changes).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • larryrider
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title describes a primary goal (adding mail endpoints and user avatar refresh) that aligns with the substantial changes in the changeset, including new Mail service, avatar refresh functionality, and error centralization.
Description check ✅ Passed The description accurately outlines the main additions (mail endpoints, avatar refresh) and refactoring (error centralization) that are present in the changeset, with relevant detail about the endpoints being added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/fetch-mails

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.env.example:
- Around line 1-3: Reorder the environment variable entries so they are
alphabetically consistent: place VITE_MAIL_API_URL before VITE_PAYMENTS_API_URL
(keeping VITE_DRIVE_API_URL where appropriate), i.e., update the .env.example
listing to alphabetic order referencing the variables VITE_MAIL_API_URL,
VITE_PAYMENTS_API_URL, and VITE_DRIVE_API_URL so the linter warning is resolved.

In `@sonar-project.properties`:
- Line 7: The PR description/messaging incorrectly states that `**/*.errors.ts`
was replaced; update the summary to accurately say that the
`sonar.coverage.exclusions` property now adds `errors/**` in addition to the
existing `**/*.errors.ts` pattern (key: sonar.coverage.exclusions in
sonar-project.properties), and optionally note that `**/*.errors.ts` can be
removed later once migration is complete.

In `@src/store/slices/user/thunks/refreshAvatarThunk/index.ts`:
- Around line 9-14: The thunk currently calls
UserService.instance.refreshUserAvatar() before ensuring a user exists; update
the async thunk (the function using getState and dispatch) to first read
getState().user.user and if no user return undefined, then call
UserService.instance.refreshUserAvatar() and proceed; in other words, move the
user existence guard above the call to refreshUserAvatar() so the API is only
invoked when a user is present.

In `@src/store/slices/user/thunks/refreshAvatarThunk/refreshAvatarThunk.test.ts`:
- Around line 31-43: The test currently stubs
UserService.instance.refreshUserAvatar but doesn't assert it wasn't invoked;
update the test in refreshAvatarThunk.test.ts to assert that
UserService.instance.refreshUserAvatar was not called when the store's user.user
is undefined by adding an expectation like
expect(UserService.instance.refreshUserAvatar).not.toHaveBeenCalled() after
dispatching refreshAvatarThunk(); keep the existing spy creation
(vi.spyOn(...).mockResolvedValue(null)), the store setup with user: { user:
undefined }, and the existing payload/state assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7f98ff57-19f9-4697-80d4-dc58d6a933c0

📥 Commits

Reviewing files that changed from the base of the PR and between 105accd and ed0d6c4.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (29)
  • .env.example
  • package.json
  • sonar-project.properties
  • src/App.tsx
  • src/errors/config/index.ts
  • src/errors/index.ts
  • src/errors/navigation/index.ts
  • src/errors/oauth/index.ts
  • src/errors/shared/index.ts
  • src/errors/storage/index.ts
  • src/main.tsx
  • src/services/config/config.service.test.ts
  • src/services/config/index.ts
  • src/services/navigation/index.ts
  • src/services/navigation/navigation.service.test.ts
  • src/services/oauth/oauth.service.test.ts
  • src/services/oauth/oauth.service.ts
  • src/services/sdk/index.ts
  • src/services/sdk/mail/index.ts
  • src/services/sdk/mail/mail.service.test.ts
  • src/services/user/user.service.ts
  • src/store/queries/storage/storage.query.test.ts
  • src/store/queries/storage/storage.query.ts
  • src/store/slices/user/index.ts
  • src/store/slices/user/thunks/index.ts
  • src/store/slices/user/thunks/refreshAvatarThunk/index.ts
  • src/store/slices/user/thunks/refreshAvatarThunk/refreshAvatarThunk.test.ts
  • src/store/slices/user/userSlice.test.ts
  • vite.config.ts

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.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/store/slices/user/thunks/refreshAvatarThunk/index.ts (1)

13-20: ⚠️ Potential issue | 🟠 Major

Missing validation for userAvatar before dispatch.

Per the context snippet from user.service.ts, refreshUserAvatar() can return null or undefined. The current code dispatches setUser unconditionally, which would overwrite any existing avatar with null/undefined when the refresh fails to return a valid avatar.

The AI summary also indicates test expectations of "no state change when it resolves to null", suggesting this validation was intended.

🔧 Proposed fix
     const userAvatar = await UserService.instance.refreshUserAvatar();

+    if (!userAvatar) return undefined;
+
     dispatch(
       userActions.setUser({
         ...user,
         avatar: userAvatar,
       }),
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/store/slices/user/thunks/refreshAvatarThunk/index.ts` around lines 13 -
20, The thunk currently calls UserService.instance.refreshUserAvatar() and
unconditionally dispatches userActions.setUser with avatar: userAvatar, which
can overwrite the existing avatar with null/undefined; update the logic in the
refreshAvatarThunk so that after calling refreshUserAvatar() you validate the
result (check userAvatar !== null && userAvatar !== undefined) and only call
dispatch(userActions.setUser({...user, avatar: userAvatar})) when a truthy/valid
avatar is returned; otherwise do nothing (or return early) so the existing
user.avatar remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/store/slices/user/thunks/refreshAvatarThunk/index.ts`:
- Around line 7-22: The thunk refreshAvatarThunk currently calls
UserService.instance.refreshUserAvatar() without error handling; wrap the async
call in a try-catch inside the createAsyncThunk payload so network or API errors
are caught, dispatch userActions.setUser only on success, and return/propagate a
controlled rejection (e.g., via thunkAPI.rejectWithValue or undefined) in the
catch block so callers receive a predictable failure shape; ensure you reference
refreshAvatarThunk, UserService.instance.refreshUserAvatar, and
userActions.setUser when making the changes.

---

Duplicate comments:
In `@src/store/slices/user/thunks/refreshAvatarThunk/index.ts`:
- Around line 13-20: The thunk currently calls
UserService.instance.refreshUserAvatar() and unconditionally dispatches
userActions.setUser with avatar: userAvatar, which can overwrite the existing
avatar with null/undefined; update the logic in the refreshAvatarThunk so that
after calling refreshUserAvatar() you validate the result (check userAvatar !==
null && userAvatar !== undefined) and only call
dispatch(userActions.setUser({...user, avatar: userAvatar})) when a truthy/valid
avatar is returned; otherwise do nothing (or return early) so the existing
user.avatar remains unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: de57e1d4-27d7-43ae-b55b-1e96a487e671

📥 Commits

Reviewing files that changed from the base of the PR and between ed0d6c4 and 93656a3.

📒 Files selected for processing (1)
  • src/store/slices/user/thunks/refreshAvatarThunk/index.ts

Comment on lines +7 to +22
export const refreshAvatarThunk = createAsyncThunk<UserSettings | undefined, void, { state: RootState }>(
'user/refreshAvatar',
async (_, { getState, dispatch }) => {
const user = getState().user.user;
if (!user) return undefined;

const userAvatar = await UserService.instance.refreshUserAvatar();

dispatch(
userActions.setUser({
...user,
avatar: userAvatar,
}),
);
},
);
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider adding error handling for the API call.

If UserService.instance.refreshUserAvatar() throws (e.g., network failure), the thunk will reject without graceful handling. Depending on how this thunk is consumed, you may want to wrap the call in a try-catch to handle failures gracefully or ensure callers handle the rejected promise appropriately.

♻️ Optional: Add try-catch for resilience
 export const refreshAvatarThunk = createAsyncThunk<UserSettings | undefined, void, { state: RootState }>(
   'user/refreshAvatar',
   async (_, { getState, dispatch }) => {
     const user = getState().user.user;
     if (!user) return undefined;

-    const userAvatar = await UserService.instance.refreshUserAvatar();
+    let userAvatar: string | null | undefined;
+    try {
+      userAvatar = await UserService.instance.refreshUserAvatar();
+    } catch {
+      return undefined;
+    }

     if (!userAvatar) return undefined;

     dispatch(
       userActions.setUser({
         ...user,
         avatar: userAvatar,
       }),
     );
   },
 );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/store/slices/user/thunks/refreshAvatarThunk/index.ts` around lines 7 -
22, The thunk refreshAvatarThunk currently calls
UserService.instance.refreshUserAvatar() without error handling; wrap the async
call in a try-catch inside the createAsyncThunk payload so network or API errors
are caught, dispatch userActions.setUser only on success, and return/propagate a
controlled rejection (e.g., via thunkAPI.rejectWithValue or undefined) in the
catch block so callers receive a predictable failure shape; ensure you reference
refreshAvatarThunk, UserService.instance.refreshUserAvatar, and
userActions.setUser when making the changes.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
79.3% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@xabg2 xabg2 merged commit 4a82ac7 into master Mar 26, 2026
4 of 5 checks passed
@xabg2 xabg2 deleted the feature/fetch-mails branch March 26, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants