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

532 create the frontend for tours #553

Open
wants to merge 24 commits into
base: develop
Choose a base branch
from

Conversation

MandeepPaul
Copy link
Collaborator

Describe your changes

Created frontend for tour

Issue number

#532

Please ensure all items are checked off before requesting a review:

  • I deployed the code locally.
  • I have performed a self-review of my code.
  • I have included the issue # in the PR.
  • I have labelled the PR correctly.
  • The issue I am working on is assigned to me.
  • I didn't use any hardcoded values (otherwise it will not scale, and will make it difficult to maintain consistency across the application).
  • I made sure font sizes, color choices etc are all referenced from the theme.
  • My PR is granular and targeted to one specific feature.
  • I took a screenshot or a video and attached to this PR if there is a UI change.

Preview

image
image
image

- Added formik form to set tour appearance.
- Added form validation.
- Completed preview tab to reflect live changes.
- Bug fixes.
- Draggable step component was added.
- Added steps functionality.
- Added formik form to set tour appearance.
- Added form validation.
- Completed preview tab to reflect live changes.
- Bug fixes.
- Draggable step component was added.
- Added steps functionality.
@MandeepPaul MandeepPaul requested a review from erenfn February 24, 2025 13:38
Copy link
Contributor

coderabbitai bot commented Feb 24, 2025

Walkthrough

This pull request introduces several new features for managing product tours. It adds new DnD Kit dependencies for enhanced drag-and-drop functionality and updates the tour routing to enforce authentication. New components such as DraggableTourStep, TourPage, TourLeftContent, TourLeftAppearance, TourPreview, and TourDefaultPage have been introduced to support tour creation, editing, and previewing. Additionally, the PR streamlines form management using Formik and removes outdated tour components and styles. API service methods and utility functions for tour validation were also added.

Changes

File(s) Change Summary
frontend/package.json Added DnD Kit dependencies: @dnd-kit/core, @dnd-kit/sortable, and @dnd-kit/utilities.
frontend/src/App.jsx Renamed ToursDefaultPage to TourDefaultPage and updated the /tour route to wrap with Private for authentication.
frontend/src/assets/icons/utilityIcons.jsx Updated TrashIcon to accept a stroke prop; added a new Hamburger icon.
frontend/src/components/DraggableTourStep/DraggableTourStep.jsx
frontend/src/components/DraggableTourStep/DraggableTourStep.module.scss
Introduced DraggableTourStep component with drag-and-drop functionality and corresponding SCSS styling.
frontend/src/components/DropdownList/DropdownList.jsx Added a new styles prop for enhanced styling options.
frontend/src/components/Links/ColorInput/ColorInput.module.scss Added a new &__error style block for error messaging.
frontend/src/components/Links/ColorInput/index.jsx Modified ColorInput to integrate Formik’s useField hook, simplify input change handling, and conditionally display error messages.
frontend/src/components/TextFieldComponents/CustomTextField/CustomTextField.jsx Added new labelTextStyles prop to enable custom styling for label sub-text.
frontend/src/data/guideMainPageData.js Added a new tour entry in activityInfoData with properties for product tours.
frontend/src/scenes/dashboard/Dashboard.jsx Added a new button entry to create a tour that navigates to /tour with an auto-open state.
frontend/src/scenes/popup/PopupPageComponents/PopupAppearance/PopupAppearance.jsx Simplified Formik initial values by directly spreading popupAppearance.
frontend/src/scenes/tours/CreateTourPage.jsx Introduced the new TourPage component for creating and editing tours.
frontend/src/scenes/tours/CreateToursPopup/CreateToursPopup.jsx
frontend/src/scenes/tours/CreateToursPopup/CreateToursPopup.module.scss
frontend/src/scenes/tours/ProductTour.jsx
frontend/src/scenes/tours/ProductTourStyles.css
Removed obsolete tour creation components and their associated styles.
frontend/src/scenes/tours/TourDefaultPage.jsx Added the new TourDefaultPage component with dialog integration and enhanced authentication.
frontend/src/scenes/tours/TourPageComponents/TourLeftContent/TourLeftContent.jsx
frontend/src/scenes/tours/TourPageComponents/TourLeftContent/TourLeftContent.module.scss
Added TourLeftContent component to manage and reorder tour steps via drag-and-drop.
frontend/src/scenes/tours/TourPageComponents/TourleftAppearance/TourLeftAppearance.jsx
frontend/src/scenes/tours/TourPageComponents/TourleftAppearance/TourLeftAppearance.module.scss
Added TourLeftAppearance component to customise tour appearance settings through Formik.
frontend/src/scenes/tours/TourPreview/TourPreview.jsx
frontend/src/scenes/tours/TourPreview/TourPreview.module.scss
Added TourPreview component for previewing tour steps and navigating between them.
frontend/src/scenes/tours/ToursDefaultPage.jsx Removed the deprecated ToursDefaultPage component.
frontend/src/services/tourServices.js Added new asynchronous API functions: addTour, getTours, getTourById, editTour, and deleteTour.
frontend/src/templates/GuideMainPageTemplate/GuideMainPageTemplate.css Updated .tour-info-container to include flex: 1; for improved layout.
frontend/src/templates/GuideTemplate/GuideTemplate.jsx Expanded props to include headerButtons, enableActiveButton, switchValue, and onSwitchChange for conditional rendering.
frontend/src/utils/tourHelper.js Added a new URL validation function and appearanceSchema for validating tour appearance settings.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant TourPage
    participant TourLeftContent
    participant TourLeftAppearance
    participant TourPreview
    participant API

    User->>TourPage: Open Tour Creation/Edit
    TourPage->>TourLeftContent: Render and manage tour steps
    User->>TourLeftContent: Reorder or edit steps (drag-and-drop)
    TourLeftContent->>TourPage: Update steps state
    User->>TourLeftAppearance: Adjust appearance settings
    TourLeftAppearance->>TourPage: Validate and update appearance via Formik
    User->>TourPreview: Navigate through tour steps for preview
    User->>TourPage: Save tour changes
    TourPage->>API: Trigger addTour/editTour API call
    API-->>TourPage: Return response (success/error)
Loading

Possibly related PRs

  • Fixed 'ListItem' icons #473: Involved similar dependency updates for the DnD Kit and revised the TrashIcon component, providing context for icon replacement and usage.

Suggested reviewers

  • gorkem-bwl
  • erenfn
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

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:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

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

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

🔭 Outside diff range comments (1)
frontend/src/scenes/dashboard/Dashboard.jsx (1)

38-38: ⚠️ Potential issue

Don't lose yourself: Add 'tour' to metricNames! 📊

The mapMetricName function supports 'tour' metrics, but 'tour' is missing from the metricNames array. Add it to ensure tour statistics are displayed:

- const metricNames = ['popup', 'banner', 'link', 'hint']
+ const metricNames = ['popup', 'banner', 'link', 'hint', 'tour']
🧹 Nitpick comments (16)
frontend/package.json (1)

7-9: Mom's spaghetti moment: Let's lock these versions down! 🍝

While the DnD Kit packages are solid choices for drag-and-drop functionality, using caret versions (^) could lead to unexpected breaks. Consider pinning the versions:

-    "@dnd-kit/core": "^6.3.1",
-    "@dnd-kit/sortable": "^10.0.0",
-    "@dnd-kit/utilities": "^3.2.2",
+    "@dnd-kit/core": "6.3.1",
+    "@dnd-kit/sortable": "10.0.0",
+    "@dnd-kit/utilities": "3.2.2",
frontend/src/scenes/dashboard/Dashboard.jsx (1)

80-84: Knees weak, arms heavy: Tour button needs its own identity! 🎯

Using HintSkeleton for the tour button might confuse users. Consider creating a dedicated TourSkeleton component to better represent the tour functionality.

// Create a new file: HomePageComponents/Skeletons/TourSkeleton.jsx
const TourSkeleton = () => {
  // Implement tour-specific skeleton UI
};

// Update the button configuration
{
  skeletonType: <TourSkeleton />,
  placeholder: "Create a new tour",
  onClick: () => navigate("/tour", { state: { autoOpen: true } }),
}
frontend/src/utils/tourHelper.js (1)

4-4: Yo, the validation schema is straight fire! 🎯

The Yup schema implementation is solid with proper validation rules. Just one suggestion to make the color regex case-insensitive for better flexibility.

-const COLOR_REGEX = /^#[0-9A-Fa-f]{6}$/;
+const COLOR_REGEX = /^#[0-9A-Fa-f]{6}$/i;

Also applies to: 15-41

frontend/src/scenes/tours/TourPreview/TourPreview.module.scss (1)

45-49: Yo, let's make this heading accessible! ♿

Add proper ARIA attributes to improve accessibility for screen readers.

 h2 {
   font-size: 1.5rem;
   font-weight: bold;
   color: var(--primary-text-color);
+  /* Add role and aria-level for better accessibility */
+  role: heading;
+  aria-level: 2;
 }
frontend/src/scenes/popup/PopupPageComponents/PopupAppearance/PopupAppearance.jsx (1)

17-19: Yo dawg, we need to handle undefined values!

The direct spread of popupAppearance could lead to undefined values in the form. Consider adding a default empty object as fallback.

  initialValues={{
-   ...popupAppearance,
+   ...(popupAppearance || {}),
  }}
frontend/src/components/DraggableTourStep/DraggableTourStep.module.scss (1)

9-9: Consider using CSS variables for these magic numbers!

Hardcoded values like 241px, 30px, and 100px should be moved to CSS variables for better maintainability and consistency.

:root {
+  --tour-step-width: 241px;
+  --tour-button-size: 30px;
+  --tour-input-width: 100px;
}

.stepContainer {
-  width: 241px;
+  width: var(--tour-step-width);
  /* ... */
  &__button {
-    height: 30px;
-    width: 30px;
+    height: var(--tour-button-size);
+    width: var(--tour-button-size);
  }
  &__customInput {
-    width: 100px;
+    width: var(--tour-input-width);
  }
}

Also applies to: 19-19, 49-49

frontend/src/templates/GuideTemplate/GuideTemplate.jsx (2)

32-37: Heads up on that state object, fam! 🤔

While the optional chaining is solid, consider making the empty state object more explicit about what properties are being cleared:

-    if (location.state?.autoOpen) navigate('/', { state: {} });
+    if (location.state?.autoOpen) navigate('/', { state: { autoOpen: false } });

75-99: Let's level up that switch component! 💪

The switch implementation could use some accessibility love:

 <Switch
   id="switch"
   name="isActive"
   value={switchValue}
   onChange={onSwitchChange}
+  aria-label="Toggle active state"
 />
 <label
+  htmlFor="switch"
   style={{
     fontSize: 'var(--font-regular)',
     alignSelf: 'center',
   }}
 >

Also, consider moving those inline styles to your CSS module for better maintainability.

frontend/src/components/DropdownList/DropdownList.jsx (2)

14-14: Watch out for style collisions, dawg! ⚠️

While spreading styles is flexible, it could override important base styles. Consider using a whitelist approach:

-  sx={{ marginTop: 1, ...styles }}
+  sx={{ marginTop: 1, ...(styles?.custom || {}) }}

Also applies to: 46-46


18-26: Let's make this function zoom! 🏃‍♂️

The case-insensitive comparison could be optimized by converting to lowercase once:

 const getInitialSelectedAction = () => {
   if (selectedActionString) {
+    const searchString = selectedActionString.toLowerCase();
     const index = actions.findIndex(
-      (action) => action.toLowerCase() === selectedActionString.toLowerCase()
+      (action) => action.toLowerCase() === searchString
     );
     return index !== -1 ? actions[index] : actions[0] || '';
   }
   return actions[selectedActionIndex] || '';
 };
frontend/src/components/DraggableTourStep/DraggableTourStep.jsx (1)

16-29: Let's make this drag-n-drop accessible! ♿

Add ARIA attributes to improve accessibility:

 const style = {
   transform: CSS.Transform.toString(transform),
   transition,
   opacity: isDragging ? 0.5 : 1,
+  cursor: isDragging ? 'grabbing' : 'grab',
 };
frontend/src/scenes/tours/CreateTourPage.jsx (1)

17-26: Consider using a more descriptive initial step content.

The default step content appears to be hardcoded with GuideFox-specific content. This might not be suitable for all use cases.

 const [stepsData, setStepsData] = useState([
   {
     id: 0,
     stepName: 'Step 1',
-    header: 'Welcome to GuideFox',
-    content:
-      'Serve your users and increase product adoption with hints, popups, banners, and helper links. \n\nEarn an extra 30% if you purchase an annual plan with us.',
+    header: 'Welcome',
+    content: 'Add your tour content here...',
     targetElement: '',
   },
 ]);
frontend/src/scenes/tours/TourPageComponents/TourleftAppearance/TourLeftAppearance.jsx (1)

103-122: Add URL validation feedback.

Consider adding real-time URL validation feedback to improve user experience.

 <CustomTextField
   TextFieldWidth="206px"
   name="url"
   value={values.url}
+  helperText="Enter a valid URL starting with http:// or https://"
+  error={Boolean(touched.url && errors.url)}
   onChange={(e) => {
     handleChange({
       target: { name: 'url', value: e.target.value },
     });
     setTourPopupAppearance((prev) => ({
       ...prev,
       url: e.target.value,
     }));
   }}
   onBlur={(e) => {
     handleBlur(e);
     validateField('url');
   }}
 />
frontend/src/services/tourServices.js (1)

1-60: Bruh, we need some retry logic for those flaky network calls!

Consider implementing a retry mechanism for failed API requests using exponential backoff.

const retryWithBackoff = async (fn, maxRetries = 3) => {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
    }
  }
};
frontend/src/scenes/tours/TourPageComponents/TourLeftContent/TourLeftContent.jsx (2)

71-81: That delete handler needs some love! 💔

The delete handler should update step names to maintain sequential order.

 const deleteHandler = (identity) => {
   if (stepsData.length === 1) return;

   const updatedSteps = stepsData.filter(({ id }) => id !== identity);
+  const renamedSteps = updatedSteps.map((step, index) => ({
+    ...step,
+    stepName: `Step ${index + 1}`,
+  }));

   if (identity === currentStep.id) {
-    setCurrentStep(updatedSteps[0]);
+    setCurrentStep(renamedSteps[0]);
   }

-  setStepsData(updatedSteps);
+  setStepsData(renamedSteps);
 };

95-153: Performance optimization time! 🚀

Consider memoizing the handlers and using useCallback to prevent unnecessary re-renders.

const memoizedHandlers = {
  onDragStart: useCallback(({ active }) => setActiveDragId(active.id), []),
  onDragEnd: useCallback(handleDragEnd, [setStepsData, setActiveDragId]),
  onSelect: useCallback(selectHandler, [stepsData, setCurrentStep]),
  onDelete: useCallback(deleteHandler, [stepsData, currentStep, setCurrentStep, setStepsData])
};
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 458e104 and 1e5d1d3.

⛔ Files ignored due to path filters (2)
  • frontend/package-lock.json is excluded by !**/package-lock.json
  • frontend/public/no-background.jpg is excluded by !**/*.jpg
📒 Files selected for processing (30)
  • frontend/package.json (1 hunks)
  • frontend/src/App.jsx (2 hunks)
  • frontend/src/assets/icons/utilityIcons.jsx (3 hunks)
  • frontend/src/components/DraggableTourStep/DraggableTourStep.jsx (1 hunks)
  • frontend/src/components/DraggableTourStep/DraggableTourStep.module.scss (1 hunks)
  • frontend/src/components/DropdownList/DropdownList.jsx (3 hunks)
  • frontend/src/components/Links/ColorInput/ColorInput.module.scss (1 hunks)
  • frontend/src/components/Links/ColorInput/index.jsx (1 hunks)
  • frontend/src/components/RichTextEditor/RichTextEditor.jsx (2 hunks)
  • frontend/src/components/TextFieldComponents/CustomTextField/CustomTextField.jsx (3 hunks)
  • frontend/src/data/guideMainPageData.js (1 hunks)
  • frontend/src/scenes/dashboard/Dashboard.jsx (1 hunks)
  • frontend/src/scenes/popup/PopupPageComponents/PopupAppearance/PopupAppearance.jsx (1 hunks)
  • frontend/src/scenes/tours/CreateTourPage.jsx (1 hunks)
  • frontend/src/scenes/tours/CreateToursPopup/CreateToursPopup.jsx (0 hunks)
  • frontend/src/scenes/tours/CreateToursPopup/CreateToursPopup.module.scss (0 hunks)
  • frontend/src/scenes/tours/ProductTour.jsx (0 hunks)
  • frontend/src/scenes/tours/ProductTourStyles.css (0 hunks)
  • frontend/src/scenes/tours/TourDefaultPage.jsx (1 hunks)
  • frontend/src/scenes/tours/TourPageComponents/TourLeftContent/TourLeftContent.jsx (1 hunks)
  • frontend/src/scenes/tours/TourPageComponents/TourLeftContent/TourLeftContent.module.scss (1 hunks)
  • frontend/src/scenes/tours/TourPageComponents/TourleftAppearance/TourLeftAppearance.jsx (1 hunks)
  • frontend/src/scenes/tours/TourPageComponents/TourleftAppearance/TourLeftAppearance.module.scss (1 hunks)
  • frontend/src/scenes/tours/TourPreview/TourPreview.jsx (1 hunks)
  • frontend/src/scenes/tours/TourPreview/TourPreview.module.scss (1 hunks)
  • frontend/src/scenes/tours/ToursDefaultPage.jsx (0 hunks)
  • frontend/src/services/tourServices.js (1 hunks)
  • frontend/src/templates/GuideMainPageTemplate/GuideMainPageTemplate.css (1 hunks)
  • frontend/src/templates/GuideTemplate/GuideTemplate.jsx (4 hunks)
  • frontend/src/utils/tourHelper.js (1 hunks)
💤 Files with no reviewable changes (5)
  • frontend/src/scenes/tours/ToursDefaultPage.jsx
  • frontend/src/scenes/tours/CreateToursPopup/CreateToursPopup.module.scss
  • frontend/src/scenes/tours/ProductTourStyles.css
  • frontend/src/scenes/tours/ProductTour.jsx
  • frontend/src/scenes/tours/CreateToursPopup/CreateToursPopup.jsx
✅ Files skipped from review due to trivial changes (2)
  • frontend/src/scenes/tours/TourPageComponents/TourleftAppearance/TourLeftAppearance.module.scss
  • frontend/src/scenes/tours/TourPageComponents/TourLeftContent/TourLeftContent.module.scss
🔇 Additional comments (7)
frontend/src/templates/GuideMainPageTemplate/GuideMainPageTemplate.css (1)

24-26: Yo, this flex layout is straight fire! 🔥

The addition of flex: 1 allows the container to grow and fill available space, maintaining a clean layout structure.

frontend/src/components/Links/ColorInput/ColorInput.module.scss (1)

75-82: These styles are cleaner than my sweater! ✨

Excellent use of CSS variables and BEM methodology for error state styling. The implementation maintains consistency with the design system.

frontend/src/components/TextFieldComponents/CustomTextField/CustomTextField.jsx (1)

15-15: Yo, these changes are fire! 🔥

The addition of labelTextStyles prop with proper PropTypes definition and implementation looks clean. The spread operator usage in the sx prop is on point!

Also applies to: 46-46, 124-124

frontend/src/components/RichTextEditor/RichTextEditor.jsx (1)

46-49: Yo, why we commenting out this cleanup code?

Removing the cleanup logic in onDestroy could lead to stale state when the editor is destroyed and recreated. Consider keeping the cleanup or document why it's not needed.

frontend/src/templates/GuideTemplate/GuideTemplate.jsx (1)

12-25: Yo, these prop changes are fire! 🔥

The new props with their default values are well-structured and type-safe. Nice job handling the defaults to prevent undefined behavior.

frontend/src/App.jsx (1)

43-43: Secure route game strong! 🔒

Adding authentication protection with the Private component wrapper is a solid security move. The naming convention update to TourDefaultPage is also more consistent with the singular form used in other routes.

frontend/src/data/guideMainPageData.js (1)

38-44: LGTM! The tour activity info is well-structured.

The content is clear, concise, and follows the same pattern as other activity types. The description effectively communicates the purpose and value of product tours.

Comment on lines +29 to +39
getItems={getTours}
deleteItem={deleteTour}
setIsEdit={setIsEdit}
setItemId={setItemId}
itemType={ACTIVITY_TYPES_INFO.TOURS}
itemTypeInfo={ACTIVITY_TYPES_INFO.TOURS}
getItemDetails={getTourDetails}
itemsUpdated={itemsUpdated}
getItemById={getTourById}
duplicateItem={addTour}
/>
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

Yo, we need some error handling in here! 🚨

The service calls (getTours, deleteTour, getTourById, addTour) need proper error handling to manage API failures gracefully.

 <DefaultPageTemplate
   getItems={getTours}
-  deleteItem={deleteTour}
+  deleteItem={async (id) => {
+    try {
+      await deleteTour(id);
+    } catch (error) {
+      console.error('Failed to delete tour:', error);
+      throw new Error('Failed to delete tour. Please try again.');
+    }
+  }}
   setIsEdit={setIsEdit}
   setItemId={setItemId}
   itemType={ACTIVITY_TYPES_INFO.TOURS}
   itemTypeInfo={ACTIVITY_TYPES_INFO.TOURS}
   getItemDetails={getTourDetails}
   itemsUpdated={itemsUpdated}
-  getItemById={getTourById}
+  getItemById={async (id) => {
+    try {
+      return await getTourById(id);
+    } catch (error) {
+      console.error('Failed to fetch tour:', error);
+      throw new Error('Failed to fetch tour details. Please try again.');
+    }
+  }}
-  duplicateItem={addTour}
+  duplicateItem={async (data) => {
+    try {
+      return await addTour(data);
+    } catch (error) {
+      console.error('Failed to duplicate tour:', error);
+      throw new Error('Failed to duplicate tour. Please try again.');
+    }
+  }}
 />
📝 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
getItems={getTours}
deleteItem={deleteTour}
setIsEdit={setIsEdit}
setItemId={setItemId}
itemType={ACTIVITY_TYPES_INFO.TOURS}
itemTypeInfo={ACTIVITY_TYPES_INFO.TOURS}
getItemDetails={getTourDetails}
itemsUpdated={itemsUpdated}
getItemById={getTourById}
duplicateItem={addTour}
/>
getItems={getTours}
deleteItem={async (id) => {
try {
await deleteTour(id);
} catch (error) {
console.error('Failed to delete tour:', error);
throw new Error('Failed to delete tour. Please try again.');
}
}}
setIsEdit={setIsEdit}
setItemId={setItemId}
itemType={ACTIVITY_TYPES_INFO.TOURS}
itemTypeInfo={ACTIVITY_TYPES_INFO.TOURS}
getItemDetails={getTourDetails}
itemsUpdated={itemsUpdated}
getItemById={async (id) => {
try {
return await getTourById(id);
} catch (error) {
console.error('Failed to fetch tour:', error);
throw new Error('Failed to fetch tour details. Please try again.');
}
}}
duplicateItem={async (data) => {
try {
return await addTour(data);
} catch (error) {
console.error('Failed to duplicate tour:', error);
throw new Error('Failed to duplicate tour. Please try again.');
}
}}
/>

@@ -83,7 +83,7 @@ const RichTextEditor = ({
setMode={setMode}
sx={{
position: "absolute",
bottom: "35px",
bottom: "px",
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 this broken style value, fam!

The bottom style value is invalid. It's missing a number before "px".

-          bottom: "px",
+          bottom: "35px",
📝 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
bottom: "px",
bottom: "35px",

@@ -35,3 +35,15 @@ export const EditIcon = () => (
/>
</IconWrapper>
);

export const Hamburger = ({ styles }) => (
<IconWrapper style={styles} role="img" aria-label="Delete item">
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 that accessibility label, it's not right!

The aria-label "Delete item" is incorrect for a hamburger menu icon. It should describe its actual purpose.

-  <IconWrapper style={styles} role="img" aria-label="Delete item">
+  <IconWrapper style={styles} role="img" aria-label="Drag handle">
📝 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
<IconWrapper style={styles} role="img" aria-label="Delete item">
<IconWrapper style={styles} role="img" aria-label="Drag handle">

Comment on lines +58 to +61
&:blur {
border: 1px solid transparent;
background-color: var(--header-background);
}
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

Yo, that :blur ain't a real pseudo-class!

The :blur pseudo-class doesn't exist in CSS. You probably meant to use the blur event with JavaScript or the :focus-within pseudo-class.

-    &:blur {
+    &:not(:focus) {
       border: 1px solid transparent;
       background-color: var(--header-background);
     }
📝 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
&:blur {
border: 1px solid transparent;
background-color: var(--header-background);
}
&:not(:focus) {
border: 1px solid transparent;
background-color: var(--header-background);
}

Comment on lines +8 to +9
console.error('Add Tour error:', error.response.data.errors);
throw error;
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

Yo, we're leaking sensitive info in those error logs! 🚨

The error logging is exposing potentially sensitive information from the API responses. Consider implementing a sanitized error logging mechanism.

- console.error('Add Tour error:', error.response.data.errors);
+ console.error('Add Tour error:', 'Failed to add tour. Please try again.');

Also applies to: 18-19, 28-32, 41-45, 54-58

Comment on lines +3 to +11
export const addTour = async (tourData) => {
try {
const response = await apiClient.post('/tour/add_tour', tourData);
return response.data;
} catch (error) {
console.error('Add Tour error:', error.response.data.errors);
throw error;
}
};
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

Yo dawg, we need to validate that tour data before sending it to the server!

The addTour function should validate the input data before making the API call to prevent invalid data from reaching the server.

 export const addTour = async (tourData) => {
+  if (!tourData || typeof tourData !== 'object') {
+    throw new Error('Invalid tour data provided');
+  }
   try {
     const response = await apiClient.post('/tour/add_tour', tourData);
     return response.data;
   } catch (error) {
-    console.error('Add Tour error:', error.response.data.errors);
+    console.error('Add Tour error:', error.response?.data?.errors || error.message);
     throw error;
   }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const addTour = async (tourData) => {
try {
const response = await apiClient.post('/tour/add_tour', tourData);
return response.data;
} catch (error) {
console.error('Add Tour error:', error.response.data.errors);
throw error;
}
};
export const addTour = async (tourData) => {
if (!tourData || typeof tourData !== 'object') {
throw new Error('Invalid tour data provided');
}
try {
const response = await apiClient.post('/tour/add_tour', tourData);
return response.data;
} catch (error) {
console.error('Add Tour error:', error.response?.data?.errors || error.message);
throw error;
}
};

Comment on lines +11 to +16
const handleChange = (e) => {
const val = e.target.value;

setValue(val);
onChange(val);
};
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

Yo, we need to validate those color values! 🎨

Add color validation to ensure only valid hex colors are accepted.

 const handleChange = (e) => {
   const val = e.target.value;
+  const isValidHex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
+  if (!isValidHex.test(val)) {
+    return;
+  }
   setValue(val);
   onChange(val);
 };
📝 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 handleChange = (e) => {
const val = e.target.value;
setValue(val);
onChange(val);
};
const handleChange = (e) => {
const val = e.target.value;
const isValidHex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
if (!isValidHex.test(val)) {
return;
}
setValue(val);
onChange(val);
};

Comment on lines +32 to +53
<div className={styles.appearance__circle}>
<input
type="color"
id={id}
value={field.value}
onChange={handleChange}
style={{ zIndex: 10, cursor: 'pointer', opacity: 0 }}
onBlur={() => setTouched(true)}
/>
{error && touched ? (
<img
src="/no-background.jpg"
alt="No color selected"
className={styles['appearance__circle--mask']}
/>
) : (
<span
className={styles['appearance__circle--mask']}
style={{ backgroundColor: field.value }}
/>
)}
</div>
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

Accessibility game weak! Let's boost those ARIA attributes! 🔥

The color picker needs better accessibility support.

 <input
   type="color"
   id={id}
   value={field.value}
   onChange={handleChange}
   style={{ zIndex: 10, cursor: 'pointer', opacity: 0 }}
   onBlur={() => setTouched(true)}
+  aria-label={`Choose ${title} color`}
+  role="button"
 />
📝 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
<div className={styles.appearance__circle}>
<input
type="color"
id={id}
value={field.value}
onChange={handleChange}
style={{ zIndex: 10, cursor: 'pointer', opacity: 0 }}
onBlur={() => setTouched(true)}
/>
{error && touched ? (
<img
src="/no-background.jpg"
alt="No color selected"
className={styles['appearance__circle--mask']}
/>
) : (
<span
className={styles['appearance__circle--mask']}
style={{ backgroundColor: field.value }}
/>
)}
</div>
<div className={styles.appearance__circle}>
<input
type="color"
id={id}
value={field.value}
onChange={handleChange}
style={{ zIndex: 10, cursor: 'pointer', opacity: 0 }}
onBlur={() => setTouched(true)}
aria-label={`Choose ${title} color`}
role="button"
/>
{error && touched ? (
<img
src="/no-background.jpg"
alt="No color selected"
className={styles['appearance__circle--mask']}
/>
) : (
<span
className={styles['appearance__circle--mask']}
style={{ backgroundColor: field.value }}
/>
)}
</div>

Comment on lines +47 to +56
const addNewStepHandler = () => {
setStepsData((prev) => [
...prev,
{
...defaultStep,
id: Date.now(),
stepName: `Step ${prev.length + 1}`,
},
]);
};
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

Bruh, that Date.now() ID generation is sketchy! 🤔

Using timestamps as IDs could lead to collisions if steps are created simultaneously. Consider using a UUID instead.

+ import { v4 as uuidv4 } from 'uuid';

 const addNewStepHandler = () => {
   setStepsData((prev) => [
     ...prev,
     {
       ...defaultStep,
-      id: Date.now(),
+      id: uuidv4(),
       stepName: `Step ${prev.length + 1}`,
     },
   ]);
 };
📝 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 addNewStepHandler = () => {
setStepsData((prev) => [
...prev,
{
...defaultStep,
id: Date.now(),
stepName: `Step ${prev.length + 1}`,
},
]);
};
import { v4 as uuidv4 } from 'uuid';
const addNewStepHandler = () => {
setStepsData((prev) => [
...prev,
{
...defaultStep,
id: uuidv4(),
stepName: `Step ${prev.length + 1}`,
},
]);
};

@MandeepPaul MandeepPaul removed the request for review from erenfn February 24, 2025 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant