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

Add single product page route/component to the marketplace #70

Merged
merged 18 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions components/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Marketplace from './marketplace';
import ProductPage from './productPage';

const NewfoldMarketplace = ( { methods, constants, ...props } ) => {
const match = methods.useMatch( 'marketplace/product/:id' );
if ( match ) {
return (
<ProductPage
productPageId={ match.params.id }
methods={ methods }
constants={ constants }
/>
);
}

return (
<Marketplace methods={ methods } constants={ constants } { ...props } />
);
};

export default NewfoldMarketplace;
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import MarketplaceSkeleton from "../marketplaceSkeleton";
*/
const MarketplaceFilterBarSkeleton = ({ width, height }) => {
return (
<MarketplaceSkeleton width={ width || "500px" } height={ height || "45px" } customClass="filterbar-skeleton"/>
<MarketplaceSkeleton width={ width || "500px" } height={ height || "45px" } className="filterbar-skeleton"/>
);
}

Expand Down
12 changes: 6 additions & 6 deletions components/marketplaceIsLoading/MarketplaceItemSkeleton.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ const MarketplaceItemSkeleton = () => {
<div className="marketplace-item-skeleton">

<div className="skeleton-item-media">
<MarketplaceSkeleton width="100%" height="auto" customClass="marketplace-item-img-skeleton" />
<MarketplaceSkeleton width="100%" height="auto" className="marketplace-item-img-skeleton" />
</div>

<div className="skeleton-item-body">
<MarketplaceSkeleton width="170px" height="20px" customClass="marketplace-item-title-skeleton"/>
<MarketplaceSkeleton width="170px" height="20px" className="marketplace-item-title-skeleton"/>

<MarketplaceSkeleton width="100%" height="10px" customClass="marketplace-item-desc-skeleton"/>
<MarketplaceSkeleton width="100%" height="10px" customClass="marketplace-item-desc-skeleton"/>
<MarketplaceSkeleton width="70%" height="10px" customClass="marketplace-item-desc-skeleton"/>
<MarketplaceSkeleton width="100%" height="10px" className="marketplace-item-desc-skeleton"/>
<MarketplaceSkeleton width="100%" height="10px" className="marketplace-item-desc-skeleton"/>
<MarketplaceSkeleton width="70%" height="10px" className="marketplace-item-desc-skeleton"/>

<MarketplaceSkeleton width="80px" height="36px" customClass="marketplace-item-button-skeleton"/>
<MarketplaceSkeleton width="80px" height="36px" className="marketplace-item-button-skeleton"/>
</div>

</div>
Expand Down
64 changes: 50 additions & 14 deletions components/marketplaceItem/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { validate as isUuid } from 'uuid';
import { Button, Card, Link, Title } from '@newfold/ui-component-library';
import { ArrowRightIcon } from '@heroicons/react/24/outline';

Expand Down Expand Up @@ -150,6 +151,54 @@ const MarketplaceItem = ( { item, methods, constants } ) => {
return primaryCTA;
};

const renderSecondaryCTA = ( item ) => {
let secondaryCTA = '';
// If value is UUID, it is an internal link to a prodct page
const isInternal = isUuid( item.secondaryUrl );

const getLinkAttributes = () => {
const attributes = {
as: 'a',
className:
'nfd-inline-flex nfd-items-center nfd-gap-1.5 nfd-w-max nfd-no-underline',
href: generateSecondaryUrl(),
target: isInternal ? '_self' : '_blank',
onClick: handleNavigate,
};

return attributes;
};

const handleNavigate = ( e ) => {
const navigate = methods.useNavigate();
if ( isInternal ) {
e.preventDefault();
navigate( `/marketplace/product/${ item.secondaryUrl }` );
}
};

const generateSecondaryUrl = () => {
if ( isInternal ) {
return `${ window.NewfoldRuntime.admin_url }admin.php?page=bluehost#/marketplace/product/${ item.secondaryUrl }`;
}

return item.secondaryUrl;
};

if ( item.secondaryCallToAction && item.secondaryUrl ) {
secondaryCTA = (
<Link { ...getLinkAttributes() }>
<span className="nfd-text-primary">
{ item.secondaryCallToAction }
</span>
<ArrowRightIcon className="nfd-text-[#18181B] nfd-w-3" />
</Link>
);
}

return secondaryCTA;
};

const renderPrice = ( item ) => {
let pricewrap,
price,
Expand Down Expand Up @@ -198,20 +247,7 @@ const MarketplaceItem = ( { item, methods, constants } ) => {
{ item.name }
</Title>
<p>{ item.description }</p>

{ item.secondaryCallToAction && (
<Link
as="a"
href={ item.secondaryUrl }
target="_blank"
className="nfd-inline-flex nfd-items-center nfd-gap-1.5 nfd-w-max nfd-no-underline"
>
<span className="nfd-text-primary">
{ item.secondaryCallToAction }
</span>
<ArrowRightIcon className="nfd-text-[#18181B] nfd-w-3" />
</Link>
) }
{ renderSecondaryCTA( item ) }
</Card.Content>
<Card.Footer className="nfd-flex nfd-justify-between nfd-items-center nfd-flex-wrap nfd-gap-2 marketplace-item-footer">
{ renderPrice( item ) }
Expand Down
38 changes: 21 additions & 17 deletions components/marketplaceSkeleton/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@ import './stylesheet.scss';

/**
* MarketplaceSkeleton Component
* Use to generate content skeleton
*
* @param {*} props
* @returns
* Use to generate content loading skeleton
*
* @param {*} props
* @return {JSX.Element} MarketplaceSkeleton
*/
const MarketplaceSkeleton = ({ width, height, customClass }) => {
return (
<div
className={ "newfold-marketplace-skeleton " + ( customClass ) }
style={{
"width": width || "100%",
"height": height || "auto"
}}>
</div>
);
}

export default MarketplaceSkeleton;
const MarketplaceSkeleton = ( { width, height, className = '' } ) => {
return (
<div
// eslint-disable-next-line prettier/prettier
className={ classNames(
'newfold-marketplace-skeleton',
className
) }
style={ {
width: width || '100%',
height: height || 'auto',
} }
></div>
);
};

export default MarketplaceSkeleton;
2 changes: 1 addition & 1 deletion components/marketplaceSkeleton/stylesheet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
position: relative;
background-color: rgba(160, 170, 192, .35);
overflow: hidden;
border-radius: 2px;
border-radius: 4px;

&::after {
position: absolute;
Expand Down
32 changes: 32 additions & 0 deletions components/productPage/ProductPageError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Title } from '@newfold/ui-component-library';
import errorVector from '../../includes/assets/img/dog-walking.svg';

const ProductPageError = ( { text = {} } ) => {
return (
<div aria-live="assertive">
<div
role="alert"
className="nfd-flex nfd-flex-col nfd-items-center nfd-justify-center nfd-gap-6 nfd-p-8 nfd-min-h-[calc(100dvh-220px)]"
>
<img
src={ errorVector }
role="presentation"
alt="Dog walking with a leash"
width="300"
height="278.5"
/>
<div className="nfd-text-center">
<Title as="h2" size="1">
{ text?.title ?? 'Oops! Something Went Wrong' }
</Title>
<p className="nfd-mt-2 nfd-text-base">
{ text?.description ??
'An error occurred while loading the content. Please try again later.' }
</p>
</div>
</div>
</div>
);
};

export default ProductPageError;
129 changes: 129 additions & 0 deletions components/productPage/ProductPageLoading.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import MarketplaceSkeleton from '../marketplaceSkeleton';

const ProductPageLoading = () => {
const Hero = () => (
<div className="nfd-min-h-[35vh] nfd-flex nfd-flex-col nfd-items-center nfd-justify-center nfd-bg-[#f0f3f9] nfd-m-3 nfd-rounded-lg">
<MarketplaceSkeleton
width="35%"
height="35px"
className="nfd-mb-4"
/>
<div className="nfd-flex nfd-flex-col nfd-items-center nfd-gap-2 nfd-w-full">
<MarketplaceSkeleton width="31%" height="15px" />
<MarketplaceSkeleton width="40%" height="15px" />
<MarketplaceSkeleton width="20%" height="15px" />
</div>
</div>
);

const Features = () => (
<div className="nfd-py-10 nfd-flex nfd-flex-col nfd-items-center">
<MarketplaceSkeleton
width="28%"
height="25px"
className="nfd-mb-3"
/>
<MarketplaceSkeleton
width="20%"
height="15px"
className="nfd-mb-1.5"
/>
<MarketplaceSkeleton width="12%" height="15px" />
<div className="nfd-mt-8 nfd-flex nfd-justify-between nfd-w-10/12">
<Feature />
<Feature />
<Feature />
</div>
</div>
);

const Feature = () => (
<div className="nfd-w-1/4 nfd-flex nfd-flex-col nfd-items-center">
<MarketplaceSkeleton
width="65px"
height="65px"
className="nfd-mb-4 nfd-rounded-full"
/>
<MarketplaceSkeleton
width="100%"
height="24px"
className="nfd-mb-2.5"
/>
<div className="nfd-flex nfd-flex-col nfd-items-center nfd-gap-1.5 nfd-w-full">
<MarketplaceSkeleton width="90%" height="15px" />
<MarketplaceSkeleton width="88%" height="15px" />
<MarketplaceSkeleton width="60%" height="15px" />
</div>
</div>
);

const Pricing = () => (
<>
<div className="nfd-w-full nfd-mt-3 nfd-flex nfd-flex-col nfd-items-center">
<div className="nfd-w-10/12 nfd-min-h-0.5 nfd-bg-[#f0f3f9]"></div>
</div>
<div className="nfd-py-10 nfd-flex nfd-flex-col nfd-items-center">
<MarketplaceSkeleton width="22%" height="27px" />
<div className="nfd-mt-10 nfd-flex nfd-justify-between nfd-w-10/12">
<PricingItem />
<PricingItem />
<PricingItem />
</div>
</div>
</>
);

const PricingItem = () => (
<div className="nfd-w-1/4 nfd-flex nfd-flex-col nfd-gap-7 nfd-bg-[#f0f3f9] nfd-rounded-lg nfd-p-6">
<MarketplaceSkeleton width="90%" height="28px" />
<div className="nfd-flex nfd-flex-col nfd-gap-4">
<MarketplaceSkeleton width="80%" height="14px" />
<MarketplaceSkeleton width="55%" height="14px" />
<MarketplaceSkeleton width="100%" height="14px" />
<MarketplaceSkeleton width="72%" height="14px" />
<MarketplaceSkeleton width="47%" height="14px" />
<MarketplaceSkeleton width="80%" height="14px" />
</div>
<MarketplaceSkeleton width="55%" height="34px" />
</div>
);

const FAQ = () => (
<div className="nfd-flex nfd-flex-col nfd-items-center nfd-gap-8 nfd-py-12 nfd-mx-auto nfd-w-7/12">
<FAQitem width="96%">
<div className="nfd-flex nfd-flex-col nfd-gap-2.5 nfd-mt-4">
<MarketplaceSkeleton width="100%" height="14px" />
<MarketplaceSkeleton width="91%" height="14px" />
<MarketplaceSkeleton width="95%" height="14px" />
<MarketplaceSkeleton width="54%" height="14px" />
</div>
</FAQitem>
<FAQitem />
<FAQitem />
<FAQitem />
<FAQitem />
</div>
);

const FAQitem = ( { width = '100%', children } ) => (
<div className="nfd-w-full nfd-bg-[#f0f3f9] nfd-rounded-lg nfd-p-4">
<MarketplaceSkeleton width={ width } height="26px" />
{ children }
</div>
);

return (
<div
aria-busy="true"
aria-live="polite"
aria-label="Fetching product details"
>
<Hero />
<Features />
<Pricing />
<FAQ />
</div>
);
};

export default ProductPageLoading;
Loading
Loading