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

Added an option to upload cover image while facility registration (#7297) #9572

Conversation

Utkarsh-Anandani
Copy link
Contributor

@Utkarsh-Anandani Utkarsh-Anandani commented Dec 26, 2024

…297)

Proposed Changes

@ohcnetwork/care-fe-code-reviewers

Summary by CodeRabbit

  • New Features

    • Introduced a new route for uploading cover images for facilities.
    • Added components for managing and displaying facility cover images, including upload and edit functionalities.
    • Enhanced user guidance for cover image selection with specified requirements.
  • Bug Fixes

    • Updated navigation flow to redirect users to the cover image upload page after facility creation or update.

@Utkarsh-Anandani Utkarsh-Anandani requested a review from a team as a code owner December 26, 2024 07:20
Copy link
Contributor

coderabbitai bot commented Dec 26, 2024

Walkthrough

This pull request introduces a new feature for uploading facility cover images. A new route "/facility/:facilityId/upload-cover-image" has been added to the FacilityRoutes, along with three new components: CoverImage, FacilityCover, and modifications to the FacilityCreate component. The changes enable users to upload a cover image for a facility, with permission checks and user-friendly interfaces for image selection and management.

Changes

File Change Summary
src/Routers/routes/FacilityRoutes.tsx Added new route for facility cover image upload
src/components/Facility/CoverImage.tsx New component for managing facility cover image upload/delete
src/components/Facility/FacilityCover.tsx New component for facility cover image page with permission checks
src/components/Facility/FacilityCreate.tsx Modified navigation to redirect to cover image page after facility creation

Assessment against linked issues

Objective Addressed Explanation
Upload facility cover image during registration
Non-mandatory cover image upload
Retain existing cover image upload option The existing option in the facility dashboard remains unchanged, but the new feature does not integrate into the registration form.

Possibly related PRs

Suggested labels

tested, needs review

Suggested reviewers

  • rithviknishad
  • Jacobjeevan
  • gigincg
  • shivankacker

Poem

🐰 A rabbit's tale of pixels bright,
Cover images now take their flight!
From forms to routes, a journey bold,
Where facility stories can unfold 📸
Upload with joy, no limits in sight! 🌟


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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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

netlify bot commented Dec 26, 2024

Deploy Preview for care-ohc ready!

Name Link
🔨 Latest commit 062aede
🔍 Latest deploy log https://app.netlify.com/sites/care-ohc/deploys/676ec39609e7bc00085cc921
😎 Deploy Preview https://deploy-preview-9572--care-ohc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

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 (5)
src/Routers/routes/FacilityRoutes.tsx (1)

18-20: Route addition aligns with feature objectives.

This route addition properly passes the facilityId param to the FacilityCover component, facilitating cover image management. Ensure that any external references to this route are documented in the UI flow, so users can navigate intuitively.

If you anticipate expansions (like adding sub-routes for images), consider grouping them together under a parent route for better scalability — for instance, "/facility/:facilityId/cover/*".

src/components/Facility/FacilityCover.tsx (2)

19-32: Permission check is correctly enforced but can be centralized.

Your useEffect properly redirects unauthorized user types away from this page, showing an error message. This pattern is repeated in multiple components (e.g., FacilityCreate), so consider centralizing permission checks or employing a higher-order component (HOC) to reduce duplication.


56-69: Optional improvement: Provide user feedback on “Update Cover Image” click.

Currently, the "Update Cover Image" button navigates back to the facility page. Adding a short success or progress indicator for the cover image upload might improve the user experience.

src/components/Facility/CoverImage.tsx (1)

39-67: File upload logic is robust but could benefit from unified error handling.

  1. async (xhr: XMLHttpRequest) => { ... } uses inline checks to handle status codes. Consider extracting them into a small helper function for reusability.
  2. The sleep(1000); approach ensures that the facility data is fully updated on the server. Confirm that the UI state doesn’t need a loading indicator if the delay takes longer.
src/components/Facility/FacilityCreate.tsx (1)

417-417: Navigation change to cover image improves workflow.

Line 417 updates navigation after facility creation to /facility/${id}/cover, aligning with the new feature. This is logical and consistent with the PR’s objective.

If you foresee future steps after uploading the cover, consider a success dialog or flow that confirms successful creation before guiding them to cover image management.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 20fe265 and eee2426.

📒 Files selected for processing (4)
  • src/Routers/routes/FacilityRoutes.tsx (2 hunks)
  • src/components/Facility/CoverImage.tsx (1 hunks)
  • src/components/Facility/FacilityCover.tsx (1 hunks)
  • src/components/Facility/FacilityCreate.tsx (1 hunks)
🔇 Additional comments (8)
src/Routers/routes/FacilityRoutes.tsx (1)

4-4: Import statement looks good.

The import for FacilityCover is correctly referencing the file path and aligns with the newly added component usage.

src/components/Facility/FacilityCover.tsx (3)

12-14: Interface usage is clear.

The FacilityProps interface clarifies the optional nature of facilityId. The explicit ?: string nicely highlights that the component can render gracefully even if facilityId is absent.


34-73: Overall rendering and user guidance are clear.

  1. The crumbsReplacements mechanism for naming the steps is a nice approach for dynamic breadcrumb labeling.
  2. The guidelines for image size and format help reduce user error.

16-20: Check for potential null states of facilityId.

While destructuring facilityId from props, you’re using it as facilityId in subsequent code. The optional type suggests this might be undefined. You do handle it gracefully with "????" placeholders in crumbs, but confirm no runtime errors occur if it’s indeed undefined.

Add a short inline comment or guard that clarifies fallback behavior when facilityId is undefined.

- const { facilityId } = props;
+ const { facilityId = "" } = props; // Provide a default
src/components/Facility/CoverImage.tsx (4)

18-20: Prop usage is consistent and clearly typed.

The CoverImageProps interface is straightforward, and explicitly requiring a facilityId avoids confusion around null or undefined states.


27-37: Facility data fetch with fallback navigation is well done.

You use useTanStackQueryInstead to fetch facility data, and navigate to "/not-found" on unsuccessful responses. This ensures a consistent error-handling experience.


69-80: Cover image deletion is straightforward but watch for partial updates.

Deleting an image is as simple as calling request(routes.deleteFacilityCoverImage, ...). This is valid, but consider whether the server can return partial successes or advanced status codes to reflect partial failures.

If partial failures are possible, ensure the UI properly notifies or reverts state.


82-104: Avatar components integrated effectively.

  1. AvatarEditModal and AvatarEditable usage is clean and promotes a consistent user interface.
  2. The className usage ensures responsive design.

@Utkarsh-Anandani
Copy link
Contributor Author

import { CoverImage } from "./CoverImage";

interface FacilityProps {
facilityId?: string;
Copy link
Member

Choose a reason for hiding this comment

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

why nullable? won't we always have facilityId?

Suggested change
facilityId?: string;
facilityId: string;

Comment on lines 8 to 11
import { Cancel, Submit } from "../Common/ButtonV2";
import Page from "../Common/Page";
import { CoverImage } from "./CoverImage";

Copy link
Member

Choose a reason for hiding this comment

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

use absolute imports

title="Cover Image"
className="h-[90vh]"
crumbsReplacements={{
[facilityId || "????"]: { name: "Upload" },
Copy link
Member

Choose a reason for hiding this comment

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

show the facility name instead of "Upload"

Suggested change
[facilityId || "????"]: { name: "Upload" },
[facilityId]: { name: "Upload" },

@@ -14,6 +15,9 @@ import FacilityLocationRoutes from "@/Routers/routes/FacilityLocationRoutes";
const FacilityRoutes: AppRoutes = {
"/facility": () => <FacilityList />,
"/facility/create": () => <FacilityCreate />,
"/facility/:facilityId/cover": ({ facilityId }) => (
Copy link
Member

@rithviknishad rithviknishad Dec 27, 2024

Choose a reason for hiding this comment

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

/cover is not very meaningful.

Suggested change
"/facility/:facilityId/cover": ({ facilityId }) => (
"/facility/:facilityId/upload-cover-image": ({ facilityId }) => (

@Utkarsh-Anandani
Copy link
Contributor Author

@rithviknishad, I've made the requested changes. Please review them and let me know if further updates are needed.

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

🧹 Nitpick comments (3)
src/components/Facility/FacilityCover.tsx (1)

35-48: Consider combining permission check with data fetching

The current implementation has separate flows for permission check and data fetching, which could lead to a race condition. Consider combining these checks in the query's onResponse handler.

 const { data: facilityData } = useTanStackQueryInstead(
   routes.getPermittedFacility,
   {
     pathParams: {
       id: facilityId,
     },
     onResponse: ({ res }) => {
       if (!res?.ok) {
         navigate("/not-found");
+      } else if (
+        authUser &&
+        authUser.user_type !== "StateAdmin" &&
+        authUser.user_type !== "DistrictAdmin" &&
+        authUser.user_type !== "DistrictLabAdmin"
+      ) {
+        navigate("/facility");
+        Notification.Error({
+          msg: "You don't have permission to perform this action. Contact the admin",
+        });
       }
     },
   },
 );
-
-const authUser = useAuthUser();
-useEffect(() => {
-  if (
-    authUser &&
-    authUser.user_type !== "StateAdmin" &&
-    authUser.user_type !== "DistrictAdmin" &&
-    authUser.user_type !== "DistrictLabAdmin"
-  ) {
-    navigate("/facility");
-    Notification.Error({
-      msg: "You don't have permission to perform this action. Contact the admin",
-    });
-  }
-}, [authUser]);
src/components/Facility/CoverImage.tsx (2)

69-80: Enhance delete operation feedback

The delete operation could benefit from better error handling and loading state management.

+const [isDeleting, setIsDeleting] = useState(false);

 const handleCoverImageDelete = async (onError: () => void) => {
+  setIsDeleting(true);
   const { res } = await request(routes.deleteFacilityCoverImage, {
     pathParams: { id: facilityId },
   });
   if (res?.ok) {
     Notification.Success({ msg: "Cover image deleted" });
     facilityFetch();
     setOpenUploadModal(false);
   } else {
+    Notification.Error({ msg: res?.data?.detail || "Failed to delete cover image" });
     onError();
   }
+  setIsDeleting(false);
 };

93-100: Enhance user feedback during operations

The UI could benefit from showing loading states during operations and internationalizing more strings.

 <AvatarEditable
   id="facility-coverimage"
   imageUrl={facilityData?.read_cover_image_url}
-  name={facilityData?.name ? facilityData.name : ""}
+  name={facilityData?.name || t("facility_name_placeholder")}
   editable={true}
+  loading={isDeleting}
   onClick={() => setOpenUploadModal(true)}
   className="md:mr-2 lg:mr-6 md:w-80 md:h-80 lg:h-100 lg:w-100"
 />
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between eee2426 and 96e3b6d.

📒 Files selected for processing (4)
  • src/Routers/routes/FacilityRoutes.tsx (2 hunks)
  • src/components/Facility/CoverImage.tsx (1 hunks)
  • src/components/Facility/FacilityCover.tsx (1 hunks)
  • src/components/Facility/FacilityCreate.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/Facility/FacilityCreate.tsx
  • src/Routers/routes/FacilityRoutes.tsx
🔇 Additional comments (2)
src/components/Facility/FacilityCover.tsx (2)

1-12: Consider using absolute imports consistently

While some imports use absolute paths (e.g., @/components/Common/ButtonV2), others use relative paths (e.g., raviger). Consider using absolute imports consistently throughout the file.


67-71: Consider internationalizing guidelines and validating size limit

The guidelines contain hardcoded strings that should be internationalized. Additionally, verify that the mentioned size limit (1mb) matches the backend validation.

Comment on lines +78 to +84
<Submit
type="button"
onClick={() => {
navigate(`/facility/${facilityId}`);
}}
label={"Update Cover Image"}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix Submit button behavior

The Submit button currently behaves the same as Cancel, just navigating away. Since it's labeled "Update Cover Image", it should trigger an image update action before navigation.

Consider removing the Submit button since the actual upload is handled by the CoverImage component, or modify it to trigger the upload modal:

 <Submit
   type="button"
   onClick={() => {
-    navigate(`/facility/${facilityId}`);
+    setOpenUploadModal(true);
   }}
   label={"Update Cover Image"}
 />

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

Comment on lines 39 to 67
const handleCoverImageUpload = async (file: File, onError: () => void) => {
const formData = new FormData();
formData.append("cover_image", file);
const url = `${careConfig.apiUrl}/api/v1/facility/${facilityId}/cover_image/`;

uploadFile(
url,
formData,
"POST",
{
Authorization:
"Bearer " + localStorage.getItem(LocalStorageKeys.accessToken),
},
async (xhr: XMLHttpRequest) => {
if (xhr.status === 200) {
await sleep(1000);
facilityFetch();
Notification.Success({ msg: "Cover image updated." });
setOpenUploadModal(false);
} else {
onError();
}
},
null,
() => {
onError();
},
);
};
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

Improve upload implementation robustness

Several concerns in the upload implementation:

  1. The API URL construction should use route configuration instead of string concatenation
  2. The artificial sleep delay seems unnecessary
  3. The error handling could be more specific about what went wrong

Consider these improvements:

-const url = `${careConfig.apiUrl}/api/v1/facility/${facilityId}/cover_image/`;
+const url = routes.uploadFacilityCoverImage.path.replace(':id', facilityId);

 uploadFile(
   url,
   formData,
   "POST",
   {
     Authorization:
       "Bearer " + localStorage.getItem(LocalStorageKeys.accessToken),
   },
   async (xhr: XMLHttpRequest) => {
     if (xhr.status === 200) {
-      await sleep(1000);
       facilityFetch();
       Notification.Success({ msg: "Cover image updated." });
       setOpenUploadModal(false);
     } else {
-      onError();
+      const errorMessage = xhr.responseText ? JSON.parse(xhr.responseText).detail : "Failed to upload image";
+      Notification.Error({ msg: errorMessage });
+      onError();
     }
   },
   null,
   () => {
-    onError();
+    Notification.Error({ msg: "Network error while uploading image" });
+    onError();
   },
 );
📝 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 handleCoverImageUpload = async (file: File, onError: () => void) => {
const formData = new FormData();
formData.append("cover_image", file);
const url = `${careConfig.apiUrl}/api/v1/facility/${facilityId}/cover_image/`;
uploadFile(
url,
formData,
"POST",
{
Authorization:
"Bearer " + localStorage.getItem(LocalStorageKeys.accessToken),
},
async (xhr: XMLHttpRequest) => {
if (xhr.status === 200) {
await sleep(1000);
facilityFetch();
Notification.Success({ msg: "Cover image updated." });
setOpenUploadModal(false);
} else {
onError();
}
},
null,
() => {
onError();
},
);
};
const handleCoverImageUpload = async (file: File, onError: () => void) => {
const formData = new FormData();
formData.append("cover_image", file);
const url = routes.uploadFacilityCoverImage.path.replace(':id', facilityId);
uploadFile(
url,
formData,
"POST",
{
Authorization:
"Bearer " + localStorage.getItem(LocalStorageKeys.accessToken),
},
async (xhr: XMLHttpRequest) => {
if (xhr.status === 200) {
facilityFetch();
Notification.Success({ msg: "Cover image updated." });
setOpenUploadModal(false);
} else {
const errorMessage = xhr.responseText ? JSON.parse(xhr.responseText).detail : "Failed to upload image";
Notification.Error({ msg: errorMessage });
onError();
}
},
null,
() => {
Notification.Error({ msg: "Network error while uploading image" });
onError();
},
);
};

Comment on lines 21 to 33
const { data: facilityData } = useTanStackQueryInstead(
routes.getPermittedFacility,
{
pathParams: {
id: facilityId,
},
onResponse: ({ res }) => {
if (!res?.ok) {
navigate("/not-found");
}
},
},
);
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!!!
@rithviknishad

Copy link
Member

Choose a reason for hiding this comment

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

review the code yourself :) there are more usages of it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rithviknishad
Yeah, I saw that but the code requires reFetch, is there a way to destructure refetch out of useQuery?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

useQuery({ queryKey: [route.path], queryFn: query(route), enabled: shouldFetch })
Is this the right way? like the "enabled" thingy

Copy link
Member

Choose a reason for hiding this comment

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

you can destructure refetch :) from usequery.

const { refetch } = useQuery(...);

however, the cleaner way to trigger the refetch is by invalidating the query key instead of calling refetch.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sorry, I couldn't quiet get you

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

@Utkarsh-Anandani Utkarsh-Anandani Dec 27, 2024

Choose a reason for hiding this comment

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

@rithviknishad, can you check now

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)
src/components/Facility/FacilityCover.tsx (1)

72-78: ⚠️ Potential issue

Fix Submit button behavior.

The Submit button currently just navigates away, which is the same as Cancel. It should either be removed or modified to trigger the upload action.

-<Submit
-  type="button"
-  onClick={() => {
-    navigate(`/facility/${facilityId}`);
-  }}
-  label={"Update Cover Image"}
-/>
🧹 Nitpick comments (3)
src/components/Facility/FacilityCover.tsx (3)

22-27: Add error handling for the query.

While the query implementation is correct, consider handling potential errors:

-  const { data } = useQuery({
+  const { data, error } = useQuery({
     queryKey: ["facility", facilityId],
     queryFn: query(routes.getPermittedFacility, {
       pathParams: { id: facilityId },
     }),
   });
+
+  useEffect(() => {
+    if (error) {
+      Notification.Error({
+        msg: "Failed to fetch facility details",
+      });
+    }
+  }, [error]);

29-42: Refactor permission check for better maintainability.

Consider extracting the allowed user types to a constant and using an array includes check:

+const ALLOWED_USER_TYPES = [
+  "StateAdmin",
+  "DistrictAdmin",
+  "DistrictLabAdmin"
+] as const;
+
 export const FacilityCover = (props: FacilityProps) => {
   // ...
   useEffect(() => {
     if (
       authUser &&
-      authUser.user_type !== "StateAdmin" &&
-      authUser.user_type !== "DistrictAdmin" &&
-      authUser.user_type !== "DistrictLabAdmin"
+      !ALLOWED_USER_TYPES.includes(authUser.user_type)
     ) {

61-65: Improve accessibility of the guidelines list.

Add proper ARIA labels and more descriptive text for screen readers:

-<ul className="list-disc pl-6 text-sm text-color-body-dark">
+<ul 
+  className="list-disc pl-6 text-sm text-color-body-dark"
+  aria-label="Cover image guidelines"
+>
-  <li>Max size for image uploaded should be 1mb</li>
-  <li>Allowed formats are jpg,png,jpeg</li>
-  <li>Recommended aspect ratio for the image is 1:1</li>
+  <li>Maximum file size: 1 megabyte (MB)</li>
+  <li>Accepted file formats: JPG, PNG, JPEG</li>
+  <li>Recommended image dimensions: Square (1:1 aspect ratio)</li>
</ul>
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 96e3b6d and d986e55.

📒 Files selected for processing (1)
  • src/components/Facility/FacilityCover.tsx (1 hunks)
🔇 Additional comments (2)
src/components/Facility/FacilityCover.tsx (2)

1-14: LGTM! Imports are well-organized.

The imports follow best practices with absolute paths and logical grouping.


15-17: LGTM! Interface follows the suggested non-nullable pattern.

The FacilityProps interface correctly defines facilityId as a required string parameter.

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/Facility/CoverImage.tsx (2)

16-16: 🛠️ Refactor suggestion

Remove unnecessary sleep import

The sleep utility import is used for an artificial delay in the upload handler, which is unnecessary and should be removed.


46-74: ⚠️ Potential issue

Add file validation and improve error handling

Several security and implementation concerns:

  1. Missing file type and size validation
  2. Basic error handling without specific error messages
  3. URL construction using string concatenation
  4. Unnecessary sleep delay

Apply these improvements:

 const handleCoverImageUpload = async (file: File, onError: () => void) => {
+  // Validate file type and size
+  const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
+  const maxSize = 5 * 1024 * 1024; // 5MB
+
+  if (!allowedTypes.includes(file.type)) {
+    Notification.Error({ msg: "Invalid file type. Please upload a JPEG, PNG, or GIF image." });
+    return;
+  }
+
+  if (file.size > maxSize) {
+    Notification.Error({ msg: "File size too large. Maximum size is 5MB." });
+    return;
+  }
+
   const formData = new FormData();
   formData.append("cover_image", file);
-  const url = `${careConfig.apiUrl}/api/v1/facility/${facilityId}/cover_image/`;
+  const url = routes.uploadFacilityCoverImage.path.replace(':id', facilityId);

   uploadFile(
     url,
     formData,
     "POST",
     {
       Authorization:
         "Bearer " + localStorage.getItem(LocalStorageKeys.accessToken),
     },
     async (xhr: XMLHttpRequest) => {
       if (xhr.status === 200) {
-        await sleep(1000);
         refetchFacility();
         Notification.Success({ msg: "Cover image updated." });
         setOpenUploadModal(false);
       } else {
-        onError();
+        const errorMessage = xhr.responseText ? JSON.parse(xhr.responseText).detail : "Failed to upload image";
+        Notification.Error({ msg: errorMessage });
+        onError();
       }
     },
     null,
     () => {
-      onError();
+      Notification.Error({ msg: "Network error while uploading image" });
+      onError();
     },
   );
 };
🧹 Nitpick comments (3)
src/components/Facility/CoverImage.tsx (3)

18-20: Add JSDoc documentation for the interface

Consider adding documentation to improve code maintainability:

+/**
+ * Props for the CoverImage component
+ * @property {string} facilityId - Unique identifier for the facility
+ */
interface CoverImageProps {
  facilityId: string;
}

76-87: Improve error handling in delete operation

The error handling could be more specific:

 const handleCoverImageDelete = async (onError: () => void) => {
   const { res } = await request(routes.deleteFacilityCoverImage, {
     pathParams: { id: facilityId },
   });
   if (res?.ok) {
     Notification.Success({ msg: "Cover image deleted" });
     refetchFacility();
     setOpenUploadModal(false);
   } else {
-    onError();
+    const errorMessage = await res?.text();
+    Notification.Error({ 
+      msg: errorMessage ? JSON.parse(errorMessage).detail : "Failed to delete cover image" 
+    });
+    onError();
   }
 };

89-111: Add accessibility improvements

The render implementation looks good but could benefit from accessibility enhancements:

 return (
-  <div className="my-auto mx-auto flex">
+  <div 
+    className="my-auto mx-auto flex"
+    role="region"
+    aria-label="Facility cover image"
+  >
     <AvatarEditModal
       title={t("edit_cover_photo")}
       open={openUploadModal}
       imageUrl={data?.read_cover_image_url}
       handleUpload={handleCoverImageUpload}
       handleDelete={handleCoverImageDelete}
       onClose={() => setOpenUploadModal(false)}
     />
     <div>
       <AvatarEditable
         id="facility-coverimage"
         imageUrl={data?.read_cover_image_url}
         name={data?.name ? data.name : ""}
         editable={true}
         onClick={() => setOpenUploadModal(true)}
+        aria-label={t("edit_cover_photo")}
         className="md:mr-2 lg:mr-6 md:w-80 md:h-80 lg:h-100 lg:w-100"
       />
     </div>
   </div>
 );
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d986e55 and 062aede.

📒 Files selected for processing (1)
  • src/components/Facility/CoverImage.tsx (1 hunks)
🔇 Additional comments (1)
src/components/Facility/CoverImage.tsx (1)

35-44: LGTM! Well-implemented refetch function

The refetch implementation properly invalidates the query cache and handles errors appropriately.

Comment on lines +28 to +33
const { data } = useQuery({
queryKey: ["facility", facilityId],
queryFn: query(routes.getPermittedFacility, {
pathParams: { id: facilityId },
}),
});
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

Add error and loading state handling

The query setup should handle error and loading states to improve user experience:

- const { data } = useQuery({
+ const { data, isError, isLoading } = useQuery({
   queryKey: ["facility", facilityId],
   queryFn: query(routes.getPermittedFacility, {
     pathParams: { id: facilityId },
   }),
 });

+ if (isLoading) {
+   return <div>Loading...</div>;
+ }

+ if (isError) {
+   return <div>Error loading facility data</div>;
+ }

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

@github-actions github-actions bot added the merge conflict pull requests with merge conflict label Dec 31, 2024
Copy link

👋 Hi, @Utkarsh-Anandani,
Conflicts have been detected against the base branch. Please rebase your branch against the base branch.


This message is automatically generated by prince-chrismc/label-merge-conflicts-action so don't hesitate to report issues/improvements there.

@rithviknishad
Copy link
Member

no longer relevant in new architecture

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge conflict pull requests with merge conflict needs review needs testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Facility registration form- cover photo upload
2 participants