2023-07-20 13:53:06 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { __ } from '@wordpress/i18n';
|
2023-10-04 16:59:34 +00:00
|
|
|
import { useContext, useEffect, useState } from '@wordpress/element';
|
2023-07-20 13:53:06 +00:00
|
|
|
import { Button } from '@wordpress/components';
|
|
|
|
import classNames from 'classnames';
|
2023-07-20 16:00:22 +00:00
|
|
|
import { getNewPath, navigateTo, useQuery } from '@woocommerce/navigation';
|
2023-07-20 13:53:06 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import './tabs.scss';
|
|
|
|
import { DEFAULT_TAB_KEY, MARKETPLACE_PATH } from '../constants';
|
[wccom-17942] Only showing feedback snackbar when content of in-app marketplace has finished loading. Making sure snackbar is fixed position, so it's visible wherever you are on the page.
- `ProductListContextProvider` provides `setIsLoading` function as well as `isLoading`.
- `Discover` uses these values from context, instead of keeping a loading state in itself.
- `FeedbackModal` calls `maybSetTimeout` when `isLoading` changes. If `isLoading` isn't truthy, and snackbar hasn't already rendered, it sets a timeout of 5 seconds to show it.
- Removed wrapping <WooFooterItem> from around Footer component, so it's no longer a child of the WooCommerce Admin `.woocommerce-layout__footer` footer.
- Removed the `position: relative` from `.woocommerce-layout__footer`. It needs to be `position: fixed`.
- Added FooterContent component to Footer, to allow the layout we want.
- Changed use of context. This now only has states for the selected tab and loading state.
- We use this context in `Tabs` and `Content` to keep track of which tab is selected, and set the selected tab.
- We also use it in `Discover` and `Extensions`, which both report loading state to the context. This allows us to use it to only render the snackbar when loading is complete.
- Extensions: moved `productList` and `setProductList` and logic for getting product list from the context provider to a state in this component. We don't need to share the list of products in the context.
- Renamed `ProductListContext`, `ProductListContextProvider` and `productListContextValue` to more generic `MarketplaceContext`, `MarketplaceContextProvider` and `marketplaceContextValue`.
- Renamed a constant and created constants for API paths.
- Only shows snackbar after content has loaded, and after a timeout. We set a date `marketplace_redesign_2023_last_shown_date` in local storage to ensure we only show one snackbar.
2023-08-23 15:49:36 +00:00
|
|
|
import { MarketplaceContext } from '../../contexts/marketplace-context';
|
|
|
|
import { MarketplaceContextType } from '../../contexts/types';
|
2024-04-02 15:04:57 +00:00
|
|
|
import { getAdminSetting } from '../../../utils/admin-settings';
|
2023-07-20 13:53:06 +00:00
|
|
|
|
|
|
|
export interface TabsProps {
|
2023-07-26 11:31:59 +00:00
|
|
|
additionalClassNames?: Array< string > | undefined;
|
2023-07-20 13:53:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
interface Tab {
|
|
|
|
name: string;
|
|
|
|
title: string;
|
2023-08-02 11:46:54 +00:00
|
|
|
href?: string;
|
2024-04-02 15:04:57 +00:00
|
|
|
showUpdateCount: boolean;
|
|
|
|
updateCount: number;
|
2023-07-20 13:53:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
interface Tabs {
|
|
|
|
[ key: string ]: Tab;
|
|
|
|
}
|
|
|
|
|
2024-04-02 15:04:57 +00:00
|
|
|
const wccomSettings = getAdminSetting( 'wccomHelper', {} );
|
|
|
|
const wooUpdateCount = wccomSettings?.wooUpdateCount ?? 0;
|
|
|
|
|
2023-07-20 13:53:06 +00:00
|
|
|
const tabs: Tabs = {
|
2023-10-04 16:59:34 +00:00
|
|
|
search: {
|
|
|
|
name: 'search',
|
|
|
|
title: __( 'Search results', 'woocommerce' ),
|
2024-04-02 15:04:57 +00:00
|
|
|
showUpdateCount: false,
|
|
|
|
updateCount: 0,
|
2023-10-04 16:59:34 +00:00
|
|
|
},
|
2023-07-20 13:53:06 +00:00
|
|
|
discover: {
|
|
|
|
name: 'discover',
|
|
|
|
title: __( 'Discover', 'woocommerce' ),
|
2024-04-02 15:04:57 +00:00
|
|
|
showUpdateCount: false,
|
|
|
|
updateCount: 0,
|
2023-07-20 13:53:06 +00:00
|
|
|
},
|
|
|
|
extensions: {
|
|
|
|
name: 'extensions',
|
2023-07-26 14:58:22 +00:00
|
|
|
title: __( 'Browse', 'woocommerce' ),
|
2024-04-02 15:04:57 +00:00
|
|
|
showUpdateCount: false,
|
|
|
|
updateCount: 0,
|
2023-07-20 13:53:06 +00:00
|
|
|
},
|
2023-10-04 16:59:34 +00:00
|
|
|
themes: {
|
|
|
|
name: 'themes',
|
|
|
|
title: __( 'Themes', 'woocommerce' ),
|
2024-04-02 15:04:57 +00:00
|
|
|
showUpdateCount: false,
|
|
|
|
updateCount: 0,
|
2023-10-04 16:59:34 +00:00
|
|
|
},
|
2024-05-15 12:43:06 +00:00
|
|
|
'business-services': {
|
|
|
|
name: 'business-services',
|
|
|
|
title: __( 'Business services', 'woocommerce' ),
|
|
|
|
showUpdateCount: false,
|
|
|
|
updateCount: 0,
|
|
|
|
},
|
2023-08-02 11:46:54 +00:00
|
|
|
'my-subscriptions': {
|
|
|
|
name: 'my-subscriptions',
|
2023-09-21 14:00:22 +00:00
|
|
|
title: __( 'My subscriptions', 'woocommerce' ),
|
2024-04-02 15:04:57 +00:00
|
|
|
showUpdateCount: true,
|
|
|
|
updateCount: wooUpdateCount,
|
2023-08-02 11:46:54 +00:00
|
|
|
},
|
2023-07-20 13:53:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const setUrlTabParam = ( tabKey: string ) => {
|
|
|
|
navigateTo( {
|
2023-10-04 17:37:41 +00:00
|
|
|
url: getNewPath(
|
|
|
|
{ tab: tabKey === DEFAULT_TAB_KEY ? undefined : tabKey },
|
|
|
|
MARKETPLACE_PATH,
|
|
|
|
{}
|
|
|
|
),
|
2023-07-20 13:53:06 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2024-05-15 12:43:06 +00:00
|
|
|
const getVisibleTabs = ( selectedTab: string, hasBusinessServices = false ) => {
|
2023-10-04 16:59:34 +00:00
|
|
|
if ( selectedTab === '' ) {
|
|
|
|
return tabs;
|
|
|
|
}
|
|
|
|
const currentVisibleTabs = { ...tabs };
|
|
|
|
if ( selectedTab !== 'search' ) {
|
|
|
|
delete currentVisibleTabs.search;
|
|
|
|
}
|
2024-05-15 12:43:06 +00:00
|
|
|
if ( ! hasBusinessServices ) {
|
|
|
|
delete currentVisibleTabs[ 'business-services' ];
|
|
|
|
}
|
2023-10-04 16:59:34 +00:00
|
|
|
|
|
|
|
return currentVisibleTabs;
|
|
|
|
};
|
2024-04-02 15:04:57 +00:00
|
|
|
|
2023-10-04 16:59:34 +00:00
|
|
|
const renderTabs = (
|
|
|
|
marketplaceContextValue: MarketplaceContextType,
|
|
|
|
visibleTabs: Tabs
|
|
|
|
) => {
|
|
|
|
const { selectedTab, setSelectedTab } = marketplaceContextValue;
|
2023-10-17 16:32:23 +00:00
|
|
|
|
|
|
|
const onTabClick = ( tabKey: string ) => {
|
|
|
|
if ( tabKey === selectedTab ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
setSelectedTab( tabKey );
|
|
|
|
setUrlTabParam( tabKey );
|
|
|
|
};
|
|
|
|
|
2023-07-20 13:53:06 +00:00
|
|
|
const tabContent = [];
|
2023-10-04 16:59:34 +00:00
|
|
|
for ( const tabKey in visibleTabs ) {
|
2023-07-20 13:53:06 +00:00
|
|
|
tabContent.push(
|
2023-08-14 13:53:07 +00:00
|
|
|
tabs[ tabKey ]?.href ? (
|
|
|
|
<a
|
|
|
|
className={ classNames(
|
|
|
|
'woocommerce-marketplace__tab-button',
|
|
|
|
'components-button',
|
|
|
|
`woocommerce-marketplace__tab-${ tabKey }`
|
|
|
|
) }
|
|
|
|
href={ tabs[ tabKey ]?.href }
|
|
|
|
key={ tabKey }
|
|
|
|
>
|
|
|
|
{ tabs[ tabKey ]?.title }
|
|
|
|
</a>
|
|
|
|
) : (
|
|
|
|
<Button
|
|
|
|
className={ classNames(
|
|
|
|
'woocommerce-marketplace__tab-button',
|
|
|
|
`woocommerce-marketplace__tab-${ tabKey }`,
|
|
|
|
{
|
|
|
|
'is-active': tabKey === selectedTab,
|
|
|
|
}
|
|
|
|
) }
|
2023-10-17 16:32:23 +00:00
|
|
|
onClick={ () => onTabClick( tabKey ) }
|
2023-08-14 13:53:07 +00:00
|
|
|
key={ tabKey }
|
|
|
|
>
|
|
|
|
{ tabs[ tabKey ]?.title }
|
2024-04-02 15:04:57 +00:00
|
|
|
{ tabs[ tabKey ]?.showUpdateCount &&
|
|
|
|
tabs[ tabKey ]?.updateCount > 0 && (
|
|
|
|
<span className="woocommerce-marketplace__update-count">
|
|
|
|
<span> { tabs[ tabKey ]?.updateCount } </span>
|
|
|
|
</span>
|
|
|
|
) }
|
2023-08-14 13:53:07 +00:00
|
|
|
</Button>
|
|
|
|
)
|
2023-07-20 13:53:06 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
return tabContent;
|
|
|
|
};
|
|
|
|
|
|
|
|
const Tabs = ( props: TabsProps ): JSX.Element => {
|
[wccom-17942] Only showing feedback snackbar when content of in-app marketplace has finished loading. Making sure snackbar is fixed position, so it's visible wherever you are on the page.
- `ProductListContextProvider` provides `setIsLoading` function as well as `isLoading`.
- `Discover` uses these values from context, instead of keeping a loading state in itself.
- `FeedbackModal` calls `maybSetTimeout` when `isLoading` changes. If `isLoading` isn't truthy, and snackbar hasn't already rendered, it sets a timeout of 5 seconds to show it.
- Removed wrapping <WooFooterItem> from around Footer component, so it's no longer a child of the WooCommerce Admin `.woocommerce-layout__footer` footer.
- Removed the `position: relative` from `.woocommerce-layout__footer`. It needs to be `position: fixed`.
- Added FooterContent component to Footer, to allow the layout we want.
- Changed use of context. This now only has states for the selected tab and loading state.
- We use this context in `Tabs` and `Content` to keep track of which tab is selected, and set the selected tab.
- We also use it in `Discover` and `Extensions`, which both report loading state to the context. This allows us to use it to only render the snackbar when loading is complete.
- Extensions: moved `productList` and `setProductList` and logic for getting product list from the context provider to a state in this component. We don't need to share the list of products in the context.
- Renamed `ProductListContext`, `ProductListContextProvider` and `productListContextValue` to more generic `MarketplaceContext`, `MarketplaceContextProvider` and `marketplaceContextValue`.
- Renamed a constant and created constants for API paths.
- Only shows snackbar after content has loaded, and after a timeout. We set a date `marketplace_redesign_2023_last_shown_date` in local storage to ensure we only show one snackbar.
2023-08-23 15:49:36 +00:00
|
|
|
const { additionalClassNames } = props;
|
|
|
|
const marketplaceContextValue = useContext( MarketplaceContext );
|
2024-05-15 12:43:06 +00:00
|
|
|
const { selectedTab, setSelectedTab, hasBusinessServices } =
|
|
|
|
marketplaceContextValue;
|
2023-10-04 16:59:34 +00:00
|
|
|
const [ visibleTabs, setVisibleTabs ] = useState( getVisibleTabs( '' ) );
|
2023-07-20 13:53:06 +00:00
|
|
|
|
2023-09-04 14:45:24 +00:00
|
|
|
const query: Record< string, string > = useQuery();
|
2023-07-20 13:53:06 +00:00
|
|
|
|
2023-07-20 16:00:22 +00:00
|
|
|
useEffect( () => {
|
2023-07-20 13:53:06 +00:00
|
|
|
if ( query?.tab && tabs[ query.tab ] ) {
|
|
|
|
setSelectedTab( query.tab );
|
2023-10-04 16:59:34 +00:00
|
|
|
} else if ( Object.keys( query ).length > 0 ) {
|
2023-07-20 16:00:22 +00:00
|
|
|
setSelectedTab( DEFAULT_TAB_KEY );
|
2023-07-20 13:53:06 +00:00
|
|
|
}
|
2023-07-20 16:00:22 +00:00
|
|
|
}, [ query, setSelectedTab ] );
|
2023-07-20 13:53:06 +00:00
|
|
|
|
2023-10-04 16:59:34 +00:00
|
|
|
useEffect( () => {
|
2024-05-15 12:43:06 +00:00
|
|
|
setVisibleTabs( getVisibleTabs( selectedTab, hasBusinessServices ) );
|
|
|
|
}, [ selectedTab, hasBusinessServices ] );
|
2023-07-20 13:53:06 +00:00
|
|
|
return (
|
2023-07-26 11:31:59 +00:00
|
|
|
<nav
|
|
|
|
className={ classNames(
|
|
|
|
'woocommerce-marketplace__tabs',
|
|
|
|
additionalClassNames || []
|
|
|
|
) }
|
|
|
|
>
|
2023-10-04 16:59:34 +00:00
|
|
|
{ renderTabs( marketplaceContextValue, visibleTabs ) }
|
2023-07-20 13:53:06 +00:00
|
|
|
</nav>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default Tabs;
|