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

feat: React Skeleton #2403

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

Conversation

shohag121
Copy link
Member

@shohag121 shohag121 commented Oct 17, 2024

All Submissions:

  • My code follow the WordPress' coding standards
  • My code satisfies feature requirements
  • My code is tested
  • My code passes the PHPCS tests
  • My code has proper inline documentation
  • I've included related pull request(s) (optional)
  • I've included developer documentation (optional)
  • I've added proper labels to this pull request

Changes proposed in this Pull Request:

Related Pull Request(s)

Closes

How to test the changes in this Pull Request:

  • Steps or issue link

Changelog entry

Title

Detailed Description of the pull request. What was previous behaviour
and what will be changed in this PR.

Before Changes

Describe the issue before changes with screenshots(s).

After Changes

Describe the issue after changes with screenshot(s).

Feature Video (optional)

Link of detailed video if this PR is for a feature.

PR Self Review Checklist:

  • Code is not following code style guidelines
  • Bad naming: make sure you would understand your code if you read it a few months from now.
  • KISS: Keep it simple, Sweetie (not stupid!).
  • DRY: Don't Repeat Yourself.
  • Code that is not readable: too many nested 'if's are a bad sign.
  • Performance issues
  • Complicated constructions that need refactoring or comments: code should almost always be self-explanatory.
  • Grammar errors.

FOR PR REVIEWER ONLY:

As a reviewer, your feedback should be focused on the idea, not the person. Seek to understand, be respectful, and focus on constructive dialog.

As a contributor, your responsibility is to learn from suggestions and iterate your pull request should it be needed based on feedback. Seek to collaborate and produce the best possible contribution to the greater whole.

  • Correct — Does the change do what it’s supposed to? ie: code 100% fulfilling the requirements?
  • Secure — Would a nefarious party find some way to exploit this change? ie: everything is sanitized/escaped appropriately for any SQL or XSS injection possibilities?
  • Readable — Will your future self be able to understand this change months down the road?
  • Elegant — Does the change fit aesthetically within the overall style and architecture?

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new Tailwind CSS configuration for scoped styles, enhancing layout styling.
    • Added a React-based dashboard component with integrated routing functionality.
    • Implemented new layout components including Header, Footer, Sidebar, ContentArea, NotFound, and ThemeProvider.
    • Enhanced asset management by integrating React frontend capabilities, including new styles and scripts.
    • Added custom REST API controllers for managing continent and country data with Dokan-specific permission checks.
    • Introduced a new REST API controller for managing customer data with search functionality and vendor-specific permissions.
    • Enhanced the existing OrderController with improved handling of downloadable products.
    • Added new dependencies to support the React frontend and Tailwind CSS.
  • Bug Fixes

    • Improved error handling and permission checks in the new REST API controllers.
  • Documentation

    • Updated package dependencies to support new features and enhancements.
  • Chores

    • Modified Webpack configuration to include new entry points for the dashboard.

Copy link
Contributor

coderabbitai bot commented Oct 17, 2024

Walkthrough

The pull request introduces enhancements to the asset management system by adding a new React frontend asset in the Assets class. It includes several new React components for a dashboard layout, integrates routing capabilities, and updates the Webpack configuration to accommodate these changes. Additionally, new dependencies related to Tailwind CSS and WordPress components are added to the package.json file.

Changes

File Path Change Summary
includes/Assets.php Updated Assets class to include new style and script for 'dokan-react-frontend'.
package.json Added new dependencies for Tailwind CSS and WordPress components.
src/Dashboard/index.tsx Introduced a React component for the dashboard with routing capabilities.
src/Dashboard/tailwind.scss Imported Tailwind CSS configuration and base styles.
src/Layout/404.tsx Added NotFound component for 404 error handling.
src/Layout/ContentArea.tsx Created ContentArea component for layout structure.
src/Layout/Footer.tsx Introduced Footer component using WordPress Slot.
src/Layout/Header.tsx Added Header component with title prop and slots for content.
src/Layout/Sidebar.tsx Created Sidebar component (currently empty).
src/Layout/index.tsx Managed theme state and added Layout component with context and hooks.
src/Routing/index.tsx Added getRoutes function to construct routing for the application.
webpack.config.js Added new entry point for the dashboard and updated module resolution settings.
includes/REST/DokanDataContinentsController.php Added custom REST API controller for continents data.
includes/REST/DokanDataCountriesController.php Added custom REST API controller for countries data.
includes/REST/Manager.php Updated REST API class map to include new controllers for countries and continents.
includes/REST/CustomersController.php Introduced custom REST API controller for managing customer data with search functionality.
tests/php/src/REST/CustomersControllerTest.php Added unit tests for CustomersController to validate API functionality and permissions.
includes/REST/OrderControllerV3.php Added OrderControllerV3 class with enhanced order download capabilities.
includes/REST/ProductController.php Updated ProductController to handle downloadable products with a new query parameter.

Assessment against linked issues

Objective Addressed Explanation
Setup Skeleton for new vendor dashboard implementation (#83)

Possibly related PRs

Suggested labels

Needs: Testing, Needs: Dev Review

Suggested reviewers

  • mrabbani

Poem

🐰 In the garden of code, new blooms arise,
Tailwind's colors dance under the skies.
React components hop, layout in sight,
A dash of style makes everything bright!
With routes that guide and a 404 to find,
In this patch of joy, all bunnies unwind! 🌼


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 46bcda5 and 16f8a1d.

📒 Files selected for processing (2)
  • includes/Assets.php (5 hunks)
  • webpack.config.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • webpack.config.js
🔇 Additional comments (4)
includes/Assets.php (4)

364-367: LGTM! React frontend styles properly registered.

The style registration follows WordPress best practices with proper versioning using filemtime().


381-381: Variable name needs to be updated

The variable name suggests shipping-specific functionality but is used for general frontend assets.


576-580: Update variable references in script registration

The script registration uses the misleading variable name in dependencies and version.


887-891: 🛠️ Refactor suggestion

Consider conditional loading of React frontend assets

The React frontend assets are currently loaded unconditionally in the dashboard. Consider wrapping these in a condition to load only when needed:

 $wc_instance = WCAdminAssets::get_instance();
 $wc_instance->register_scripts();

-wp_enqueue_script( 'dokan-react-frontend' );
-wp_enqueue_style( 'dokan-react-frontend' );
+if ( /* condition to check if React frontend is needed */ ) {
+    wp_enqueue_script( 'dokan-react-frontend' );
+    wp_enqueue_style( 'dokan-react-frontend' );
+}

This would help optimize performance by loading assets only when required.

Likely invalid or redundant comment.


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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
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: 11

🧹 Outside diff range and nitpick comments (18)
src/Layout/404.tsx (2)

9-9: Export statement looks good.

The default export is correct and follows common React practices.

As an alternative, some teams prefer named exports for consistency and easier refactoring. If your project follows such a convention, you might consider:

export const NotFound: React.FC = () => {
  // ... component implementation
};

This is just a suggestion based on potential team preferences, not a required change.


1-1: Consider adding imports and explicit return type.

To improve code quality and maintainability, consider the following additions:

  1. Import React at the top of the file (if necessary for your project setup):

    import React from 'react';
  2. Add an explicit return type to the component:

    const NotFound: React.FC = (): JSX.Element => {
      // ... component implementation
    }

These changes can enhance type safety and make the code more self-documenting.

src/Layout/Footer.tsx (1)

3-5: Component looks good, but consider simplifying and adding documentation.

The Footer component is correctly implemented as a functional component. However, there are a couple of suggestions for improvement:

  1. Since there's only one child element, you can remove the fragment syntax:

    const Footer = () => <Slot name="dokan-footer-area" />;
  2. Consider adding a brief comment explaining the purpose of the "dokan-footer-area" slot and how it's intended to be used.

Could you provide more context on how this Footer component and the "dokan-footer-area" slot are intended to be used in the application?

src/Layout/ContentArea.tsx (2)

5-15: LGTM: Well-structured component with good use of React patterns.

The component structure is clean and logical. Good use of fragments and slots for flexible content injection. The separation of sidebar and content area is clear.

Consider adding PropTypes or TypeScript types for better type checking and documentation of the component's props.

Would you like me to provide an example of how to add PropTypes or TypeScript types to this component?


1-17: Overall, excellent implementation with room for minor enhancements.

The ContentArea component is well-implemented, following React and WordPress development best practices. It provides a flexible layout structure with good separation of concerns.

To further improve the code:

  1. Consider adding JSDoc comments to describe the component's purpose and any props it accepts.
  2. If not using TypeScript, consider adding PropTypes for better type checking and documentation.
  3. You might want to add a brief comment explaining the purpose of the named slots for future developers.

Would you like assistance in implementing any of these suggestions?

src/base-tailwind.scss (1)

5-21: LGTM: Well-structured table reset styles. Consider adding more context.

The custom base layer for resetting table styles within the .dokan-layout class is well-implemented. It provides a clean slate for table styling, which can be beneficial for consistent designs across the application.

Consider adding a brief comment explaining why these resets are specifically needed for the .dokan-layout class. This would provide valuable context for other developers working on the project. For example:

// Reset unwanted table styles but keep structure intact
// This is necessary for .dokan-layout to ensure consistent table styling
// across different components and to prevent conflicts with external styles.
@layer base {
    // ... (rest of the code remains the same)
}
src/Layout/Header.tsx (2)

5-17: LGTM: JSX structure is well-organized, with a minor suggestion for accessibility.

The component's structure is logical and makes good use of WordPress Slots for flexibility. The main content is appropriately placed between "before" and "after" slots.

Consider adding an aria-label to the header actions div for improved accessibility:

-            <div className="dokan-header-actions">
+            <div className="dokan-header-actions" aria-label="Header actions">

9-10: LGTM: Styling approach is modern and responsive, with a suggestion for flexibility.

The use of Tailwind CSS classes provides a consistent and maintainable styling approach. The gradient effect and responsive text sizes enhance the visual appeal and ensure good display across different devices.

Consider extracting the title styles into a separate className for easier customization:

-            <h1 className="mb-4 text-3xl font-extrabold text-gray-900 dark:text-white md:text-5xl lg:text-6xl"><span
-                className="text-transparent bg-clip-text bg-gradient-to-r to-emerald-600 from-sky-400">{title}</span> </h1>
+            <h1 className="dokan-header-title mb-4 text-3xl font-extrabold text-gray-900 dark:text-white md:text-5xl lg:text-6xl">
+                <span className="dokan-header-title-text text-transparent bg-clip-text bg-gradient-to-r to-emerald-600 from-sky-400">{title}</span>
+            </h1>

This change would allow easier overriding of styles if needed.

src/Dashboard/index.tsx (1)

1-9: LGTM! Consider grouping imports for better organization.

The imports look good and cover all necessary dependencies for the dashboard functionality. However, consider grouping the imports for better organization:

  1. External libraries (@WordPress and react-router-dom)
  2. Local imports
  3. Style imports

Here's a suggested regrouping:

import { createRoot } from "@wordpress/element";
import domReady from "@wordpress/dom-ready";
import {
    createBrowserRouter, createHashRouter,
    RouterProvider,
} from "react-router-dom";

import Layout from "../Layout";
import getRoutes from "../Routing";

import './tailwind.scss';
package.json (2)

25-26: LGTM! Consider documenting the purpose of new Tailwind CSS dependencies.

The addition of Tailwind CSS related packages (@tailwindcss/forms, @tailwindcss/typography, and tailwindcss-scoped-preflight) aligns well with the PR objective of introducing a React Skeleton feature. These are up-to-date versions, which is good practice.

Consider adding a comment in the package.json file or updating the project's documentation to explain the purpose and benefits of these new Tailwind CSS dependencies for future maintainers.

Also applies to: 39-39


56-63: LGTM! Consider documenting the purpose of new WordPress and React Router dependencies.

The addition of WordPress-related packages and react-router-dom aligns well with the PR objective of introducing a React Skeleton feature and integrating with WordPress core functionality. All added packages are using up-to-date versions, which is good practice.

Consider adding comments in the package.json file or updating the project's documentation to explain the purpose and benefits of these new WordPress and React Router dependencies for future maintainers.

src/Layout/index.tsx (4)

24-33: Standardize type definitions for React nodes to improve consistency.

In the DokanRoute type, properties like icon and element are typed as JSX.Element | React.ReactNode. Since React.ReactNode already encompasses JSX.Element, it's more concise to use React.ReactNode alone for these properties.

Apply this diff to simplify the type definitions:

-icon?: JSX.Element | React.ReactNode;
-element: JSX.Element | React.ReactNode;
+icon?: React.ReactNode;
+element: React.ReactNode;

This change enhances readability and maintains type accuracy.


35-41: Align prop types with common React patterns for more flexibility.

The headerComponent and footerComponent props are currently typed as JSX.Element, which may be too restrictive. Typing them as React.ReactNode allows for a broader range of values, such as strings, numbers, or null, providing more flexibility in what can be passed as props.

Apply this diff to update the prop types:

-headerComponent?: JSX.Element;
-footerComponent?: JSX.Element;
+headerComponent?: React.ReactNode;
+footerComponent?: React.ReactNode;

This adjustment aligns with common React typing practices.


44-67: Ensure consistent indentation and formatting for better readability.

The indentation within the JSX structure of the Layout component is inconsistent, which can make the code harder to read and maintain. Consistent formatting improves readability and makes collaboration easier.

Consider formatting the code using a tool like Prettier to standardize the indentation and spacing throughout the file.


70-72: Enhance type safety in the useTheme hook by specifying the context type.

Currently, the useTheme hook does not specify the type of the value it returns, which can lead to type inaccuracies. By defining the context type and using it consistently, you can improve type safety and developer experience.

Apply this diff to specify the return type:

-export const useTheme = () => {
+export const useTheme = (): ThemeContextType => {

Ensure that ThemeContextType is defined as shown in the previous comment for the ThemeContext.

Alternatively, if you've applied the default value to ThemeContext as suggested earlier, TypeScript can infer the types, and you can write:

-export const useTheme = () => {
+export const useTheme = () => useContext(ThemeContext);
src/Routing/index.tsx (3)

79-79: Remove debugging console.log statement

The console.log(routes); statement is useful for debugging but should be removed or commented out in production code to prevent unnecessary logging.

Apply this diff to remove the console log:

-    console.log(routes);

28-28: Assign unique order values for route sorting

Multiple routes have the same order value of 10. If the order property is used for sorting routes in navigation menus or rendering order, assigning the same value might not produce the desired sequence.

Consider assigning unique order values based on the intended order of the routes.

Also applies to: 38-38, 48-48, 59-59


25-25: Replace placeholder elements with actual components

The element properties are currently using placeholder <h1> tags with sample text. Replace these placeholders with the actual React components or content intended for these routes.

For example:

-            element: <h1>Dashboard body</h1>,
+            element: <Dashboard />,

Ensure that you import the necessary components at the top of the file:

import Dashboard from '../Components/Dashboard';

Also applies to: 35-35, 45-45, 56-56

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between ead0858 and a2701f5.

📒 Files selected for processing (14)
  • base-tailwind.config.js (1 hunks)
  • includes/Assets.php (4 hunks)
  • package.json (3 hunks)
  • src/Dashboard/index.tsx (1 hunks)
  • src/Dashboard/tailwind.scss (1 hunks)
  • src/Layout/404.tsx (1 hunks)
  • src/Layout/ContentArea.tsx (1 hunks)
  • src/Layout/Footer.tsx (1 hunks)
  • src/Layout/Header.tsx (1 hunks)
  • src/Layout/Sidebar.tsx (1 hunks)
  • src/Layout/index.tsx (1 hunks)
  • src/Routing/index.tsx (1 hunks)
  • src/base-tailwind.scss (1 hunks)
  • webpack.config.js (2 hunks)
✅ Files skipped from review due to trivial changes (2)
  • src/Dashboard/tailwind.scss
  • src/Layout/Sidebar.tsx
🧰 Additional context used
🔇 Additional comments (22)
src/Layout/Footer.tsx (2)

1-1: LGTM: Import statement is correct and follows best practices.

The destructured import of the Slot component from "@wordpress/components" is appropriate and adheres to modern JavaScript conventions.


7-7: LGTM: Default export is appropriate for this component.

Exporting the Footer component as the default export is a good practice for React components that are the primary export of their file.

src/Layout/ContentArea.tsx (3)

1-2: LGTM: Imports are appropriate and well-structured.

The import statements are concise and import the necessary components. Using Slot from "@wordpress/components" aligns with WordPress development practices.


4-4: LGTM: Component declaration follows React best practices.

The ContentArea component is well-defined using an arrow function and properly destructures the children prop. The naming convention (PascalCase) is correct for React components.


17-17: LGTM: Correct export statement.

The default export of the ContentArea component is appropriate and follows React best practices for exporting a single component from a file.

src/base-tailwind.scss (1)

1-3: LGTM: Tailwind directives are correctly implemented.

The Tailwind CSS directives are properly included at the top of the file, following the recommended setup for Tailwind CSS projects.

src/Layout/Header.tsx (4)

1-1: LGTM: Import statement is correct and appropriate.

The import of Slot from @wordpress/components is properly formatted and aligns with the WordPress ecosystem of the project.


3-3: LGTM: Component declaration and props are well-defined.

The Header component is correctly declared as a functional component using an arrow function. The use of a default value for the title prop is a good practice to prevent undefined errors.


20-20: LGTM: Export statement is correct.

The default export of the Header component is appropriate and follows common React practices.


1-20: Overall, excellent implementation of the Header component.

The Header component is well-structured, follows React best practices, and integrates nicely with the WordPress ecosystem. The use of Tailwind CSS for styling and WordPress Slots for content injection demonstrates a good understanding of the project's tech stack.

A few minor suggestions have been made for potential improvements:

  1. Adding an aria-label to the header actions div for better accessibility.
  2. Extracting title styles into separate classNames for easier customization.

These suggestions are optional and do not detract from the overall quality of the implementation.

src/Dashboard/index.tsx (2)

30-36: Consider safer element selection and error handling.

The use of domReady and createRoot is correct, but the element selection could be improved for better error handling and type safety.

Here's a suggested improvement:

domReady(function () {
  const rootElement = document.querySelector('.dashboard-content-area');
  if (rootElement) {
    const root = createRoot(rootElement);
    root.render(<App />);
  } else {
    console.error('Dashboard content area not found');
    // Optionally, you could render an error message to the body
    // document.body.innerHTML = '<p>Error: Dashboard content area not found</p>';
  }
});

This approach checks if the element exists before creating the root and provides an error message if it doesn't, which can help with debugging.

Let's verify if the '.dashboard-content-area' class is consistently used:

#!/bin/bash
# Description: Check for consistent use of '.dashboard-content-area' class

# Test: Search for '.dashboard-content-area' in the project
rg --type html --type php --type typescript --type javascript '\.dashboard-content-area' -C 3

11-28: Good structure, but consider adding types and addressing the TODO.

The App component is well-structured and follows React best practices. However, there are a few points to consider:

  1. Add TypeScript types to improve code quality and maintainability.
  2. Address the TODO comment about parent route support.

Here's a suggested improvement with types:

import { RouteObject } from 'react-router-dom';

interface AppRoute extends RouteObject {
  title: string;
  element: React.ReactNode;
}

const App: React.FC = () => {
  const routes: AppRoute[] = getRoutes();

  const mappedRoutes: RouteObject[] = routes.map((route) => ({
    path: route.path,
    element: <Layout route={route} title={route.title}>{route.element}</Layout>,
  }));

  const router = createHashRouter(mappedRoutes);

  return <RouterProvider router={router} />;
}

Regarding the TODO comment, let's verify if parent route support is needed:

package.json (1)

Line range hint 25-63: Overall changes align well with PR objectives.

The additions to both devDependencies and dependencies in package.json are consistent with the PR objective of introducing a React Skeleton feature. The new Tailwind CSS related packages will enhance styling capabilities, while the WordPress and React Router packages will facilitate integration with WordPress core functionality and implement routing in the React application.

All added packages are using up-to-date versions, which is a good practice. These changes lay a solid foundation for the development of the React Skeleton feature in a WordPress environment.

webpack.config.js (3)

Line range hint 1-165: Overall, the webpack configuration changes look good.

The modifications to webpack.config.js are consistent with the PR objectives of introducing a React Skeleton feature. The new entry point and resolve alias for the frontend have been added correctly. These changes will enable the build process to include the new React components while maintaining the existing configuration.

To ensure everything is set up correctly, please make sure to:

  1. Verify the existence and content of ./src/Dashboard/index.tsx
  2. Check the structure of the ./src/frontend/ directory

If the verification scripts pass without issues, these changes are ready for integration.


Line range hint 70-76: LGTM! Verify the frontend directory structure.

The modifications to the resolve section are correct:

  1. Spreading the defaultConfig.resolve properties maintains existing configurations.
  2. The new 'frontend' alias allows for easier imports from the frontend directory.

These changes complement the new entry point addition and improve the overall webpack configuration.

Please run the following script to verify the frontend directory structure:

#!/bin/bash
# Description: Verify the frontend directory structure.

# Test: Check if the frontend directory exists
if [ -d "./src/frontend" ]; then
    echo "Directory ./src/frontend exists."
else
    echo "Error: Directory ./src/frontend does not exist."
    exit 1
fi

# Test: List the contents of the frontend directory
echo "Contents of ./src/frontend:"
ls -la ./src/frontend

# Test: Check for common React component files
echo "Checking for common React component files:"
find ./src/frontend -name "*.tsx" -o -name "*.jsx" -o -name "*.js"

12-12: LGTM! Verify the file structure for the new entry point.

The addition of the 'frontend' entry point for the React dashboard is correct and aligns with the PR objective. This will allow webpack to build the new React frontend separately.

Please run the following script to verify the existence of the new entry point file:

✅ Verification successful

Verified: ./src/Dashboard/index.tsx exists and is not empty.

The addition of the 'frontend' entry point in webpack.config.js is correct and functions as intended, allowing webpack to build the new React frontend separately.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence of the new entry point file for the React frontend.

# Test: Check if the file exists
if [ -f "./src/Dashboard/index.tsx" ]; then
    echo "File ./src/Dashboard/index.tsx exists."
else
    echo "Error: File ./src/Dashboard/index.tsx does not exist."
    exit 1
fi

# Test: Check if the file is not empty
if [ -s "./src/Dashboard/index.tsx" ]; then
    echo "File ./src/Dashboard/index.tsx is not empty."
else
    echo "Warning: File ./src/Dashboard/index.tsx is empty."
fi

Length of output: 744


Script:

#!/bin/bash
# Description: Verify the existence and non-emptiness of ./src/Dashboard/index.tsx

# Test: Check if the file exists
if [ -f "./src/Dashboard/index.tsx" ]; then
    echo "File ./src/Dashboard/index.tsx exists."
else
    echo "Error: File ./src/Dashboard/index.tsx does not exist."
    exit 1
fi

# Test: Check if the file is not empty
if [ -s "./src/Dashboard/index.tsx" ]; then
    echo "File ./src/Dashboard/index.tsx is not empty."
else
    echo "Warning: File ./src/Dashboard/index.tsx is empty."
fi

Length of output: 263

src/Layout/index.tsx (2)

1-9: Imports are correctly organized and necessary dependencies are included.

All the required modules and components are imported properly, ensuring that the Layout component has access to all its dependencies.


14-22: Verify that the theme state is utilized by child components or remove it if unnecessary.

The ThemeProvider initializes a theme state and provides it via context, but there's no evidence in this file that theme is being consumed by any child components. If theme is not used elsewhere, consider removing it to simplify the code.

Would you like assistance in identifying where the theme context is used or suggestions on how to utilize it within the Layout component or its children?

src/Routing/index.tsx (1)

24-25: Verify placeholder content in titles and elements

The title 'Kola bagan' and element content <h1>asdasd</h1> seem to be placeholders or test data. Please update them with the appropriate content before merging.

base-tailwind.config.js (2)

10-10: LGTM!

Setting important to rootClass scopes all styles correctly under the specified root class. This is an effective approach for style encapsulation.


1-4: Verify that 'tailwindcss-scoped-preflight' is installed

The configuration imports from 'tailwindcss-scoped-preflight'. Please ensure that this package is installed in your project dependencies to avoid runtime errors.

Run the following command to check if the package is installed:

✅ Verification successful

'tailwindcss-scoped-preflight' is listed in devDependencies

The package 'tailwindcss-scoped-preflight' is present under devDependencies in your package.json, ensuring it is installed for development purposes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

npm list tailwindcss-scoped-preflight

Length of output: 110


Script:

#!/bin/bash
# Check if 'tailwindcss-scoped-preflight' is listed in dependencies or devDependencies
jq '{
  dependencies: .dependencies | has("tailwindcss-scoped-preflight"),
  devDependencies: .devDependencies | has("tailwindcss-scoped-preflight")
}' package.json

Length of output: 221

includes/Assets.php (1)

355-358: Verify the correctness of 'DOKAN_PLUGIN_ASSEST' constant

It appears that the constant DOKAN_PLUGIN_ASSEST might be misspelled. Typically, "asset" is spelled with one 's' after the 'a' (i.e., "ASSET") or as "ASSETS" in plural form. This could potentially lead to undefined constant errors if DOKAN_PLUGIN_ASSEST is not properly defined elsewhere in the codebase. Please verify that this constant is correctly defined and consistently used.

Run the following script to check for the definition and usage of DOKAN_PLUGIN_ASSEST and to identify any possible typos:

✅ Verification successful

'DOKAN_PLUGIN_ASSEST' is correctly defined and used consistently.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify if 'DOKAN_PLUGIN_ASSEST' is defined and check for any misspellings.

# Expected: 'DOKAN_PLUGIN_ASSEST' should be defined, and there should be no occurrences of 'DOKAN_PLUGIN_ASSET' or 'DOKAN_PLUGIN_ASSETS'.

# Search for the definition of 'DOKAN_PLUGIN_ASSEST'
rg "define\(\s*'DOKAN_PLUGIN_ASSEST'"

# Search for any uses of 'DOKAN_PLUGIN_ASSET' or 'DOKAN_PLUGIN_ASSETS' which might indicate a typo
rg "DOKAN_PLUGIN_ASSET\b"
rg "DOKAN_PLUGIN_ASSETS\b"

Length of output: 195

Comment on lines +1 to +7
const NotFound = () => {
return (
<div>
<h1>404 - Not Found!</h1>
</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

Consider enhancing the NotFound component for better user experience and maintainability.

While the current implementation is functional, consider the following improvements:

  1. Use more semantic HTML elements, such as <main> or <section>.
  2. Add a brief explanation and a link back to the home page to help users navigate.
  3. Consider adding some basic styling for better visual appeal.
  4. Add TypeScript type annotation for the component.

Here's an example of how you could improve the component:

import React from 'react';
import { Link } from 'react-router-dom';

const NotFound: React.FC = () => {
  return (
    <main className="not-found">
      <h1>404 - Not Found!</h1>
      <p>Sorry, the page you are looking for does not exist.</p>
      <Link to="/">Go back to homepage</Link>
    </main>
  );
}

export default NotFound;

Note: This assumes you're using React Router for navigation. If not, adjust the import and Link component accordingly.

Comment on lines +1 to +7
import {Slot} from "@wordpress/components";

const Footer = () => {
return <><Slot name="dokan-footer-area" /></>;
};

export default Footer;
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

Consider enhancing type safety and documentation.

The Footer component looks good overall, but consider these enhancements:

  1. Add TypeScript type annotations:

    import React from 'react';
    import { Slot } from "@wordpress/components";
    
    const Footer: React.FC = () => <Slot name="dokan-footer-area" />;
    
    export default Footer;
  2. Add a JSDoc comment to describe the component's purpose and usage:

    /**
     * Footer component that renders a slot for the "dokan-footer-area".
     * This allows for dynamic injection of content into the footer area.
     *
     * @returns {React.ReactElement} The Footer component
     */
    const Footer: React.FC = () => <Slot name="dokan-footer-area" />;

These changes would improve type safety and make the component's purpose clearer to other developers.

Would you like me to prepare a diff with these changes?

Comment on lines +11 to +12
const ThemeContext = createContext( null );

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

Provide a default value for ThemeContext to enhance type safety.

Currently, ThemeContext is initialized with null, which could lead to undefined errors when consuming the context without a provider. It's advisable to provide a default value that matches the expected shape of the context to improve type safety and prevent potential runtime errors.

Apply this diff to set a default value for ThemeContext:

-const ThemeContext = createContext( null );
+interface ThemeContextType {
+  theme: string;
+  setTheme: React.Dispatch<React.SetStateAction<string>>;
+}
+
+const ThemeContext = createContext<ThemeContextType>({
+  theme: 'light',
+  setTheme: () => {},
+});

This defines an interface for the context and provides a default implementation.

📝 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 ThemeContext = createContext( null );
interface ThemeContextType {
theme: string;
setTheme: React.Dispatch<React.SetStateAction<string>>;
}
const ThemeContext = createContext<ThemeContextType>({
theme: 'light',
setTheme: () => {},
});

<ContentArea>{ children }</ContentArea>
{ footerComponent ? footerComponent : <Footer /> }
</div>
<PluginArea scope={route.id} />
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 a null check for route to prevent potential runtime errors.

In <PluginArea scope={route.id} />, if route or route.id is undefined or null, it could lead to a runtime error. It's advisable to include a null check to ensure that route is defined before attempting to access its properties.

Apply this diff to add a safety check:

-<PluginArea scope={route.id} />
+{ route?.id && <PluginArea scope={route.id} /> }

This change ensures that the PluginArea is only rendered when route and route.id are valid.

📝 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
<PluginArea scope={route.id} />
{ route?.id && <PluginArea scope={route.id} /> }

id: 'dokan-kola',
title: __( 'Kola bagan', 'dokan-lite' ),
element: <h1>asdasd</h1>,
path: '/kola',
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

Ensure consistent use of path prefixes in route definitions

The path properties in your route definitions are inconsistent. Some paths start with a '/' while others do not. This inconsistency can lead to unexpected routing behavior. It's recommended to consistently start all paths with a '/'.

Apply this diff to make the paths consistent:

             path: '/kola',
             path: '/',
-            path: 'settings',
+            path: '/settings',
-            path: 'store',
+            path: '/store',

Also applies to: 36-36, 46-46, 57-57

colors: {
primary: 'var(--dokan-button-background-color, #F05025)',
dokan: {
sidebar: 'var(--dokan-button-background-color, #1B233B)',
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

Potential typo in 'sidebar' color variable

In line 51, the sidebar color is set to 'var(--dokan-button-background-color, #1B233B)'. This seems inconsistent with the variable naming convention used elsewhere. Should it be 'var(--dokan-sidebar-background-color, #1B233B)' to match the sidebar background color variable used in the backgroundColor section?

Apply this diff to correct the variable name:

                     sidebar: 'var(--dokan-button-background-color, #1B233B)',
+                    sidebar: 'var(--dokan-sidebar-background-color, #1B233B)',
📝 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
sidebar: 'var(--dokan-button-background-color, #1B233B)',
sidebar: 'var(--dokan-sidebar-background-color, #1B233B)',

/** @type {import('tailwindcss').Config} */
const baseConfig = {
important: rootClass,
content: [ './src/**/*.{js,jsx,ts,tsx}', '!./**/*.asset.php' ],
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

Use 'exclude' option instead of negation in 'content' array

In line 11, the content array includes a negation pattern '!./**/*.asset.php'. Tailwind CSS does not support negation patterns in the content array. Instead, you should use the exclude option to exclude files or directories.

Apply this diff to correct the configuration:

 const baseConfig = {
     important: rootClass,
-    content: [ './src/**/*.{js,jsx,ts,tsx}', '!./**/*.asset.php' ],
+    content: [ './src/**/*.{js,jsx,ts,tsx}' ],
+    exclude: [ './**/*.asset.php' ],
     theme: {

Committable suggestion was skipped due to low confidence.

Comment on lines +869 to +870
wp_enqueue_script( 'dokan-react-frontend' );
wp_enqueue_style( 'dokan-react-frontend' );
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

Conditionally enqueue 'dokan-react-frontend' assets to optimize performance

Currently, the scripts and styles for 'dokan-react-frontend' are enqueued unconditionally in the dokan_dashboard_scripts() method. Loading these assets on pages where they are not required can negatively impact performance. Consider enqueueing these assets only when they are needed.

For example, you can modify the code to enqueue the assets conditionally:

if ( /* condition to check if the assets are needed */ ) {
    wp_enqueue_script( 'dokan-react-frontend' );
    wp_enqueue_style( 'dokan-react-frontend' );
}

Replace /* condition to check if the assets are needed */ with the appropriate conditional logic based on your application's requirements.

Comment on lines +562 to +566
'dokan-react-frontend' => [
'src' => $asset_url . '/js/frontend.js',
'deps' => $frontend_shipping_asset['dependencies'],
'version' => $frontend_shipping_asset['version'],
],
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

Update variable references after renaming

Following the renaming of $frontend_shipping_asset to $frontend_asset, please update the variable references in the script registration to reflect this change.

Apply this diff to update the variable references:

 'dokan-react-frontend' => [
     'src'     => $asset_url . '/js/frontend.js',
-    'deps'    => $frontend_shipping_asset['dependencies'],
-    'version' => $frontend_shipping_asset['version'],
+    'deps'    => $frontend_asset['dependencies'],
+    'version' => $frontend_asset['version'],
 ],
📝 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
'dokan-react-frontend' => [
'src' => $asset_url . '/js/frontend.js',
'deps' => $frontend_shipping_asset['dependencies'],
'version' => $frontend_shipping_asset['version'],
],
'dokan-react-frontend' => [
'src' => $asset_url . '/js/frontend.js',
'deps' => $frontend_asset['dependencies'],
'version' => $frontend_asset['version'],
],

@@ -365,6 +369,7 @@ public function get_styles() {
public function get_scripts() {
global $wp_version;

$frontend_shipping_asset = require DOKAN_DIR . '/assets/js/frontend.asset.php';
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

Correct the variable name to match the asset being loaded

The variable $frontend_shipping_asset is assigned the contents of frontend.asset.php. The name suggests it's related to shipping assets, which might be misleading in this context. To improve clarity and maintain consistent naming conventions, please rename the variable to $frontend_asset.

Apply this diff to correct the variable name:

-$frontend_shipping_asset = require DOKAN_DIR . '/assets/js/frontend.asset.php';
+$frontend_asset = require DOKAN_DIR . '/assets/js/frontend.asset.php';

Ensure to update all references to $frontend_shipping_asset accordingly.

📝 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
$frontend_shipping_asset = require DOKAN_DIR . '/assets/js/frontend.asset.php';
$frontend_asset = require DOKAN_DIR . '/assets/js/frontend.asset.php';

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

🧹 Outside diff range and nitpick comments (1)
src/Layout/index.tsx (1)

46-69: LGTM: Layout component structure is well-designed and flexible.

The Layout component is well-structured and provides flexibility through conditional rendering of header and footer components. The use of SlotFillProvider is appropriate for WordPress plugin integration.

Consider using default prop values for better readability:

const Layout = ({
    children,
    route,
-   title = '',
+   title = '', // Consider moving this default to the prop definition
    headerComponent,
    footerComponent,
}: LayoutProps) => {
    // ...
}

This change doesn't affect functionality but can improve code readability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between a2701f5 and 057a92f.

📒 Files selected for processing (4)
  • src/Dashboard/index.tsx (1 hunks)
  • src/Layout/Header.tsx (1 hunks)
  • src/Layout/index.tsx (1 hunks)
  • src/Routing/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Dashboard/index.tsx
  • src/Layout/Header.tsx
  • src/Routing/index.tsx
🧰 Additional context used
🔇 Additional comments (6)
src/Layout/index.tsx (6)

1-9: LGTM: Imports are appropriate and comprehensive.

The imports cover all necessary dependencies for the component's functionality, including WordPress-specific elements and custom components.


14-22: LGTM: ThemeProvider implementation is correct and follows best practices.

The ThemeProvider component correctly manages the theme state and provides it to its children through the context. The use of useState for theme management is appropriate for this use case.


24-43: LGTM: Type definitions are comprehensive and enhance type safety.

The DokanRoute type and LayoutProps interface provide clear and comprehensive type definitions, which will improve code readability and catch potential type-related errors early in development.


72-74: LGTM: useTheme custom hook is correctly implemented.

The useTheme custom hook provides a convenient way to access the theme context in other components. Its implementation follows React hook conventions.


76-76: LGTM: Default export is correct.

The Layout component is correctly exported as the default export, following common React component export patterns.


1-76: Overall, the Layout component is well-implemented with room for minor improvements.

The new Layout component provides a flexible and type-safe structure for the application. It effectively integrates WordPress-specific components and implements theming capabilities. The code follows React best practices and is well-organized.

To further improve the code:

  1. Address the issue raised in the previous review comment regarding the default value for ThemeContext (lines 11-12).
  2. Implement the null check for route.id as suggested in the previous review comment (line 65).
  3. Consider moving the default value for the title prop to the prop definition for improved readability.

These changes will enhance the robustness and maintainability of the component.

To ensure that the Layout component is being used correctly throughout the project, you can run the following verification script:

This script will help identify where the Layout component and useTheme hook are being used, allowing you to verify that they are being implemented correctly across the project.

mralaminahamed and others added 2 commits October 21, 2024 13:47
This commit introduces a new REST API endpoint for searching customers
specific to a vendor's orders. Key changes include:

- Add new route `/dokan/v1/customers/search` in CustomersController
- Implement `search_customers` method with the following features:
  * Search customers by ID or term (name/email)
  * Limit results to customers who have ordered from the current vendor
  * Support excluding specific customer IDs
  * Limit results to 20 when search term is less than 3 characters
  * Apply `dokan_json_search_found_customers` filter for extensibility
- Add permission check to ensure only users with 'edit_shop_orders' capability can access
- Include detailed PHPDoc for the new filter

This feature allows vendors to efficiently search their customer base
through the REST API, mirroring the functionality of the existing AJAX action
while providing a standardized API interface.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
src/Routing/index.tsx (2)

1-5: Remove unused imports to improve code cleanliness and performance.

The following imports are not used in this file and should be removed:

  • redirect
  • replace

Apply this diff to remove unused imports:

-import { useNavigate, useParams, useLocation, redirect, replace, useMatches, useNavigation,  } from 'react-router-dom';
+import { useNavigate, useParams, useLocation, useMatches, useNavigation } from 'react-router-dom';

7-41: LGTM! Minor formatting suggestion.

The withRouter higher-order component is well-implemented and provides a good abstraction for adding routing props to other components. It correctly handles both function and element components.

Consider removing extra spaces in the parameter destructuring for consistency:

-        let params   = useParams();
+        let params = useParams();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 057a92f and 3d4d19c.

📒 Files selected for processing (2)
  • src/Dashboard/index.tsx (1 hunks)
  • src/Routing/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Dashboard/index.tsx
🧰 Additional context used
🔇 Additional comments (2)
src/Routing/index.tsx (2)

70-70: LGTM! Default export is correct.

The default export of the getRoutes function is appropriate and follows good module design practices.


43-68: ⚠️ Potential issue

Address TypeScript errors and ensure consistent path prefixes.

  1. The paths in the route definitions are inconsistent. Some start with '/' while others don't. This can lead to unexpected routing behavior.

  2. The use of @ts-ignore suppresses TypeScript errors, which can hide potential issues. Instead, properly type the wp object.

To resolve these issues:

  1. Make the paths consistent by adding a leading '/' to all paths:
-            path: 'settings',
+            path: '/settings',
  1. Remove the @ts-ignore comment and properly type the wp object. You can declare the type for wp or extend the Window interface:
declare global {
  interface Window {
    wp: {
      hooks: {
        applyFilters: (filterName: string, value: any, ...args: any[]) => any;
      };
    };
  }
}

routes = window.wp.hooks.applyFilters('dokan-dashboard-routes', routes) as Array<DokanRoute>;

These changes will improve type safety and consistency in your routing logic.

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

🧹 Outside diff range and nitpick comments (2)
src/Routing/index.tsx (2)

1-5: Consider optimizing imports from react-router-dom

The current import from react-router-dom includes several hooks that might not all be necessary. To improve code maintainability and potentially reduce bundle size, consider importing only the hooks that are actually used in this file.

You could refactor the import like this:

import { useNavigate, useParams, useLocation, useMatches, useNavigation } from 'react-router-dom';

Note that redirect and replace are not used in this file and can be removed from the import.


7-39: Excellent implementation of withRouter HOC

The withRouter higher-order component is well-implemented, providing flexibility for both function components and React elements. It correctly uses React Router hooks to inject routing props into the wrapped component.

For improved type safety, consider adding TypeScript types to the Component parameter and return type:

export function withRouter<P extends object>(Component: React.ComponentType<P>): React.FC<Omit<P, keyof typeof routerProps>> {
  // ... existing implementation ...
}

This change will provide better type inference for components wrapped with withRouter.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 15994f8 and c295722.

📒 Files selected for processing (1)
  • src/Routing/index.tsx (1 hunks)
🧰 Additional context used
🔇 Additional comments (1)
src/Routing/index.tsx (1)

1-68: Overall, well-implemented routing setup with minor improvements suggested

This file introduces a robust routing system for the React application, including a flexible withRouter HOC and a extensible getRoutes function. The implementation follows good practices and allows for easy integration with WordPress hooks.

The suggested improvements focus on:

  1. Optimizing imports for better maintainability.
  2. Enhancing type safety, particularly in the withRouter HOC and when using WordPress hooks.
  3. Ensuring consistency in route path definitions.

These changes will further improve the code quality and maintainability of this crucial routing component.

Comment on lines +41 to +68
const getRoutes = () => {
let routes : Array<DokanRoute> = [];

routes.push(
{
id: 'dokan-base',
title: __( 'Dashboard', 'dokan-lite' ),
element: <h1>Dashboard body</h1>,
path: '/',
exact: true,
order: 10,
}
);

// @ts-ignore
routes = wp.hooks.applyFilters('dokan-dashboard-routes', routes) as Array<DokanRoute>;
routes.push(
{
id: 'dokan-404',
element: <NotFound />,
path: '*',
}
);

return routes;
}

export default getRoutes;
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 type safety and consistency in route definitions

The getRoutes function is well-structured and allows for extensibility through WordPress hooks. However, there are a couple of areas for improvement:

  1. TypeScript error suppression:
    The use of @ts-ignore is hiding potential type issues. Instead, consider properly typing the wp.hooks.applyFilters function.

  2. Inconsistent path definitions:
    Some paths start with '/' while others don't, which can lead to routing inconsistencies.

To address these issues:

  1. Replace the @ts-ignore with proper typing:
declare global {
  interface Window {
    wp: {
      hooks: {
        applyFilters<T>(hookName: string, ...args: any[]): T;
      };
    };
  }
}

routes = window.wp.hooks.applyFilters<Array<DokanRoute>>('dokan-dashboard-routes', routes);
  1. Ensure all paths start with '/':
routes.push(
  {
    id: 'dokan-base',
    title: __( 'Dashboard', 'dokan-lite' ),
    element: <h1>Dashboard body</h1>,
    path: '/',  // This is correct
    exact: true,
    order: 10,
  }
);

// ... other routes ...

routes.push(
  {
    id: 'dokan-404',
    element: <NotFound />,
    path: '/*',  // Change this to '/*' for consistency
  }
);

These changes will improve type safety and ensure consistent routing behavior.

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

🧹 Outside diff range and nitpick comments (2)
src/Layout/Header.tsx (2)

7-18: LGTM: Well-structured and flexible component rendering.

The component's structure is well-organized and utilizes Tailwind CSS for responsive styling. The use of Slot components for extensibility is a great practice. The conditional rendering of the title and passing of the navigate function to the header actions slot are implemented correctly.

Consider adding an aria-label to the outer div to improve accessibility:

- <div className="flex items-center sm:flex-wrap md:flex-nowrap">
+ <div className="flex items-center sm:flex-wrap md:flex-nowrap" aria-label="Page header">

1-21: Overall: Excellent implementation of the Header component.

This Header component is well-implemented and aligns perfectly with the PR objectives of setting up a skeleton for the new vendor dashboard. It provides a flexible and extensible structure, utilizing WordPress components and React Router for navigation. The use of Slot components allows for easy customization, which is crucial for a dashboard layout.

The component follows React best practices, uses modern functional component syntax, and leverages Tailwind CSS for responsive styling. This implementation sets a solid foundation for further development of the dashboard layout.

As you continue developing the dashboard, consider the following:

  1. Implement unit tests for this component to ensure its behavior remains consistent as the project evolves.
  2. Document the usage of the Slot components to guide other developers on how to extend the header functionality.
  3. Consider creating a theme context if you plan to implement dark mode or other theme variations in the future.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c295722 and 0b1ce02.

📒 Files selected for processing (1)
  • src/Layout/Header.tsx (1 hunks)
🧰 Additional context used
🔇 Additional comments (4)
src/Layout/Header.tsx (4)

1-2: LGTM: Imports are appropriate and necessary.

The imports of Slot from @wordpress/components and useNavigate from react-router-dom are well-chosen for the component's requirements. They align with the WordPress ecosystem and provide necessary routing functionality.


4-4: LGTM: Component definition is clear and follows best practices.

The Header component is well-defined as a functional component with a descriptive name. The use of default prop value for title is a good practice for handling optional props.


5-5: LGTM: Proper use of the useNavigate hook.

The useNavigate hook is correctly used and stored in a well-named constant. This setup will allow for programmatic navigation within the component.


21-21: LGTM: Appropriate default export.

The default export of the Header component is correct and follows common React component export patterns.

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

🧹 Outside diff range and nitpick comments (1)
includes/REST/DokanDataCountriesController.php (1)

80-80: Update the @since tags with the correct version numbers.

The @since annotations currently use placeholders DOKAN_SINCE and DOKAN_PRO_SINCE. Please replace them with the appropriate version numbers before merging to maintain accurate documentation.

Also applies to: 107-107

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 0b1ce02 and e59521e.

📒 Files selected for processing (3)
  • includes/REST/DokanDataContinentsController.php (1 hunks)
  • includes/REST/DokanDataCountriesController.php (1 hunks)
  • includes/REST/Manager.php (1 hunks)
🧰 Additional context used
🪛 GitHub Check: Run PHPCS inspection
includes/REST/DokanDataContinentsController.php

[warning] 31-31:
Possible useless method overriding detected

includes/REST/DokanDataCountriesController.php

[warning] 31-31:
Possible useless method overriding detected

🔇 Additional comments (8)
includes/REST/Manager.php (1)

237-238: LGTM! Verify controller files exist.

The new REST API controller mappings follow the established pattern and are well-aligned with the vendor dashboard requirements.

Let's verify the existence of the new controller files:

✅ Verification successful

Since both controller files were found in the expected location (includes/REST/), I can now generate the final response. The verification was successful as both files exist exactly where they are referenced in the Manager.php file.

✓ Controller files verified and present

Both new REST API controller files are correctly placed in the expected location:

  • includes/REST/DokanDataCountriesController.php
  • includes/REST/DokanDataContinentsController.php
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the new REST API controller files exist
# Expected: Both files should exist in the includes/REST directory

echo "Checking for REST API controller files..."
for file in "DokanDataCountriesController.php" "DokanDataContinentsController.php"; do
    if fd -p "includes/REST/$file$"; then
        echo "✓ Found: $file"
    else
        echo "✗ Missing: $file"
    fi
done

Length of output: 662

includes/REST/DokanDataCountriesController.php (2)

87-87: Verify the capability 'dokandar' used in permission checks.

Ensure that 'dokandar' is the correct capability or role intended for permission checks. If it's a custom role or capability, confirm that it is properly registered and that using current_user_can( 'dokandar' ) will function as expected.


116-122: ⚠️ Potential issue

Review the permission override in add_subscriptions_read_permission_to_vendors().

The method grants read permissions unconditionally by returning true when $context is 'read'. This could allow users without the necessary permissions to access data they shouldn't. Please ensure this behavior is intended and does not introduce security risks.

includes/REST/DokanDataContinentsController.php (5)

42-46: Verify the necessity of setting permissions in get_items

In the get_items method, you're calling $this->set_woocommerce_rest_check_permissions(); before invoking the parent method. Verify if setting the permissions here is required, or if it can be managed elsewhere to avoid repetitive calls.


55-58: Verify the necessity of setting permissions in get_item

Similar to get_items, the get_item method calls $this->set_woocommerce_rest_check_permissions();. Ensure this is necessary and consider consolidating permission setups to a central location if possible.


67-74: Review the permission check logic in get_item_permissions_check

The method get_item_permissions_check calls both $this->set_woocommerce_rest_check_permissions(); and $this->get_items_permissions_check( $request ) before invoking the parent method. Confirm that this sequence is intentional and doesn't introduce redundant permission checks.


116-122: Review the permission logic in add_subscriptions_read_permission_to_vendors

The method returns true for any context where $context is 'read', granting read permissions universally. Ensure this aligns with your security requirements and doesn't inadvertently expose sensitive data to unauthorized users.


85-98: Confirm the capability checks in get_items_permissions_check

The capability checks using current_user_can( dokan_admin_menu_capability() ) and current_user_can( 'dokandar' ) are critical for security. Ensure that these capabilities correctly represent the intended user roles and that unauthorized access is properly restricted.

Run the following script to locate where these capabilities are defined and how they're used throughout the codebase:

✅ Verification successful

Let me gather more information about these capabilities with refined search patterns.


Based on the search results, I can now provide a comprehensive verification of the capability checks.

The capability checks in get_items_permissions_check are correctly implemented

The capability checks are properly implemented and align with the plugin's security model:

  1. dokan_admin_menu_capability() is defined in includes/functions.php and returns 'manage_woocommerce' by default (filterable via 'dokan_menu_capability')
  2. The 'dokandar' capability is:
    • Added to the 'seller' role during installation (includes/Install/Installer.php)
    • Also granted to 'shop_manager' and 'administrator' roles
    • Used consistently across the codebase for vendor-specific permissions
  3. The combination of these capabilities ensures that:
    • Store administrators (with manage_woocommerce capability) have access
    • Vendors (with dokandar capability) have access
    • Other users are properly restricted with a WP_Error response
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find definitions and usages of 'dokandar' and 'dokan_admin_menu_capability'

# Search for the definition of the 'dokandar' role.
rg "add_role\(['\"]dokandar['\"]"

# Search for the definition of 'dokan_admin_menu_capability' function.
rg "function dokan_admin_menu_capability"

# Find all usages of these capabilities.
rg "current_user_can\((['\"]dokandar['\"]|dokan_admin_menu_capability\(\))"

Length of output: 233


Script:

#!/bin/bash
# Search for the definition and context of dokan_admin_menu_capability function
rg -B 2 -A 5 "function dokan_admin_menu_capability"

# Search for dokandar role/capability usage with broader context
rg -B 2 -A 2 "dokandar"

# Search for any role registration or capability setup in the codebase
rg -B 2 -A 5 "(\badd_role\b|\bregister_role\b|\bget_role\b)"

# Look for any capability-related setup files
fd -e php capability
fd -e php role

Length of output: 12743

Comment on lines +31 to +33
public function register_routes() {
parent::register_routes();
}
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

Consider removing the unnecessary method override of register_routes().

The register_routes() method overrides the parent method without adding any additional functionality. Unless there's a specific reason for this override or plans to extend it in the future, it can be removed to simplify the code.

🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[warning] 31-31:
Possible useless method overriding detected

Comment on lines +31 to +33
public function register_routes() {
parent::register_routes();
}
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

Consider removing the redundant register_routes method override

The register_routes method simply calls the parent method without adding any additional functionality. Removing this method will simplify the code without affecting behavior.

Apply this diff to remove the redundant method:

 class DokanDataContinentsController extends WC_REST_Data_Continents_Controller {

-    /**
-     * Register routes.
-     *
-     * @since 3.5.0
-     */
-    public function register_routes() {
-        parent::register_routes();
-    }
-
     // Other methods...

 }
📝 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
public function register_routes() {
parent::register_routes();
}
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[warning] 31-31:
Possible useless method overriding detected

Comment on lines +100 to +102
private function set_woocommerce_rest_check_permissions() {
add_filter( 'woocommerce_rest_check_permissions', [ $this, 'add_subscriptions_read_permission_to_vendors' ], 10, 4 );
}
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

Avoid adding the same filter multiple times

The set_woocommerce_rest_check_permissions method adds a filter each time it's called. If multiple methods call this within the same request, the filter could be added repeatedly. Consider adding the filter once, possibly in the constructor, to prevent redundant additions.

Apply this diff to move the filter setup to the constructor:

 class DokanDataContinentsController extends WC_REST_Data_Continents_Controller {

+    public function __construct() {
+        $this->set_woocommerce_rest_check_permissions();
+    }
+
     // Other methods...

     public function get_items( $request ) {
-        $this->set_woocommerce_rest_check_permissions();
         return parent::get_items( $request );
     }

     public function get_item( $request ) {
-        $this->set_woocommerce_rest_check_permissions();
         return parent::get_item( $request );
     }

     public function get_item_permissions_check( $request ) {
-        $this->set_woocommerce_rest_check_permissions();
         $item_permission = $this->get_items_permissions_check( $request );
         // ...
     }

     private function set_woocommerce_rest_check_permissions() {
         add_filter( 'woocommerce_rest_check_permissions', [ $this, 'add_subscriptions_read_permission_to_vendors' ], 10, 4 );
     }
     // ...
 }
📝 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
private function set_woocommerce_rest_check_permissions() {
add_filter( 'woocommerce_rest_check_permissions', [ $this, 'add_subscriptions_read_permission_to_vendors' ], 10, 4 );
}
class DokanDataContinentsController extends WC_REST_Data_Continents_Controller {
public function __construct() {
$this->set_woocommerce_rest_check_permissions();
}
// Other methods...
public function get_items( $request ) {
return parent::get_items( $request );
}
public function get_item( $request ) {
return parent::get_item( $request );
}
public function get_item_permissions_check( $request ) {
$item_permission = $this->get_items_permissions_check( $request );
// ...
}
private function set_woocommerce_rest_check_permissions() {
add_filter( 'woocommerce_rest_check_permissions', [ $this, 'add_subscriptions_read_permission_to_vendors' ], 10, 4 );
}
// ...
}

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

🧹 Outside diff range and nitpick comments (3)
src/Layout/index.tsx (1)

25-44: Add JSDoc documentation and improve type consistency.

The type definitions would benefit from documentation and consistent optionality.

+/**
+ * Represents a route configuration in the Dokan dashboard
+ */
 export type DokanRoute = {
+    /** Unique identifier for the route */
     id: string;
+    /** Display title for the route */
     title?: string;
-    icon?: JSX.Element | React.ReactNode;
+    /** Icon component to display (React.ReactNode includes JSX.Element) */
+    icon?: React.ReactNode;
-    element: JSX.Element | React.ReactNode;
+    /** Component to render for this route */
+    element: React.ReactNode;
     // ... rest of the type
 };

+/**
+ * Props for the Layout component
+ */
 interface LayoutProps {
     children: React.ReactNode;
     route: DokanRoute;
     title?: string;
-    headerComponent?: JSX.Element|React.ReactNode;
-    footerComponent?: JSX.Element|React.ReactNode;
+    headerComponent?: React.ReactNode;
+    footerComponent?: React.ReactNode;
 }
package.json (2)

64-64: Consider code-splitting for React Router.

The addition of react-router-dom is appropriate for dashboard navigation. However, ensure route-based code splitting is implemented to optimize initial load performance.

Recommendations:

  1. Use React.lazy() for route components
  2. Implement Suspense boundaries
  3. Consider implementing progressive loading for dashboard sections

Line range hint 25-64: Review bundle size impact.

The addition of multiple new dependencies could significantly increase the bundle size. Consider implementing appropriate optimization strategies.

Recommendations:

  1. Implement tree-shaking for all new dependencies
  2. Consider using dynamic imports for less frequently used components
  3. Monitor the bundle size impact using webpack-bundle-analyzer
  4. Implement chunking strategies to optimize loading performance
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between e59521e and e6bf1ec.

📒 Files selected for processing (2)
  • package.json (3 hunks)
  • src/Layout/index.tsx (1 hunks)
🔇 Additional comments (4)
src/Layout/index.tsx (1)

1-10: LGTM! Well-organized imports following WordPress conventions.

The imports are properly structured, using WordPress-specific packages where appropriate.

package.json (3)

57-63: Verify WordPress package versions compatibility.

The WordPress packages being added (@wordpress/components, @wordpress/data, etc.) are at different major versions (v28.x vs v4.x vs v7.x). This might lead to compatibility issues.

#!/bin/bash
# Check for potential version conflicts in WordPress packages
echo "Checking @wordpress/* package usage..."
rg -l "@wordpress" | xargs cat | rg "from '@wordpress/"

56-56: Verify @getdokan/dokan-ui compatibility.

The addition of @getdokan/dokan-ui (v1.0.14) is a significant change. Ensure it's compatible with the WordPress admin environment and follows the project's design system.

#!/bin/bash
# Check for potential UI component usage
echo "Checking dokan-ui component usage..."
rg -l "@getdokan/dokan-ui" | xargs cat | rg "from '@getdokan/dokan-ui"

25-26: Verify Tailwind CSS configuration to prevent style conflicts.

The addition of Tailwind CSS utilities (@tailwindcss/forms, @tailwindcss/typography, tailwindcss-scoped-preflight) is appropriate for a modern React dashboard. However, ensure proper scoping to prevent conflicts with WordPress admin styles.

Consider the following recommendations:

  1. Use tailwindcss-scoped-preflight to scope Tailwind's base styles
  2. Configure content paths in tailwind.config.js to minimize bundle size
  3. Add appropriate CSS cascade layers to manage style precedence

Also applies to: 39-39

Comment on lines +47 to +71
const Layout = ( {
children,
route,
title = '',
headerComponent,
footerComponent,
}: LayoutProps ) => {
return (
<ThemeProvider>
<SlotFillProvider>
<div className="dokan-layout">
{ headerComponent ? (
headerComponent
) : (
<Header title={ title } />
) }
<ContentArea>{ children }</ContentArea>
{ footerComponent ? footerComponent : <Footer /> }
</div>
<PluginArea scope={route.id} />
<DokanToaster />
</SlotFillProvider>
</ThemeProvider>
);
};
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

Consider adding error boundaries and improving accessibility.

The Layout component should handle errors gracefully and provide proper ARIA attributes.

Consider implementing an error boundary:

class LayoutErrorBoundary extends React.Component<{children: React.ReactNode}> {
  state = { hasError: false };
  
  static getDerivedStateFromError() {
    return { hasError: true };
  }
  
  render() {
    if (this.state.hasError) {
      return <div role="alert">Something went wrong. Please try again.</div>;
    }
    return this.props.children;
  }
}

Then wrap the layout content:

 const Layout = ({ ... }: LayoutProps ) => {
   return (
     <ThemeProvider>
       <SlotFillProvider>
+        <LayoutErrorBoundary>
         <div className="dokan-layout">
-          { headerComponent ? (
-            headerComponent
-          ) : (
-            <Header title={ title } />
-          ) }
+          <header role="banner">
+            { headerComponent || <Header title={ title } /> }
+          </header>
           <ContentArea>{ children }</ContentArea>
-          { footerComponent ? footerComponent : <Footer /> }
+          <footer role="contentinfo">
+            { footerComponent || <Footer /> }
+          </footer>
         </div>
+        </LayoutErrorBoundary>
         <PluginArea scope={route.id} />
         <DokanToaster />
       </SlotFillProvider>
     </ThemeProvider>
   );
 };

Comment on lines +74 to +76
export const useTheme = () => {
return useContext( ThemeContext );
};
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 handling to useTheme hook.

The hook should handle cases where it's used outside of ThemeProvider.

 export const useTheme = () => {
-    return useContext( ThemeContext );
+    const context = useContext( ThemeContext );
+    if (context === null) {
+        throw new Error('useTheme must be used within a ThemeProvider');
+    }
+    return context;
 };
📝 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 useTheme = () => {
return useContext( ThemeContext );
};
export const useTheme = () => {
const context = useContext( ThemeContext );
if (context === null) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
};

Comment on lines +15 to +23
const ThemeProvider = ( { children } ) => {
const [ theme, setTheme ] = useState( 'light' ); // Example theme state

return (
<ThemeContext.Provider value={ { theme, setTheme } }>
{ children }
</ThemeContext.Provider>
);
};
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

Enhance type safety for theme values.

The theme state should be constrained to specific valid values.

+type ThemeType = 'light' | 'dark';
+
 const ThemeProvider = ( { children } ) => {
-    const [ theme, setTheme ] = useState( 'light' ); // Example theme state
+    const [ theme, setTheme ] = useState<ThemeType>( 'light' );
📝 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 ThemeProvider = ( { children } ) => {
const [ theme, setTheme ] = useState( 'light' ); // Example theme state
return (
<ThemeContext.Provider value={ { theme, setTheme } }>
{ children }
</ThemeContext.Provider>
);
};
type ThemeType = 'light' | 'dark';
const ThemeProvider = ( { children } ) => {
const [ theme, setTheme ] = useState<ThemeType>( 'light' );
return (
<ThemeContext.Provider value={ { theme, setTheme } }>
{ children }
</ThemeContext.Provider>
);
};

…er-api' into update/vendor-dashboard-structure

# Conflicts:
#	includes/REST/Manager.php
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: 13

🧹 Outside diff range and nitpick comments (10)
includes/REST/CustomersController.php (6)

216-221: Simplify String Concatenation Without sprintf

The use of sprintf with a single %s placeholder is unnecessary when concatenating strings. You can simplify the code by directly concatenating the first and last names.

Apply this diff to simplify:

 $found_customers[ $id ] = [
     'id' => $id,
-    'name' => sprintf(
-        '%s',
-        $customer->get_first_name() . ' ' . $customer->get_last_name()
-    ),
+    'name' => $customer->get_first_name() . ' ' . $customer->get_last_name(),
     'email' => $customer->get_email(),
 ];

185-192: Handle Non-Existent Customer IDs Gracefully

When searching by ID, if a customer does not exist, $customer->get_id() will return 0. However, there's no handling for invalid IDs beyond that. Consider providing feedback if no customer is found.

Apply this diff to add an else case:

 if ( is_numeric( $term ) ) {
     $customer = new WC_Customer( intval( $term ) );

     // Customer exists.
     if ( 0 !== $customer->get_id() ) {
         $ids = [ $customer->get_id() ];
+    } else {
+        // No customer found with that ID.
+        return rest_ensure_response( [] );
     }
 }

216-223: Handle Missing Customer Names Gracefully

When constructing the customer name, if either the first name or last name is empty, the result may have leading or trailing spaces. Consider trimming the result or handling empty names.

Apply this diff to handle empty names:

 $customer_name = trim( $customer->get_first_name() . ' ' . $customer->get_last_name() );
 $found_customers[ $id ] = [
     'id' => $id,
-    'name' => $customer->get_first_name() . ' ' . $customer->get_last_name(),
+    'name' => $customer_name ? $customer_name : __( 'Guest', 'dokan-lite' ),
     'email' => $customer->get_email(),
 ];

This ensures the name is properly formatted and defaults to 'Guest' if no name is available.


244-245: Replace DOKAN_SINCE with Actual Version Number

In the documentation block, @since DOKAN_SINCE is used, which might be a placeholder. Replace it with the actual version number when releasing.

  * @since DOKAN_SINCE
+ * @since 3.7.5

Ensure that the version number reflects the release in which this feature is introduced.


170-247: Consider Caching Customer Search Results

For better performance, especially under heavy load, consider caching the results of customer searches to reduce database queries.

Implement caching mechanisms like transient API or object caching to store frequent search results.


1-13: Missing Class Documentation

The CustomersController class lacks a documentation block explaining its purpose. Adding a docblock improves readability and maintainability.

Apply this diff to add class documentation:

 class CustomersController extends WC_REST_Customers_Controller {

+    /**
+     * Dokan Customers REST Controller.
+     *
+     * Extends WooCommerce Customers Controller to add vendor-specific capabilities.
+     */
tests/php/src/REST/CustomersControllerTest.php (4)

35-59: Initialize Parent setUp Method First

In the setUp method, it's a best practice to call parent::setUp(); after initializing the properties specific to this test class. This ensures that any initializations done in the parent class are not overridden by subclass initializations.

Apply this diff to adjust the order:

 protected function setUp(): void {
-    parent::setUp();

     $this->controller = new CustomersController();

     // Create test customers with specific data
     $this->customer_data = [
         [
             'first_name' => 'John',
             'last_name'  => 'Doe',
             'email'      => '[email protected]',
             'username'   => 'johndoe',
         ],
         [
             'first_name' => 'Jane',
             'last_name'  => 'Smith',
             'email'      => '[email protected]',
             'username'   => 'janesmith',
         ],
     ];

     foreach ( $this->customer_data as $data ) {
         $this->customers[] = $this->factory()->customer->create( $data );
     }

+    parent::setUp();
 }

100-106: Reset User Outside the Loop

Inside the foreach loop in test_endpoint_permissions, wp_set_current_user( 0 ); is called at the beginning of each iteration. Since all test cases require the user to be not authenticated, consider setting the current user to 0 before the loop to enhance readability.

Apply this diff:

+wp_set_current_user( 0 );

 foreach ( $test_cases as [ $method, $endpoint, $expected_status, $expected_code ] ) {

-    wp_set_current_user( 0 );

     $response = $this->request( $method, $endpoint );

     $this->assertEquals( $expected_status, $response->get_status() );
     $this->assertEquals( $expected_code, $response->get_data()['code'] );
 }

145-146: Use Appropriate Assertion Methods for Readability

The conditional inside assertTrue can be replaced with a more specific assertion for better readability and clearer test failure messages.

Replace the assertTrue with assertGreaterThanOrEqual:

-$this->assertTrue(
-    strtotime( $data[0]['date_created'] ) >= strtotime( $data[1]['date_created'] )
-);
+$this->assertGreaterThanOrEqual(
+    strtotime( $data[1]['date_created'] ),
+    strtotime( $data[0]['date_created'] )
+);

565-567: Redundant Verification of Customer Role

In the assertion after updating the customer roles, the test repeats the same check as before. Since the roles weren't changed in the update, this assertion may not provide additional value.

Consider adjusting the update data to change the roles and then verify that the change occurred.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between e6bf1ec and 8b2b753.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • includes/REST/CustomersController.php (1 hunks)
  • includes/REST/Manager.php (1 hunks)
  • tests/php/src/REST/CustomersControllerTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • includes/REST/Manager.php
🔇 Additional comments (6)
includes/REST/CustomersController.php (2)

257-271: ⚠️ Potential issue

Verify the Use of Undefined $this->post_type

In the prepare_object_for_database method, you're using $this->post_type in the filter hook name, but $post_type is not defined in this class. This may lead to an undefined property notice.

Run the following script to check if $this->post_type is defined or inherited:

If $this->post_type is not defined, consider defining it or adjusting the filter to use the appropriate property.


198-204: Confirm the Usage of $limit in Customer Search

The variable $limit is set based on the length of the search term but is initialized as an empty string. Ensure that the $limit variable is correctly utilized in the search_customers method of the data store.

Run the following script to check if $limit is used appropriately in search_customers:

If $limit is expected to be an integer, ensure it is properly defined.

✅ Verification successful

The previous search didn't give us the complete picture. Let's try to find the data store implementation and how it handles the search_customers method. This will help us verify if the $limit parameter is properly utilized.


Let's try a broader search since the DataStore directory wasn't found. This will help us locate where the search_customers method is implemented and how it handles the limit parameter.


From the previous results, we can see that search_customers is called on a $data_store object, but we need to find its implementation to verify how it handles the $limit parameter. Since this appears to be a WooCommerce integration, let's look for the customer data store implementation.


The $limit variable is properly initialized and used

The code is correctly handling the $limit variable:

  1. It's initialized as an empty string: $limit = '';
  2. When the search term is less than 3 characters, it's set to 20: $limit = 20;
  3. The $limit parameter is then passed to WooCommerce's core customer data store's search_customers method through $data_store->search_customers($term, $limit)

This is the expected behavior as it limits the result set only for short search terms to prevent performance issues with too many results.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the $limit parameter is used correctly in search_customers method.

# Test: Search for the definition of search_customers and its parameters.
rg -A 5 'function search_customers' includes/

Length of output: 1018


Script:

#!/bin/bash
# Let's search for the data store implementation and check how $limit is used
rg -A 10 'class.*DataStore' includes/

# Also search for any search_customers method in data store files
rg -A 10 'search_customers' includes/DataStore/

Length of output: 147


Script:

#!/bin/bash
# Let's try to find all files that might contain the data store implementation
fd -t f -e php

# And then search for search_customers implementation in all PHP files
rg -A 10 'search_customers' --type php

Length of output: 20674


Script:

#!/bin/bash
# Let's find the data store implementation that contains the search_customers method
rg -A 5 'class.*WC_Customer_Data_Store' --type php

# Also search for any WooCommerce core data store references
rg -A 5 'WC_Data_Store::load.*customer' --type php

Length of output: 2342

tests/php/src/REST/CustomersControllerTest.php (4)

128-129: Clarify Expected Customer Count

In test_get_items, the assertion expecting a count of 3 customers may be confusing because only two customers are created in the setUp method. Ensure that the test environment contains three customers or update the expected count accordingly.

Confirm whether there's an additional customer being included unintentionally.


246-254: Ensure Valid Email Format in Test Data

In the test_update_item method, when updating a customer's email, ensure that the new email address is unique and valid. Using an email like '[email protected]' may clash with existing users if the tests run multiple times.

Check if the email '[email protected]' is unique in the test environment to prevent conflicts.


473-473: Incorrect Assertion About Meta Data Support

The comment states that the WooCommerce API does not support meta data retrieval, and asserts that 'meta_data' should not be present in the response. However, if the API does support meta data, this assertion would fail.

Confirm whether the WooCommerce API supports 'meta_data' in customer responses. If it does, adjust the test accordingly.


431-433: Duplicate Line Ranges in Review Comments

Notice that the line ranges 431-433 were already commented on earlier. Ensure that each review comment addresses distinct code segments to avoid redundancy.

Comment on lines +170 to +247
public function search_customers( $request ) {
if ( ! current_user_can( 'edit_shop_orders' ) ) {
return new WP_Error( 'dokan_rest_cannot_search', __( 'You do not have permission to search customers.', 'dokan-lite' ), [ 'status' => rest_authorization_required_code() ] );
}

$term = $request->get_param( 'search' );
$exclude = $request->get_param( 'exclude' ) ? explode( ',', $request->get_param( 'exclude' ) ) : [];
$limit = '';

if ( empty( $term ) ) {
return new WP_Error( 'dokan_rest_empty_search', __( 'Search term is required.', 'dokan-lite' ), [ 'status' => 400 ] );
}

$ids = [];
// Search by ID.
if ( is_numeric( $term ) ) {
$customer = new WC_Customer( intval( $term ) );

// Customer exists.
if ( 0 !== $customer->get_id() ) {
$ids = [ $customer->get_id() ];
}
}

// Usernames can be numeric so we first check that no users was found by ID before searching for numeric username, this prevents performance issues with ID lookups.
if ( empty( $ids ) ) {
$data_store = WC_Data_Store::load( 'customer' );

// If search is smaller than 3 characters, limit result set to avoid
// too many rows being returned.
if ( 3 > strlen( $term ) ) {
$limit = 20;
}
$ids = $data_store->search_customers( $term, $limit );
}

$found_customers = [];

$ids = array_diff( $ids, $exclude );

foreach ( $ids as $id ) {
if ( ! dokan_customer_has_order_from_this_seller( $id ) ) {
continue;
}

$customer = new WC_Customer( $id );
$found_customers[ $id ] = [
'id' => $id,
'name' => sprintf(
'%s',
$customer->get_first_name() . ' ' . $customer->get_last_name()
),
'email' => $customer->get_email(),
];
}

/**
* Filter the found customers for Dokan REST API search.
*
* This filter allows you to modify the list of customers found during a search
* before it is returned by the REST API.
*
* @since DOKAN_SINCE
*
* @param array $found_customers An array of found customers. Each customer is an array containing:
* 'id' => (int) The customer's ID.
* 'name' => (string) The customer's full name.
* 'email' => (string) The customer's email address.
* @param string $term The search term used to find customers.
* @param array $exclude An array of customer IDs to exclude from the search results.
* @param int $limit The maximum number of results to return (if any).
*
* @return array The filtered array of found customers.
*/
$found_customers = apply_filters( 'dokan_json_search_found_customers', $found_customers, $term, $exclude, $limit );

return rest_ensure_response( array_values( $found_customers ) );
}
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

Ensure Consistent Permission Checks in search_customers Method

In search_customers, you're using current_user_can( 'edit_shop_orders' ) for the permission check. To maintain consistency across your controller, consider using the check_permission method with the 'search' action instead.

Apply this diff to use the consistent permission check:

 public function search_customers( $request ) {
-    if ( ! current_user_can( 'edit_shop_orders' ) ) {
-        return new WP_Error( 'dokan_rest_cannot_search', __( 'You do not have permission to search customers.', 'dokan-lite' ), [ 'status' => rest_authorization_required_code() ] );
-    }
+    $permission = $this->check_permission( $request, 'search' );
+    if ( is_wp_error( $permission ) ) {
+        return $permission;
+    }

This ensures that all permission checks are centralized and consistent.

Committable suggestion was skipped due to low confidence.

Comment on lines +60 to +73
protected function check_permission( $request, $action ) {
if ( ! $this->check_vendor_permission() ) {
$messages = [
'view' => __( 'Sorry, you cannot list resources.', 'dokan-lite' ),
'create' => __( 'Sorry, you are not allowed to create resources.', 'dokan-lite' ),
'edit' => __( 'Sorry, you are not allowed to edit this resource.', 'dokan-lite' ),
'delete' => __( 'Sorry, you are not allowed to delete this resource.', 'dokan-lite' ),
'batch' => __( 'Sorry, you are not allowed to batch update resources.', 'dokan-lite' ),
'search' => __( 'Sorry, you are not allowed to search customers.', 'dokan-lite' ),
];
return new WP_Error( "dokan_rest_cannot_$action", $messages[ $action ], [ 'status' => rest_authorization_required_code() ] );
}
return true;
}
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

Handle Undefined Actions in check_permission Method

In the check_permission method, if an undefined $action is passed, accessing $messages[ $action ] will result in an undefined index notice. Consider adding a default error message or handling unexpected actions to improve robustness.

Apply this diff to handle undefined actions:

 protected function check_permission( $request, $action ) {
     if ( ! $this->check_vendor_permission() ) {
         $messages = [
             'view'   => __( 'Sorry, you cannot list resources.', 'dokan-lite' ),
             'create' => __( 'Sorry, you are not allowed to create resources.', 'dokan-lite' ),
             'edit'   => __( 'Sorry, you are not allowed to edit this resource.', 'dokan-lite' ),
             'delete' => __( 'Sorry, you are not allowed to delete this resource.', 'dokan-lite' ),
             'batch'  => __( 'Sorry, you are not allowed to batch update resources.', 'dokan-lite' ),
             'search' => __( 'Sorry, you are not allowed to search customers.', 'dokan-lite' ),
+            'default' => __( 'Sorry, you are not allowed to perform this action.', 'dokan-lite' ),
         ];
+        $message = isset( $messages[ $action ] ) ? $messages[ $action ] : $messages['default'];
-        return new WP_Error( "dokan_rest_cannot_$action", $messages[ $action ], [ 'status' => rest_authorization_required_code() ] );
+        return new WP_Error( "dokan_rest_cannot_$action", $message, [ 'status' => rest_authorization_required_code() ] );
     }
     return true;
 }
📝 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
protected function check_permission( $request, $action ) {
if ( ! $this->check_vendor_permission() ) {
$messages = [
'view' => __( 'Sorry, you cannot list resources.', 'dokan-lite' ),
'create' => __( 'Sorry, you are not allowed to create resources.', 'dokan-lite' ),
'edit' => __( 'Sorry, you are not allowed to edit this resource.', 'dokan-lite' ),
'delete' => __( 'Sorry, you are not allowed to delete this resource.', 'dokan-lite' ),
'batch' => __( 'Sorry, you are not allowed to batch update resources.', 'dokan-lite' ),
'search' => __( 'Sorry, you are not allowed to search customers.', 'dokan-lite' ),
];
return new WP_Error( "dokan_rest_cannot_$action", $messages[ $action ], [ 'status' => rest_authorization_required_code() ] );
}
return true;
}
protected function check_permission( $request, $action ) {
if ( ! $this->check_vendor_permission() ) {
$messages = [
'view' => __( 'Sorry, you cannot list resources.', 'dokan-lite' ),
'create' => __( 'Sorry, you are not allowed to create resources.', 'dokan-lite' ),
'edit' => __( 'Sorry, you are not allowed to edit this resource.', 'dokan-lite' ),
'delete' => __( 'Sorry, you are not allowed to delete this resource.', 'dokan-lite' ),
'batch' => __( 'Sorry, you are not allowed to batch update resources.', 'dokan-lite' ),
'search' => __( 'Sorry, you are not allowed to search customers.', 'dokan-lite' ),
'default' => __( 'Sorry, you are not allowed to perform this action.', 'dokan-lite' ),
];
$message = isset( $messages[ $action ] ) ? $messages[ $action ] : $messages['default'];
return new WP_Error( "dokan_rest_cannot_$action", $message, [ 'status' => rest_authorization_required_code() ] );
}
return true;
}

Comment on lines +280 to +285
private function perform_vendor_action( callable $action ) {
add_filter( 'woocommerce_rest_check_permissions', [ $this, 'check_vendor_permission' ] );
$result = $action();
remove_filter( 'woocommerce_rest_check_permissions', [ $this, 'check_vendor_permission' ] );
return $result;
}
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

Ensure Proper Use of Filters in perform_vendor_action Method

In the perform_vendor_action method, you're adding a filter to woocommerce_rest_check_permissions using $this->check_vendor_permission, which returns a boolean. The filter expects a capability string or an array of capabilities.

Consider modifying the method to align with how WooCommerce expects permissions to be checked, or adjust the filter callback accordingly.

Apply this diff to adjust the callback:

 private function perform_vendor_action( callable $action ) {
-    add_filter( 'woocommerce_rest_check_permissions', [ $this, 'check_vendor_permission' ] );
+    add_filter( 'woocommerce_rest_check_permissions', [ $this, 'vendor_permission_callback' ], 10, 4 );
     $result = $action();
     remove_filter( 'woocommerce_rest_check_permissions', [ $this, 'check_vendor_permission' ] );
     return $result;
 }

+public function vendor_permission_callback( $permission, $context, $object_id, $post_type ) {
+    return $this->check_vendor_permission();
+}

This ensures the filter callback matches the expected parameters and behavior.

Committable suggestion was skipped due to low confidence.

Comment on lines +65 to +83
$routes = $this->server->get_routes();

$base_endpoints = [
"/$this->namespace/customers",
"/$this->namespace/customers/(?P<id>[\\d]+)",
"/$this->namespace/customers/search",
"/$this->namespace/customers/batch",
];

foreach ( $base_endpoints as $endpoint ) {
$this->assertArrayHasKey( $endpoint, $routes );
}

// Verify HTTP methods for each endpoint
$this->assertCount( 2, $routes[ "/$this->namespace/customers" ] );
$this->assertCount( 3, $routes[ "/$this->namespace/customers/(?P<id>[\\d]+)" ] );
$this->assertCount( 1, $routes[ "/$this->namespace/customers/search" ] );
$this->assertCount( 1, $routes[ "/$this->namespace/customers/batch" ] );
}
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

Ensure Correct Assertions for Route Methods

In the test_register_routes method, when verifying the HTTP methods available for each endpoint, it's unclear which methods are being tested. To improve clarity and robustness, explicitly check that the expected HTTP methods are registered for each route.

Consider modifying the test to assert the specific HTTP methods, like so:

$this->assertEquals( ['GET', 'POST'], array_keys( $routes[ "/$this->namespace/customers" ] ) );
$this->assertEquals( ['GET', 'POST', 'PUT'], array_keys( $routes[ "/$this->namespace/customers/(?P<id>[\\d]+)" ] ) );

This ensures that the routes not only exist but also support the correct HTTP methods.

Comment on lines +90 to +97
[ 'GET', 'customers', 401, 'dokan_rest_cannot_view' ],
[ 'POST', 'customers', 400, 'rest_missing_callback_param' ],
[ 'GET', "customers/{$this->customers[0]}", 401, 'dokan_rest_cannot_view' ],
[ 'PUT', "customers/{$this->customers[0]}", 401, 'dokan_rest_cannot_edit' ],
[ 'DELETE', "customers/{$this->customers[0]}", 401, 'dokan_rest_cannot_delete' ],
[ 'POST', 'customers/batch', 401, 'dokan_rest_cannot_batch' ],
[ 'GET', 'customers/search', 400, 'rest_missing_callback_param' ],
];
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

Potential Confusion in Expected Status Codes

In the test_endpoint_permissions method, the expected status codes and error codes for some test cases may not align with typical REST API practices.

Specifically:

  • For the POST request to 'customers', expecting a 400 status code with 'rest_missing_callback_param' might be inappropriate if the user is unauthorized.
  • Similarly, the GET request to 'customers/search' expecting a 400 status code due to missing parameters may need reconsideration.

Verify that the status codes and error codes accurately reflect the permission issues versus missing parameters. Unauthorized requests should usually return a 401 Unauthorized status.

/**
* @var CustomersController
*/
protected CustomersController $controller;
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

Inconsistent Property Declaration

The property $controller is declared with a type hint using the syntax protected CustomersController $controller;. However, in the other property declarations (e.g., $customers), type hints are not used. For consistency and compatibility with older PHP versions, consider removing the type hint or adding type hints to all properties.

Apply this diff to remove the type hint:

-protected CustomersController $controller;
+protected $controller;
📝 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
protected CustomersController $controller;
protected $controller;

Comment on lines +553 to +554
$customer_role = $customer->get_role();
$this->assertEquals( 'customer', $customer_role );
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

Incorrect Method for Retrieving Customer Role

In test_customer_role_handling, the method $customer->get_role() may not exist in the WC_Customer class, leading to a fatal error.

Use the appropriate WooCommerce method to retrieve the customer's roles. Since WC_Customer extends WP_User, you can access the roles directly.

Apply this diff:

-$customer_role = $customer->get_role();
+$customer_role = $customer->get_role(); // This method may not exist
+$customer_role = $customer->get_roles()[0]; // Access the roles array

$this->assertEquals( 'customer', $customer_role );

Committable suggestion was skipped due to low confidence.

Comment on lines +398 to +404
$customer_id = $this->factory()->customer->create(
[
'email' => '[email protected]',
'first_name' => 'Multi',
'last_name' => 'Vendor',
]
);
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

Missing Password in Customer Creation

In the test_vendor_customer_filtering method, when creating a new customer, the 'password' field is not provided. This might lead to issues if the password is required for customer creation.

Add the 'password' field to the customer data:

$customer_id = $this->factory()->customer->create(
    [
        'email'      => '[email protected]',
        'first_name' => 'Multi',
        'last_name'  => 'Vendor',
+       'password'   => 'password123',
    ]
);
📝 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
$customer_id = $this->factory()->customer->create(
[
'email' => '[email protected]',
'first_name' => 'Multi',
'last_name' => 'Vendor',
]
);
$customer_id = $this->factory()->customer->create(
[
'email' => '[email protected]',
'first_name' => 'Multi',
'last_name' => 'Vendor',
'password' => 'password123',
]
);

Comment on lines +621 to +627
protected function request( $method, $endpoint, $data = [] ): WP_REST_Response {
$request = new WP_REST_Request( $method, "/$this->namespace/$endpoint" );
if ( ! empty( $data ) ) {
$request->set_body_params( $data );
}
return $this->server->dispatch( $request );
}
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

Avoid Return Type Declarations for Compatibility

The method protected function request( $method, $endpoint, $data = [] ): WP_REST_Response includes a return type declaration. If compatibility with older PHP versions is desired, consider removing the return type declaration.

Apply this diff:

-protected function request( $method, $endpoint, $data = [] ): WP_REST_Response {
+protected function request( $method, $endpoint, $data = [] ) {
📝 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
protected function request( $method, $endpoint, $data = [] ): WP_REST_Response {
$request = new WP_REST_Request( $method, "/$this->namespace/$endpoint" );
if ( ! empty( $data ) ) {
$request->set_body_params( $data );
}
return $this->server->dispatch( $request );
}
protected function request( $method, $endpoint, $data = [] ) {
$request = new WP_REST_Request( $method, "/$this->namespace/$endpoint" );
if ( ! empty( $data ) ) {
$request->set_body_params( $data );
}
return $this->server->dispatch( $request );
}

Comment on lines +431 to +433
$response1 = $this->get_request( "customers/$customer_id" );
$response2 = $this->get_request( "customers/$customer_id" );
$this->assertEquals( $response1->get_data(), $response2->get_data() );
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

Duplicate Requests Without User Context Change

In test_vendor_customer_filtering, two requests are made to the same endpoint without changing the user context, but the responses are compared for equality.

To test that both vendors receive the same customer data, ensure that the user is switched between the two requests.

Apply this diff:

$response1 = $this->get_request( "customers/$customer_id" );

+// Switch to the other vendor
+wp_set_current_user( $this->seller_id1 );

$response2 = $this->get_request( "customers/$customer_id" );
$this->assertEquals( $response1->get_data(), $response2->get_data() );

Committable suggestion was skipped due to low confidence.

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

🧹 Outside diff range and nitpick comments (5)
includes/REST/ProductController.php (2)

57-64: Replace DOKAN_SINCE placeholder with actual version number

The @since DOKAN_SINCE docblock tag contains a placeholder that should be replaced with the actual version number where this feature was introduced.


66-85: Improve method documentation

The method documentation could be enhanced:

  1. Add return type annotation @return array
  2. Add proper parameter descriptions:
    • $args - The existing query arguments
    • $request - The REST API request object
     /**
      * Add only downloadable meta query.
      *
      * @since DOKAN_SINCE
      *
-     * @param array $args
-     *
-     * @param \WP_REST_Request $request
+     * @param array           $args    The existing query arguments
+     * @param \WP_REST_Request $request The REST API request object
+     *
+     * @return array Modified query arguments
      */
includes/REST/OrderControllerV3.php (3)

5-7: Remove unused import statements

The use statements for WC_Data_Store and WP_REST_Server are not utilized in this file. It's good practice to remove unused imports to keep the code clean.

Apply this diff to remove the unused imports:

-use WC_Data_Store;
-use WP_Error;
-use WP_REST_Server;
+use WP_Error;

12-14: Update the @SInCE annotations with the correct version number

The @since DOKAN_SINCE annotations are placeholders. Replace DOKAN_SINCE with the actual version number when this feature is introduced to maintain proper documentation.

Apply this diff to update the annotations:

  * Dokan Order ControllerV3 Class
  *
- * @since DOKAN_SINCE
+ * @since 3.8.0
  *
  * @package dokan
  */

Repeat this change for all occurrences of @since DOKAN_SINCE.


56-56: Optimize file title retrieval

The function wc_get_filename_from_url() is used to extract the filename from the URL. If the product file path is already known, you might directly use the file name without parsing the URL.

Consider this alternative to simplify the code:

 $download->file_data['file_title'] = basename( $product->get_file_download_path( $download->download_id ) );

This uses PHP's basename() function to get the file name from the path.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8b2b753 and a064fe7.

📒 Files selected for processing (3)
  • includes/REST/Manager.php (1 hunks)
  • includes/REST/OrderControllerV3.php (1 hunks)
  • includes/REST/ProductController.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • includes/REST/Manager.php
🧰 Additional context used
🪛 GitHub Check: Run PHPCS inspection
includes/REST/ProductController.php

[failure] 98-98:
Mismatched text domain. Expected 'dokan-lite' but got 'dokan'.

🔇 Additional comments (2)
includes/REST/ProductController.php (1)

75-82: Well-structured implementation of downloadable products filter

The implementation of the downloadable products filter is clean and follows best practices:

  1. Proper meta query structure
  2. Input validation using dokan_string_to_bool
  3. Clean integration with existing query arguments
includes/REST/OrderControllerV3.php (1)

25-25: Ensure namespace consistency across API versions

The $namespace property is set to 'dokan/v3'. Verify that this namespace does not conflict with existing namespaces and that all routes are properly adjusted to accommodate version 3.

Run the following script to check for namespace conflicts:

If any files other than OrderControllerV3.php appear, investigate potential conflicts.

✅ Verification successful

Namespace 'dokan/v3' follows consistent versioning pattern

The namespace 'dokan/v3' is correctly implemented and follows the established versioning pattern in the codebase:

  • OrderController: dokan/v1
  • OrderControllerV2: dokan/v2
  • OrderControllerV3: dokan/v3

This pattern is consistently used across other versioned controllers:

  • StoreSettingController (v1, v2)
  • ProductController (v1, v2)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for usage of the 'dokan/v3' namespace to ensure it's unique.

# Test: Find all occurrences of 'namespace = \'dokan/v3\''. Expect: Only in OrderControllerV3.php.
rg --files-with-matches "namespace\s*=\s*'dokan/v3'" | grep -v 'OrderControllerV3.php'

Length of output: 92


Script:

#!/bin/bash
# Let's try a more comprehensive search for namespace patterns

# Search for any dokan/v3 namespace pattern
rg "dokan/v3" -A 2 -B 2

# Also search for other dokan API versions to understand the versioning pattern
rg "protected\s+\$namespace\s*=\s*['\"]dokan/v" -A 2 -B 2

# Search for route registrations to verify proper version handling
rg "register_rest_route.*dokan" -A 2 -B 2

Length of output: 383


Script:

#!/bin/bash
# Let's search for all REST controller classes to understand the API versioning structure
rg "class.*Controller.*extends.*REST_Controller" -A 5

# Also search for any other namespace declarations in REST controllers
fd Controller --exec grep -l "protected.*namespace" {} \;

# Look for base REST controller class to understand the versioning pattern
fd REST_Controller --type f --exec cat {} \;

Length of output: 3727


Script:

#!/bin/bash
# Let's examine the namespace declarations in the versioned controllers
grep -r "protected.*namespace.*dokan" includes/REST/OrderController*.php
grep -r "protected.*namespace.*dokan" includes/REST/StoreSettingController*.php
grep -r "protected.*namespace.*dokan" includes/REST/ProductController*.php

# Also check the base classes for any version-related configurations
grep -r "protected.*namespace.*dokan" includes/Abstracts/DokanREST*.php

Length of output: 1144

Comment on lines +97 to +104
$schema['only_downloadable'] = [
'description' => __( 'If truthy value then only downloadable products will be returned', 'dokan' ),
'type' => [ 'boolean', 'string' ],
'enum' => [ true, false, 0, 1 ],
'sanitize_callback' => 'dokan_string_to_bool',
'validate_callback' => 'dokan_string_to_bool',
'default' => false,
];
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 text domain mismatch

The text domain used in the translation function should be 'dokan-lite' to maintain consistency across the plugin.

-            'description' => __( 'If truthy value then only downloadable products will be returned', 'dokan' ),
+            'description' => __( 'If truthy value then only downloadable products will be returned', 'dokan-lite' ),
📝 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
$schema['only_downloadable'] = [
'description' => __( 'If truthy value then only downloadable products will be returned', 'dokan' ),
'type' => [ 'boolean', 'string' ],
'enum' => [ true, false, 0, 1 ],
'sanitize_callback' => 'dokan_string_to_bool',
'validate_callback' => 'dokan_string_to_bool',
'default' => false,
];
$schema['only_downloadable'] = [
'description' => __( 'If truthy value then only downloadable products will be returned', 'dokan-lite' ),
'type' => [ 'boolean', 'string' ],
'enum' => [ true, false, 0, 1 ],
'sanitize_callback' => 'dokan_string_to_bool',
'validate_callback' => 'dokan_string_to_bool',
'default' => false,
];
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 98-98:
Mismatched text domain. Expected 'dokan-lite' but got 'dokan'.

Comment on lines +54 to +56
$file = $product->get_file( $download->download_id );
$download->file_data = $file->get_data();
$download->file_data['file_title'] = wc_get_filename_from_url( $product->get_file_download_path( $download->download_id ) );
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

Handle potential null return from get_file method

The method $product->get_file( $download->download_id ) may return null if the file doesn't exist. Ensure that $file is not null before calling $file->get_data() to prevent fatal errors.

This can be addressed with the validity check added in the previous comment.

Comment on lines +36 to +62
public function get_order_downloads( $requests ) {
$response = parent::get_order_downloads( $requests );
$data = $response->get_data();
$downloads = $data['downloads'];
$updated_response = [];

foreach ( $downloads as $download ) {
$product = dokan()->product->get( $download->product_id );
$download->product = [
'id' => $product->get_id(),
'name' => $product->get_name(),
'slug' => $product->get_slug(),
'link' => $product->get_permalink(),
];

/**
* @var $file \WC_Product_Download
*/
$file = $product->get_file( $download->download_id );
$download->file_data = $file->get_data();
$download->file_data['file_title'] = wc_get_filename_from_url( $product->get_file_download_path( $download->download_id ) );

$updated_response[] = $download;
}

return rest_ensure_response( $updated_response );
}
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

Consider using data sanitization and validation

When handling data, especially from external sources like $requests, ensure that all inputs are properly sanitized and validated to prevent security vulnerabilities.

[security]

Review the data processing steps and apply appropriate sanitization functions where necessary.

public function get_order_downloads( $requests ) {
$response = parent::get_order_downloads( $requests );
$data = $response->get_data();
$downloads = $data['downloads'];

This comment was marked as off-topic.

Comment on lines +42 to +59
foreach ( $downloads as $download ) {
$product = dokan()->product->get( $download->product_id );
$download->product = [
'id' => $product->get_id(),
'name' => $product->get_name(),
'slug' => $product->get_slug(),
'link' => $product->get_permalink(),
];

/**
* @var $file \WC_Product_Download
*/
$file = $product->get_file( $download->download_id );
$download->file_data = $file->get_data();
$download->file_data['file_title'] = wc_get_filename_from_url( $product->get_file_download_path( $download->download_id ) );

$updated_response[] = $download;
}

This comment was marked as off-topic.

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

🧹 Outside diff range and nitpick comments (3)
package.json (3)

25-26: Consider scoping Tailwind CSS to prevent style conflicts.

The addition of Tailwind CSS dependencies is appropriate for a modern UI implementation. However, in a WordPress environment, global CSS can cause conflicts with other plugins or themes.

Recommendations:

  1. Ensure Tailwind CSS is properly scoped using tailwindcss-scoped-preflight
  2. Consider adding a unique prefix for your Tailwind classes
  3. Document the CSS architecture decisions in your README

Also applies to: 39-39


64-64: Consider implications of client-side routing.

The addition of react-router-dom suggests client-side routing implementation. While this is good for SPA-like experience, ensure proper handling of:

  1. WordPress admin URLs
  2. Browser history
  3. Page refreshes

Consider documenting the routing architecture and its integration with WordPress admin.


Line range hint 25-64: Review bundle size impact.

The addition of multiple new dependencies will increase the bundle size.

Recommendations:

  1. Consider implementing code splitting for the dashboard
  2. Use dynamic imports for route-based code splitting
  3. Monitor the bundle size during development
  4. Consider adding bundle analysis scripts to your build process
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a064fe7 and 322dc62.

📒 Files selected for processing (2)
  • includes/Assets.php (4 hunks)
  • package.json (3 hunks)
🔇 Additional comments (6)
package.json (2)

56-56: Verify Dokan UI package compatibility.

The addition of @getdokan/dokan-ui (^1.0.14) seems to be a custom UI package.

✅ Verification successful

Let me check the actual usage of the package to verify compatibility.


The Dokan UI package usage appears compatible and minimal

The package is only used to import the DokanToaster component in src/Layout/index.tsx, which is a simple UI component. There are no version conflicts found in the project as only one version (^1.0.14) is specified. The limited usage suggests low risk of compatibility issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for existing usage of dokan-ui components
rg -l "@getdokan/dokan-ui"

# Check package.json files in the project for version conflicts
fd package.json --exec cat {} \; | jq -r 'select(.dependencies."@getdokan/dokan-ui" != null) | .dependencies."@getdokan/dokan-ui"'

Length of output: 204


Script:

#!/bin/bash
# Check how the dokan-ui components are being used
rg -A 5 "@getdokan/dokan-ui" src/Layout/index.tsx

# Check if there are any other UI component imports that might conflict
rg "import.*from.*@getdokan/dokan-ui" src/Layout/index.tsx

Length of output: 319


57-63: Verify WordPress package version compatibility.

The WordPress packages (@wordpress/components: ^28.9.0, etc.) are relatively recent versions. This could potentially cause compatibility issues with older WordPress installations.

✅ Verification successful

Let me check the actual usage of these WordPress packages in the files to verify compatibility.


WordPress package versions are compatible with the minimum requirements

The package versions are appropriate for the project's requirements:

  • The plugin requires WordPress 6.4+ as per readme.txt
  • The @WordPress packages are being used correctly for basic functionality (i18n, components, element, dom-ready)
  • The usage patterns in the codebase are standard and don't utilize any cutting-edge features
  • Package-lock.json shows that dependencies resolve to compatible versions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check WordPress version compatibility in readme.txt
rg -A 2 "Requires at least:" readme.txt

# Check if these package versions are used consistently across the project
rg -l "@wordpress/(components|data|dom-ready|element|hooks|i18n|plugins)"

Length of output: 358


Script:

#!/bin/bash
# Check the actual imports and usage of WordPress packages
for file in src/Routing/index.tsx src/Layout/index.tsx src/Layout/Header.tsx src/Dashboard/index.tsx src/Layout/Footer.tsx src/Layout/ContentArea.tsx src/utils/Mixin.js; do
    echo "=== $file ==="
    rg "@wordpress/" "$file" -A 2
done

# Check package-lock.json for actual resolved versions
rg '"@wordpress/[^"]+": "([^"]+)"' package-lock.json

Length of output: 4447

includes/Assets.php (4)

355-358: LGTM! Style registration follows the established pattern.

The registration of 'dokan-react-frontend' style is consistent with other style registrations in the file.


372-372: Existing comment is still valid.

A past review comment already addresses the need to rename $frontend_shipping_asset to $frontend_asset.


562-566: Existing comment is still valid.

A past review comment already addresses the need to update variable references in the script registration.


870-871: Existing comment is still valid.

A past review comment already addresses the need to conditionally enqueue these assets for better performance.

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 322dc62 and c9478eb.

📒 Files selected for processing (4)
  • includes/Assets.php (4 hunks)
  • includes/REST/Manager.php (1 hunks)
  • package.json (3 hunks)
  • webpack.config.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • includes/REST/Manager.php
  • webpack.config.js
🔇 Additional comments (8)
package.json (4)

25-26: LGTM! Good choice using scoped Tailwind preflight.

The Tailwind CSS setup looks good. Using tailwindcss-scoped-preflight is particularly important as it will prevent style conflicts with WordPress admin styles.

Also applies to: 39-39


Line range hint 25-64: LGTM! Package structure is well-organized.

The new dependencies are properly categorized between dev and runtime dependencies, and all additions align well with the PR's objective of implementing a React-based vendor dashboard.


64-64: Verify React Router compatibility with project's React version.

React Router 6.x requires React 16.8 or higher. Let's ensure our React version is compatible.

✅ Verification successful

React Router 6.27.0 is compatible with project's React version

The project uses React 18.3.1 which fully supports React Router 6.x (requires React 16.8+).

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check React version compatibility

# Search for React version in package-lock.json or yarn.lock
echo "Searching for React peer dependencies:"
rg "react\":" "package-lock.json" || rg "react@" "yarn.lock" || echo "Lock file not found"

# Check if we're using React in WordPress context
echo -e "\nChecking WordPress React usage:"
rg -l "wp.element" || echo "No WordPress React usage found"

Length of output: 566


57-63: Verify WordPress package version compatibility.

While the WordPress packages are properly structured for integration, there's a significant version gap between some packages (e.g., [email protected] vs [email protected]). This might lead to compatibility issues.

✅ Verification successful

The version differences between WordPress packages are actually expected and correct. Let me verify this further by checking the official compatibility information.


Let me try a different approach to verify the package versions by checking the package.json directly from the repository.


WordPress package versions are compatible - no action needed

The version differences between WordPress packages are intentional and correct. From the package-lock.json analysis:

  • Each package follows its own versioning scheme based on its individual development lifecycle
  • The packages are properly resolved without conflicts
  • The project requires WordPress 6.4+ as per readme.txt, and all package versions are compatible with this requirement
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check WordPress package compatibility matrix

# Get WordPress core version from composer.json or readme.txt
echo "WordPress Core version requirement:"
rg -A 1 "Requires at least:" "readme.txt" || echo "readme.txt not found"

# List all WordPress package versions for comparison
echo -e "\nWordPress package versions in use:"
jq -r '.dependencies | with_entries(select(.key | startswith("@wordpress"))) | to_entries[] | "\(.key): \(.value)"' package.json

Length of output: 570


Script:

#!/bin/bash
# Check package.json in wordpress/wordpress-develop repository to verify latest versions
echo "Checking latest WordPress core package versions:"
gh api repos/WordPress/wordpress-develop/contents/package.json --raw | jq -r '.dependencies | with_entries(select(.key | startswith("@wordpress"))) | to_entries[] | "\(.key): \(.value)"' || echo "Failed to fetch WordPress develop package.json"

# Also check if there are any peer dependencies specified in our package.json
echo -e "\nChecking peer dependencies:"
jq -r '.peerDependencies // empty | with_entries(select(.key | startswith("@wordpress"))) | to_entries[] | "\(.key): \(.value)"' package.json

Length of output: 1874


Script:

#!/bin/bash
# Check if there are any version conflicts or warnings in package-lock.json
echo "Checking for any WordPress package conflicts:"
if [ -f "package-lock.json" ]; then
    jq '.packages | to_entries[] | select(.key | contains("@wordpress")) | {name: .key, version: .value.version}' package-lock.json
else
    echo "package-lock.json not found"
fi

# Check if there are any specific WordPress version requirements in README
echo -e "\nChecking README for WordPress version requirements:"
rg -i "wordpress.*version|requires.*wordpress" README.md || echo "No explicit WordPress version requirements found in README.md"

Length of output: 3148

includes/Assets.php (4)

362-365: LGTM! Style registration follows standard patterns.

The React frontend style registration is properly implemented with correct versioning and path handling.


379-379: Variable naming issue already identified.

A previous review has already addressed the misleading variable name.


569-573: Script registration uses incorrect variable references.

A previous review has already addressed the need to update variable references after renaming.


880-881: Consider optimizing asset loading.

A previous review has already suggested conditional loading. Additionally, consider:

  1. Deferring the script loading using the defer attribute
  2. Adding preload hints for critical assets
-wp_enqueue_script( 'dokan-react-frontend' );
-wp_enqueue_style( 'dokan-react-frontend' );
+// Add preload hint for critical assets
+add_action('wp_head', function() {
+    echo '<link rel="preload" href="' . DOKAN_PLUGIN_ASSEST . '/css/frontend.css" as="style">';
+});
+
+// Defer script loading
+add_filter('script_loader_tag', function($tag, $handle) {
+    if ('dokan-react-frontend' === $handle) {
+        return str_replace(' src', ' defer src', $tag);
+    }
+    return $tag;
+}, 10, 2);
+
+wp_enqueue_script( 'dokan-react-frontend' );
+wp_enqueue_style( 'dokan-react-frontend' );

@@ -50,6 +53,14 @@
"wp-readme-to-markdown": "^1.0.1"
},
"dependencies": {
"@wordpress/i18n": "^5.8.0"
"@getdokan/dokan-ui": "^1.0.14",
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Update @getdokan/dokan-ui package to version 1.0.17

The package.json currently uses version 1.0.14, but version 1.0.17 is available on npm. Consider updating to the latest version to get the newest features and bug fixes.

🔗 Analysis chain

Verify dokan-ui package version and stability.

Let's ensure we're using the latest stable version of the internal UI library.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check dokan-ui package status

# Check if package is published on npm
echo "Checking npm registry for @getdokan/dokan-ui versions:"
npm view @getdokan/dokan-ui versions --json 2>/dev/null || echo "Package not found on npm"

# Look for internal package references
echo -e "\nChecking for local references:"
fd -g "*dokan-ui*" || echo "No local package references found"

Length of output: 349

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.

4 participants