Skip to content

Latest commit

 

History

History
200 lines (173 loc) · 8.07 KB

File metadata and controls

200 lines (173 loc) · 8.07 KB

Dynamics 365 Commerce - online extensibility samples

License

License is listed in the LICENSE file.

Sample - Promo code affiliation

Overview

In this sample, you will learn how to apply any valid promo code and get the benefits.

When a user applies the promo code, an API is called to ensure the code is valid (ie: not expired, correct category,...) then will apply the promotion to the cart.

Promo-code affiliation extends the above default behavior to performs below functions: Website landing Page: End user can land to website with promo code in URL. Empty Cart: Apply the promo code from URL to the empty cart. Cart with products: Apply promo-code automatically on the cart.

promocode

Starter kit license

License for starter kit is listed in the LICENSE .

Prerequisites

Follow the instructions mentioned in document to set up the development environment.

Procedure to create custom theme

Follow the instructions mentioned in document to create the custom theme,in this sample, we'll assume a custom theme has been cloned from the fabrikam theme named "fabrikam-extended".

Detailed Steps

1. Extend definition file for header

  1. Create a new file named header.definition.ext.json under src\themes\fabrikam-extended\definition-extensions folder and paste the code below in it
{
    "$type": "definitionExtension",
    "resources": {
      "cartLabelNoItems": {
        "comment": "Cart label for no items",
        "value": "Shopping bag, having no items"
      },
      "cartLabelWithOneItem": {
        "comment": "Cart label for one items",
        "value": "Shopping bag, having one item"
      }
    }
}

2. Extend view file for header

  1. Create a new file named header.view.tsx under src\themes\fabrikam-extended\views\header.view.tsx folder and paste the code below in it
/*--------------------------------------------------------------
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * See License.txt in the project root for license information.
 *--------------------------------------------------------------*/

import { Module, Node } from '@msdyn365-commerce-modules/utilities';
import * as React from 'react';

import { IHeaderViewProps } from '@msdyn365-commerce-modules/header';
import { format } from '@msdyn365-commerce/retail-proxy';
import { IHeaderProps as IHeaderExtensionProps } from '../definition-extensions/header.ext.props.autogenerated';
import { CartIconComponent } from '@msdyn365-commerce/components';

const headerView: React.FC<IHeaderViewProps & IHeaderExtensionProps<{}>> = props => {
    const {
        HeaderTag,
        HeaderContainer,
        HeaderTopBarContainer,
        MobileMenuContainer,
        MobileMenuBodyContainer,
        MobileMenuLinksContainer,
        Divider
    } = props;
    return (
        <Module {...HeaderTag}>
            <Node {...HeaderContainer}>
                <Node {...HeaderTopBarContainer}>
                    {props.navIcon}
                    {props.logo}
                    {_renderReactFragment(props.search)}
                    {props.preferredStore}
                    {_renderDesktopAccountBlock(props)}
                    {props.wishListIconDesktop}
                    <Node {...Divider} />
                    {_renderCartIcon(props)}
                    {_renderReactFragment(props.siteOptions)}
                </Node>
                <Node {...MobileMenuContainer}>
                    <Node {...MobileMenuBodyContainer}>
                        { props.MobileMenuHeader }
                        {_renderReactFragment(props.menuBar)}
                        <Node {...MobileMenuLinksContainer}>
                            { props.accountLinks ? props.accountLinks.map(link => link) : false }
                            { props.siteOptions }
                            { props.wishListIconMobile }
                            { props.signInLink }
                            { props.signOutLink }
                        </Node>
                    </Node>
                </Node>
                {_renderReactFragment(props.menuBar)}
            </Node>
        </Module>
    );
};

function _renderCartIcon(props: IHeaderViewProps & IHeaderExtensionProps<{}>): JSX.Element | null {
    const _promoCode = props.context.request!.query!['promocode'];
    if (props.data.cart.result) {
        if (_promoCode != undefined && _promoCode != '') {
            props.data.cart.result.addPromoCode({ promoCode: _promoCode })
                .then(
                    (result: any) => {
                        console.log(result.status)
                    }
                )
        }

        const cartItem = `${props.data.cart.result.totalItemsInCart}`;
        const itemCount = cartItem && parseInt(cartItem, 10) || 0;
        let label = props.resources.cartLabelNoItems || 'Shopping bag, having no items';
        if (itemCount === 1) {
            label = props.resources.cartLabelWithOneItem || 'Shopping bag, having one item';
        } else if (itemCount > 1) {
            label = props.resources.cartLabel && format(props.resources.cartLabel, cartItem) || `Shopping bag, having ${itemCount} items`;
        }
        return (
            <CartIconComponent
                cartLabel={label}
                cartQtyLabel= {props.resources.cartQtyLabel}
                context={props.context}
                id={props.id}
                typeName={props.typeName}
                data={{ cart: props.data.cart.result }}
            />
        );
    } else {
        return null;
    }
}

function _renderDesktopAccountBlock(props: IHeaderViewProps): JSX.Element | null {
    const {
        AccountInfoDropdownParentContainer,
        AccountInfoDropdownPopoverConentContainer,
        accountInfoDropdownButton,
        signOutLink,
        signInLink,
        accountLinks
    } = props;

    if (AccountInfoDropdownParentContainer) {
        if (AccountInfoDropdownPopoverConentContainer) {
            return (
                <Node {...AccountInfoDropdownParentContainer}>
                    {accountInfoDropdownButton}
                    <Node {...AccountInfoDropdownPopoverConentContainer}>
                        { accountLinks ? accountLinks.map(link => link) : false }
                        {signOutLink}
                    </Node>
                </Node>
            );
        } else if (signInLink) {
            return (
                <Node {...AccountInfoDropdownParentContainer}>
                    {signInLink}
                </Node>
            );
        }
    }
    props.context.telemetry.error('Header content is empty, module wont render.');
    return null;
}

function _renderReactFragment(items: React.ReactNode[]): JSX.Element | null {
    return (
        <>
            {items && items.length > 0 ? items.map((slot: React.ReactNode, index: number) => {
                return (<React.Fragment key={index}>
                    {slot}
                </React.Fragment>);
            }) : null}
        </>
    );
}

export default headerView;

5. Build and test module

The sample can now be tested in a web browser using the yarn start command.

Go to browser and open the site with theme (https://localhost:4000/?theme=fabrikam-extended) and navigate to cart page , then apply promocode in the url as query string like "&promocode=WEEKLYAD",final url will be (https://localhost:4000/?theme=fabrikam-extended&promocode=WEEKLYAD)

Third party Image and Video Usage restrictions

The software may include third party images and videos that are for personal use only and may not be copied except as provided by Microsoft within the demo websites. You may install and use an unlimited number of copies of the demo websites., You may not publish, rent, lease, lend, or redistribute any images or videos without authorization from the rights holder, except and only to the extent that the applicable copyright law expressly permits doing so.