Skip to content

Commit

Permalink
PWA-1673: View Product Attributes values on PDP - Content (#3759)
Browse files Browse the repository at this point in the history
* PWA-1673: View Product Attributes values on PDP - Content

- Updated styling to PDP
- Updated page format for PDP

* PWA-1673: View Product Attributes values on PDP - Content

* PWA-1673: View Product Attributes values on PDP - Content

- Updated plain html renderer to modify img src

* PWA-1673: View Product Attributes values on PDP - Content

- Resolved test failure

* PWA-1673: View Product Attributes values on PDP - Content
 - PWA-2534: [bug]: Widget\Link does not convert the link for PWA

* PWA-1673: View Product Attributes values on PDP - Content
 - Add SKU to details list

Co-authored-by: Hwashiang (Michael) Yu <[email protected]>
Co-authored-by: Devagouda <[email protected]>
Co-authored-by: Jason Poteet <[email protected]>
  • Loading branch information
4 people authored Apr 22, 2022
1 parent 2704930 commit c1a5670
Show file tree
Hide file tree
Showing 23 changed files with 565 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@
"createWishlist.dialogTitle": "Nouvelle liste de favoris",
"createWishlist.handleCreateListText": "Créer une liste",
"createWishlist.listName": "Nom de la liste",
"customAttributes.title": "Détails",
"Customer Service": "Service à la clientèle",
"customerForm.defaultShipping": "Faites-en mon adresse par défaut",
"customerForm.formMessage": "L'adresse de livraison que vous entrez sera enregistrée dans votre carnet d'adresses et définie par défaut pour vos futurs achats.",
Expand Down Expand Up @@ -312,6 +311,7 @@
"productFullDetail.errorToken": "Un problème est survenu avec votre panier. Veuillez vous reconnecter et réessayer d'ajouter l'élément.",
"productFullDetail.errorUnknown": "Impossible d'ajouter l'article au panier. Veuillez vérifier les options requises et réessayer.",
"productFullDetail.productDescription": "Description du produit",
"productFullDetail.details": "Détails",
"productList.each": " ch.",
"productList.outOfStock": "en rupture de stock",
"productList.quantity": "Qté : {quantity}",
Expand Down
2 changes: 1 addition & 1 deletion packages/pagebuilder/lib/ContentTypes/Banner/banner.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import defaultClasses from './banner.module.css';
import { useStyle } from '@magento/venia-ui/lib/classify';
import { arrayOf, bool, oneOf, shape, string, func, object } from 'prop-types';
import Button from '@magento/venia-ui/lib/components/Button/button';
import resolveLinkProps from '../../resolveLinkProps';
import resolveLinkProps from '@magento/peregrine/lib/util/resolveLinkProps';
import { Link, useHistory } from 'react-router-dom';
import resourceUrl from '@magento/peregrine/lib/util/makeUrl';
import useIntersectionObserver from '@magento/peregrine/lib/hooks/useIntersectionObserver';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useHistory } from 'react-router-dom';
import { useStyle } from '@magento/venia-ui/lib/classify';
import Button from '@magento/venia-ui/lib/components/Button/button';

import resolveLinkProps from '../../resolveLinkProps';
import resolveLinkProps from '@magento/peregrine/lib/util/resolveLinkProps';
import defaultClasses from './buttonItem.module.css';

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/pagebuilder/lib/ContentTypes/Image/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import defaultClasses from './image.module.css';
import { arrayOf, bool, oneOf, shape, string, number } from 'prop-types';
import { Link } from 'react-router-dom';
import resolveLinkProps from '../../resolveLinkProps';
import resolveLinkProps from '@magento/peregrine/lib/util/resolveLinkProps';
import { useStyle } from '@magento/venia-ui/lib/classify';
import resourceUrl from '@magento/peregrine/lib/util/makeUrl';

Expand Down
4 changes: 3 additions & 1 deletion packages/pagebuilder/lib/ContentTypes/Text/text.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import defaultClasses from './text.module.css';
import { useHistory } from 'react-router-dom';
import handleHtmlContentClick from '../../handleHtmlContentClick';

const toHTML = str => ({ __html: str });
import htmlStringImgUrlConverter from '@magento/peregrine/lib/util/htmlStringImgUrlConverter';

const toHTML = str => ({ __html: htmlStringImgUrlConverter(str) });

/**
* Page Builder Text component.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ export const useProductFullDetail = props => {
// Normalization object for product details we need for rendering.
const productDetails = {
description: product.description,
shortDescription: product.short_description,
name: product.name,
price: productPrice,
sku: product.sku
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export const ProductDetailsFragment = gql`
description {
html
}
short_description {
html
}
id
uid
# eslint-disable-next-line @graphql-eslint/require-id-when-available
Expand Down
53 changes: 53 additions & 0 deletions packages/peregrine/lib/util/__tests__/resolveLinkProps.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import resolveLinkProps from '../resolveLinkProps';

describe('resolve to internal link', () => {
process.env.MAGENTO_BACKEND_URL = 'http://magento.com/';

test('when base url matches', () => {
const linkProps = resolveLinkProps('http://magento.com/cms-page');
expect(linkProps).toEqual({
to: '/cms-page'
});
});

test('when base url matches product URL', () => {
const linkProps = resolveLinkProps(
'http://magento.com/product-page.html'
);
expect(linkProps).toEqual({
to: '/product-page.html'
});
});

test('with root-relative url', () => {
const linkProps = resolveLinkProps('/cms-page');
expect(linkProps).toEqual({
to: '/cms-page'
});
});

test('with relative url', () => {
const linkProps = resolveLinkProps('cms-page');
expect(linkProps).toEqual({
to: '/cms-page'
});
});
});

test('resolve to external anchor if external link', () => {
process.env.MAGENTO_BACKEND_URL = 'http://magento.com/';
const linkProps = resolveLinkProps(
'http://not-magento.com/product-page.html'
);
expect(linkProps).toEqual({
href: 'http://not-magento.com/product-page.html'
});
});

test('return original input if input is invalid', () => {
process.env.MAGENTO_BACKEND_URL = null;
const linkProps = resolveLinkProps(null);
expect(linkProps).toEqual({
href: null
});
});
26 changes: 26 additions & 0 deletions packages/peregrine/lib/util/htmlStringImgUrlConverter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import makeUrl from './makeUrl';
import resolveLinkProps from './resolveLinkProps';

/**
* Modifies html string images to use makeUrl as source and resolves links to use internal path.
*
* @param {string} htmlString - the html string to be updated
* @return {string}
*/
const htmlStringImgUrlConverter = htmlString => {
const temporaryElement = document.createElement('div');
temporaryElement.innerHTML = htmlString;
for (const imgElement of temporaryElement.getElementsByTagName('img')) {
imgElement.src = makeUrl(imgElement.src, {
type: 'image-wysiwyg',
quality: 85
});
}
for (const linkElement of temporaryElement.getElementsByTagName('a')) {
const linkProps = resolveLinkProps(linkElement.href);
linkElement.href = linkProps.to || linkProps.href;
}
return temporaryElement.innerHTML;
};

export default htmlStringImgUrlConverter;
25 changes: 25 additions & 0 deletions packages/peregrine/lib/util/resolveLinkProps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Resolve link properties
*
* @param {string} link
*/
export default link => {
let isExternalUrl;
const linkProps = {};

try {
const baseUrlObj = new URL(process.env.MAGENTO_BACKEND_URL);
const urlObj = new URL(link, baseUrlObj);
isExternalUrl = baseUrlObj.host !== urlObj.host;

if (isExternalUrl) {
linkProps['href'] = link;
} else {
linkProps['to'] = urlObj.pathname;
}
} catch (e) {
linkProps['href'] = link;
}

return linkProps;
};
2 changes: 1 addition & 1 deletion packages/venia-ui/i18n/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@
"createWishlistForm.privateRadio": "Private",
"createWishlistForm.publicRadio": "Public",
"createWishlistForm.saveButton": "Save",
"customAttributes.title": "Details",
"Customer Service": "Customer Service",
"customerForm.defaultShipping": "Make this my default address",
"customerForm.formMessage": "The shipping address you enter will be saved to your address book and set as your default for future purchases.",
Expand Down Expand Up @@ -357,6 +356,7 @@
"productFullDetail.errorToken": "There was a problem with your cart. Please sign in again and try adding the item once more.",
"productFullDetail.errorUnknown": "Could not add item to cart. Please check required options and try again.",
"productFullDetail.productDescription": "Product Description",
"productFullDetail.details": "Details",
"productFullDetail.unavailableProduct": "This product is currently unavailable for purchase.",
"productImageCarousel.previousButtonAriaLabel": "Previous Image",
"productImageCarousel.nextButtonAriaLabel": "Next Image",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
}

.contentHtml {
composes: block from global;
composes: inline-block from global;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
}

.contentHtml {
composes: block from global;
composes: inline-block from global;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,24 @@ import defaultClasses from './textarea.module.css';
*/
const Textarea = props => {
const classes = useStyle(defaultClasses, props.classes);
const { attribute_metadata = {}, entered_attribute_value = {} } = props;
const {
attribute_metadata = {},
entered_attribute_value = {},
showLabels = true
} = props;

const attributeLabel = attribute_metadata.label ? (
<div className={classes.label}>{attribute_metadata.label}</div>
) : null;
const attributeLabel =
attribute_metadata.label && showLabels ? (
<div className={classes.label}>{attribute_metadata.label}</div>
) : null;
let attributeContent;

if (entered_attribute_value.value) {
const { is_html_allowed: isHtml } = attribute_metadata.ui_input;

if (isHtml) {
// TODO: Get decoded wysiwyg widgets from GraphQl

attributeContent = (
<div className={classes.contentHtml}>
<RichContent html={entered_attribute_value.value} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ const defaultTypeConfig = {
},
textarea: {
component: Textarea
},
texteditor: {
component: Textarea
},
pagebuilder: {
component: Textarea
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

exports[`#CustomAttributes renders with custom attributes visible on front only 1`] = `
<div>
<p>
Details
</p>
<ul>
<li>
<mock-AttributeType
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useMemo } from 'react';
import { array, shape, string } from 'prop-types';
import { FormattedMessage } from 'react-intl';

import { useStyle } from '@magento/venia-ui/lib/classify';

Expand All @@ -10,7 +9,7 @@ import defaultClasses from './customAttributes.module.css';
export const IS_VISIBLE_ON_FRONT = 'PRODUCT_DETAILS_PAGE';

const CustomAttributes = props => {
const { customAttributes } = props;
const { customAttributes, showLabels } = props;
const classes = useStyle(defaultClasses, props.classes);

const list = useMemo(
Expand All @@ -26,7 +25,10 @@ const CustomAttributes = props => {
key={currentAttribute.attribute_metadata.uid}
className={classes.listItem}
>
<AttributeType data={currentAttribute} />
<AttributeType
showLabels={showLabels}
data={currentAttribute}
/>
</li>
);

Expand All @@ -35,7 +37,7 @@ const CustomAttributes = props => {

return previousAttribute;
}, []),
[classes, customAttributes]
[classes, customAttributes, showLabels]
);

if (list.length === 0) {
Expand All @@ -44,12 +46,6 @@ const CustomAttributes = props => {

return (
<div className={classes.root}>
<p className={classes.title}>
<FormattedMessage
id={'customAttributes.title'}
defaultMessage={'Details'}
/>
</p>
<ul className={classes.list}>{list}</ul>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
.root {
composes: mt-8 from global;
}

.title {
composes: font-semibold from global;
}

.list {
Expand Down
Loading

0 comments on commit c1a5670

Please sign in to comment.