Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

pageCard統一 #449

Merged
merged 7 commits into from
Dec 20, 2024
Merged

pageCard統一 #449

merged 7 commits into from
Dec 20, 2024

Conversation

ttizze
Copy link
Owner

@ttizze ttizze commented Dec 19, 2024

Summary by CodeRabbit

  • New Features

    • Introduced the PageCard component for displaying page information, including title, creation date, and user details.
    • Enhanced page data structure to include user information with each page.
    • Updated the Home and UserPage components to utilize the new PageCard for rendering pages.
  • Bug Fixes

    • Improved test assertions for user authentication status in the UserProfile tests.
  • Documentation

    • Added new type definitions for better type safety and clarity in the data model.
  • Chores

    • Streamlined imports and component structure across several files for improved maintainability.

…eld and enhance auto-save functionality to handle undefined title and page content values.
… field and improving auto-save functionality to set empty strings for undefined title and page content values.
…sWithInfo and update related components. Add textAndOccurrenceHash field to SeedText model for improved data handling.
…move unnecessary props and simplify structure by integrating PageCard directly, enhancing code readability and maintainability.
Copy link

coderabbitai bot commented Dec 19, 2024

Walkthrough

This pull request introduces a new PageCard component and makes corresponding updates across multiple files to improve page rendering and data retrieval. The changes focus on enhancing the display of pages with more comprehensive user and page information, streamlining component structures, and adding type safety. The modifications span several files in the web application, including route components, type definitions, and server-side query functions.

Changes

File Change Summary
web/app/components/PageCard.tsx New React component for displaying page information with user details, actions, and like button
web/app/routes/$userName+/functions/queries.server.ts Added user information to page objects returned by fetchSanitizedUserWithPages
web/app/routes/$userName+/index.test.tsx Updated test cases for UserProfile component with more robust assertions
web/app/routes/$userName+/index.tsx Replaced previous page rendering with new PageCard component
web/app/routes/home/_home.tsx Updated home page to use PageCard and modified data retrieval
web/app/routes/home/functions/queries.server.ts Enhanced fetchPaginatedPublicPages to return more page details
web/app/routes/types.ts Added new type aliases for page card data
web/prisma/seed.ts Added textAndOccurrenceHash to seed text interface

Possibly related PRs

Poem

🐰 A Card of Pages, Sleek and Bright
With User Details Dancing Light
Components Refactored with Care
Rendering Magic Beyond Compare
CodeRabbit's Whiskers Twitch with Glee! 🎉


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

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

@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: 4

🧹 Nitpick comments (6)
web/app/routes/$userName+/functions/queries.server.ts (1)

67-71: Consider optimizing repeated user data.

While adding user information to each page object improves data accessibility, it introduces data duplication when multiple pages belong to the same user. Consider these optimizations:

  1. Use a normalized data structure to avoid duplication
  2. Implement caching for user data
  3. Consider moving user data to a separate response field if it's constant across pages

Example of a normalized structure:

interface NormalizedResponse {
  user: {
    userName: string;
    displayName: string;
    icon: string;
  };
  pages: Array<{
    ...pageFields;
    userId: string; // Reference to user
  }>;
}
web/app/components/PageCard.tsx (2)

16-23: Props interface looks good, but consider adding JSDoc comments

The props interface is well-structured with clear types. Consider adding JSDoc comments to document the purpose of each prop, especially for callback functions.

Example documentation:

type PageCardProps = {
  /** The page data to display */
  pageCard: PageCardType;
  /** URL for the page link */
  pageLink: string;
  /** URL for the user profile link */
  userLink: string;
  /** Whether to show owner-specific actions */
  showOwnerActions?: boolean;
  /** Callback to toggle the page's public status */
  onTogglePublicStatus?: (pageId: number) => void;
  /** Callback to archive the page */
  onArchive?: (pageId: number) => void;
};

35-44: Consider extracting action buttons to a separate component

The conditional rendering of actions could be extracted to improve readability and maintainability.

-{showOwnerActions && onTogglePublicStatus && onArchive && (
-  <div className="absolute top-2 right-2">
-    <PageActionsDropdown
-      editPath={`${pageLink}/edit`}
-      onTogglePublic={() => onTogglePublicStatus(pageCard.id)}
-      onDelete={() => onArchive(pageCard.id)}
-      isPublished={pageCard.isPublished}
-    />
-  </div>
-)}
+{showOwnerActions && onTogglePublicStatus && onArchive && (
+  <PageCardActions
+    pageId={pageCard.id}
+    pageLink={pageLink}
+    isPublished={pageCard.isPublished}
+    onTogglePublicStatus={onTogglePublicStatus}
+    onArchive={onArchive}
+  />
+)}
web/app/routes/$userName+/index.test.tsx (1)

Line range hint 144-149: Complete or remove the commented test code

The commented test code suggests an incomplete implementation of the toggle publish functionality test. Either complete the test implementation or remove the commented code to maintain test clarity.

Would you like me to help implement the complete test case for toggle publish functionality?

web/app/routes/$userName+/index.tsx (2)

181-189: Add prop validation for PageCard component

The PageCard component receives multiple critical props. Consider adding runtime prop validation using PropTypes or TypeScript interfaces to ensure type safety.

Here's a suggested TypeScript interface for the props:

interface PageCardProps {
  pageCard: {
    id: number;
    slug: string;
    // Add other required page fields
  };
  pageLink: string;
  userLink: string;
  showOwnerActions: boolean;
  onTogglePublicStatus: (pageId: number) => void;
  onArchive: (pageId: number) => void;
}

Line range hint 193-252: Consider extracting pagination logic into a separate component

The pagination implementation, while functional, could be extracted into a reusable component to improve maintainability and reusability.

Consider creating a separate PaginationComponent that accepts:

  • currentPage
  • totalPages
  • onPageChange
    This would make the pagination logic reusable across different parts of the application.
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between fc05765 and 46fac66.

⛔ Files ignored due to path filters (1)
  • web/bun.lockb is excluded by !**/bun.lockb
📒 Files selected for processing (8)
  • web/app/components/PageCard.tsx (1 hunks)
  • web/app/routes/$userName+/functions/queries.server.ts (1 hunks)
  • web/app/routes/$userName+/index.test.tsx (2 hunks)
  • web/app/routes/$userName+/index.tsx (2 hunks)
  • web/app/routes/home/_home.tsx (3 hunks)
  • web/app/routes/home/functions/queries.server.ts (3 hunks)
  • web/app/routes/types.ts (1 hunks)
  • web/prisma/seed.ts (6 hunks)
🔇 Additional comments (9)
web/app/routes/types.ts (1)

1-8: LGTM! Type definitions look clean and well-structured.

The type transformations are well-designed, particularly the explicit typing of createdAt as string. This ensures type safety when working with date fields in the UI layer.

Let's verify that all components using PageCardType handle the createdAt field correctly:

✅ Verification successful

Type transformation and usage verified successfully

The PageCard component correctly handles the createdAt field as a string in its display, and the type transformation from the original Prisma Date type (from queries.server.ts) to string is appropriate for the UI layer. The component simply renders the createdAt value within a CardDescription component without any date manipulation, which aligns with receiving it as a pre-formatted string.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for components using PageCardType and verify date handling
rg -t typescript -t tsx "PageCardType|createdAt.*string" --glob '!*.test.*' --glob '!*types.ts'

Length of output: 132


Script:

#!/bin/bash
# Search for components using PageCardType and verify date handling with correct file extensions
rg -t ts -t tsx "PageCardType|createdAt.*string" --glob '!*.test.*' --glob '!*types.ts'

Length of output: 117


Script:

#!/bin/bash
# Search for components using PageCardType and verify date handling without file type filters
rg "PageCardType|createdAt.*string" --type-not test --glob '!*types.ts'

Length of output: 102


Script:

#!/bin/bash
# Search for components using PageCardType and verify date handling
rg "PageCardType|createdAt.*string" --glob '!*.test.*' --glob '!*types.ts'

# Also search for any usage of the imported type
rg "FetchPaginatedPublicPagesReturn" --glob '!*.test.*'

Length of output: 571


Script:

#!/bin/bash
# Let's check the PageCard component to see how it handles the createdAt field
cat web/app/components/PageCard.tsx

# Also check the query implementation to understand the original type
cat web/app/routes/home/functions/queries.server.ts

Length of output: 3690

web/app/routes/home/functions/queries.server.ts (3)

28-29: Good addition of title and isPublished fields.

Including these fields in the select clause improves data completeness and reduces the need for additional queries.


71-74: Improved naming with pagesWithInfo.

The rename from pages to pagesWithInfo better reflects the enriched data structure.


77-79: Good practice: Exporting return type.

Exporting the return type improves type safety across the application.

web/app/routes/$userName+/functions/queries.server.ts (1)

Line range hint 74-80: Verify error handling for missing user data.

The current implementation assumes user data will always be available. Let's verify error handling for edge cases.

✅ Verification successful

Let me analyze the error handling patterns in the codebase, particularly around user data access. The previous command failed due to typescript file type recognition, so I've adjusted it and also included the specific file content to examine the context better.


The previous commands failed due to incorrect file paths. Let's first locate the file and then analyze its error handling patterns. I've also broadened the search to look for general error handling patterns in the routes directory.


Looking at the code and error handling patterns, I can now generate a final response regarding the error handling for missing user data.

Error handling for missing user data is properly implemented

The fetchSanitizedUserWithPages function in the code has appropriate error handling:

  • It returns null when the user is not found
  • The sanitizeUser function is only called after confirming user exists
  • The calling code handles the null case appropriately by throwing a 404 response

The error handling follows the pattern used throughout the codebase where:

  1. Null checks are performed before data access
  2. Appropriate HTTP responses are thrown for missing resources
  3. Type safety is maintained through the sanitization process
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for error handling patterns in related components
rg -t typescript -t tsx "user\.(userName|displayName|icon)" -C 2 --glob '!*.test.*' | grep -C 2 "if|try|catch|throw|Error"

Length of output: 159


Script:

#!/bin/bash
# Search for error handling patterns in related components with ripgrep
rg --type-add 'ts:*.{ts,tsx}' -t ts "user\.(userName|displayName|icon)" -C 2 --glob '!*.test.*' | grep -C 2 "if|try|catch|throw|Error"

# Also check the specific file for error handling
cat "web/app/routes/$userName+/functions/queries.server.ts"

Length of output: 264


Script:

#!/bin/bash
# Let's first find the correct path to the file
fd "queries.server.ts"

# Then examine the file content and surrounding context
fd "queries.server.ts" --exec cat {}

# Search for error handling patterns without filtering by user properties
rg --type-add 'ts:*.{ts,tsx}' -t ts "throw|Error|try|catch" -C 2 "web/app/routes"

Length of output: 32114

web/app/routes/home/_home.tsx (1)

56-61: LGTM! Clean integration of PageCard component

The PageCard integration looks good with proper prop passing and key usage.

web/prisma/seed.ts (1)

148-148: LGTM! Proper database schema update

The addition of textAndOccurrenceHash to the database schema is implemented correctly.

web/app/routes/$userName+/index.test.tsx (1)

86-86: LGTM: Test assertion updated to handle multiple text occurrences

The change from findByText to findAllByText correctly handles potential multiple occurrences of "Test User" text, which could appear in both the profile header and page cards.

Also applies to: 113-113

web/app/routes/$userName+/index.tsx (1)

9-11: Verify removal of Lock icon

The Lock icon import has been removed. Let's verify this doesn't affect any existing functionality.

✅ Verification successful

Lock icon removal is safe in this file

The Lock icon import was safely removed from $userName+/index.tsx as it's not used in this file. The Lock icon is still properly imported and used in other components where it's needed:

  • PageCard.tsx - shows lock for unpublished pages
  • EditHeader.tsx - uses lock in edit interface
  • SourceTextAndTranslationSection.tsx - displays lock for unpublished content
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining usage of Lock icon in the codebase
rg -l "Lock" --type tsx --type jsx

# Search specifically for lock-related UI elements
ast-grep --pattern 'Lock className="$_"'

Length of output: 207


Script:

#!/bin/bash
# Let's try a more comprehensive search for Lock icon usage
rg "Lock" --type-add 'tsx:*.tsx' --type-add 'jsx:*.jsx'

# Also search for specific imports of Lock
rg "import.*Lock.*from.*lucide" --type-add 'tsx:*.tsx' --type-add 'jsx:*.jsx'

# Let's check the history of this specific file to see how Lock was used before
git log -p -- web/app/routes/$userName+/index.tsx

Length of output: 1344

Comment on lines +56 to +69
<Link to={userLink} className="flex items-center">
<Avatar className="w-6 h-6 mr-2">
<AvatarImage
src={pageCard.user.icon}
alt={pageCard.user.displayName}
/>
<AvatarFallback>
{pageCard.user.displayName.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
<span className="text-sm text-gray-600">
{pageCard.user.displayName}
</span>
</Link>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add aria-label to user link for better accessibility

The user link should have an aria-label describing its purpose.

-<Link to={userLink} className="flex items-center">
+<Link 
+  to={userLink} 
+  className="flex items-center"
+  aria-label={`View ${pageCard.user.displayName}'s profile`}
+>
📝 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
<Link to={userLink} className="flex items-center">
<Avatar className="w-6 h-6 mr-2">
<AvatarImage
src={pageCard.user.icon}
alt={pageCard.user.displayName}
/>
<AvatarFallback>
{pageCard.user.displayName.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
<span className="text-sm text-gray-600">
{pageCard.user.displayName}
</span>
</Link>
<Link
to={userLink}
className="flex items-center"
aria-label={`View ${pageCard.user.displayName}'s profile`}
>
<Avatar className="w-6 h-6 mr-2">
<AvatarImage
src={pageCard.user.icon}
alt={pageCard.user.displayName}
/>
<AvatarFallback>
{pageCard.user.displayName.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
<span className="text-sm text-gray-600">
{pageCard.user.displayName}
</span>
</Link>

Comment on lines +47 to +50
<CardTitle className="flex items-center pr-3 break-all overflow-wrap-anywhere">
{!pageCard.isPublished && <Lock className="h-4 w-4 mr-2" />}
{pageCard.title}
</CardTitle>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add aria-label for better accessibility

The lock icon needs an aria-label for screen readers.

 <CardTitle className="flex items-center pr-3 break-all overflow-wrap-anywhere">
-  {!pageCard.isPublished && <Lock className="h-4 w-4 mr-2" />}
+  {!pageCard.isPublished && (
+    <Lock className="h-4 w-4 mr-2" aria-label="Private page" />
+  )}
   {pageCard.title}
 </CardTitle>
📝 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
<CardTitle className="flex items-center pr-3 break-all overflow-wrap-anywhere">
{!pageCard.isPublished && <Lock className="h-4 w-4 mr-2" />}
{pageCard.title}
</CardTitle>
<CardTitle className="flex items-center pr-3 break-all overflow-wrap-anywhere">
{!pageCard.isPublished && (
<Lock className="h-4 w-4 mr-2" aria-label="Private page" />
)}
{pageCard.title}
</CardTitle>

Comment on lines +28 to +29
const { pagesWithInfo, totalPages, currentPage } =
await fetchPaginatedPublicPages(page, 9, currentUser?.id);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding error handling for fetchPaginatedPublicPages

The loader should handle potential errors from the database query.

-  const { pagesWithInfo, totalPages, currentPage } =
-    await fetchPaginatedPublicPages(page, 9, currentUser?.id);
+  try {
+    const { pagesWithInfo, totalPages, currentPage } =
+      await fetchPaginatedPublicPages(page, 9, currentUser?.id);
+    // ... rest of the code
+  } catch (error) {
+    console.error('Failed to fetch pages:', error);
+    throw new Response('Failed to load pages', { status: 500 });
+  }

Committable suggestion skipped: line range outside the PR's diff.

@@ -6,6 +6,7 @@ const prisma = new PrismaClient();
interface SeedText {
text: string;
number: number;
textAndOccurrenceHash: string;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider using a hash function instead of hardcoded values

The textAndOccurrenceHash values are currently hardcoded. Consider using a hash function to generate these values consistently.

import { createHash } from 'crypto';

function generateTextHash(text: string): string {
  return createHash('sha256')
    .update(text)
    .digest('hex')
    .substring(0, 32); // Use first 32 chars for brevity
}

// Usage in seed data:
textAndOccurrenceHash: generateTextHash(text),

Also applies to: 32-32, 44-45, 57-57, 69-70

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

1 participant