Skip to content

Commit

Permalink
Merge branch 'update/vendor-dashboard-structure' into enhance/add-rea…
Browse files Browse the repository at this point in the history
…ct-table-filter-component

# Conflicts:
#	docs/frontend/components.md
#	includes/Assets.php
#	src/components/dataviews/DataViewTable.tsx
#	src/components/index.tsx
#	webpack.config.js
  • Loading branch information
Aunshon committed Jan 20, 2025
2 parents 6439152 + 4692634 commit aa90f8f
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 19 deletions.
4 changes: 2 additions & 2 deletions docs/frontend/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ if (file_exists($script_assets)) {
For `Dokan Free`, we can import the components via `@/components`:

```js
import { DataViews, useWindowDimensions } from '@/components';
import { DataViews } from '@/components';
```

In `Dokan Pro`, components can be imported directly from `@dokan/components`:

```js
import { DataViews, useWindowDimensions } from '@dokan/components';
import { DataViews } from '@dokan/components';
```

For external `plugins`, we must include the `dokan-react-components` as scripts dependency and the `@dokan/components` should be introduced as an external resource configuration to resolve the path via `webpack`:
Expand Down
90 changes: 90 additions & 0 deletions docs/frontend/hooks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Dokan Hooks

## Overview

`Dokan` provides a set of reusable `hooks` that can be used across both `Free` and `Pro` versions. This documentation explains how to properly set up and use `hooks` in your project.

## Important Dependencies

For both `Dokan Free and Pro` versions, we must register the `dokan-react-components` dependency when using `global` components.

### Implementation Example

```php
// Register scripts with dokan-react-components dependency
$script_assets = 'add_your_script_assets_path_here';

if (file_exists($script_assets)) {
$vendor_asset = require $script_assets;
$version = $vendor_asset['version'] ?? '';

// Add dokan-react-components as a dependency
$component_handle = 'dokan-react-components';
$dependencies = $vendor_asset['dependencies'] ?? [];
$dependencies[] = $component_handle;

// Register Script
wp_register_script(
'handler-name',
'path_to_your_script_file',
$dependencies,
$version,
true
);

// Register Style
wp_register_style(
'handler-name',
'path_to_your_style_file',
[ $component_handle ],
$version
);
}
```

## Component Access

For `Dokan Free`, we can import the components via `@/hooks`:

```js
import { useWindowDimensions } from '@/hooks';
```

In `Dokan Pro`, components can be imported directly from `@dokan/components`:

```js
import { useWindowDimensions } from '@dokan/hooks';
```

For external `plugins`, we must include the `dokan-react-components` as scripts dependency and the `@dokan/hooks` should be introduced as an external resource configuration to resolve the path via `webpack`:

```js
externals: {
'@dokan/hooks': 'dokan.hooks',
...
},
```

## Adding Global Components

### File Structure

```
|____ src/
| |___ hooks/
| | |___ index.tsx # Main export file
| | |___ ViewportDimensions.tsx # Existing hook
| | |___ YourHook # Your new hook
| | |
| | |___ Other Files
| |
| |___ Other Files
|
|____ Other Files
```

**Finally,** we need to export the new `hook` from the `src/hooks/index.tsx` file. Then, we can import the new component from `@dokan/hooks` in `dokan pro` version.

```tsx
export { default as useWindowDimensions } from '@/hooks/ViewportDimensions';
```
20 changes: 14 additions & 6 deletions includes/Assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -587,17 +587,25 @@ public function get_scripts() {
'src' => $asset_url . '/js/utilities.js',
'version' => filemtime( $asset_path . 'js/utilities.js' ),
],
'dokan-hooks' => [
'deps' => [],
'src' => $asset_url . '/js/hooks.js',
'version' => filemtime( $asset_path . 'js/hooks.js' ),
],
];

$components_asset_dir = DOKAN_DIR . '/assets/js/components.asset.php';
if ( file_exists( $components_asset_dir ) ) {
$components_asset = require $components_asset_dir;
$components_asset['dependencies'][] = 'dokan-utilities';
$components_asset_file = DOKAN_DIR . '/assets/js/components.asset.php';
if ( file_exists( $components_asset_file ) ) {
$components_asset = require $components_asset_file;

// Register React components.
$scripts['dokan-react-components'] = [
'src' => $asset_url . '/js/components.js',
'deps' => $components_asset['dependencies'],
'version' => $components_asset['version'],
'src' => $asset_url . '/js/components.js',
'deps' => array_merge(
$components_asset['dependencies'],
[ 'dokan-utilities', 'dokan-hooks' ]
),
];
}

Expand Down
18 changes: 11 additions & 7 deletions includes/functions-dashboard-navigation.php
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,12 @@ function dokan_dashboard_nav( $active_menu = '' ) {
}

$submenu .= sprintf(
'<li class="submenu-item %s"><a href="%s" class="submenu-link">%s %s</a></li>',
/* translators: 1) submenu class, 2) submenu route, 3) submenu icon, 4) submenu title */
'<li class="submenu-item %1$s" data-react-route="%2$s"><a href="%3$s" class="submenu-link">%4$s %5$s</a></li>',
$submenu_class,
isset( $sub['url'] ) ? $sub['url'] : dokan_get_navigation_url( "{$key}/{$sub_key}" ),
isset( $sub['icon'] ) ? $sub['icon'] : '<i class="fab fa-staylinked"></i>',
$sub['react_route'] ?? '',
$sub['url'] ?? dokan_get_navigation_url( "{$key}/{$sub_key}" ),
$sub['icon'] ?? '<i class="fab fa-staylinked"></i>',
apply_filters( 'dokan_vendor_dashboard_menu_title', $submenu_title, $sub )
);

Expand All @@ -278,11 +280,13 @@ function dokan_dashboard_nav( $active_menu = '' ) {
}

$menu .= sprintf(
'<li class="%s"><a href="%s" target="%s">%s %s</a>%s</li>',
/* translators: 1) menu class, 2) menu route, 3) menu url, 4) menu target, 5) menu icon, 6) menu title, 7) submenu */
'<li class="%1$s" data-react-route="%2$s"><a href="%3$s" target="%4$s">%5$s %6$s</a>%7$s</li>',
$class,
isset( $item['url'] ) ? $item['url'] : dokan_get_navigation_url( $menu_slug ),
isset( $item['target'] ) ? $item['target'] : '_self',
isset( $item['icon'] ) ? $item['icon'] : '<i class="fab fa-staylinked"></i>',
$item['react_route'] ?? '',
$item['url'] ?? dokan_get_navigation_url( $menu_slug ),
$item['target'] ?? '_self',
$item['icon'] ?? '<i class="fab fa-staylinked"></i>',
apply_filters( 'dokan_vendor_dashboard_menu_title', $title, $item ),
$submenu
);
Expand Down
5 changes: 2 additions & 3 deletions src/components/dataviews/DataViewTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import { Slot } from "@wordpress/components";
import { ViewportDimensions } from '@/Hooks/ViewportDimensions';
import type { Action, Field, SupportedLayouts, View } from "@wordpress/dataviews/src/types";
import { kebabCase, snakeCase } from "@/utilities";
import { useWindowDimensions } from "@/components";
import { useEffect } from "@wordpress/element";
import type { ReactNode } from "react";
import { useWindowDimensions } from "@/hooks";
import './style.scss';

type ItemWithId = { id: string };
Expand All @@ -31,7 +30,7 @@ type DataViewsProps< Item > = {
onChangeSelection?: ( items: string[] ) => void;
onClickItem?: ( item: Item ) => void;
isItemClickable?: ( item: Item ) => boolean;
header?: ReactNode;
header?: JSX.Element;
} & ( Item extends ItemWithId
? { getItemId?: ( item: Item ) => string }
: { getItemId: ( item: Item ) => string } );
Expand Down
1 change: 0 additions & 1 deletion src/components/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export { default as DataViews } from './dataviews/DataViewTable';
export { default as useWindowDimensions } from '@/hooks/ViewportDimensions';

export {
DataForm,
Expand Down
46 changes: 46 additions & 0 deletions src/hooks/ViewportDimensions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useState, useEffect, useCallback } from '@wordpress/element';

interface ViewportDimensions {
width: number | null;
height: number | null;
}

/**
* Hook to track viewport dimensions.
*
* @since DOKAN_PRO_SINCE
*
* @return {ViewportDimensions} The viewport dimensions.
*/
export default function useWindowDimensions() {
const getViewportDimensions = useCallback((): ViewportDimensions => ({
width: typeof window !== 'undefined' ? window.innerWidth : null,
height: typeof window !== 'undefined' ? window.innerHeight : null,
}), []);

const [viewport, setViewport] = useState<ViewportDimensions>(getViewportDimensions());

useEffect(() => {
if (typeof window === 'undefined') {
return;
}

const handleResize = () => {
// Use requestAnimationFrame to throttle updates
window.requestAnimationFrame(() => {
setViewport(getViewportDimensions());
});
};

window.addEventListener('resize', handleResize);

// Initial measurement after mount
handleResize();

return () => {
window.removeEventListener('resize', handleResize);
};
}, [getViewportDimensions]);

return viewport;
};
1 change: 1 addition & 0 deletions src/hooks/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as useWindowDimensions } from '@/hooks/ViewportDimensions';
32 changes: 32 additions & 0 deletions src/layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@wordpress/components';
import { PluginArea } from '@wordpress/plugins';
import { DokanToaster } from "@getdokan/dokan-ui";
import { useLocation } from 'react-router-dom';

// Create a ThemeContext
const ThemeContext = createContext( null );
Expand Down Expand Up @@ -43,6 +44,34 @@ interface LayoutProps {
footerComponent?: JSX.Element|React.ReactNode;
}

const handleMenuActiveStates = ( currentPath ) => {
const menuRoute = currentPath.replace( /^\//, '' ); // Remove leading slash.
const menuItem = document.querySelector( `.dokan-dashboard-menu li[data-react-route='${ menuRoute }']` ) || null;

// Return if menu item not found.
if ( ! menuItem ) {
return;
}

document.querySelectorAll( '.dokan-dashboard-menu li' ).forEach( item => {
item.classList.remove( 'active' );
item.querySelectorAll( '.navigation-submenu li' ).forEach( subItem => {
subItem.classList.remove( 'current' );
});
});

// Get parent menu item if this is a submenu item.
const parentMenuItem = menuItem.closest( '.dokan-dashboard-menu > li' );
if ( parentMenuItem ) { // Add `active` to parent menu.
parentMenuItem.classList.add( 'active' );
}

const subMenuItem = document.querySelector( `.navigation-submenu li[data-react-route='${ menuRoute }']` );
if ( subMenuItem ) { // Add `current` to submenu item.
subMenuItem.classList.add( 'current' );
}
};

// Create a Layout component that uses the ThemeProvider
const Layout = ( {
children,
Expand All @@ -51,6 +80,9 @@ const Layout = ( {
headerComponent,
footerComponent,
}: LayoutProps ) => {
const location = useLocation(); // Use the location hook to get the current path.
handleMenuActiveStates( location?.pathname );

return (
<ThemeProvider>
<SlotFillProvider>
Expand Down
3 changes: 3 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const updatedConfig = {
'utilities': {
import: '@/utilities/index.ts',
},
'hooks': {
import: '@/hooks/index.tsx',
},
},
output: {
path: path.resolve(__dirname, './assets/js'),
Expand Down

0 comments on commit aa90f8f

Please sign in to comment.