Skip to content

Conversation

AshishViradiya153
Copy link
Contributor

@AshishViradiya153 AshishViradiya153 commented Jul 6, 2025

Summary by CodeRabbit

  • New Features

    • Introduced dataroom templates with a dedicated "Templates" tab for browsing and using pre-built templates.
    • Added interactive template cards and modals to facilitate dataroom creation from templates.
    • Provided a guided flow for creating datarooms from scratch or templates, including success confirmation and shareable link generation.
    • Implemented animated and responsive UI components for template browsing and selection.
  • Improvements

    • Centralized default banner image usage across components for consistent branding.
    • Enhanced error handling and user feedback related to dataroom creation limits and trial activations.
  • Bug Fixes

    • Strengthened enforcement of dataroom creation limits based on user plan and trial status.
  • Chores

    • Refactored imports and removed unused dependencies for cleaner codebase.

@AshishViradiya153 AshishViradiya153 requested a review from mfts as a code owner July 6, 2025 21:38
Copy link

vercel bot commented Jul 6, 2025

@AshishViradiya153 is attempting to deploy a commit to the mftsio Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

coderabbitai bot commented Jul 6, 2025

Walkthrough

This update introduces a dataroom template system, enabling users to browse, preview, and create datarooms from pre-defined templates. New React components and SWR hooks manage template fetching, display, and creation workflows, while backend API endpoints support template listing and duplication. UI changes include new tabs, modals, and animated transitions.

Changes

File(s) Change Summary
components/datarooms/template-card.tsx
components/datarooms/use-template-modal.tsx
Added new React components for displaying dataroom templates (TemplateCard) and a modal to create datarooms from templates (UseTemplateModal).
components/welcome/browse-templates.tsx
components/welcome/dataroom-choice.tsx
components/welcome/dataroom-created.tsx
Added new React components for browsing templates, choosing dataroom creation methods, and confirming dataroom creation with link sharing.
lib/swr/use-dataroom-templates.ts Added a custom SWR hook and type for fetching and managing dataroom templates.
lib/utils.ts Added exported constant DEFAULT_BANNER_IMAGE.
pages/api/teams/[teamId]/datarooms/duplicate-template.ts
pages/api/teams/[teamId]/datarooms/templates.ts
Added new API endpoints for duplicating a dataroom template and listing available templates.
pages/api/teams/[teamId]/datarooms/index.ts
pages/api/teams/[teamId]/datarooms/trial.ts
Refined dataroom creation logic and trial handling, including plan-based limits and response structure changes.
components/view/dataroom/nav-dataroom.tsx
pages/datarooms/[id]/branding/index.tsx
pages/room_ppreview_demo.tsx
Refactored to import DEFAULT_BANNER_IMAGE from shared utilities instead of local constants.
pages/datarooms/index.tsx Introduced a tabbed interface for "My Datarooms" and "Templates", with template browsing and creation functionality.
pages/welcome.tsx Updated to conditionally render new welcome flow components and hide the skip button for certain steps.
prisma/migrations/20250706215107_add_is_template_to_dataroom/migration.sql Added a new isTemplate boolean column to the Dataroom table with default false.
prisma/schema/dataroom.prisma Added isTemplate boolean field with default false to the Dataroom model.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI (BrowseTemplates/DataroomsPage)
    participant SWR Hook
    participant API /templates
    participant API /duplicate-template

    User->>UI (BrowseTemplates/DataroomsPage): Visit Templates tab or Browse Templates
    UI (BrowseTemplates/DataroomsPage)->>SWR Hook: Fetch templates
    SWR Hook->>API /templates: GET /api/teams/{teamId}/datarooms/templates
    API /templates-->>SWR Hook: Return template list
    SWR Hook-->>UI (BrowseTemplates/DataroomsPage): Provide templates

    User->>UI (TemplateCard/UseTemplateModal): Click "Use Template"
    UI (UseTemplateModal)->>API /duplicate-template: POST /api/teams/{teamId}/datarooms/duplicate-template
    API /duplicate-template-->>UI (UseTemplateModal): Return new dataroom
    UI (UseTemplateModal)->>SWR Hook: Mutate datarooms cache
    UI (UseTemplateModal)-->>User: Show success, navigate to new dataroom
Loading
sequenceDiagram
    participant User
    participant WelcomePage
    participant DataroomChoice
    participant API /datarooms/index
    participant API /datarooms/trial

    User->>WelcomePage: Visit /welcome
    WelcomePage->>DataroomChoice: Render choice UI
    User->>DataroomChoice: Select "Create from Scratch"
    DataroomChoice->>API /datarooms/index: POST create dataroom
    API /datarooms/index-->>DataroomChoice: Return new dataroom
    DataroomChoice-->>WelcomePage: Navigate to upload or created screen

    User->>DataroomChoice: Select "Start Trial"
    DataroomChoice->>API /datarooms/trial: POST trial
    API /datarooms/trial-->>DataroomChoice: Return success/teamId
    DataroomChoice-->>WelcomePage: Navigate to next welcome step
Loading
sequenceDiagram
    participant User
    participant DataroomCreated
    participant API /links

    User->>DataroomCreated: View dataroom created confirmation
    User->>DataroomCreated: Click "Create Shareable Link"
    DataroomCreated->>API /links: POST create link
    API /links-->>DataroomCreated: Return link info
    DataroomCreated-->>User: Show link options
Loading

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-07-06T22_05_52_558Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

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

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 generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @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.

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: 6

🧹 Nitpick comments (9)
pages/api/teams/[teamId]/datarooms/index.ts (1)

104-104: Remove debug logging before production.

The console.log("teamthis", team) statement should be removed as it's debug code that shouldn't be in production.

-      console.log("teamthis", team);
pages/api/teams/[teamId]/datarooms/templates.ts (1)

9-13: Consider making template IDs configurable.

The hardcoded template IDs work for the initial implementation, but consider moving them to environment variables or database configuration for better maintainability as the template system grows.

pages/api/teams/[teamId]/datarooms/duplicate-template.ts (2)

28-32: Consider using environment variables for template configuration.

The hardcoded template IDs make the system inflexible and require code changes to add new templates. Consider moving these to environment variables or a database configuration table.

-// Template dataroom IDs from Papermark Templates account
-const TEMPLATE_DATAROOM_IDS = [
-    "cmclsvtli0001jp04xhvtsbc8",
-    "cmcnpybt1000sjx04zz2p34kn",
-];
+// Template dataroom IDs from Papermark Templates account
+const TEMPLATE_DATAROOM_IDS = process.env.TEMPLATE_DATAROOM_IDS?.split(',') || [
+    "cmclsvtli0001jp04xhvtsbc8",
+    "cmcnpybt1000sjx04zz2p34kn",
+];

58-88: Optimize recursive folder fetching to prevent N+1 queries.

The current implementation makes individual database queries for each folder, which can lead to performance issues with deeply nested folder structures. Consider using a single query to fetch all folders and then organize them hierarchically in memory.

-    // Recursive function to fetch folder contents
-    async function getFolderContents(
-        folderId: string,
-    ): Promise<DataroomFolderWithContents> {
-        const folder = await prisma.dataroomFolder.findUnique({
-            where: { id: folderId },
-            include: {
-                documents: true,
-                childFolders: {
-                    include: { documents: true },
-                },
-            },
-        });
-
-        if (!folder) {
-            throw new Error(`Folder with id ${folderId} not found`);
-        }
-
-        const childFolders = await Promise.all(
-            folder.childFolders.map(async (childFolder) => {
-                const nestedContents = await getFolderContents(childFolder.id);
-                return nestedContents;
-            }),
-        );
-
-        return {
-            ...folder,
-            documents: folder.documents,
-            childFolders: childFolders,
-        };
-    }
+    // Fetch all folders in a single query and organize hierarchically
+    const allFolders = await prisma.dataroomFolder.findMany({
+        where: { dataroomId: templateId },
+        include: { documents: true },
+    });
+    
+    // Build folder hierarchy
+    const folderMap = new Map<string, DataroomFolderWithContents>();
+    const rootFolders: DataroomFolderWithContents[] = [];
+    
+    // Initialize all folders
+    allFolders.forEach(folder => {
+        folderMap.set(folder.id, {
+            ...folder,
+            documents: folder.documents,
+            childFolders: [],
+        });
+    });
+    
+    // Organize into hierarchy
+    allFolders.forEach(folder => {
+        const folderWithContents = folderMap.get(folder.id)!;
+        if (folder.parentId) {
+            const parent = folderMap.get(folder.parentId);
+            if (parent) {
+                parent.childFolders.push(folderWithContents);
+            }
+        } else {
+            rootFolders.push(folderWithContents);
+        }
+    });
components/datarooms/use-template-modal.tsx (5)

52-56: Simplify state management with proper prop handling.

The component maintains both controlled and uncontrolled state which can lead to confusion. Consider using a custom hook to manage the modal state more cleanly.

-  const [isOpen, setIsOpen] = useState(false);
-  const [isLoading, setIsLoading] = useState(false);
-  const [selectedTemplate, setSelectedTemplate] =
-    useState<DataroomTemplate | null>(template || null);
-  const [dataroomName, setDataroomName] = useState("");
+  const [isOpen, setIsOpen] = useState(false);
+  const [isLoading, setIsLoading] = useState(false);
+  const [selectedTemplate, setSelectedTemplate] = useState<DataroomTemplate | null>(template || null);
+  const [dataroomName, setDataroomName] = useState("");
+  
+  // Reset selected template when template prop changes
+  useEffect(() => {
+    setSelectedTemplate(template || null);
+  }, [template]);

95-100: Simplify modal state management.

The modal state logic is overly complex with multiple conditionals. Consider using a more straightforward approach.

-      const modalOpen = open !== undefined ? open : isOpen;
-      if (open !== undefined && setOpen) {
-        setOpen(false);
-      } else {
-        setIsOpen(false);
-      }
+      // Close modal using the appropriate setter
+      handleOpenChange(false);

126-127: Extract modal state logic into a custom hook.

The modal state management pattern is repeated and could be extracted into a reusable hook for better maintainability.

// Create a custom hook for modal state management
function useModalState(controlledOpen?: boolean, controlledSetOpen?: (open: boolean) => void) {
  const [internalOpen, setInternalOpen] = useState(false);
  
  const isControlled = controlledOpen !== undefined;
  const open = isControlled ? controlledOpen : internalOpen;
  const setOpen = isControlled && controlledSetOpen ? controlledSetOpen : setInternalOpen;
  
  return { open, setOpen };
}

// Then use it in the component:
const { open: modalOpen, setOpen: handleOpenChange } = useModalState(open, setOpen);

168-184: Add loading state for individual templates.

The template selection cards don't provide visual feedback when clicked, which can feel unresponsive. Consider adding a loading state or immediate visual feedback.

                  <div className="grid gap-3">
                    {templates.map((tmpl) => (
                      <Card
                        key={tmpl.id}
-                        className="cursor-pointer transition-all duration-200 hover:border-primary/50 hover:bg-muted/50"
+                        className="cursor-pointer transition-all duration-200 hover:border-primary/50 hover:bg-muted/50 focus:outline-none focus:ring-2 focus:ring-primary/50"
                        onClick={() => setSelectedTemplate(tmpl)}
+                        onKeyDown={(e) => {
+                          if (e.key === 'Enter' || e.key === ' ') {
+                            e.preventDefault();
+                            setSelectedTemplate(tmpl);
+                          }
+                        }}
+                        tabIndex={0}
+                        role="button"
+                        aria-label={`Select template: ${tmpl.name}`}
                      >

201-210: Improve accessibility for the name input.

The input field lacks proper accessibility attributes and could benefit from better user guidance.

                <Label htmlFor="dataroom-name">Dataroom Name</Label>
                <Input
                  id="dataroom-name"
                  placeholder={`${selectedTemplate.name}`}
                  value={dataroomName}
                  onChange={(e) => setDataroomName(e.target.value)}
+                  aria-describedby="dataroom-name-help"
                />
-                <p className="text-xs text-muted-foreground">
+                <p id="dataroom-name-help" className="text-xs text-muted-foreground">
                  Leave empty to use default name: &quot;{selectedTemplate.name}
                  &quot;
                </p>
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ae1fbbe and fefdf2f.

📒 Files selected for processing (17)
  • components/datarooms/template-card.tsx (1 hunks)
  • components/datarooms/use-template-modal.tsx (1 hunks)
  • components/view/dataroom/nav-dataroom.tsx (1 hunks)
  • components/welcome/browse-templates.tsx (1 hunks)
  • components/welcome/dataroom-choice.tsx (1 hunks)
  • components/welcome/dataroom-created.tsx (1 hunks)
  • components/welcome/dataroom-trial.tsx (1 hunks)
  • lib/swr/use-dataroom-templates.ts (1 hunks)
  • lib/utils.ts (1 hunks)
  • pages/api/teams/[teamId]/datarooms/duplicate-template.ts (1 hunks)
  • pages/api/teams/[teamId]/datarooms/index.ts (2 hunks)
  • pages/api/teams/[teamId]/datarooms/templates.ts (1 hunks)
  • pages/api/teams/[teamId]/datarooms/trial.ts (1 hunks)
  • pages/datarooms/[id]/branding/index.tsx (2 hunks)
  • pages/datarooms/index.tsx (5 hunks)
  • pages/room_ppreview_demo.tsx (2 hunks)
  • pages/welcome.tsx (4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
components/datarooms/template-card.tsx (5)
lib/swr/use-dataroom-templates.ts (1)
  • DataroomTemplate (7-9)
components/ui/card.tsx (4)
  • Card (80-80)
  • CardHeader (81-81)
  • CardTitle (83-83)
  • CardContent (85-85)
lib/utils.ts (1)
  • DEFAULT_BANNER_IMAGE (752-752)
components/datarooms/use-template-modal.tsx (1)
  • UseTemplateModal (39-232)
components/ui/button.tsx (1)
  • Button (71-71)
components/welcome/browse-templates.tsx (3)
lib/swr/use-dataroom-templates.ts (1)
  • useDataroomTemplates (11-29)
lib/constants.ts (1)
  • STAGGER_CHILD_VARIANTS (8-15)
components/datarooms/template-card.tsx (1)
  • TemplateCard (10-50)
components/welcome/dataroom-choice.tsx (2)
context/team-context.tsx (1)
  • useTeam (85-85)
lib/constants.ts (1)
  • STAGGER_CHILD_VARIANTS (8-15)
pages/api/teams/[teamId]/datarooms/templates.ts (2)
pages/api/auth/[...nextauth].ts (1)
  • authOptions (32-215)
lib/types.ts (1)
  • CustomUser (17-17)
lib/swr/use-dataroom-templates.ts (2)
context/team-context.tsx (1)
  • useTeam (85-85)
lib/utils.ts (1)
  • fetcher (36-50)
pages/api/teams/[teamId]/datarooms/index.ts (1)
ee/limits/server.ts (1)
  • getLimits (58-141)
pages/welcome.tsx (3)
components/welcome/dataroom-choice.tsx (1)
  • DataroomChoice (14-135)
components/welcome/browse-templates.tsx (1)
  • BrowseTemplates (11-88)
components/welcome/dataroom-created.tsx (1)
  • DataroomCreated (21-157)
🪛 Biome (1.9.4)
pages/datarooms/index.tsx

[error] 151-191: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (27)
lib/utils.ts (1)

752-752: Excellent refactoring to centralize the banner image constant.

This eliminates duplication across multiple files and provides a single source of truth for the default banner image path.

components/view/dataroom/nav-dataroom.tsx (1)

9-9: Good refactoring to use the centralized constant.

The import correctly references the newly centralized DEFAULT_BANNER_IMAGE from the utils module, eliminating local duplication.

pages/room_ppreview_demo.tsx (1)

7-7: Consistent with the centralization pattern.

Properly imports the centralized DEFAULT_BANNER_IMAGE constant, maintaining consistency across the codebase.

pages/datarooms/[id]/branding/index.tsx (1)

29-34: Well-structured import consolidation.

The import statement cleanly groups related utilities including the centralized DEFAULT_BANNER_IMAGE, improving code organization and consistency.

pages/api/teams/[teamId]/datarooms/trial.ts (1)

112-112: All frontend consumers updated to handle the new response format

Both components/welcome/dataroom-trial.tsx and components/datarooms/dataroom-trial-modal.tsx now do:

const { success, teamId } = await response.json();

—and handle errors via the returned message. No remaining consumers expect the old dataroom payload.

components/welcome/dataroom-trial.tsx (3)

80-84: LGTM! API response structure update is consistent.

The change from expecting dataroomId to success and teamId aligns with the updated trial API that no longer creates a dataroom entity directly but activates the trial instead.


89-89: Analytics payload updated appropriately.

The analytics now captures teamId instead of dataroom-specific information, which is consistent with the trial activation flow where no dataroom is created yet.


96-96: Navigation flow improvement aligns with new UX.

Redirecting to the dataroom-choice screen allows users to choose between creating from scratch or using templates, which is a better user experience than directly creating a dataroom.

pages/welcome.tsx (3)

12-15: New component imports are properly organized.

The imports for the new template-related components are correctly added and will support the enhanced dataroom creation flow.


45-49: Skip button logic is well-designed.

Hiding the skip button for template-related flows (dataroom-trial, dataroom-choice, browse-templates) makes sense as these are guided workflows that shouldn't be skipped.


90-102: Conditional rendering for new components is correct.

The template-related components are properly integrated with appropriate query parameter checks. The DataroomCreated component correctly requires both type and dataroomId parameters.

components/datarooms/template-card.tsx (3)

10-16: Well-defined component interface.

The TypeScript interface clearly defines the required template prop and optional onTemplateCreated callback, promoting type safety and clear API design.


22-27: Proper fallback handling for banner images.

The implementation correctly uses the template's brand banner if available, falling back to the default banner image. This ensures a consistent UI even when templates don't have custom banners.


37-46: Modal integration follows controlled component pattern.

The UseTemplateModal is properly integrated with controlled open state and passes through the necessary props including the template and callback handler.

components/welcome/browse-templates.tsx (3)

57-70: Excellent loading state implementation.

The skeleton placeholders during template loading provide a great user experience. The grid layout matches the actual template cards, maintaining visual consistency.


72-84: Proper conditional rendering and data handling.

The component correctly checks for both templates existence and length before rendering, preventing potential runtime errors. The grid layout is responsive and well-structured.


15-17: Navigation handler is clean and purposeful.

The handleTemplateCreated function properly navigates to the dataroom-created screen with the necessary dataroomId parameter, maintaining the flow consistency.

pages/api/teams/[teamId]/datarooms/index.ts (4)

86-87: Trial plan support properly implemented.

Adding "free+drtrial" and other trial variants to the allowed plans list correctly enables dataroom creation for trial users while maintaining plan restrictions.


96-102: Query optimization improves performance.

Using Prisma's _count include is more efficient than a separate count query, reducing database round trips while maintaining the same functionality.


109-116: Trial limit enforcement is correctly implemented.

The logic properly identifies trial plans using the includes("drtrial") check and enforces a 1-dataroom limit with appropriate error messaging. The error response format is consistent with other API endpoints.


120-120: Proper exclusion of trial plans from general limits.

Adding the !isTrial condition ensures that trial plans are handled by their specific limit check rather than the general limits system, maintaining clear separation of concerns.

lib/swr/use-dataroom-templates.ts (1)

11-29: LGTM! Clean SWR hook implementation.

The hook follows SWR best practices with conditional fetching, proper type definitions, and appropriate return interface. The 120-second deduplication interval is reasonable for template data that doesn't change frequently.

components/welcome/dataroom-choice.tsx (1)

20-70: Excellent error handling and state management.

The createFromScratch function demonstrates robust error handling with proper loading states, toast notifications, and analytics tracking. The trial limit handling and navigation flow are well-implemented.

pages/api/teams/[teamId]/datarooms/templates.ts (1)

15-73: Well-structured API route with proper security.

The implementation follows API best practices with proper authentication, authorization, error handling, and appropriate HTTP status codes. The team membership verification ensures data access security.

pages/datarooms/index.tsx (1)

139-252: Excellent tabbed interface implementation.

The tabbed layout with proper loading states, skeleton UI, and empty state handling provides a great user experience. The template integration is well-structured.

components/welcome/dataroom-created.tsx (2)

36-80: Robust link creation with excellent error handling.

The createLink function demonstrates proper error handling, loading states, and analytics tracking. The source attribution in analytics ("template_onboarding") provides valuable context for tracking.


82-91: Clean conditional rendering pattern.

The conditional rendering based on showLinkOptions and linkId provides a smooth user flow transition to the link configuration interface.

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: 0

♻️ Duplicate comments (1)
pages/api/teams/[teamId]/datarooms/duplicate-template.ts (1)

203-225: Duplicate limits fetching still present despite previous review.

The code still calls getLimits() twice - once implicitly suggested in previous comments and once explicitly at line 213. The trial check uses a hardcoded limit of 1, while regular plans use getLimits().

Consider consolidating the limits logic:

+ const limits = await getLimits({ teamId, userId });
  const isTrial = team.plan.includes("drtrial");
+ const dataroomLimit = isTrial ? 1 : limits?.datarooms;

- if (isTrial && team._count.datarooms >= 1) {
+ if (team._count.datarooms >= dataroomLimit) {
      return res.status(403).json({
          message:
              "You've reached the limit of datarooms. Consider upgrading your plan.",
-         info: "trial_limit_reached",
+         info: isTrial ? "trial_limit_reached" : "limit_reached",
      });
  }

- const limits = await getLimits({ teamId, userId });
- 
- if (limits && team._count.datarooms >= limits.datarooms && !isTrial) {
-     console.log(
-         "Dataroom limit reached",
-         limits.datarooms,
-         team._count.datarooms,
-     );
-     return res.status(400).json({
-         message:
-             "You've reached the limit of datarooms. Consider upgrading your plan.",
-     });
- }
🧹 Nitpick comments (1)
pages/api/teams/[teamId]/datarooms/duplicate-template.ts (1)

260-264: Generic error handling could be more informative.

The catch block returns a generic error message regardless of the specific failure. Consider differentiating between different types of errors for better debugging and user experience.

} catch (error) {
    console.error("Request error", error);
-   res.status(500).json({ message: "Error creating dataroom from template" });
+   if (error.message.includes("Template dataroom") || error.message.includes("not found")) {
+       res.status(404).json({ message: "Template not found" });
+   } else if (error.message.includes("Failed to create") || error.message.includes("Failed to duplicate")) {
+       res.status(500).json({ message: "Error duplicating template contents" });
+   } else {
+       res.status(500).json({ message: "Error creating dataroom from template" });
+   }
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between fefdf2f and f170bda.

📒 Files selected for processing (5)
  • pages/api/teams/[teamId]/datarooms/duplicate-template.ts (1 hunks)
  • pages/api/teams/[teamId]/datarooms/templates.ts (1 hunks)
  • pages/datarooms/index.tsx (5 hunks)
  • prisma/migrations/20250706215107_add_is_template_to_dataroom/migration.sql (1 hunks)
  • prisma/schema/dataroom.prisma (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • prisma/migrations/20250706215107_add_is_template_to_dataroom/migration.sql
🚧 Files skipped from review as they are similar to previous changes (2)
  • pages/api/teams/[teamId]/datarooms/templates.ts
  • pages/datarooms/index.tsx
🔇 Additional comments (5)
prisma/schema/dataroom.prisma (1)

30-30: LGTM! Schema change supports template functionality effectively.

The isTemplate field addition is well-designed with a sensible default value that ensures existing datarooms remain unaffected while enabling the new template functionality.

pages/api/teams/[teamId]/datarooms/duplicate-template.ts (4)

18-27: Well-structured type definitions for template duplication.

The interface definitions properly extend the Prisma types to include nested relationships needed for template duplication. The recursive structure for DataroomFolderWithContents correctly models the folder hierarchy.


29-94: Efficient recursive template fetching with proper error handling.

The fetchTemplateDataroomContents function correctly:

  • Validates the template exists with isTemplate: true
  • Recursively fetches nested folder contents
  • Filters root-level documents appropriately
  • Handles errors with meaningful messages

The implementation efficiently loads the complete template structure in a single operation.


114-137: Improved error handling addresses previous review concerns.

The error handling for document creation has been enhanced compared to the previous review comments. The code now:

  • Logs specific error details for failed document creations
  • Throws an error if any document creation fails, ensuring transaction rollback
  • Provides clear error messages for debugging

This addresses the previous concern about silently ignoring failures.


231-258: Excellent use of database transaction for atomicity.

The implementation correctly uses prisma.$transaction() to ensure all operations (dataroom creation, document duplication, and folder duplication) are performed atomically. This addresses the previous review concern about data consistency.

The transaction structure is well-organized and will properly roll back all changes if any step fails.

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.

1 participant