Skip to content

DocumentLibraryView #408

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

Open
wants to merge 53 commits into
base: main
Choose a base branch
from
Open

DocumentLibraryView #408

wants to merge 53 commits into from

Conversation

reneefromhold
Copy link
Contributor

@reneefromhold reneefromhold commented Feb 10, 2025

Overview

This PR has 3 components.
Components

  1. DocumentLibraryPreview
  2. DocumentLibraryView
  3. DocumentDetailView

Full spec here

Security

REMINDER: All file contents are public.

  • [ x] I have ensured no secure credentials or sensitive information remain in code, metadata, comments, etc.
    • [ x] Please verify that you double checked that .storybook/preview.js does not contain your participant access key details.
    • [x ] There are no temporary testing changes committed such as API base URLs, access tokens, print/log statements, etc.
  • [ x] These changes do not introduce any security risks, or any such risks have been properly mitigated.

Describe briefly what security risks you considered, why they don't apply, or how they've been mitigated.

Checklist

Testing

Documentation

  • [ x] I have added relevant Storybook updates to this PR as well.
  • If this feature requires a developer doc update, tag @CareEvolution/api-docs.

Consider "Squash and merge" as needed to keep the commit history reasonable on main.

Reviewers

Assign to the appropriate reviewer(s). Minimally, a second set of eyes is needed ensure no non-public information is published. Consider also including:

  • Subject-matter experts
  • Style/editing reviewers
  • Others requested by the content owner

@reneefromhold reneefromhold force-pushed the renee/DocumentLibaryView branch from 9077f7f to 9cf48bf Compare February 19, 2025 18:55
@reneefromhold reneefromhold marked this pull request as ready for review February 20, 2025 21:40
Copy link
Contributor

coderabbitai bot commented Feb 20, 2025

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Walkthrough

The changes encompass several areas across the codebase. Unit tests have been added for managing survey files, specifically to verify file querying and deletion behaviors using mocked external modules. New helper functions have been introduced for querying all survey files and deleting survey result files, along with corresponding TypeScript interfaces. Enhancements have been made to the DocumentDetailView component, including new props, asynchronous initialization logic, file download handling, and deletion confirmation, as well as a dedicated CSS file for styling. A preview function for DocumentDetailView and another for DocumentLibraryView have been implemented to provide sample data. Storybook configurations for both DocumentDetailView and DocumentLibraryView have been expanded with multiple stories to cover different document types and states. Additionally, localization strings for various file-related actions have been added or updated across several language files to ensure consistent internationalization of document management features.


🪧 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 or @coderabbitai title 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: 8

🧹 Nitpick comments (21)
src/helpers/query-all-survey-files.ts (4)

33-33: Consider removing async from the forEach callback.

This callback does not await any asynchronous operation, so marking it as async can be misleading and might cause confusion if future modifications introduce asynchronous steps that won’t be properly awaited.


38-38: Use optional chaining for cleaner and safer expressions.

Repetitive checks like x && x.answers && x.answers[0] can be replaced with optional chaining to reduce complexity. For instance, change:

- const fileName = fileNameResults && fileNameResults.answers ? fileNameResults.answers[0] : "";
+ const fileName = fileNameResults?.answers?.[0] ?? "";

Apply similar changes for the date, title, fileNameResultID, type, and notes to improve readability.

Also applies to: 44-44, 46-47, 49-49, 51-51

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


91-94: Avoid mixing async/await with .then(...).

Currently, the function is declared as async, yet a promise chain handles the result. For better consistency and clarity, either remove async and return the promise, or use await fully. For example:

-export async function queryAllSurveyFiles(props: SurveyUploadedFileQueryParameters): Promise<SurveyUploadedFile[]> {
-    return await queryAllSurveyAnswers(queryParameters).then((surveyAnswers: SurveyAnswer[]) => {
-        return groupSurveyAnswersByResults(surveyAnswers);
-    });
+export async function queryAllSurveyFiles(props: SurveyUploadedFileQueryParameters): Promise<SurveyUploadedFile[]> {
+    const surveyAnswers = await queryAllSurveyAnswers(queryParameters);
+    return groupSurveyAnswersByResults(surveyAnswers);
}

101-106: Consider re-throwing errors to allow callers to handle them.

Currently, errors are only logged without providing feedback to the caller about failure. Re-throwing or returning an error value ensures upstream code can respond appropriately:

}).catch((error) => {
    console.error('Error deleting survey results', error);
    console.error('The survey must be configured to support result deletion');
+   throw error;
});
src/components/view/DocumentLibraryView/DocumentLibraryView.previewData.ts (1)

23-23: Use deterministic dates if you rely on snapshot testing.

Generating random dates can produce inconsistent test snapshots. If you want consistent outputs, consider using a fixed date or a predictable seed for the random calculation.

src/components/view/DocumentLibraryView/DocumentLibraryView.stories.tsx (1)

33-46: Consider adding error state story.

While the current stories cover Default, Loading, and Live states, consider adding an error state story to demonstrate how the component handles failures.

export const Error: Story = {
    args: { ...defaultProps, preview: 'PreviewError' },
    render: render
};
src/components/view/DocumentDetailView/DocumentDetailView.previewData.ts (1)

24-36: Refactor preview data for better maintainability.

Consider extracting common properties into a base object to reduce duplication and improve maintainability.

const basePreviewData: Partial<DocumentDetail> = {
    surveyResultId: "12345",
    fileCategory: "test category",
    showDownload: false,
    fileKey: "file key"
};

const previewPdfData: DocumentDetail = {
    ...basePreviewData,
    title: "Sample Portrait PDF",
    fileName: "PDF32000_2008.pdf",
    // ... other specific properties
} as DocumentDetail;

Also applies to: 38-50, 52-64, 66-78, 80-92, 94-106, 108-120

src/components/view/DocumentLibraryView/DocumentLibraryView.tsx (2)

104-112: Improve sorting logic readability and type safety.

The sorting logic in buildFileList could be more readable and type-safe.

Consider using a more structured approach:

function buildFileList(files: SurveyUploadedFile[], selectedSegment: "date" | "name" | "type") {
+   const sortingStrategies = {
+       date: (a: SurveyUploadedFile, b: SurveyUploadedFile) => b.date.getTime() - a.date.getTime(),
+       name: (a: SurveyUploadedFile, b: SurveyUploadedFile) => a.title.localeCompare(b.title),
+       type: (a: SurveyUploadedFile, b: SurveyUploadedFile) => a.type.localeCompare(b.type)
+   };
+   const sortingStrategy = sortingStrategies[selectedSegment];
-   const sortedFiles = files.sort((a, b) => {
-       if (selectedSegment === "date") {
-           return a.date > b.date ? -1 : 1;
-       } else if (selectedSegment === "name") {
-           return a.title < b.title ? -1 : 1;
-       } else {
-           return a.type < b.type ? -1 : 1;
-       }
-   });
+   const sortedFiles = [...files].sort(sortingStrategy);

122-124: Consider adding cleanup in useInitializeView.

The useInitializeView hook might need cleanup if the component unmounts during initialization.

Add cleanup:

useInitializeView(() => {
+   let mounted = true;
    initialize();
+   return () => {
+       mounted = false;
+   };
}, [], []);
src/components/view/DocumentDetailView/DocumentDetailView.tsx (1)

22-27: Consider making DocumentDetail properties optional.

The DocumentDetail interface extends SurveyUploadedFile but some properties might not be available when file is not found.

Make properties optional:

export interface DocumentDetail extends SurveyUploadedFile {
-   presignedDocUrl: string,
-   presignedImageUrl: string,
+   presignedDocUrl?: string,
+   presignedImageUrl?: string,
    showDownload: boolean,
    fileKey: string
}
__tests__/helpers/query-all-survey-files.test.ts (2)

83-87: Add test for concurrent file operations.

The test doesn't verify behavior during concurrent delete operations.

Add concurrent operation test:

test("should handle concurrent delete operations correctly", async () => {
    const deletePromises = [
        deleteSurveyResultFiles("test-id-1", "test-file-key-1"),
        deleteSurveyResultFiles("test-id-2", "test-file-key-2")
    ];
    await Promise.all(deletePromises);
    
    expect(MyDataHelps.deleteSurveyResult).toHaveBeenCalledTimes(2);
    expect(MyDataHelps.deleteFile).toHaveBeenCalledTimes(2);
});

89-94: Add retry mechanism test.

The test doesn't verify retry behavior for transient failures.

Add retry test:

test("should retry failed operations", async () => {
    (MyDataHelps.deleteSurveyResult as jest.Mock)
        .mockRejectedValueOnce(new Error("Transient error"))
        .mockResolvedValueOnce(undefined);
    
    await deleteSurveyResultFiles("test-id", "test-file-key");
    expect(MyDataHelps.deleteSurveyResult).toHaveBeenCalledTimes(2);
});
src/helpers/strings-en.ts (1)

526-533: Consider adding more descriptive error messages.

The error message for file loading failure could be more specific.

Enhance error messages:

-   "file-not-loaded": "The file could not be loaded. Please contact support.",
+   "file-not-loaded": "Unable to load the file. This could be due to network issues or the file may have been deleted. Please try again or contact support if the problem persists.",
+   "file-load-network-error": "Network error while loading the file. Please check your connection and try again.",
+   "file-load-permission-error": "You don't have permission to access this file.",
src/helpers/strings-pt.ts (1)

525-533: Well-structured localization implementation!

The localization implementation follows best practices:

  • Consistent string keys across all language files
  • Type-safe implementation using TypeScript
  • Clear and maintainable organization of UI strings

Consider adding JSDoc comments for the string keys to help other developers understand their context and usage.

Also applies to: 526-533, 526-533

src/helpers/strings-fr.ts (1)

526-533: LGTM! Consider adding a period to the error message.

The French translations for document-related functionality are accurate and well-structured. Consider adding a period at the end of the error message for consistency with other error messages in the file.

Apply this diff to add a period to the error message:

-    "file-not-loaded": "Le fichier n'a pas pu être chargé. Veuillez contacter le support.",
+    "file-not-loaded": "Le fichier n'a pas pu être chargé. Veuillez contacter le support."
src/components/view/DocumentDetailView/DocumentDetailView.css (6)

1-8: Consider using CSS variables for better maintainability.

The container styles look good, but consider using CSS variables for values that might need to be adjusted across different themes or breakpoints.

Apply this diff to use CSS variables:

 .mdhui-survey-answer-file-container {
     max-width: 600px;
     margin: auto;
-    padding: 16px;
-    border-radius: 8px;
+    padding: var(--mdhui-spacing-4, 16px);
+    border-radius: var(--mdhui-border-radius-2, 8px);
     background: #f9f9f9;
-    box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
+    box-shadow: var(--mdhui-box-shadow-1, 0px 4px 10px rgba(0, 0, 0, 0.1));
 }

10-19: Consider a more responsive height approach.

Using a fixed viewport height percentage might cause issues on mobile devices. Consider using a min-height or a more responsive approach.

Apply this diff to make the height more responsive:

 .mdhui-survey-answer-file-preview-container {
     width: 100%;
-    height: 55vh;
+    min-height: 300px;
+    height: min(55vh, 600px);
     display: flex;
     align-items: center;
     justify-content: center;
     background: #fff;
-    border-radius: 8px;
+    border-radius: var(--mdhui-border-radius-2, 8px);
     overflow: hidden;
 }

32-37: Consider using CSS variables for spacing.

The file name styles look good, but consider using CSS variables for consistency with other spacing values.

Apply this diff to use CSS variables:

 .mdhui-survey-answer-file-document-file-name {
     display: flex;
     justify-content: center;
-    margin-top: 10px;
+    margin-top: var(--mdhui-spacing-2-5, 10px);
 }

38-41: Consider using CSS variables for padding.

Consider using CSS variables for consistent spacing across the application.

Apply this diff to use CSS variables:

 .mdhui-survey-answer-file-document-details-parent {
-    padding: 10px;
+    padding: var(--mdhui-spacing-2-5, 10px);
 }

42-45: Consider using CSS variables for spacing and font size.

The use of em units for font size is good for accessibility. Consider using CSS variables for consistent spacing and typography.

Apply this diff to use CSS variables:

 .mdhui-survey-answer-file-document-details {
-    font-size: .88em;
-    margin: 5px;
+    font-size: var(--mdhui-font-size-sm, .88em);
+    margin: var(--mdhui-spacing-1-25, 5px);
 }

47-53: Consider using CSS variables for spacing.

The button container styles are well-structured. Consider using CSS variables for consistent spacing.

Apply this diff to use CSS variables:

 .mdhui-survey-answer-file-download-button {
     display: flex;
     flex-direction: column;
     align-items: flex-end;
     justify-content: flex-end;
-    margin-bottom: 10px;
+    margin-bottom: var(--mdhui-spacing-2-5, 10px);
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6a49b32 and 8a74f3f.

📒 Files selected for processing (21)
  • __tests__/helpers/query-all-survey-files.test.ts (1 hunks)
  • src/components/view/DocumentDetailView/DocumentDetailView.css (1 hunks)
  • src/components/view/DocumentDetailView/DocumentDetailView.previewData.ts (1 hunks)
  • src/components/view/DocumentDetailView/DocumentDetailView.stories.tsx (1 hunks)
  • src/components/view/DocumentDetailView/DocumentDetailView.tsx (1 hunks)
  • src/components/view/DocumentDetailView/index.ts (1 hunks)
  • src/components/view/DocumentLibraryView/DocumentLibraryView.previewData.ts (1 hunks)
  • src/components/view/DocumentLibraryView/DocumentLibraryView.stories.tsx (1 hunks)
  • src/components/view/DocumentLibraryView/DocumentLibraryView.tsx (1 hunks)
  • src/components/view/DocumentLibraryView/index.ts (1 hunks)
  • src/components/view/index.ts (1 hunks)
  • src/helpers/index.ts (1 hunks)
  • src/helpers/query-all-survey-files.ts (1 hunks)
  • src/helpers/strings-de.ts (1 hunks)
  • src/helpers/strings-en.ts (1 hunks)
  • src/helpers/strings-es.ts (1 hunks)
  • src/helpers/strings-fr.ts (1 hunks)
  • src/helpers/strings-it.ts (1 hunks)
  • src/helpers/strings-nl.ts (1 hunks)
  • src/helpers/strings-pl.ts (1 hunks)
  • src/helpers/strings-pt.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • src/components/view/DocumentDetailView/index.ts
  • src/components/view/DocumentLibraryView/index.ts
🧰 Additional context used
🪛 Biome (1.9.4)
src/components/view/DocumentDetailView/DocumentDetailView.tsx

[error] 128-128: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 151-151: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

src/helpers/query-all-survey-files.ts

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (15)
src/helpers/index.ts (1)

11-11: Export additions look good.

These exports expand the helper module’s interface without issues.

src/components/view/DocumentLibraryView/DocumentLibraryView.previewData.ts (1)

5-12: Good use of a preview helper function.

Providing multiple sample files with different types and notes is handy for testing and demonstrations.

src/components/view/DocumentLibraryView/DocumentLibraryView.stories.tsx (1)

23-31: Props naming follows a clear pattern.

The props follow a consistent naming convention with clear identifiers for different document attributes. This makes the component's configuration intuitive and maintainable.

src/components/view/index.ts (1)

8-9: Exports are correctly placed and follow consistent pattern.

The new exports maintain alphabetical ordering and follow the same syntax as other exports in the file.

src/components/view/DocumentDetailView/DocumentDetailView.stories.tsx (2)

31-59: Excellent coverage of different file types.

The stories comprehensively cover various file types (PDF, Text, Image, CSV, Video, Unsupported) which is great for testing and documentation.


71-89:

✅ Verification successful

Verify the hardcoded surveyResultIds.

The live examples use hardcoded surveyResultIds. Ensure these IDs are:

  1. Not tied to sensitive or production data
  2. Will remain valid for testing purposes

🏁 Script executed:

#!/bin/bash
# Check if these IDs exist in any configuration or test data files
rg -l "2e3f7062-87e8-ef11-bafe-0affe8024cad|97477698-85e9-ef11-bafe-0affe8024cad|ad6d89b3-a1ef-ef11-bafe-0affe8024cad|a90c0337-cfe4-ef11-bafe-0affe8024cad"

Length of output: 227


Hardcoded surveyResultIds verification complete.
The search confirms that the IDs used in the story file
src/components/view/DocumentDetailView/DocumentDetailView.stories.tsx
(2e3f7062-87e8-ef11-bafe-0affe8024cad, 97477698-85e9-ef11-bafe-0affe8024cad, ad6d89b3-a1ef-ef11-bafe-0affe8024cad, and a90c0337-cfe4-ef11-bafe-0affe8024cad) appear only in test story examples. There’s no indication that they are tied to any sensitive or production data. Please confirm that these IDs will remain valid for testing purposes over time.

src/helpers/strings-nl.ts (1)

525-532: Dutch translations look good!

The added translations are accurate, maintain consistent tone, and follow Dutch language conventions for UI strings.

src/helpers/strings-pl.ts (1)

526-533: Polish translations look good!

The added translations are accurate, maintain consistent tone, and follow Polish language conventions for UI strings.

src/helpers/strings-pt.ts (1)

526-533: Portuguese translations look good!

The added translations are accurate, maintain consistent tone, and follow Portuguese language conventions for UI strings.

src/helpers/strings-es.ts (1)

526-533: Well-structured Spanish translations for document management!

The translations are accurate, use standard Spanish UI terminology, and maintain consistent meaning with English terms. Good security practice in the error handling message directing users to support.

src/helpers/strings-it.ts (1)

526-533: Well-structured Italian translations for document management!

The translations are accurate, use standard Italian UI terminology, and maintain consistent meaning with English terms. Good security practice in the error handling message directing users to support.

src/helpers/strings-de.ts (2)

526-533: Well-structured German translations for document management!

The translations are accurate, use standard German UI terminology, and maintain consistent meaning with English terms. Good security practice in the error handling message directing users to support.


526-533: Excellent localization implementation across all language files!

The implementation demonstrates several good practices:

  • Consistent structure and messaging across all language files
  • Security-conscious error handling directing users to support
  • Use of standard UI terminology in each language
  • Clear and user-friendly delete confirmation dialogs
src/components/view/DocumentDetailView/DocumentDetailView.css (2)

21-27: LGTM!

The preview content styles are well-structured and responsive.


28-30: LGTM!

The image preview styles use the appropriate object-fit property to maintain aspect ratio.

type: "Test Results",
notes: "These are some notes for a sample PDF",
date: new Date(),
presignedDocUrl: "https://freelawlibrary.org/wp-content/uploads/2022/10/The-Constitution-Full-Text-The-National-Constitution-Center.pdf",
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

⚠️ Potential issue

🧩 Analysis chain

Security: Validate and secure external URLs.

The preview data uses external URLs which could pose several risks:

  1. URLs might become unavailable
  2. Content might change without notice
  3. External dependencies for testing

Consider:

  1. Using local assets for testing
  2. Implementing URL validation
  3. Adding fallback content

Also applies to: 46-46, 61-61, 88-88, 102-102, 116-116


🏁 Script executed:

#!/bin/bash
# Test URL availability and content type
for url in \
  "https://freelawlibrary.org/wp-content/uploads/2022/10/The-Constitution-Full-Text-The-National-Constitution-Center.pdf" \
  "https://www.gutenberg.org/cache/epub/42671/pg42671.txt" \
  "https://careevolution.com/wp-content/themes/careevolution-2023/assets/images/logo.svg" \
  "https://people.sc.fsu.edu/~jburkardt/data/csv/airtravel.csv" \
  "https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
do
  echo "Checking $url"
  curl -sI "$url" | head -n 1
done

Length of output: 3536


Security Concern: External URLs in Preview Data

Although our tests show that the current external URLs (e.g., the presigned document URL returning HTTP/2 200) are accessible, relying on external resources for preview data poses inherent risks. These URLs might change or become unavailable without notice, which could lead to unexpected behavior or broken previews.

Recommendations:

  • Local Assets: Where feasible, replace external URLs with local assets to ensure reliable testing and consistent behavior.
  • URL Validation & Fallbacks: Implement a mechanism to validate the URL content dynamically and provide fallback content if the external resource is unreachable or returns an unexpected status (e.g., the BigBuckBunny URL returned a 302 redirect).

These concerns apply not only at line 32 in src/components/view/DocumentDetailView/DocumentDetailView.previewData.ts but also at the similar occurrences on lines 46, 61, 88, 102, and 116.

Comment on lines +58 to +61
const onUploadClick = () => {
setLoading(true);
MyDataHelps.startSurvey(props.uploadDocumentSurveyName);
}
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

Add error handling for startSurvey call.

The onUploadClick function doesn't handle potential errors from MyDataHelps.startSurvey.

Add error handling:

const onUploadClick = () => {
    setLoading(true);
-   MyDataHelps.startSurvey(props.uploadDocumentSurveyName);
+   MyDataHelps.startSurvey(props.uploadDocumentSurveyName).catch(error => {
+       console.error('Failed to start survey:', error);
+       setLoading(false);
+   });
}
📝 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
const onUploadClick = () => {
setLoading(true);
MyDataHelps.startSurvey(props.uploadDocumentSurveyName);
}
const onUploadClick = () => {
setLoading(true);
MyDataHelps.startSurvey(props.uploadDocumentSurveyName).catch(error => {
console.error('Failed to start survey:', error);
setLoading(false);
});
}

Comment on lines 95 to 103
async function downloadFile() {
const deviceInfo = await MyDataHelps.getDeviceInfo();

if (!deviceInfo || deviceInfo.platform == "Web") {
window.open(documentDetail?.presignedDocUrl ?? documentDetail?.presignedImageUrl, "_blank");
} else {
(window as any).webkit.messageHandlers.OpenFile.postMessage({ url: documentDetail?.presignedDocUrl ?? documentDetail?.presignedImageUrl });
}
}
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

Improve cross-platform compatibility in downloadFile.

The downloadFile function assumes iOS-specific message handler.

Add platform-specific handling:

async function downloadFile() {
    const deviceInfo = await MyDataHelps.getDeviceInfo();
+   const fileUrl = documentDetail?.presignedDocUrl ?? documentDetail?.presignedImageUrl;
+   if (!fileUrl) return;

    if (!deviceInfo || deviceInfo.platform == "Web") {
-       window.open(documentDetail?.presignedDocUrl ?? documentDetail?.presignedImageUrl, "_blank");
+       window.open(fileUrl, "_blank");
    } else {
-       (window as any).webkit.messageHandlers.OpenFile.postMessage({ url: documentDetail?.presignedDocUrl ?? documentDetail?.presignedImageUrl });
+       if (deviceInfo.platform === "iOS") {
+           (window as any).webkit.messageHandlers.OpenFile.postMessage({ url: fileUrl });
+       } else if (deviceInfo.platform === "Android") {
+           (window as any).Android.openFile(fileUrl);
+       }
    }
}
📝 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
async function downloadFile() {
const deviceInfo = await MyDataHelps.getDeviceInfo();
if (!deviceInfo || deviceInfo.platform == "Web") {
window.open(documentDetail?.presignedDocUrl ?? documentDetail?.presignedImageUrl, "_blank");
} else {
(window as any).webkit.messageHandlers.OpenFile.postMessage({ url: documentDetail?.presignedDocUrl ?? documentDetail?.presignedImageUrl });
}
}
async function downloadFile() {
const deviceInfo = await MyDataHelps.getDeviceInfo();
const fileUrl = documentDetail?.presignedDocUrl ?? documentDetail?.presignedImageUrl;
if (!fileUrl) return;
if (!deviceInfo || deviceInfo.platform === "Web") {
window.open(fileUrl, "_blank");
} else {
if (deviceInfo.platform === "iOS") {
(window as any).webkit.messageHandlers.OpenFile.postMessage({ url: fileUrl });
} else if (deviceInfo.platform === "Android") {
(window as any).Android.openFile(fileUrl);
}
}
}

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

🧹 Nitpick comments (6)
src/components/view/DocumentDetailView/DocumentDetailView.stories.tsx (2)

22-30: Add JSDoc comments to document the base props.

The uploadDocumentSurveyProps object contains several result identifiers that would benefit from documentation explaining their purpose and expected values. Additionally, consider documenting the 'auto' colorScheme behavior.

Add JSDoc comments like this:

+/**
+ * Base props for document upload survey stories.
+ * @property {string} colorScheme - Controls the component's color theme ('auto'|'light'|'dark').
+ * @property {string} surveyResultId - Unique identifier for the survey result.
+ * @property {string} fileResultIdentifier - Field identifier for the uploaded file.
+ * @property {string} typeResultIdentifier - Field identifier for the document type.
+ * @property {string} nameResultIdentifier - Field identifier for the document name.
+ * @property {string} dateResultIdentifier - Field identifier for the document date.
+ * @property {string} notesResultIdentifier - Field identifier for document notes.
+ */
 const uploadDocumentSurveyProps: DocumentDetailViewProps = {

32-70: Use constants for preview values.

The preview values are currently hardcoded strings. Consider defining an enum or constants to ensure type safety and maintainability.

Create a constants file or enum:

// previewTypes.ts
export enum PreviewType {
  PDF = 'PreviewPdf',
  TEXT = 'PreviewText',
  IMAGE = 'PreviewImage',
  CSV = 'PreviewCsvFile',
  VIDEO = 'PreviewMp4',
  UNKNOWN = 'PreviewUnknown',
  LOADING = 'PreviewLoading',
  FILE_NOT_FOUND = 'PreviewFileNotFound'
}

Then update the stories:

-    args: { ...uploadDocumentSurveyProps, preview: 'PreviewPdf' },
+    args: { ...uploadDocumentSurveyProps, preview: PreviewType.PDF },
src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.previewData.ts (1)

1-7: Consider using an enum or constant for document types.

The document types are hardcoded strings which could lead to maintenance issues. Consider:

  1. Using an enum to ensure type safety
  2. Moving these strings to a centralized constants file for reusability
+export enum DocumentType {
+    InsuranceCard = "Insurance Card",
+    MammogramResults = "Mammogram Results",
+    BloodTestResults = "Blood Test Results"
+}
+
 export function getPreviewData(): string[] {
     return [
-        "Insurance Card",
-        "Mammogram Results",
-        "Blood Test Results",
+        DocumentType.InsuranceCard,
+        DocumentType.MammogramResults,
+        DocumentType.BloodTestResults,
     ];
 }
src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.stories.tsx (2)

26-34: Consider adding JSDoc comments for defaultProps.

The defaultProps object contains important configuration that would benefit from documentation explaining the purpose of each identifier.

+/**
+ * Default configuration for DocumentLibraryPreview stories
+ * @property {string} uploadDocumentSurveyName - Name of the survey for document uploads
+ * @property {string} fileResultIdentifier - Identifier for the file result
+ * @property {string} typeResultIdentifier - Identifier for the document type
+ * @property {string} nameResultIdentifier - Identifier for the document name
+ * @property {string} dateResultIdentifier - Identifier for the document date
+ * @property {string} notesResultIdentifier - Identifier for document notes
+ * @property {string} documentViewBaseUrl - Base URL for document viewing
+ */
 const defaultProps: DocumentLibraryPreviewProps = {

36-54: Consider adding test cases for error scenarios.

The stories cover basic use cases but lack scenarios for error handling, such as:

  • Network errors during file upload
  • Invalid document types
  • Maximum file size exceeded
export const NetworkError: Story = {
    args: { ...defaultProps, preview: 'PreviewError' },
    render: render
};
src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.tsx (1)

10-20: Consider adding validation for required props.

The interface doesn't indicate which props are required vs optional. Consider:

  1. Adding proper type annotations
  2. Using Zod or similar for runtime validation
 export interface DocumentLibraryPreviewProps {
     preview?: "PreviewNoDocuments" | "PreviewDocuments" | "PreviewLoading",
-    uploadDocumentSurveyName: string,
-    fileResultIdentifier: string,
-    typeResultIdentifier: string,
-    nameResultIdentifier: string,
-    dateResultIdentifier: string,
-    notesResultIdentifier: string,
-    documentViewBaseUrl: string,
+    uploadDocumentSurveyName: string & { _brand: 'NonEmptyString' },
+    fileResultIdentifier: string & { _brand: 'NonEmptyString' },
+    typeResultIdentifier: string & { _brand: 'NonEmptyString' },
+    nameResultIdentifier: string & { _brand: 'NonEmptyString' },
+    dateResultIdentifier: string & { _brand: 'NonEmptyString' },
+    notesResultIdentifier: string & { _brand: 'NonEmptyString' },
+    documentViewBaseUrl: string & { _brand: 'ValidURL' },
     innerRef?: React.Ref<HTMLDivElement>;
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8a74f3f and f4133b9.

📒 Files selected for processing (14)
  • src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.css (1 hunks)
  • src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.previewData.ts (1 hunks)
  • src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.stories.tsx (1 hunks)
  • src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.tsx (1 hunks)
  • src/components/view/DocumentDetailView/DocumentDetailView.stories.tsx (1 hunks)
  • src/components/view/DocumentLibraryView/DocumentLibraryView.stories.tsx (1 hunks)
  • src/helpers/strings-de.ts (1 hunks)
  • src/helpers/strings-en.ts (1 hunks)
  • src/helpers/strings-es.ts (1 hunks)
  • src/helpers/strings-fr.ts (1 hunks)
  • src/helpers/strings-it.ts (1 hunks)
  • src/helpers/strings-nl.ts (1 hunks)
  • src/helpers/strings-pl.ts (1 hunks)
  • src/helpers/strings-pt.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.css
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/view/DocumentLibraryView/DocumentLibraryView.stories.tsx
  • src/helpers/strings-it.ts
🧰 Additional context used
🪛 Biome (1.9.4)
src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.tsx

[error] 77-77: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🔇 Additional comments (6)
src/helpers/strings-en.ts (1)

526-539: LGTM! The English translations are clear and consistent.

The new document management strings follow a consistent style and provide clear, user-friendly messages.

src/helpers/strings-nl.ts (1)

525-538: LGTM! The Dutch translations are accurate and consistent.

The translations maintain appropriate formality using "je" and follow Dutch language conventions.

src/helpers/strings-pl.ts (1)

526-539: LGTM! The Polish translations are accurate and consistent.

The translations follow Polish language conventions and maintain appropriate formality.

src/helpers/strings-pt.ts (1)

526-539: LGTM! The Portuguese translations are accurate and consistent.

The translations follow Portuguese language conventions and maintain appropriate formality.

src/helpers/strings-de.ts (1)

526-539: LGTM! German translations are accurate and consistent.

The translations use correct German terminology for document management actions, maintaining consistency between related terms (e.g., "Hochladen" for upload actions).

src/components/view/DocumentDetailView/DocumentDetailView.stories.tsx (1)

1-18: LGTM! Well-structured Storybook configuration.

The imports and metadata are properly configured following Storybook best practices. The fullscreen layout is appropriate for a document viewer component.

Comment on lines 72 to 75
export const Live: Story = {
args: { ...uploadDocumentSurveyProps, surveyResultId: '2e3f7062-87e8-ef11-bafe-0affe8024cad' },
render: render
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace hardcoded UUID in Live story.

The Live story uses a hardcoded UUID which could make the story brittle and difficult to maintain. Consider using a mock service or a more maintainable approach.

Options to consider:

  1. Use a mock service worker (MSW) to intercept API calls
  2. Create a helper function that generates valid test IDs
  3. Document the UUID's source and purpose if it must be hardcoded

Example using MSW:

import { rest } from 'msw'
import { setupServer } from 'msw/node'

const server = setupServer(
  rest.get('/api/survey-result/:id', (req, res, ctx) => {
    return res(
      ctx.json({
        // mock response data
      })
    )
  })
)

export const Live: Story = {
  args: { ...uploadDocumentSurveyProps, surveyResultId: 'test-survey-result' },
  parameters: {
    msw: {
      handlers: [server]
    }
  }
}

Comment on lines 44 to 54
queryAllSurveyFiles({ ...params }).then((uploadedFiles: SurveyUploadedFile[]) => {
const sortedFiles = uploadedFiles.sort((a, b) => {
return a.date > b.date ? -1 : 1;
});

const top3Files = sortedFiles.slice(0, 3).map((file: SurveyUploadedFile, index: number) =>
file.title
);
setSurveyFiles(top3Files);
});
}
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

Add error handling for queryAllSurveyFiles.

The promise chain lacks error handling which could lead to unhandled rejections.

-        queryAllSurveyFiles({ ...params }).then((uploadedFiles: SurveyUploadedFile[]) => {
+        queryAllSurveyFiles({ ...params })
+        .then((uploadedFiles: SurveyUploadedFile[]) => {
             const sortedFiles = uploadedFiles.sort((a, b) => {
                 return a.date > b.date ? -1 : 1;
             });

             const top3Files = sortedFiles.slice(0, 3).map((file: SurveyUploadedFile, index: number) =>
                 file.title
             );
             setSurveyFiles(top3Files);
-        });
+        })
+        .catch((error) => {
+            console.error('Failed to query survey files:', error);
+            setSurveyFiles([]);
+        });
📝 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
queryAllSurveyFiles({ ...params }).then((uploadedFiles: SurveyUploadedFile[]) => {
const sortedFiles = uploadedFiles.sort((a, b) => {
return a.date > b.date ? -1 : 1;
});
const top3Files = sortedFiles.slice(0, 3).map((file: SurveyUploadedFile, index: number) =>
file.title
);
setSurveyFiles(top3Files);
});
}
queryAllSurveyFiles({ ...params })
.then((uploadedFiles: SurveyUploadedFile[]) => {
const sortedFiles = uploadedFiles.sort((a, b) => {
return a.date > b.date ? -1 : 1;
});
const top3Files = sortedFiles.slice(0, 3).map((file: SurveyUploadedFile, index: number) =>
file.title
);
setSurveyFiles(top3Files);
})
.catch((error) => {
console.error('Failed to query survey files:', error);
setSurveyFiles([]);
});

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

🧹 Nitpick comments (1)
package.json (1)

3-3: Correct the version string spelling.

The version string currently reads "2.68.1-DocumentLibaryView.0", but based on the PR objectives and component naming, it appears the intended name should be "DocumentLibraryView" rather than "DocumentLibaryView". Please update the spelling to maintain consistency and avoid confusion.

-  "version": "2.68.1-DocumentLibaryView.0",
+  "version": "2.68.1-DocumentLibraryView.0",
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f4133b9 and 3976e4c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • package.json (1 hunks)
  • src/components/container/DocumentLibraryPreview/index.ts (1 hunks)
  • src/components/container/index.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/components/container/DocumentLibraryPreview/index.ts
🔇 Additional comments (1)
src/components/container/index.ts (1)

17-17: LGTM! Export follows consistent patterns.

The new export for DocumentLibraryPreview is correctly placed in alphabetical order and follows the established export pattern in the file.

@reneefromhold reneefromhold changed the title Start of DocumentLibraryView DocumentLibraryView Feb 21, 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: 1

♻️ Duplicate comments (2)
src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.tsx (2)

45-55: ⚠️ Potential issue

Add error handling for queryAllSurveyFiles.

The promise chain lacks error handling which could lead to unhandled rejections.

-        queryAllSurveyFiles({ ...params }).then((uploadedFiles: SurveyUploadedFile[]) => {
+        queryAllSurveyFiles({ ...params })
+        .then((uploadedFiles: SurveyUploadedFile[]) => {
             const sortedFiles = uploadedFiles.sort((a, b) => {
                 return a.date > b.date ? -1 : 1;
             });

             const top3Files = sortedFiles.slice(0, 3).map((file: SurveyUploadedFile, index: number) =>
                 file.title
             );
             setSurveyFiles(top3Files);
-        });
+        })
+        .catch((error) => {
+            console.error('Failed to query survey files:', error);
+            setSurveyFiles([]);
+        });

75-91: ⚠️ Potential issue

Fix React children prop issue.

The static analysis tool correctly identified an issue with passing children as a prop.

-                <Action title={` ${language("uploaded-documents")}`}
-                    className="font-size"
-                    indicatorPosition="default"
-                    subtitle={surveyFiles.length === 0
-                        ? language("upload-documents-subtitle")
-                        : ""}
-                    children={surveyFiles.length > 0
-                        ? surveyFiles.map((file, index) => <div className="file-title" key={index}>{file}</div>)
-                        : undefined
-                    }
-                    titleIcon={<FontAwesomeSvgIcon icon={faCamera} />}
-                    indicatorValue={surveyFiles.length > 0 ? surveyFiles.length.toString() : undefined}
-                    indicator={surveyFiles.length === 0
-                        ? <Button variant="default" fullWidth={false} onClick={noop}>{language("upload-button")}</Button>
-                        : undefined}
-                />
+                <Action 
+                    title={` ${language("uploaded-documents")}`}
+                    className="font-size"
+                    indicatorPosition="default"
+                    subtitle={surveyFiles.length === 0
+                        ? language("upload-documents-subtitle")
+                        : ""}
+                    titleIcon={<FontAwesomeSvgIcon icon={faCamera} />}
+                    indicatorValue={surveyFiles.length > 0 ? surveyFiles.length.toString() : undefined}
+                    indicator={surveyFiles.length === 0
+                        ? <Button variant="default" fullWidth={false} onClick={onPreviewClick}>{language("upload-button")}</Button>
+                        : undefined}
+                >
+                    {surveyFiles.length > 0
+                        ? surveyFiles.map((file, index) => <div className="file-title" key={index}>{file}</div>)
+                        : undefined}
+                </Action>
🧰 Tools
🪛 Biome (1.9.4)

[error] 82-82: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 471e45e and 75e5462.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • package.json (2 hunks)
  • src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🪛 Biome (1.9.4)
src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.tsx

[error] 82-82: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🔇 Additional comments (3)
src/components/container/DocumentLibraryPreview/DocumentLibraryPreview.tsx (3)

1-21: LGTM! Well-structured imports and interface definition.

The imports are organized logically, and the interface is comprehensive with clear prop types.


23-34: LGTM! Clean state management and preview mode handling.

The state initialization and preview mode handling are well-implemented with clear conditional logic.


57-69: LGTM! Well-implemented event handlers.

The event handlers have clear conditional logic and proper initialization.

@reneefromhold reneefromhold force-pushed the renee/DocumentLibaryView branch from 46148c8 to 94f8fda Compare March 4, 2025 18:23
@reneefromhold reneefromhold force-pushed the renee/DocumentLibaryView branch from 82b248e to 9c761eb Compare March 4, 2025 19:11
@reneefromhold reneefromhold force-pushed the renee/DocumentLibaryView branch from f92d34c to b679caf Compare March 4, 2025 20:02
@reneefromhold reneefromhold force-pushed the renee/DocumentLibaryView branch from b66c090 to 4f97e8b Compare March 5, 2025 19:04
@reneefromhold reneefromhold force-pushed the renee/DocumentLibaryView branch from 26b9591 to 0cd7830 Compare March 5, 2025 20:46
@reneefromhold reneefromhold force-pushed the renee/DocumentLibaryView branch 2 times, most recently from 0278a11 to 4c712fa Compare March 5, 2025 21:35
@reneefromhold reneefromhold force-pushed the renee/DocumentLibaryView branch from 4c712fa to 6161bcd Compare March 6, 2025 15:56
@reneefromhold reneefromhold force-pushed the renee/DocumentLibaryView branch from 8e9f34a to 8131c9f Compare March 6, 2025 16:39
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