Skip to content

Comments

Refactored client-side data fetching to server side#556

Merged
MrgSub merged 10 commits intostagingfrom
feat/sr-mail
Apr 3, 2025
Merged

Refactored client-side data fetching to server side#556
MrgSub merged 10 commits intostagingfrom
feat/sr-mail

Conversation

@MrgSub
Copy link
Collaborator

@MrgSub MrgSub commented Apr 2, 2025

READ CAREFULLY THEN REMOVE

Remove bullet points that are not relevant.

PLEASE REFRAIN FROM USING AI TO WRITE YOUR CODE AND PR DESCRIPTION. IF YOU DO USE AI TO WRITE YOUR CODE PLEASE PROVIDE A DESCRIPTION AND REVIEW IT CAREFULLY. MAKE SURE YOU UNDERSTAND THE CODE YOU ARE SUBMITTING USING AI.

  • Pull requests that do not follow these guidelines will be closed without review or comment.
  • If you use AI to write your PR description your pr will be close without review or comment.
  • If you are unsure about anything, feel free to ask for clarification.

Description

Please provide a clear description of your changes.


Type of Change

Please delete options that are not relevant.

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature with breaking changes)
  • 📝 Documentation update
  • 🎨 UI/UX improvement
  • 🔒 Security enhancement
  • ⚡ Performance improvement

Areas Affected

Please check all that apply:

  • Email Integration (Gmail, IMAP, etc.)
  • User Interface/Experience
  • Authentication/Authorization
  • Data Storage/Management
  • API Endpoints
  • Documentation
  • Testing Infrastructure
  • Development Workflow
  • Deployment/Infrastructure

Testing Done

Describe the tests you've done:

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • Cross-browser testing (if UI changes)
  • Mobile responsiveness verified (if UI changes)

Security Considerations

For changes involving data or authentication:

  • No sensitive data is exposed
  • Authentication checks are in place
  • Input validation is implemented
  • Rate limiting is considered (if applicable)

Checklist

  • I have read the CONTRIBUTING document
  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in complex areas
  • I have updated the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix/feature works
  • All tests pass locally
  • Any dependent changes are merged and published

Additional Notes

Add any other context about the pull request here.

Screenshots/Recordings

Add screenshots or recordings here if applicable.


By submitting this pull request, I confirm that my contribution is made under the terms of the project's license.

Summary by CodeRabbit

  • New Features

    • Revamped the mail page to display a side-by-side view of your mail list with the selected email thread, enhanced by asynchronous loading indicators.
    • Introduced an interactive thread view that enables actions like replying, moving, and managing emails for an improved experience.
    • Added a new ComposeButton for creating new mail items with responsive design considerations.
    • Enhanced the search functionality by integrating URL parameters for initial state.
  • Bug Fixes

    • Enhanced session validation and loading states for better user experience.
  • Refactor

    • Streamlined the mail list component for a more efficient and focused display.
    • Simplified the MailLayout component by removing unnecessary complexity and adjusting rendering logic.
    • Removed unused states and props in various components to simplify the structure.

@vercel
Copy link

vercel bot commented Apr 2, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
0 ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 3, 2025 5:37pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 2, 2025

Walkthrough

The changes update several mail-related components. The mail page now accepts a new folder parameter and displays both a mail list and a thread display using Suspense for asynchronous loading. Several files have been marked for client-side rendering with the addition of the 'use client'; directive. In the mail list component, variable names, props, and loading logic have been refactored, and a new thread display function is introduced. Additionally, type definitions have been enhanced to include lists of threads and standardized string literal formatting.

Changes

File(s) Change Summary
apps/mail/app/(routes)/mail/[folder]/[threadId]/page.tsx, apps/mail/app/(routes)/mail/[folder]/page.tsx Updated MailPage to extract both threadId and folder, added the asynchronous SRMailList function, and restructured the layout to include two Suspense-wrapped columns (mail list and thread display).
apps/mail/components/mail/mail-display.tsx, apps/mail/components/mail/mail-iframe.tsx, apps/mail/components/mail/note-panel.tsx Added the 'use client'; directive to each file to enforce client-side rendering.
apps/mail/components/mail/mail-list.tsx Renamed items to demo_items in MailListDemo, updated function signatures to accept external items, removed scroll/loading logic, and simplified conditional rendering for loading states.
apps/mail/components/mail/thread-display.tsx Introduced a new function SRThreadDisplay to handle thread display with state management, event handling, and integration with thread actions.
apps/mail/types/index.ts Updated MailListProps to include an items property (an array of threads) and standardized the MailSelectMode string literals to use single quotes.
apps/mail/actions/mail.ts Modified getMails to accept a single parameter of type IGetThreads, simplifying the function signature and altering the arguments passed to driver.list.
apps/mail/app/(routes)/mail/[folder]/list.server.tsx Introduced a new asynchronous component SRMailList to render a list of threads within a ScrollArea.
apps/mail/components/mail/compose.button.tsx Added a new ComposeButton component for creating new mail items with responsive design considerations.
apps/mail/components/mail/mail-quick-actions.tsx Removed handleDelete and handleQuickReply functions, simplifying the MailQuickActions component.
apps/mail/components/mail/mail.tsx Refactored MailLayout component to simplify state management and rendering logic, removing unnecessary complexity.
apps/mail/components/mail/search-bar.tsx Simplified the SearchBar component by removing unused states and focusing on essential search functionality.
apps/mail/components/mail/thread-subject.tsx Removed tooltip functionality from the ThreadSubject component, simplifying its rendering.
apps/mail/components/ui/app-sidebar.tsx Removed the isMobile variable from the AppSidebar component.
apps/mail/components/ui/settings-content.tsx Adjusted layout and styling of the settings-content component without altering functionality.
apps/mail/config/navigation.ts Standardized string delimiters and formatting in the navigation.ts file.
apps/mail/hooks/use-threads.ts Updated return types and parameter types in the use-threads file to reflect new response structures.
apps/mail/next.config.ts Added useCache: true to the experimental section of the Next.js configuration.

Sequence Diagram(s)

sequenceDiagram
  participant U as User
  participant MP as MailPage
  participant SML as SRMailList
  participant STD as SRThreadDisplay
  participant Loader as Suspense

  U->>MP: Request mail page with threadId & folder
  MP->>MP: Fetch thread messages via getMail
  MP->>SML: Call SRMailList with folder
  SML-->>MP: Return mail list data
  MP->>STD: Render thread display with messages
  STD-->>MP: Return thread display content
  MP-->>U: Complete UI rendered with both mail list and thread display
Loading

Possibly related PRs

  • fix: reduced useSession() calls ; layout inconsistencies  #432: The changes in the main PR are related to the modifications in the MailList component's structure and logic, particularly in how session data is handled, which aligns with the updates made in the retrieved PR regarding the Thread component's signature and session data management.
  • fix: re-rendering #478: The changes in the main PR are related to the modifications in the MailList component from the retrieved PR, as both involve updates to the handling of mail items and the structure of the MailList component.
  • thread movement & context menu #498: The changes in the main PR are related to those in the retrieved PR as both involve modifications to the handling of email threads, specifically with respect to parameters like folder and the introduction of new functions for managing thread actions.

Suggested reviewers

  • nizzyabi

Poem

I'm a hopping coder, quick on my feet,
With folders and threads, my joy is complete!
My whiskers twitch at each code delight,
Suspense-loaded magic makes every bug take flight.
Carrot dreams fuel my nightly code spree,
Celebrating clean changes with a happy bunny glee!
🥕🐇


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 89327cc and a4ab734.

📒 Files selected for processing (2)
  • apps/mail/components/ui/app-sidebar.tsx (0 hunks)
  • apps/mail/config/navigation.ts (3 hunks)
💤 Files with no reviewable changes (1)
  • apps/mail/components/ui/app-sidebar.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/mail/config/navigation.ts

🪧 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.
    • Generate unit testing code for this file.
    • 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. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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

Documentation and Community

  • 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.

@MrgSub MrgSub marked this pull request as draft April 2, 2025 05:53
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: 3

🧹 Nitpick comments (5)
apps/mail/types/index.ts (1)

97-97: Standardized string literals for consistent code style

The change from double quotes to single quotes for string literals in the MailSelectMode type aligns with TypeScript/JavaScript coding conventions and improves consistency throughout the codebase.

Consider applying this string literal standardization across all type definitions in the file for complete consistency.

apps/mail/app/(routes)/mail/[folder]/[threadId]/page.tsx (1)

26-56: Improved layout with side-by-side mail list and thread display.

The two-column layout provides a better user experience by showing both the mail list and the selected thread simultaneously. The use of Suspense for both components handles asynchronous loading states elegantly.

However, there's an inconsistency in the loading states - the mail list has a detailed skeleton loader while the thread display just shows "Loading".

Consider replacing the simple "Loading" text with a more detailed skeleton for the thread display to maintain UI consistency:

-        <Suspense fallback={<p>Loading</p>}>
+        <Suspense 
+          fallback={
+            <div className="p-4">
+              <div className="flex items-center justify-between mb-4">
+                <Skeleton className="h-6 w-1/3" />
+                <Skeleton className="h-4 w-24" />
+              </div>
+              <Skeleton className="h-4 w-full mb-2" />
+              <Skeleton className="h-4 w-3/4 mb-2" />
+              <div className="mt-6">
+                <Skeleton className="h-32 w-full mb-4" />
+                <Skeleton className="h-24 w-full" />
+              </div>
+            </div>
+          }
+        >
           <SRThreadDisplay messages={threadMessages ?? []} />
         </Suspense>
apps/mail/components/mail/thread-display.tsx (2)

531-536: Remove commented-out code for better readability.

This commented-out effect is leftover code from the original component and no longer applies to this implementation.

Remove the commented-out code since it's not being used:

-  // useEffect(() => {
-  //   if (emailData?.[0]) {
-  //     setIsMuted(emailData[0].unread ?? false);
-  //   }
-  // }, [emailData]);

569-661: Remove large block of commented-out code.

This large block of commented-out code for loading states is no longer needed since loading is handled by Suspense in the parent component.

Remove this entire commented-out section to improve code readability and maintainability.

apps/mail/components/mail/mail-list.tsx (1)

587-605: Clean up commented-out load more functionality.

The LoadMore button is commented out but still references variables like isLoading and isValidating that no longer exist in this context after the refactoring.

Either remove this commented-out code completely or properly update it to work with the new data flow:

-  {/* {items.length >= 9 && (
-    <Button
-      variant={'ghost'}
-      className="w-full rounded-none"
-      onClick={handleScroll}
-      disabled={isLoading || isValidating}
-    >
-      {isLoading || isValidating ? (
-        <div className="flex items-center gap-2">
-          <div className="h-4 w-4 animate-spin rounded-full border-2 border-neutral-900 border-t-transparent dark:border-white dark:border-t-transparent" />
-          {t('common.actions.loading')}
-        </div>
-      ) : (
-        <>
-          {t('common.mail.loadMore')} <ChevronDown />
-        </>
-      )}
-    </Button>
-  )} */}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1118b21 and ef8a2aa.

📒 Files selected for processing (7)
  • apps/mail/app/(routes)/mail/[folder]/[threadId]/page.tsx (1 hunks)
  • apps/mail/components/mail/mail-display.tsx (1 hunks)
  • apps/mail/components/mail/mail-iframe.tsx (1 hunks)
  • apps/mail/components/mail/mail-list.tsx (6 hunks)
  • apps/mail/components/mail/note-panel.tsx (1 hunks)
  • apps/mail/components/mail/thread-display.tsx (4 hunks)
  • apps/mail/types/index.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
apps/mail/components/mail/thread-display.tsx (4)
apps/mail/types/index.ts (1)
  • ParsedMessage (37-60)
apps/mail/hooks/use-mobile.tsx (1)
  • useIsMobile (5-19)
apps/mail/lib/thread-actions.ts (2)
  • ThreadDestination (4-4)
  • moveThreadsTo (43-81)
apps/mail/actions/mail.ts (1)
  • modifyLabels (80-113)
🔇 Additional comments (15)
apps/mail/components/mail/mail-iframe.tsx (1)

1-1: Appropriate use of 'use client' directive

The addition of 'use client'; correctly designates this component for client-side rendering, which is necessary since it uses React hooks, DOM manipulation via refs, and browser APIs like URL.createObjectURL().

apps/mail/components/mail/mail-display.tsx (1)

1-1: Appropriate use of 'use client' directive

The addition of 'use client'; is necessary for this component as it uses React hooks (useState, useEffect, useMemo), contains complex UI logic, and interacts with client-side APIs. This change ensures proper functioning in Next.js's hybrid rendering model.

apps/mail/components/mail/note-panel.tsx (1)

1-1: Appropriate use of 'use client' directive

The addition of 'use client'; correctly marks this component for client-side rendering, which is essential as it contains extensive React hooks, state management, DOM interactions, and browser API calls like navigator.clipboard.

apps/mail/types/index.ts (1)

94-94: Required items property ensures proper data flow

Adding the items: InitialThread[] property to the MailListProps interface indicates that external thread data is now required by the mail list component. This change improves type safety and explicitly shows the data dependency.

apps/mail/app/(routes)/mail/[folder]/[threadId]/page.tsx (4)

1-8: Good addition of necessary imports for the updated component structure.

The imports properly reflect the components needed for the new layout structure, with both mail list and thread display components being imported. The use of Suspense for asynchronous loading is a good practice.


10-15: Appropriate interface update to support folder navigation.

The MailPageProps interface has been correctly updated to include the folder parameter, which is necessary for the enhanced functionality of displaying both mail list and thread details.


17-20: Well-structured server component for mail list retrieval.

The SRMailList function is well-implemented as an async component that fetches mail data and passes it to the MailList component. The error handling for empty results is handled via the nullish coalescing operator.


22-25: Clean parameter extraction and data fetching.

The destructuring of both threadId and folder from params is clear, and the renaming of thread to threadMessages is more descriptive of the data being fetched.

apps/mail/components/mail/thread-display.tsx (3)

1-1: Correct use of 'use client' directive.

The 'use client' directive is properly placed at the top of the file, indicating that this component uses client-side features like hooks and event handlers.


497-509: Good component structure with appropriate props and hooks.

The SRThreadDisplay component is well-structured with properly typed props. The useState hooks for managing component state (isMuted, isReplyOpen, etc.) and other hooks for mobile detection and route parameters are appropriate.


663-788: Implementation follows best practices for thread display.

The component implementation correctly renders the thread messages with appropriate styling and functionality. The handling of different folder states (inbox, archive, spam) is well-implemented.

apps/mail/components/mail/mail-list.tsx (4)

43-43: Good import of demo data for development.

Correctly importing the demo data from a JSON file for use in the demo component.


303-309: Updated props to use the imported demo data.

The component now properly uses demo_items as the default value for filteredItems and the type has been updated accordingly.


331-331: Improved component architecture with props-based data passing.

The MailList component now accepts an items prop directly instead of fetching data internally. This separation of concerns improves reusability and testability.


532-540: ⚠️ Potential issue

Fix dependency array in useEffect.

The effect only includes isFiltering in its dependency array but also uses setSearchValue. This can lead to stale closures.

Update the dependency array to include all external values used in the effect:

  useEffect(() => {
    if (isFiltering) {
      // Reset the search value when loading is complete
      setSearchValue((prev) => ({
        ...prev,
        isLoading: false,
      }));
    }
-  }, [isFiltering, setSearchValue]);
+  }, [isFiltering, setSearchValue]);

Likely an incorrect or invalid review comment.

@MrgSub MrgSub marked this pull request as ready for review April 3, 2025 06:30
@MrgSub MrgSub changed the title wip Refactoring client-side data fetching to server side Apr 3, 2025
@MrgSub MrgSub changed the title Refactoring client-side data fetching to server side Refactored client-side data fetching to server side Apr 3, 2025
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: 3

🔭 Outside diff range comments (2)
apps/mail/components/draft/drafts-list.tsx (1)

343-345: 💡 Verification agent

🧩 Analysis chain

TODO comment about proper typing needs to be addressed.

There's a TODO comment about adding proper typing and a @ts-expect-error annotation that suggests there are type issues that need to be fixed.

Consider adding proper type definitions for the props parameter to remove the need for the ts-expect-error comment:


🌐 Web query:

What is the proper typing for react-virtuoso row renderer props?

💡 Result:

To properly type React Virtuoso row renderer props, use the library's built-in TypeScript interfaces from the Components type. Here's the standard approach:

import { Components } from 'react-virtuoso'

const CustomRow: Components['Item'] = React.forwardRef<HTMLDivElement, ItemProps>((props, ref) => {
  return <div {...props} ref={ref}>{/* Your row content */}</div>
})

// Usage in Virtuoso:
<Virtuoso components={{ Item: CustomRow }} {/* other props */} />

Key typing considerations:

  1. Component Types: Access specific component props through Components['ComponentName']
  2. Core Props Interface:
interface ItemProps {
  index: number;         // Item index in the list
  data?: unknown;        // Optional data from itemContent
  context?: unknown;     // Optional context passed via Virtuoso
  style?: CSSProperties; // Required for positioning
}
  1. Forward Refs: Components must use React.forwardRef and pass it to DOM elements
  2. Data-driven Lists: Use generics when working with typed data:
const TypedRow = React.forwardRef<HTMLDivElement, ItemProps<YourDataType>>(({ data }, ref) => {
  return <div ref={ref}>{data.yourProperty}</div>
})

For table rows in TableVirtuoso, use TableComponents interface instead[4][7]:

import { TableComponents } from 'react-virtuoso'

const TableRow: TableComponents['TableRow'] = React.forwardRef((props, ref) => {
  return <tr {...props} ref={ref} />
})

Remember to:

  • Include all DOM props passed by Virtuoso
  • Preserve style positioning calculations
  • Use optional context prop for state management[6]
  • Avoid inline component definitions to prevent unnecessary remounts[1][4]

Citations:


Action Required: Update the Row Renderer Typing

Please remove the temporary @ts-expect-error and the accompanying TODO comment by adding proper type definitions for the row renderer component. Based on the React Virtuoso documentation, you can type the props using the built-in interfaces from the library. For example:

import { Components } from 'react-virtuoso'

const CustomRow: Components['Item'] = React.forwardRef<HTMLDivElement, ItemProps>((props, ref) => (
  <div {...props} ref={ref}>
    {/* Your row content */}
  </div>
))

Key Actions:

  • Replace the inline anonymous function at apps/mail/components/draft/drafts-list.tsx (lines 343-345) with a properly typed component using the approach above.
  • Remove both the //TODO: Add proper typing comment and the // @ts-expect-error annotation once typing is properly implemented.
apps/mail/components/mail/search-bar.tsx (1)

92-156: ⚠️ Potential issue

Missing dependency in submitSearch useCallback

The submitSearch function has dependencies on router and folder that are not included in the dependency array.

-  }, [setSearchValue, isAISearching]);
+  }, [setSearchValue, isAISearching, router, folder]);

This could lead to stale closures where the function doesn't have access to the latest values of these dependencies when it runs.

🧹 Nitpick comments (13)
apps/mail/components/mail/thread-subject.tsx (1)

3-3: Remove unused imports.

The Tooltip, TooltipContent, and TooltipTrigger components are imported but not used in the component. They should be removed to keep the code clean and avoid unnecessary imports.

-import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
apps/mail/components/mail/compose.button.tsx (1)

12-17: Link component used as a button.

The ComposeButton component uses a Link component with styling that makes it look like a button. Consider using the Button component with an "asChild" prop and wrapping it with the Link component for better semantics.

-  return (
-    <Link
-      prefetch={true}
-      href={'/mail/create'}
-      className="bg-secondary bg-subtleWhite text-primary hover:bg-subtleWhite dark:bg-subtleBlack dark:hover:bg-subtleBlack relative isolate mt-1 h-8 w-[calc(100%)] overflow-hidden whitespace-nowrap shadow-inner"
-      onMouseEnter={() => iconRef.current?.startAnimation?.()}
-      onMouseLeave={() => iconRef.current?.stopAnimation?.()}
-    >
+  return (
+    <Button
+      asChild
+      className="bg-secondary bg-subtleWhite text-primary hover:bg-subtleWhite dark:bg-subtleBlack dark:hover:bg-subtleBlack relative isolate mt-1 h-8 w-[calc(100%)] overflow-hidden whitespace-nowrap shadow-inner"
+    >
+      <Link
+        prefetch={true}
+        href={'/mail/create'}
+        onMouseEnter={() => iconRef.current?.startAnimation?.()}
+        onMouseLeave={() => iconRef.current?.stopAnimation?.()}
+      >
apps/mail/hooks/use-threads.ts (1)

37-38: Consider handling potential null/undefined data more safely

The non-null assertion (data!) assumes that data will never be null or undefined, which could lead to runtime errors.

Consider adding proper null checking or providing a default value:

-    return data!;
+    return data ?? { nextPageToken: undefined, threads: [], resultSizeEstimate: 0 };
apps/mail/components/mail/mail.tsx (1)

301-313: Remove commented-out code

There are large blocks of commented-out code related to the ResizablePanel and Drawer functionality. Commented code increases the file size and can be confusing for other developers.

Consider removing these commented sections if they're no longer needed, or add an explanatory comment if they're kept for future reference.

Also applies to: 316-334

apps/mail/components/mail/thread-display.tsx (2)

533-534: Fix missing dependency in useCallback

The moveThreadTo function's dependency array is missing router, which could lead to stale closures if the router changes.

-  }, [threadId, folder, mutateStats]);
+  }, [threadId, folder, mutateStats, router, handleClose]);

572-580: Add handleClose to useEffect dependencies

The useEffect for ESC key handling has an empty dependency array but uses handleClose. This could cause stale closures.

-  }, []);
+  }, [handleClose]);
apps/mail/app/(routes)/mail/[folder]/[threadId]/page.tsx (1)

24-64: Well-implemented responsive layout with proper loading states

The two-column layout with appropriate widths for different screen sizes is well designed. Using Suspense for both the mail list and thread display provides a smooth user experience with appropriate loading states.

However, the fallback for the thread display is quite basic compared to the detailed Skeleton UI for the mail list:

-          <Suspense fallback={<p>Loading</p>}>
+          <Suspense fallback={<div className="flex h-full items-center justify-center p-4">
+            <div className="w-full max-w-md space-y-4">
+              <Skeleton className="h-8 w-3/4" />
+              <Skeleton className="h-4 w-full" />
+              <Skeleton className="h-32 w-full" />
+              <Skeleton className="h-4 w-1/2" />
+            </div>
+          </div>}>
apps/mail/types/index.ts (1)

7-13: Clear interface definition for thread retrieval parameters

The IGetThreads interface clearly defines the parameters needed for retrieving mail threads, with appropriate optional fields.

However, the pageToken parameter type could be more specific than string | number | undefined:

-  pageToken: string | number | undefined;
+  pageToken?: string | number;

This would be more consistent with TypeScript conventions for optional parameters.

apps/mail/components/mail/search-bar.tsx (2)

125-127: Simplified router navigation with query parameters

The current implementation works but could be more consistent and maintainable:

-        if (threadId) router.push(`/mail/${folder}/${threadId}/?q=${searchQuery}`);
-        else router.push(`/mail/${folder}/?q=${searchQuery}`);
+        const baseUrl = `/mail/${folder}${threadId ? `/${threadId}` : ''}`;
+        router.push(`${baseUrl}?q=${encodeURIComponent(searchQuery)}`);

This approach encodes the search query properly and makes the pattern more maintainable.


173-182: Inconsistent state management in resetSearch function

The resetSearch function sets isAISearching to false, but this state isn't fully tracked in the component's state:

  const resetSearch = useCallback(() => {
    form.reset();
+   setIsAISearching(false);
    setSearchValue({
      value: '',
      highlight: '',
      folder: '',
      isLoading: false,
      isAISearching: false,
    });
  }, [form, setSearchValue]);

This would ensure the local component state stays in sync with the shared state.

apps/mail/app/(routes)/mail/[folder]/page.tsx (2)

13-27: Clean session handling and data fetching

The simplified session check and structured data fetching make the code more readable and maintainable.

However, there's potential duplication with the thread page. Consider extracting the common data fetching logic:

// In a shared utility file
export async function fetchMailData(params, searchParams) {
  const { folder } = await params;
  const { pageToken, q, max, labelIds } = await searchParams;
  return getMails({
    folder,
    q,
    max,
    pageToken,
    labelIds,
  });
}

Then both pages could use this shared function to reduce duplication.


33-64: Well-implemented Suspense boundary with appropriate fallback UI

The use of Suspense with a detailed Skeleton UI for the loading state provides a smooth user experience. The structured passing of props to SRMailList is clear and complete.

Consider adding error boundaries to handle potential failures gracefully:

+import { ErrorBoundary } from '@/components/error-boundary';

// In the return statement
+      <ErrorBoundary fallback={<div>Failed to load mail list. Please try again.</div>}>
        <Suspense
          fallback={
            // ... existing fallback
          }
        >
          <SRMailList
            threads={threadsResponse?.threads}
            nextPageToken={threadsResponse?.nextPageToken}
            resultSizeEstimate={threadsResponse?.resultSizeEstimate}
          />
        </Suspense>
+      </ErrorBoundary>
apps/mail/components/mail/mail-list.tsx (1)

523-540: Implemented pagination UI with Back and Next buttons.

The pagination UI is cleanly implemented with conditional rendering based on the size of the data set. The Next button properly constructs the URL with pageToken and prev parameters.

However, consider using a more semantic HTML element for pagination to improve accessibility.

-<div className="flex justify-center pb-3">
+<nav aria-label="Mail pagination" className="flex justify-center pb-3">
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ef8a2aa and 89327cc.

📒 Files selected for processing (20)
  • apps/mail/actions/mail.ts (1 hunks)
  • apps/mail/app/(routes)/mail/[folder]/[threadId]/page.tsx (1 hunks)
  • apps/mail/app/(routes)/mail/[folder]/list.server.tsx (1 hunks)
  • apps/mail/app/(routes)/mail/[folder]/page.tsx (1 hunks)
  • apps/mail/app/api/driver/types.ts (2 hunks)
  • apps/mail/components/draft/drafts-list.tsx (2 hunks)
  • apps/mail/components/draft/drafts.tsx (1 hunks)
  • apps/mail/components/mail/compose.button.tsx (1 hunks)
  • apps/mail/components/mail/mail-list.tsx (7 hunks)
  • apps/mail/components/mail/mail-quick-actions.tsx (0 hunks)
  • apps/mail/components/mail/mail.tsx (10 hunks)
  • apps/mail/components/mail/search-bar.tsx (7 hunks)
  • apps/mail/components/mail/thread-display.tsx (6 hunks)
  • apps/mail/components/mail/thread-subject.tsx (1 hunks)
  • apps/mail/components/ui/app-sidebar.tsx (0 hunks)
  • apps/mail/components/ui/settings-content.tsx (3 hunks)
  • apps/mail/config/navigation.ts (3 hunks)
  • apps/mail/hooks/use-threads.ts (3 hunks)
  • apps/mail/next.config.ts (1 hunks)
  • apps/mail/types/index.ts (2 hunks)
💤 Files with no reviewable changes (2)
  • apps/mail/components/ui/app-sidebar.tsx
  • apps/mail/components/mail/mail-quick-actions.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/mail/config/navigation.ts
🧰 Additional context used
🧬 Code Definitions (10)
apps/mail/components/draft/drafts.tsx (1)
apps/mail/components/draft/drafts-list.tsx (1)
  • DraftsList (83-379)
apps/mail/components/mail/thread-subject.tsx (1)
apps/mail/lib/utils.ts (1)
  • cn (48-48)
apps/mail/app/(routes)/mail/[folder]/list.server.tsx (2)
apps/mail/types/index.ts (1)
  • InitialThread (85-97)
apps/mail/components/mail/mail-list.tsx (1)
  • MailList (264-545)
apps/mail/components/mail/thread-display.tsx (3)
apps/mail/types/index.ts (1)
  • ParsedMessage (53-76)
apps/mail/hooks/use-mobile.tsx (1)
  • useIsMobile (5-19)
apps/mail/lib/thread-actions.ts (2)
  • ThreadDestination (4-4)
  • moveThreadsTo (43-81)
apps/mail/hooks/use-threads.ts (2)
apps/mail/types/index.ts (1)
  • IGetThreadsResponse (110-114)
apps/mail/actions/mail.ts (1)
  • getMails (5-18)
apps/mail/actions/mail.ts (2)
apps/mail/types/index.ts (1)
  • IGetThreads (7-13)
apps/mail/app/api/driver/google.ts (1)
  • driver (81-524)
apps/mail/components/mail/search-bar.tsx (2)
apps/mail/hooks/use-search-value.ts (1)
  • useSearchValue (19-21)
apps/mail/lib/utils.ts (1)
  • cn (48-48)
apps/mail/app/api/driver/types.ts (1)
apps/mail/types/index.ts (1)
  • IGetThreadsResponse (110-114)
apps/mail/app/(routes)/mail/[folder]/[threadId]/page.tsx (4)
apps/mail/types/index.ts (2)
  • MailPageProps (15-21)
  • ParsedMessage (53-76)
apps/mail/actions/mail.ts (3)
  • getMails (5-18)
  • getMail (20-32)
  • markAsRead (34-44)
apps/mail/app/(routes)/mail/[folder]/list.server.tsx (1)
  • SRMailList (5-19)
apps/mail/components/mail/thread-display.tsx (1)
  • SRThreadDisplay (503-747)
apps/mail/components/mail/mail.tsx (2)
apps/mail/app/(routes)/mail/layout.tsx (1)
  • MailLayout (4-12)
apps/mail/lib/utils.ts (1)
  • cn (48-48)
🪛 Biome (1.9.4)
apps/mail/app/(routes)/mail/[folder]/[threadId]/page.tsx

[error] 22-22: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (39)
apps/mail/components/ui/settings-content.tsx (4)

5-5: Import added for AppSidebar component.

The AppSidebar import is now explicitly included, which aligns with its usage on line 14.


13-13: Width adjusted to fill available space.

Adding w-full class ensures the component takes the full width of its container, improving layout consistency.


15-15: Class ordering updated for background styling.

The dark:bg-black class has been moved to the end of the className list. While this doesn't affect functionality, it helps maintain consistent class ordering patterns.


26-26: Class order reorganized for improved readability.

The classes have been reordered with the commonly used flexbox and layout classes grouped together, improving code readability.

apps/mail/components/draft/drafts.tsx (1)

144-144: Simplified component interface by removing isCompact prop.

The isCompact prop has been removed from the DraftsList component call. This aligns with changes in the DraftsList implementation where isCompact is now hardcoded to false in the row renderer, as shown in the provided code snippets.

apps/mail/next.config.ts (1)

30-30:

Details

✅ Verification successful

Added cache support in experimental features.

Enabling the useCache experimental feature can improve performance by caching responses and reducing redundant computations or network requests, which is particularly valuable for a mail application where data might be accessed frequently.


🌐 Web query:

What does the useCache experimental feature do in Next.js?

💡 Result:

The useCache experimental feature in Next.js introduces a new caching mechanism through the 'use cache' directive, enabling granular control over caching functions, components, and entire routes. Here's a detailed breakdown:

Key Features

  • Cache Boundaries:
    The 'use cache' directive marks components/functions as cacheable, serializing their inputs and outputs. This allows Next.js to reuse cached results for subsequent requests with matching parameters[1][4].

  • Multi-Level Caching:
    Apply caching at three levels:

    // File-level caching (all exports)
    'use cache'
    export default async function Page() { ... }
    
    // Component-level caching
    export async function ProductComponent() {
      'use cache'
      return <></>
    }
    
    // Function-level caching
    export async function getData() {
      'use cache'
      return await fetch('/api/data')
    }

    [1][4][7]

  • Automatic Dependency Tracking:
    Next.js automatically detects serializable arguments/props used in cached functions and includes them in cache keys. Non-serializable values become opaque references that don't affect cache validity[4][7].

Configuration Requirements

// next.config.js
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  experimental: {
    dynamicIO: true, // Required (enables useCache)
    // or explicitly:
    useCache: true
  }
}

This flag enables opt-in caching behavior, shifting from Next.js' previous cache-by-default approach[5][9].

Advanced Capabilities

  • Route-Level Caching:
    Apply 'use cache' to layout/page files to prerender entire routes:

    'use cache'
    import Products from '@/components/products'
    
    export default function Page() {
      return <Products /> // Children inherit caching
    }

    [3][6]

  • Revalidation & Cache Control:

    • Default cache duration: 15 minutes[4]
    • Customize with cacheLife:
    import { unstable_cacheLife as cacheLife } from 'next/cache'
    
    export async function getData() {
      'use cache'
      cacheLife('hours') // Set expiration
      return db.query()
    }
    • Invalidate with revalidateTag()
      [4][6]
  • Serializable Data Support:
    Unlike earlier unstable_cache, this works with any serializable data including React components, JSX, and rendered output[3][7].

Experimental Status

While powerful, useCache remains experimental:

  • Requires Next.js canary version
  • Potential breaking changes in future releases
  • Not recommended for production yet[4][6][9]

This feature represents a paradigm shift toward composable caching, enabling fine-grained performance optimizations while maintaining React's component model[7]. Developers should monitor Next.js documentation for updates as the API stabilizes.

Citations:


Verified: Experimental Cache Feature Enabled Correctly

The use of the experimental useCache: true flag in apps/mail/next.config.ts is correctly enabling Next.js’s new caching mechanism to optimize performance through caching responses. This configuration is expected to reduce redundant computations and network requests, particularly benefiting the mail application where data is accessed frequently.

  • Location: apps/mail/next.config.ts, line 30
  • Purpose: Activates experimental caching as described by Next.js’s documentation, leveraging the 'use cache' directive for granular cache control.

No further changes are required based on the current implementation.

apps/mail/app/(routes)/mail/[folder]/list.server.tsx (3)

1-4: Appropriate imports for the mail list component.

The imports are clean and focused, bringing in only what's needed for the component's functionality.


5-13: Well-structured component interface with proper TypeScript typing.

The component parameters are well defined with optional types that properly match their usage in the component. This makes the component flexible while maintaining type safety.


14-19: Clean implementation with proper fallback for missing threads.

The component ensures that even if threads is undefined, the MailList component receives an empty array, preventing potential rendering issues. The ScrollArea height calculation uses viewport units which provides good responsiveness.

apps/mail/components/mail/thread-subject.tsx (1)

17-25: Subject text now displayed without tooltip.

The tooltip functionality has been removed from the subject text, simplifying the component. The subject is now displayed directly in a span element with proper classes for styling.

apps/mail/components/draft/drafts-list.tsx (3)

83-83: Function signature simplified by removing isCompact parameter.

The DraftsList function no longer accepts the isCompact parameter, simplifying its interface. This is a good change if the component always needs to be displayed in a non-compact mode.


350-350: isCompact prop hardcoded to false.

The isCompact prop is now hardcoded to false instead of being passed from a parameter. This is consistent with the function signature change.


355-355: Updated dependency array by removing isCompact.

The dependency array for the rowRenderer callback has been correctly updated to remove isCompact, reflecting its removal from the component's logic.

apps/mail/components/mail/compose.button.tsx (1)

2-2:

Details

✅ Verification successful

Verify SquarePenIconHandle type has animation methods.

The code uses startAnimation and stopAnimation methods on the SquarePenIconHandle, but it's unclear if these methods exist on this type.

Run the following script to verify the definition of the SquarePenIconHandle type:


🏁 Script executed:

#!/bin/bash
# Check for the definition of SquarePenIconHandle
grep -r "type SquarePenIconHandle" --include="*.tsx" --include="*.ts" .
# Check for the implementation of animation methods
grep -r "startAnimation\|stopAnimation" --include="*.tsx" --include="*.ts" .

Length of output: 12141


SquarePenIconHandle type validation complete

The verification confirms that the SquarePenIconHandle type (imported from apps/mail/components/icons/animated/square-pen.tsx) defines the animation methods (startAnimation and stopAnimation) as expected.

apps/mail/app/api/driver/types.ts (2)

1-1: Updated import to use IGetThreadsResponse type.

The import statement has been updated to import IGetThreadsResponse instead of InitialThread, which aligns with the updated return type of the list method.


10-16: Updated list method signature to use IGetThreadsResponse return type.

The list method's return type has been updated to Promise<IGetThreadsResponse | undefined>, which is a more specific type that includes an array of threads along with pagination information. This change improves type safety and makes the API more predictable.

apps/mail/actions/mail.ts (1)

12-12:

Details

❓ Verification inconclusive

Verify if undefined should replace labelIds in driver.list

You've replaced labelIds with undefined in the driver.list call. Make sure this is intentional and won't affect filtering functionality.


🏁 Script executed:

#!/bin/bash
# Check how the list method uses the labelIds parameter
rg -A 5 -B 5 "list.*labelIds" --glob "apps/mail/app/api/**"

Length of output: 61


I'm not seeing conclusive evidence from the previous run. To further verify whether undefined is intentional for the labelIds parameter in the driver.list call, let's search the entire repository for any occurrences of "labelIds". This should help us confirm if this parameter is being used or referenced in the driver implementation.


🏁 Script executed:

#!/bin/bash
# Recursively search for "labelIds" in the repository to see how and where this parameter is used.
rg "labelIds" .

Length of output: 1856


Action Required: Verify Label Filtering Behavior in driver.list

It appears that the current change is forwarding undefined for the labelIds argument in the driver.list call (at apps/mail/actions/mail.ts:12), even though the getMails function destructures labelIds from its parameters. Our repository search shows that labelIds is used elsewhere (e.g., in apps/mail/app/api/driver/google.ts and apps/mail/hooks/use-threads.ts) to control filtering (such as determining unread status via labelIds.includes('UNREAD')). This discrepancy may unintentionally disable filtering based on labels.

  • Location: apps/mail/actions/mail.ts (line 12)
    • The call currently reads:
          return await driver.list(folder, q, max, undefined, pageToken);
  • Concern: Since labelIds is expected to influence filtering behavior in the driver’s implementation, confirm that forwarding undefined—thus bypassing any label filtering—is intentional.
  • Recommendation: If label filtering should remain active, consider passing the labelIds parameter instead of undefined. Otherwise, if disabling label filtering is intended, ensure that any unused parameters (like labelIds from getMails) are either documented or cleaned up to avoid confusion.
apps/mail/components/mail/mail.tsx (2)

232-234: Layout structure changed from ResizablePanelGroup to div elements

The resizable panel functionality has been removed in favor of simpler div elements. This removes the ability for users to adjust panel sizes.

The simplified layout structure is cleaner and easier to maintain, though it removes the resizable functionality.


207-208: LGTM: Component signature updated to use children prop

The MailLayout component now accepts a children prop and uses destructuring from useParams for route parameters, making it more flexible and consistent with React component patterns.

This change improves component composition and better leverages Next.js routing capabilities.

apps/mail/components/mail/thread-display.tsx (1)

503-747: LGTM: New SRThreadDisplay component implementation

The new SRThreadDisplay component provides a clean implementation for displaying email threads with good separation of concerns, responsive design handling, and proper state management.

The component extracts common UI into a reusable ThreadContent component and properly handles both desktop and mobile views.

apps/mail/types/index.ts (4)

15-21: Well-structured page props with proper typing

The MailPageProps interface provides clear typing for both route parameters and search parameters, which aligns well with the component implementations.


109-114: Clear response interface with appropriate documentation

The IGetThreadsResponse interface is well documented and provides a clear structure for thread retrieval responses, aligning with the Gmail API convention as commented.


116-120: Improved MailListProps interface with required items property

The refactored interface now properly requires the items array of threads while keeping pagination-related properties optional.


122-122: Consistent string literal formatting

The update to use single quotes for string literals in MailSelectMode improves consistency throughout the codebase.

apps/mail/components/mail/search-bar.tsx (3)

1-11: Simplified imports with proper Next.js navigation hooks

The updated imports focus on the essential functionality, removing unnecessary items while adding the proper Next.js navigation hooks.


33-56: Improved form initialization with URL parameter support

The SearchBar component now properly initializes form values from URL parameters, which maintains state across page loads and navigation.


158-171: Simplified input change handler

The handleInputChange function has been simplified to focus on the essential functionality, which improves readability and maintainability.

apps/mail/components/mail/mail-list.tsx (12)

8-9: Added navigation icons to support new pagination feature.

The addition of ChevronLeft and ChevronRight icons supports the new pagination UI elements that appear later in the file.


17-17: Improved type safety with explicit type import.

Good addition of type ComponentProps to the import statement, ensuring type-safety for the Badge component variants used in getDefaultBadgeStyle.


35-35: Renamed import from 'items' to 'demo_items' for clarity.

The rename provides better clarity by distinguishing demo data from actual email threads. This change is properly propagated throughout the component.


56-59: Enhanced URL parameter extraction for thread navigation.

Good addition of folder parameter extraction and search parameters, which improves the navigation between mail threads while preserving the search context.


61-63: Improved thread ID handling with fallback mechanism.

The updated logic elegantly handles both cases where a message might have either a dedicated threadId or use its own id as the thread identifier.


151-153: Enhanced Link component with performance optimizations.

The addition of shallow and prefetch properties improves navigation performance. The href construction now properly includes all necessary parameters to maintain context between navigations.


237-241: Updated MailListDemo to use renamed demo data.

Properly updated the component to use the renamed demo_items both in the default prop value and the type definition.


264-264: Refactored MailList component to receive data as props.

This refactoring follows good practices by making the component receive data rather than fetching it internally, improving reusability and testability.


272-274: Added pagination state management.

Good addition of variables to track current page token and previous page token, supporting the new pagination feature.


467-476: Simplified search loading state management.

The effect has been streamlined to only depend on isFiltering, removing unnecessary dependencies that were likely related to the removed data fetching logic.


477-478: Added navigation helper for returning to previous page.

Simple but effective implementation of the back navigation functionality using router.back().


483-483: Maintained loading indicator for search operations.

Good retention of the loading indicator UI for search operations, ensuring users receive visual feedback during searches.

Comment on lines +22 to +23
onMouseEnter={() => () => iconRef.current?.startAnimation?.()}
onMouseLeave={() => () => iconRef.current?.stopAnimation?.()}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix double arrow functions in event handlers.

The onMouseEnter and onMouseLeave handlers are using double arrow functions, which will create a function that returns another function but never executes the animation. This is likely causing the animations to not work properly.

-      onMouseEnter={() => () => iconRef.current?.startAnimation?.()}
-      onMouseLeave={() => () => iconRef.current?.stopAnimation?.()}
+      onMouseEnter={() => iconRef.current?.startAnimation?.()}
+      onMouseLeave={() => iconRef.current?.stopAnimation?.()}
📝 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
onMouseEnter={() => () => iconRef.current?.startAnimation?.()}
onMouseLeave={() => () => iconRef.current?.stopAnimation?.()}
onMouseEnter={() => iconRef.current?.startAnimation?.()}
onMouseLeave={() => iconRef.current?.stopAnimation?.()}

Comment on lines +645 to +651
<Button
disabled
variant="ghost"
className="md:h-fit md:px-2"
onMouseEnter={() => moreVerticalIconRef.current?.startAnimation?.()}
onMouseLeave={() => moreVerticalIconRef.current?.stopAnimation?.()}
>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Menu trigger is disabled

The dropdown menu trigger button is set to disabled, which prevents users from accessing the dropdown menu options.

-                  disabled
+                  // Remove disabled attribute to make the menu accessible
📝 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
<Button
disabled
variant="ghost"
className="md:h-fit md:px-2"
onMouseEnter={() => moreVerticalIconRef.current?.startAnimation?.()}
onMouseLeave={() => moreVerticalIconRef.current?.stopAnimation?.()}
>
<Button
// Remove disabled attribute to make the menu accessible
variant="ghost"
className="md:h-fit md:px-2"
onMouseEnter={() => moreVerticalIconRef.current?.startAnimation?.()}
onMouseLeave={() => moreVerticalIconRef.current?.stopAnimation?.()}
>

Comment on lines +9 to +22
export default async function MailPage({ params, searchParams }: MailPageProps) {
const { threadId, folder } = await params;
const { pageToken, q, max, labelIds } = await searchParams;
const threadsResponse = await getMails({
folder,
q,
max,
pageToken,
labelIds,
});

let threadMessages: ParsedMessage[] = [];
if (threadId) threadMessages = (await getMail({ id: threadId })) ?? [];
if (threadMessages && threadMessages.some((e) => e.unread)) void markAsRead({ ids: [threadId] });
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Clean data fetching with well-structured error handling

The updated MailPage component now properly handles both params and searchParams, fetching the necessary data in a clean and organized manner. The conditional fetching of thread messages is well implemented.

However, there is a potential null reference issue in line 22:

-  if (threadMessages && threadMessages.some((e) => e.unread)) void markAsRead({ ids: [threadId] });
+  if (threadMessages?.some((e) => e.unread)) void markAsRead({ ids: [threadId] });
📝 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 default async function MailPage({ params, searchParams }: MailPageProps) {
const { threadId, folder } = await params;
const { pageToken, q, max, labelIds } = await searchParams;
const threadsResponse = await getMails({
folder,
q,
max,
pageToken,
labelIds,
});
let threadMessages: ParsedMessage[] = [];
if (threadId) threadMessages = (await getMail({ id: threadId })) ?? [];
if (threadMessages && threadMessages.some((e) => e.unread)) void markAsRead({ ids: [threadId] });
export default async function MailPage({ params, searchParams }: MailPageProps) {
const { threadId, folder } = await params;
const { pageToken, q, max, labelIds } = await searchParams;
const threadsResponse = await getMails({
folder,
q,
max,
pageToken,
labelIds,
});
let threadMessages: ParsedMessage[] = [];
if (threadId) threadMessages = (await getMail({ id: threadId })) ?? [];
if (threadMessages?.some((e) => e.unread)) void markAsRead({ ids: [threadId] });
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 22-22: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

Copy link
Contributor

@ahmetskilinc ahmetskilinc left a comment

Choose a reason for hiding this comment

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

lgtm - tested locally works much better

@MrgSub MrgSub merged commit eb60648 into staging Apr 3, 2025
4 of 5 checks passed
@BlankParticle BlankParticle deleted the feat/sr-mail branch May 25, 2025 13:43
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.

3 participants