-
Notifications
You must be signed in to change notification settings - Fork 159
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feature] Add cart icon to Masthead for SAP Commerce integration (#12089
) ### Related Ticket(s) [ADCMS-6463](https://jsw.ibm.com/browse/ADCMS-6463) ### Description Adds a new `<c4d-masthead-cart>` component to the Masthead. Needs to be opted in using `has-cart` attribute on the `<c4d-masthead-container>` component. When opted in, there is internal logic to read a cookie that will determine if the cart should be shown. ### Testing instructions The cart icon functionality is controlled by two new knobs on the Masthead > Default story. The "show the cart functionality (has-cart)" checkbox toggles whether or not the cart renders at all. The "mock active cart id" will affect the cookie that the cart is looking for to show / hide. Anytime you change the "mock active cart id", you need to toggle the "show the cart functionality (has-cart)" so that the `<c4d-masthead-card>` component will re-render and check the cookie value. The cart icon should only appear when "show the cart functionality (has-cart)" is set **and** there is a non-empty value for "mock active cart id". Check visuals against [Figma specs](https://www.figma.com/design/aQ0mMVEnxwDDoupkKeaNHc/Ecommerce-Mid-Fidelity-(delivery-file)?node-id=15928-64507&node-type=instance&t=bHBr0X1ykXryXSFP-0). ### Changelog **New** - `<c4d-masthead-cart>` component, automaticallly placed in `<c4d-masthead-global-bar>` when opted into via `has-cart` attribute on `<c4d-masthead-container>` <!-- React and Web Component deploy previews are enabled by default. --> <!-- To enable additional available deploy previews, apply the following --> <!-- labels for the corresponding package: --> <!-- *** "test: e2e": Codesandbox examples and e2e integration tests --> <!-- *** "package: services": Services --> <!-- *** "package: utilities": Utilities --> <!-- *** "RTL": React / Web Components (RTL) --> <!-- *** "feature flag": React / Web Components (experimental) -->
- Loading branch information
Showing
7 changed files
with
235 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/** | ||
* @license | ||
* | ||
* Copyright IBM Corp. 2024 | ||
* | ||
* This source code is licensed under the Apache-2.0 license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import Cookies from 'js-cookie'; | ||
|
||
const _cookieName = 'activeCartId'; | ||
|
||
class SAPCommerceAPI { | ||
/** | ||
* Check if the user has an active cart by looking for the non-empty cookie. | ||
* | ||
* @returns {boolean} | ||
*/ | ||
static hasActiveCart() { | ||
const activeCartId = SAPCommerceAPI.getActiveCartId(); | ||
// Return true if the activeCartId cookie is non-empty. | ||
return activeCartId !== ''; | ||
} | ||
|
||
/** | ||
* Returns the active cart id. | ||
* | ||
* @returns {string} | ||
* The active cart id if there is one, otherwise empty string. | ||
*/ | ||
static getActiveCartId() { | ||
const activeCartId = Cookies.get(_cookieName); | ||
return activeCartId && typeof activeCartId === 'string' | ||
? activeCartId.trim() | ||
: ''; | ||
} | ||
|
||
/** | ||
* Set the active cart id. | ||
* | ||
* @param {string} activeCartId | ||
* The active cart id. | ||
*/ | ||
static setActiveCartId(activeCartId) { | ||
Cookies.set(_cookieName, activeCartId.trim()); | ||
} | ||
|
||
/** | ||
* Remove the active cart id. | ||
*/ | ||
static removeActiveCartId() { | ||
Cookies.remove(_cookieName); | ||
} | ||
} | ||
|
||
export default SAPCommerceAPI; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** | ||
* @license | ||
* | ||
* Copyright IBM Corp. 2024 | ||
* | ||
* This source code is licensed under the Apache-2.0 license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
export { default as SAPCommerceAPI } from './SAPCommerce.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ import { | |
} from './profile-items'; | ||
import { C4D_CUSTOM_PROFILE_LOGIN } from '../../../globals/internal/feature-flags'; | ||
import readme from './README.stories.mdx'; | ||
import SAPCommerceAPI from '@carbon/ibmdotcom-services/es/services/SAPCommerce/SAPCommerce.js'; | ||
|
||
const userStatuses = { | ||
authenticated: '[email protected]', | ||
|
@@ -107,10 +108,21 @@ const enumToArray = (en) => | |
.filter((value) => typeof value === 'string') | ||
.map((key) => en[key]); | ||
|
||
const setActiveCartId = (activeCartId?: string) => { | ||
if (typeof activeCartId === 'string') { | ||
SAPCommerceAPI.setActiveCartId(activeCartId); | ||
} else { | ||
SAPCommerceAPI.removeActiveCartId(); | ||
} | ||
}; | ||
|
||
export const Default = (args) => { | ||
const { | ||
customProfileLogin, | ||
hasProfile, | ||
hasCart, | ||
mockActiveCartId, | ||
cartLabel, | ||
hasSearch, | ||
hasContact, | ||
initialSearchTerm, | ||
|
@@ -120,6 +132,7 @@ export const Default = (args) => { | |
authMethod, | ||
useMock, | ||
} = args?.MastheadComposite ?? {}; | ||
setActiveCartId(mockActiveCartId); | ||
return html` | ||
<style> | ||
${styles} | ||
|
@@ -132,6 +145,7 @@ export const Default = (args) => { | |
initial-search-term="${ifDefined(initialSearchTerm)}" | ||
searchPlaceholder="${ifDefined(searchPlaceholder)}" | ||
has-profile="${hasProfile}" | ||
?has-cart="${hasCart}" | ||
has-search="${hasSearch}" | ||
has-contact="${hasContact}" | ||
.l0Data="${mastheadL0Data}" | ||
|
@@ -140,7 +154,8 @@ export const Default = (args) => { | |
unauthenticatedProfileItems | ||
)}" | ||
custom-profile-login="${customProfileLogin}" | ||
auth-method="${MASTHEAD_AUTH_METHOD.DEFAULT}"></c4d-masthead-container> | ||
auth-method="${MASTHEAD_AUTH_METHOD.DEFAULT}" | ||
cart-label="${ifNonEmpty(cartLabel)}"></c4d-masthead-container> | ||
` | ||
: html` | ||
<c4d-masthead-container | ||
|
@@ -150,10 +165,12 @@ export const Default = (args) => { | |
initial-search-term="${ifDefined(initialSearchTerm)}" | ||
searchPlaceholder="${ifNonEmpty(searchPlaceholder)}" | ||
has-profile="${hasProfile}" | ||
?has-cart="${hasCart}" | ||
has-search="${hasSearch}" | ||
has-contact="${hasContact}" | ||
custom-profile-login="${customProfileLogin}" | ||
auth-method="${authMethod}"></c4d-masthead-container> | ||
auth-method="${authMethod}" | ||
cart-label="${ifNonEmpty(cartLabel)}"></c4d-masthead-container> | ||
`} | ||
`; | ||
}; | ||
|
@@ -211,6 +228,9 @@ WithCustomTypeahead.story = { | |
MastheadComposite: { | ||
grouped: 'false', | ||
hasProfile: 'true', | ||
hasCart: false, | ||
mockActiveCartId: '', | ||
cartLabel: '', | ||
hasSearch: 'true', | ||
searchPlaceHolder: 'Search all of IBM', | ||
selectedMenuItem: 'Services & Consulting', | ||
|
@@ -317,6 +337,9 @@ withPlatform.story = { | |
MastheadComposite: { | ||
platform: 'Platform', | ||
hasProfile: 'true', | ||
hasCart: false, | ||
mockActiveCartId: '', | ||
cartLabel: '', | ||
hasSearch: 'true', | ||
searchPlaceHolder: 'Search all of IBM', | ||
selectedMenuItem: 'Services & Consulting', | ||
|
@@ -460,6 +483,9 @@ withAlternateLogoAndTooltip.story = { | |
MastheadComposite: { | ||
platform: null, | ||
hasProfile: 'true', | ||
hasCart: false, | ||
mockActiveCartId: '', | ||
cartLabel: '', | ||
hasSearch: 'true', | ||
searchPlaceholder: 'Search all of IBM', | ||
selectedMenuItem: 'Services & Consulting', | ||
|
@@ -506,6 +532,9 @@ WithScopedSearch.story = { | |
default: { | ||
MastheadComposite: { | ||
hasProfile: 'true', | ||
hasCart: false, | ||
mockActiveCartId: '', | ||
cartLabel: '', | ||
hasSearch: 'true', | ||
searchPlaceHolder: 'Search all of IBM', | ||
selectedMenuItem: 'Services & Consulting', | ||
|
@@ -560,6 +589,9 @@ export default { | |
['true', 'false'], | ||
'true' | ||
), | ||
hasCart: boolean('show the cart functionality (has-cart)', false), | ||
mockActiveCartId: textNullable('mock active cart id', ''), | ||
cartLabel: textNullable('cart label (cart-label)', ''), | ||
hasSearch: select( | ||
'show the search functionality (has-search)', | ||
['true', 'false'], | ||
|
@@ -601,6 +633,9 @@ export default { | |
MastheadComposite: { | ||
platform: null, | ||
hasProfile: 'true', | ||
hasCart: false, | ||
mockActiveCartId: '', | ||
cartLabel: '', | ||
hasSearch: 'true', | ||
initialSearchTerm: '', | ||
searchPlaceholder: 'Search all of IBM', | ||
|
90 changes: 90 additions & 0 deletions
90
packages/web-components/src/components/masthead/masthead-cart.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/** | ||
* @license | ||
* | ||
* Copyright IBM Corp. 2024 | ||
* | ||
* This source code is licensed under the Apache-2.0 license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import StableSelectorMixin from '../../globals/mixins/stable-selector'; | ||
import { html, LitElement } from 'lit'; | ||
import { property, state } from 'lit/decorators.js'; | ||
import settings from '@carbon/ibmdotcom-utilities/es/utilities/settings/settings.js'; | ||
import { carbonElement as customElement } from '@carbon/web-components/es/globals/decorators/carbon-element'; | ||
import ShoppingCart20 from '@carbon/web-components/es/icons/shopping--cart/20.js'; | ||
import styles from './masthead.scss'; | ||
import LocaleAPI from '@carbon/ibmdotcom-services/es/services/Locale/Locale.js'; | ||
import SAPCommerceAPI from '@carbon/ibmdotcom-services/es/services/SAPCommerce/SAPCommerce.js'; | ||
|
||
const { prefix, stablePrefix: c4dPrefix } = settings; | ||
|
||
/** | ||
* The Cart icon in the masthead. | ||
* | ||
* @element c4d-masthead-cart | ||
* @csspart cart-link - The masthead cart link. Usage: `c4d-masthead-cart::part(cart-link)` | ||
*/ | ||
@customElement(`${c4dPrefix}-masthead-cart`) | ||
class C4DMastheadCart extends StableSelectorMixin(LitElement) { | ||
/** | ||
* The `aria-label` attribute for the link. | ||
*/ | ||
@property({ attribute: 'link-label' }) | ||
linkLabel = 'Cart'; | ||
|
||
/** | ||
* Tracks whether the user has an active cart to control the display. | ||
*/ | ||
@state() | ||
hasActiveCart = false; | ||
|
||
/** | ||
* Store the locale. Defaults to en-us. | ||
*/ | ||
@state() | ||
locale = { lc: 'en', cc: 'us' }; | ||
|
||
connectedCallback() { | ||
super.connectedCallback(); | ||
// Check the relevant cookie for whether the user has an active cart. | ||
this.hasActiveCart = SAPCommerceAPI.hasActiveCart(); | ||
// Fetch the locale for the page. | ||
LocaleAPI.getLocale().then((locale) => { | ||
this.locale = locale; | ||
}); | ||
} | ||
|
||
updated(changedProperties) { | ||
super.updated(changedProperties); | ||
const { hasActiveCart } = this; | ||
if (changedProperties.has('hasActiveCart')) { | ||
this.hidden = !hasActiveCart; | ||
} | ||
} | ||
|
||
render() { | ||
const { | ||
linkLabel, | ||
locale: { cc, lc }, | ||
} = this; | ||
|
||
return html` | ||
<a | ||
part="cart-link" | ||
href="/store/${lc}/${cc}/checkout" | ||
class="${prefix}--header__menu-item ${prefix}--header__menu-title" | ||
aria-label="${linkLabel}" | ||
>${ShoppingCart20()}</a | ||
> | ||
`; | ||
} | ||
|
||
static get stableSelector() { | ||
return `${c4dPrefix}--masthead-cart`; | ||
} | ||
|
||
static styles = styles; | ||
} | ||
|
||
export default C4DMastheadCart; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters