, ICittaAccountSubscriptionState> {\r\n constructor(props: ICittaAccountSubscriptionViewProps) {\r\n super(props);\r\n this._handleSubscribeClick = this._handleSubscribeClick.bind(this);\r\n this._handleUnsubscribeClick = this._handleUnsubscribeClick.bind(this);\r\n const email = this.props.data && this.props.data.accountInformation && this.props.data.accountInformation.result?.Email;\r\n const subscribed = this._getSubscriptionState();\r\n const hasDetails = email !== undefined && subscribed !== undefined;\r\n\r\n this.state = {\r\n alertMessage: '',\r\n alertClass: '',\r\n userEmail: email || '',\r\n isSubscribed: subscribed || false,\r\n hasAccountDetails: hasDetails,\r\n isProcessing: false\r\n };\r\n }\r\n\r\n public componentDidUpdate(prevProps: ICittaAccountSubscriptionViewProps): void {\r\n if (this.props.data !== prevProps.data) {\r\n const { result } = this.props.data.accountInformation;\r\n if (result) {\r\n const email: string = this.props.data.accountInformation.result?.Email || '';\r\n const subscribed: boolean = this._getSubscriptionState() || false;\r\n const hasDetails1 = email !== undefined && subscribed !== undefined;\r\n this.setState({ userEmail: email, isSubscribed: subscribed, hasAccountDetails: hasDetails1 });\r\n }\r\n }\r\n\r\n }\r\n\r\n public render(): JSX.Element | null {\r\n const { hasAccountDetails, isProcessing } = this.state;\r\n const { config } = this.props;\r\n const CittaAccountSubscriptionViewProps = {\r\n ...this.props,\r\n AccountSubscriptionWrapper: {\r\n moduleProps: this.props,\r\n className: classnames('citta-account-subscription', config.className)\r\n },\r\n AccountSubscriptionAttribute: {\r\n className: 'citta-account-has-account'\r\n },\r\n AccountSubscriptionProcessing: {\r\n className: 'citta-account-subscription-processing'\r\n },\r\n AccountSubscriptionUnSubscribe: {\r\n className: 'citta-account-subscription-unsubscription'\r\n },\r\n subscribeResponse: this._getSubscribeResponse(),\r\n hasAccountDetails: hasAccountDetails,\r\n isProcessing: isProcessing,\r\n processingMessage: this._renderProcessing(),\r\n subUnsubButtton: this._renderButtons(),\r\n subscribeAlert: this._renderSubscribeAlert(),\r\n subscribeNote: this._renderSubscribeNote()\r\n };\r\n return this.props.renderView(CittaAccountSubscriptionViewProps) as React.ReactElement;\r\n }\r\n private _getSubscriptionState(): boolean | undefined {\r\n const accountInfo = this.props.data.accountInformation.result;\r\n if (accountInfo) {\r\n const attributes = accountInfo.Attributes;\r\n if (attributes && attributes.length > 0) {\r\n let isSubscribed;\r\n attributes.forEach(attr => {\r\n if (attr.Name === this.props.resources.optInAttributeName) {\r\n isSubscribed = attr.AttributeValue?.BooleanValue;\r\n }\r\n });\r\n return isSubscribed;\r\n }\r\n }\r\n return;\r\n }\r\n private _getSubscribeResponse(): React.ReactNode {\r\n const { isSubscribed, hasAccountDetails } = this.state;\r\n const { resources } = this.props;\r\n const message = hasAccountDetails\r\n ? {resources.subscribtionText} {isSubscribed ? resources.subscribtionStatus : resources.noSubscribtionStatus}{resources.subscribtionMailText}
\r\n : {resources.missingInfoMessage}
;\r\n\r\n return (\r\n \r\n
{resources.emailHeadingText}
\r\n {message}\r\n \r\n );\r\n }\r\n\r\n private _renderProcessing(): React.ReactNode {\r\n const { resources } = this.props;\r\n return (\r\n \r\n
{resources.processingLabel}
\r\n
\r\n );\r\n }\r\n\r\n // Render subscribe/unsubscribe button\r\n private _renderButtons(): React.ReactNode {\r\n const { resources } = this.props;\r\n const { isSubscribed, isProcessing } = this.state;\r\n if (isSubscribed) {\r\n return (\r\n \r\n );\r\n } else {\r\n return (\r\n \r\n );\r\n }\r\n }\r\n\r\n // Set-subscription alert message\r\n private _renderSubscribeAlert(): React.ReactNode {\r\n const { alertMessage, alertClass } = this.state;\r\n const displayAlert: boolean = (alertMessage ? alertMessage !== '' : false);\r\n if (displayAlert) {\r\n return (\r\n \r\n );\r\n } else {\r\n return null;\r\n }\r\n }\r\n\r\n private _renderSubscribeNote(): React.ReactNode {\r\n const { resources } = this.props;\r\n return (\r\n \r\n
{resources.pleaseNoteMessage}
\r\n
\r\n );\r\n }\r\n\r\n private _handleSubscribeClick = async () => {\r\n await this._handleButtonClick(true);\r\n }\r\n\r\n private _handleUnsubscribeClick = async () => {\r\n await this._handleButtonClick(false);\r\n }\r\n\r\n private _handleButtonClick = async (subscribe: boolean) => {\r\n const { userEmail } = this.state;\r\n this.setState({\r\n isProcessing: true\r\n });\r\n // Update subscription state for user\r\n const response = await this._setSubscriptionState(userEmail, subscribe);\r\n if (response.Result && response.Message) {\r\n const isSuccess = this._isSuccess(subscribe, response.Message);\r\n this.setState({\r\n alertMessage: `${response.Message}`,\r\n alertClass: isSuccess ? 'alert-green' : 'alert-yellow',\r\n isProcessing: false\r\n });\r\n } else {\r\n this.setState({\r\n alertMessage: 'Error processing request',\r\n alertClass: 'alert-yellow',\r\n isProcessing: false\r\n });\r\n }\r\n }\r\n\r\n private async _setSubscriptionState(email: string, subscribed: boolean): Promise {\r\n try {\r\n return await subscribeEmailAction(new SubscribeEmailDataActionInput(email, subscribed), this.props.context.actionContext);\r\n } catch (e) {\r\n throw this.props.telemetry.error(`Something went wrong ------${e}`);\r\n }\r\n }\r\n\r\n private _isSuccess(subscribe: boolean, message: string): boolean {\r\n if (subscribe) {\r\n return message === 'Subscribed successfully.';\r\n } else {\r\n return message === 'Unsubscribed successfully.';\r\n }\r\n }\r\n}\r\n\r\nexport default CittaAccountSubscription;\r\n","/*!\r\n * Copyright (c) Microsoft Corporation.\r\n * All rights reserved. See LICENSE in the project root for license information.\r\n */\r\n\r\n/* eslint-disable no-duplicate-imports */\r\nimport * as Msdyn365 from '@msdyn365-commerce/core';\r\nimport { INodeProps } from '@msdyn365-commerce-modules/utilities';\r\nimport * as React from 'react';\r\n\r\nimport { IAdditionalContentData, ILinksData } from '../citta-homepage-banner.props.autogenerated';\r\n\r\n/**\r\n * IContentBlockAdditionalContentProps: Interface for\r\n * Content Block Additional Content Component props.\r\n */\r\nexport interface IContentBlockAdditionalContentProps {\r\n requestContext: Msdyn365.IRequestContext;\r\n additionalContent: IAdditionalContentData[] | undefined;\r\n handleAdditionalTextChange(index: number, event: Msdyn365.ContentEditableEvent): void;\r\n handleAdditionalParagraphChange(index: number, event: Msdyn365.ContentEditableEvent): void;\r\n handleAdditionalLinkTextChange(linkIndex: number, index: number, event: Msdyn365.ContentEditableEvent): void;\r\n}\r\n\r\n/**\r\n * IContentBlockAdditionalContentProps: Interface for\r\n * Content Block Additional Content view props.\r\n */\r\nexport interface IContentBlockAdditionalContentViewProps {\r\n additionalContentNode: INodeProps;\r\n additionalContentItems?: IContentBlockAdditionalContentItemViewProps[];\r\n}\r\n\r\n/**\r\n * IContentBlockAdditionalContentProps: Interface for\r\n * Content Block Additional Content Item view props.\r\n */\r\nexport interface IContentBlockAdditionalContentItemViewProps {\r\n heading: React.ReactNode;\r\n text: React.ReactNode;\r\n links: React.ReactNode;\r\n additionalContentItemContainer: INodeProps;\r\n additionalContentItemLinks: INodeProps;\r\n}\r\n\r\n/**\r\n * Renders additional content heading.\r\n * @param additionalContentHeading - Additional content heading.\r\n * @param props - Content Block Additional content component props.\r\n * @param itemIndex - Item index.\r\n * @returns Heading Node.\r\n */\r\nconst renderHeading = (additionalContentHeading: string, props: IContentBlockAdditionalContentProps, itemIndex: number) => {\r\n const requestContext = props.requestContext;\r\n return (\r\n {\r\n props.handleAdditionalTextChange(itemIndex, event);\r\n },\r\n requestContext\r\n }}\r\n />\r\n );\r\n};\r\n\r\n/**\r\n * Renders additional content heading.\r\n * @param additionalContentParagraphText - Additional content paragraph text.\r\n * @param props - Content Block Additional content component props.\r\n * @param itemIndex - Item index.\r\n * @returns Paragraph Node.\r\n */\r\nconst renderParagraph = (additionalContentParagraphText: string, props: IContentBlockAdditionalContentProps, itemIndex: number) => {\r\n const requestContext = props.requestContext;\r\n return (\r\n {\r\n props.handleAdditionalTextChange(itemIndex, event);\r\n },\r\n requestContext\r\n }}\r\n />\r\n );\r\n};\r\n\r\n/**\r\n * Renders additional content heading.\r\n * @param ctaLink - Additional content link.\r\n * @param props - Content Block Additional content component props.\r\n * @param itemIndex - Item index.\r\n * @param linkIndex - Additional content link index.\r\n * @returns Link Node.\r\n */\r\nconst renderLinks = (ctaLink: ILinksData, props: IContentBlockAdditionalContentProps, itemIndex: number, linkIndex: number) => {\r\n const editableLink: Msdyn365.ILinksData = {\r\n ariaLabel: ctaLink.ariaLabel,\r\n className: 'ms-content-block__details__additional-content-cta-links',\r\n linkText: ctaLink.linkText,\r\n linkUrl: ctaLink.linkUrl.destinationUrl,\r\n openInNewTab: ctaLink.openInNewTab,\r\n role: 'link'\r\n };\r\n const requestContext = props.requestContext;\r\n return (\r\n {\r\n props.handleAdditionalLinkTextChange(linkIndex, itemIndex, event);\r\n },\r\n requestContext\r\n }}\r\n />\r\n );\r\n};\r\n\r\n/**\r\n * Create node for each additonal content item.\r\n * @param item - Content block additonal content item props.\r\n * @param props - Content Block Additional content component props.\r\n * @param itemIndex - Item index.\r\n * @returns IContentBlockAdditionalContentItemViewProps.\r\n */\r\nconst assembleNode = (\r\n item: IAdditionalContentData,\r\n props: IContentBlockAdditionalContentProps,\r\n itemIndex: number\r\n): IContentBlockAdditionalContentItemViewProps => {\r\n const headingNode = item.heading && renderHeading(item.heading, props, itemIndex);\r\n const paragraphNode = item.subtext && renderParagraph(item.subtext, props, itemIndex);\r\n const linksNode = item.links?.map((ctaLink: ILinksData, index: number) => {\r\n return renderLinks(ctaLink, props, itemIndex, index);\r\n });\r\n\r\n return {\r\n heading: headingNode,\r\n text: paragraphNode,\r\n links: linksNode,\r\n additionalContentItemContainer: { className: 'ms-content-block__details__additional-content__container' },\r\n additionalContentItemLinks: { className: 'ms-content-block__details__additional-content-cta' }\r\n };\r\n};\r\n\r\n/**\r\n * ContentBlockAdditionalContent component.\r\n * @param props - Content Block Additional content component props.\r\n * @returns Content Block Additional content view props.\r\n */\r\nexport const contentBlockAdditionalContent = (\r\n props: IContentBlockAdditionalContentProps\r\n): IContentBlockAdditionalContentViewProps | undefined => {\r\n const { additionalContent } = props;\r\n if (!additionalContent) {\r\n return undefined;\r\n }\r\n\r\n const reactNodes: IContentBlockAdditionalContentItemViewProps[] = [];\r\n additionalContent.map((item, index: number) => {\r\n return reactNodes.push(assembleNode(item, props, index));\r\n });\r\n\r\n return {\r\n additionalContentNode: { className: 'ms-content-block__details__additional-content' },\r\n additionalContentItems: reactNodes\r\n };\r\n};\r\n","/*!\r\n * Copyright (c) Microsoft Corporation.\r\n * All rights reserved. See LICENSE in the project root for license information.\r\n */\r\n\r\n/* eslint-disable no-duplicate-imports */\r\nimport * as Msdyn365 from '@msdyn365-commerce/core';\r\nimport { getPayloadObject, getTelemetryAttributes, ITelemetryContent, onTelemetryClick } from '@msdyn365-commerce-modules/utilities';\r\nimport * as React from 'react';\r\n\r\nimport { ILinksData } from '../citta-homepage-banner.props.autogenerated';\r\n\r\nexport interface IContentCardLinks {\r\n links: ILinksData[];\r\n requestContext: Msdyn365.IRequestContext;\r\n telemetryContent: ITelemetryContent;\r\n role?: string;\r\n onTextChange?(index: number): (event: Msdyn365.ContentEditableEvent) => void;\r\n}\r\n\r\n/**\r\n *\r\n * ContentCardLinks component.\r\n * @extends {React.PureComponent}\r\n */\r\nexport class ContentCardLinks extends React.PureComponent {\r\n public render(): JSX.Element {\r\n const editableLinks = this._mapEditableLinks(this.props.links);\r\n return (\r\n \r\n {editableLinks && editableLinks.length > 0 ? (\r\n \r\n ) : null}\r\n
\r\n );\r\n }\r\n\r\n private readonly _mapEditableLinks = (linkdata: ILinksData[]): Msdyn365.ILinksData[] | null => {\r\n if (!linkdata || linkdata.length === 0) {\r\n return null;\r\n }\r\n const editableLinks: Msdyn365.ILinksData[] = [];\r\n linkdata.forEach((link, index) => {\r\n // Construct telemetry attribute to render\r\n const payLoad = getPayloadObject('click', this.props.telemetryContent, '', '');\r\n const linkText = link.linkText ? link.linkText : '';\r\n payLoad.contentAction.etext = linkText;\r\n const attributes = getTelemetryAttributes(this.props.telemetryContent, payLoad);\r\n const btnClass = index === 0 ? 'msc-cta__primary' : 'msc-cta__secondary';\r\n const editableLink: Msdyn365.ILinksData = {\r\n ariaLabel: link.ariaLabel,\r\n className: btnClass,\r\n linkText: link.linkText,\r\n linkUrl: link.linkUrl.destinationUrl,\r\n openInNewTab: link.openInNewTab,\r\n role: this.props.role,\r\n additionalProperties: attributes,\r\n onClick: onTelemetryClick(this.props.telemetryContent, payLoad, linkText)\r\n };\r\n editableLinks.push(editableLink);\r\n });\r\n\r\n return editableLinks;\r\n };\r\n}\r\nexport default ContentCardLinks;\r\n","/**\r\n * Copyright (c) Microsoft Corporation\r\n * All rights reserved. See License.txt in the project root for license information.\r\n * ICittaHomepageBanner contentModule Interface Properties\r\n * THIS FILE IS AUTO-GENERATED - MANUAL MODIFICATIONS WILL BE LOST\r\n */\r\n\r\nimport * as Msdyn365 from '@msdyn365-commerce/core';\r\n\r\nexport const enum actionableRegion {\r\n imageAndLinks = 'imageAndLinks',\r\n linksOnly = 'linksOnly'\r\n}\r\n\r\nexport const enum textplacement {\r\n left = 'left',\r\n right = 'right',\r\n center = 'center'\r\n}\r\n\r\nexport const enum textalignmentmobile {\r\n top = 'top',\r\n bottom = 'bottom',\r\n center = 'center'\r\n}\r\n\r\nexport const enum textalignment {\r\n top = 'top',\r\n bottom = 'bottom',\r\n center = 'center'\r\n}\r\n\r\nexport const enum imageplacement {\r\n top = 'top',\r\n bottom = 'bottom',\r\n right = 'right',\r\n left = 'left'\r\n}\r\n\r\nexport const enum texttheme {\r\n dark = 'dark',\r\n light = 'light'\r\n}\r\n\r\nexport const enum textthememobile {\r\n dark = 'dark',\r\n light = 'light'\r\n}\r\n\r\nexport interface ICittaHomepageBannerConfig extends Msdyn365.IModuleConfig {\r\n heading?: IHeadingData;\r\n paragraph?: Msdyn365.RichText;\r\n image?: Msdyn365.IImageData;\r\n mobileImage?: Msdyn365.IImageData;\r\n links?: ILinksData[];\r\n additionalContent?: IAdditionalContentData[];\r\n actionableRegion?: actionableRegion;\r\n imageLink?: Msdyn365.ILinkData;\r\n imageAriaLabel?: string;\r\n className?: string;\r\n clientRender?: boolean;\r\n textplacement?: textplacement;\r\n textalignmentmobile?: textalignmentmobile;\r\n textalignment?: textalignment;\r\n imageplacement?: imageplacement;\r\n texttheme?: texttheme;\r\n textthememobile?: textthememobile;\r\n fillbutton?: boolean;\r\n}\r\n\r\nexport const enum HeadingTag {\r\n h1 = 'h1',\r\n h2 = 'h2',\r\n h3 = 'h3',\r\n h4 = 'h4',\r\n h5 = 'h5',\r\n h6 = 'h6'\r\n}\r\n\r\nexport interface IHeadingData {\r\n text: string;\r\n tag?: HeadingTag;\r\n}\r\n\r\nexport interface ILinksData {\r\n linkText?: string;\r\n linkUrl: Msdyn365.ILinkData;\r\n ariaLabel?: string;\r\n openInNewTab?: boolean;\r\n}\r\n\r\nexport interface IAdditionalContentData {\r\n heading?: string;\r\n subtext?: string;\r\n links?: ILinksData[];\r\n}\r\n\r\nexport interface ILinksData {\r\n linkText?: string;\r\n linkUrl: Msdyn365.ILinkData;\r\n ariaLabel?: string;\r\n openInNewTab?: boolean;\r\n}\r\n\r\nexport interface ICittaHomepageBannerProps extends Msdyn365.IModule {\r\n config: ICittaHomepageBannerConfig;\r\n}\r\n","/*!\r\n * Copyright (c) Microsoft Corporation.\r\n * All rights reserved. See LICENSE in the project root for license information.\r\n */\r\n\r\n/* eslint-disable no-duplicate-imports */\r\nimport msdyn365Commerce, * as Msdyn365 from '@msdyn365-commerce/core';\r\nimport { ArrayExtensions } from '@msdyn365-commerce-modules/retail-actions';\r\nimport { getTelemetryObject, IModuleProps, INodeProps, ITelemetryContent } from '@msdyn365-commerce-modules/utilities';\r\nimport classnames from 'classnames';\r\nimport * as React from 'react';\r\nimport { observer } from 'mobx-react';\r\nimport { observable } from 'mobx';\r\n\r\nimport { contentBlockAdditionalContent, IContentBlockAdditionalContentViewProps } from './components/additional-content';\r\nimport LinksComponent from './components/links';\r\nimport { actionableRegion as region, ICittaHomepageBannerConfig, ICittaHomepageBannerProps } from './citta-homepage-banner.props.autogenerated';\r\n\r\nexport interface IContentBlockViewProps extends ICittaHomepageBannerProps<{}> {\r\n title?: React.ReactNode;\r\n text?: React.ReactNode;\r\n image?: React.ReactNode;\r\n links?: React.ReactNode;\r\n className?: string;\r\n contentBlockContainer: IModuleProps;\r\n imageContainer: INodeProps;\r\n detailsContainer: INodeProps;\r\n contentBlockAnchorTag?: INodeProps;\r\n imageLink?: string;\r\n imageAriaLabel?: string;\r\n additionalContent?: IContentBlockAdditionalContentViewProps;\r\n handleAdditionalText?(): void;\r\n handleAdditionalParagraph?(): void;\r\n handleAdditionalLinkTextChange?(): void;\r\n}\r\nexport type GridSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\r\n\r\nexport interface IContentBlockStates {\r\n \r\n isMobile: boolean;\r\n }\r\n/**\r\n * Site-builder configuration for the module.\r\n */\r\nexport interface IContentBlockFullConfig extends ICittaHomepageBannerConfig {\r\n // eslint-disable-next-line @typescript-eslint/naming-convention -- This field comes from SDK.\r\n msdyn365__moduleLayout?: string;\r\n}\r\n\r\n/**\r\n * ContentCard component.\r\n * @extends {React.Component}\r\n */\r\n@observer\r\n\r\nexport class ContentBlock extends React.Component, IContentBlockStates> {\r\n @observable\r\n // private viewport: GridSize;\r\n private telemetryContent: ITelemetryContent = getTelemetryObject(\r\n this.props.context.request.telemetryPageName!,\r\n this.props.friendlyName,\r\n this.props.telemetry\r\n );\r\n\r\n //@ts-ignore\r\n constructor(props) {\r\n super(props);\r\n this.state = {isMobile: false};\r\n this._updateIsMobile = this._updateIsMobile.bind(this);\r\n }\r\n public componentDidMount(): void {\r\n this._updateIsMobile();\r\n window.addEventListener('resize', this._updateIsMobile);\r\n }\r\n\r\n public componentWillUnmount(): void {\r\n window.removeEventListener('resize', this._updateIsMobile);\r\n }\r\n\r\n public render(): JSX.Element | null {\r\n const { heading, paragraph, image, links, className, imageAriaLabel, textplacement, textalignment, texttheme, mobileImage, textthememobile, fillbutton, textalignmentmobile } = this.props.config;\r\n\r\n let additionalClassNames = '';\r\n if(textplacement) {\r\n additionalClassNames = ` textplacement__${textplacement}`;\r\n }\r\n if(texttheme) {\r\n additionalClassNames += ` texttheme__${texttheme}`;\r\n }\r\n if(textthememobile) {\r\n additionalClassNames += ` textthememobile__${textthememobile}`;\r\n }\r\n if (textalignment) {\r\n additionalClassNames += ` textalignment__${textalignment}`;\r\n }\r\n if (textalignmentmobile) {\r\n additionalClassNames += ` textalignmentmobile__${textalignmentmobile}`;\r\n }\r\n\r\n if(fillbutton) {\r\n additionalClassNames += ' fillbutton';\r\n }\r\n\r\n const contentBlockTitle = heading && (\r\n \r\n );\r\n const imageProps = {\r\n gridSettings: this.props.context.request.gridSettings ?? {},\r\n imageSettings: image?.imageSettings\r\n };\r\n const contentBlockLinks = links && ArrayExtensions.hasElements(links) && (\r\n \r\n );\r\n const contentBlockText = paragraph && (\r\n \r\n ); \r\n \r\n let contentBlockImage = (\r\n \r\n );\r\n\r\n if (this.state.isMobile) {\r\n contentBlockImage = \r\n }\r\n\r\n if (!contentBlockTitle && !contentBlockText && !contentBlockLinks) {\r\n this.props.context.telemetry.error('Content block content is empty, module wont render.');\r\n return null;\r\n }\r\n const contentBlockviewProps = {\r\n ...this.props,\r\n title: contentBlockTitle,\r\n text: contentBlockText,\r\n image: contentBlockImage,\r\n links: contentBlockLinks,\r\n moduleClass: this.props.config.className,\r\n contentBlockContainer: {\r\n moduleProps: this.props,\r\n className: classnames(`ms-content-block citta-homepage-banner ${additionalClassNames}`, className)\r\n },\r\n imageContainer: { className: 'ms-content-block__image' },\r\n detailsContainer: { className: 'ms-content-block__details' },\r\n contentBlockAnchorTag: {\r\n tag: 'a',\r\n className: 'ms-content-block__link',\r\n role: 'link'\r\n },\r\n imageLink: this._getImageLink(),\r\n imageAriaLabel,\r\n additionalContent: contentBlockAdditionalContent({\r\n requestContext: this.props.context.request,\r\n additionalContent: this.props.config.additionalContent,\r\n handleAdditionalTextChange: this.handleAdditionalTextChange,\r\n handleAdditionalParagraphChange: this.handleAdditionalParagraphChange,\r\n handleAdditionalLinkTextChange: this.handleAdditionalLinkTextChange\r\n }),\r\n handleAdditionalText: this.handleAdditionalTextChange,\r\n handleAdditionalParagraph: this.handleAdditionalParagraphChange,\r\n handleAdditionalLinkTextChange: this.handleAdditionalLinkTextChange\r\n };\r\n\r\n return this.props.renderView(contentBlockviewProps) as React.ReactElement;\r\n }\r\n\r\n /**\r\n * To handle text change.\r\n * @param event - To handle text change event.\r\n * @name - HandleTextChange\r\n * @public\r\n * @returns - The Text value.\r\n */\r\n public handleTextChange = (event: Msdyn365.ContentEditableEvent) => (this.props.config.heading!.text = event.target.value);\r\n\r\n /**\r\n * To handle paragraph change.\r\n * @param event - To handle text change event.\r\n * @name - HandleParagraphChange\r\n * @public\r\n * @returns - The Paragraph value.\r\n */\r\n public handleParagraphChange = (event: Msdyn365.ContentEditableEvent) => (this.props.config.paragraph = event.target.value);\r\n\r\n /**\r\n * Handle link text change.\r\n * @param linkIndex - The link index.\r\n * @returns - Void.\r\n */\r\n public handleLinkTextChange = (linkIndex: number) => (event: Msdyn365.ContentEditableEvent) => {\r\n if (this.props.config.links && this.props.config.links[Number(linkIndex)]) {\r\n this.props.config.links[Number(linkIndex)].linkText = event.target.value;\r\n }\r\n };\r\n\r\n public handleAdditionalTextChange(index: number, event: Msdyn365.ContentEditableEvent): void {\r\n if (this.props.config.additionalContent) {\r\n this.props.config.additionalContent[Number(index)].heading = event.target.value;\r\n }\r\n }\r\n\r\n public handleAdditionalLinkTextChange(linkIndex: number, index: number, event: Msdyn365.ContentEditableEvent): void {\r\n const additionalContentObject =\r\n (this.props.config.additionalContent &&\r\n ArrayExtensions.hasElements(this.props.config.additionalContent) &&\r\n this.props.config.additionalContent[Number(index)]) ||\r\n {};\r\n if (additionalContentObject.links) {\r\n additionalContentObject.links[Number(linkIndex)].linkText = event.target.value;\r\n }\r\n }\r\n\r\n public handleAdditionalParagraphChange(index: number, event: Msdyn365.ContentEditableEvent): void {\r\n if (this.props.config.additionalContent) {\r\n this.props.config.additionalContent[Number(index)].subtext = event.target.value;\r\n }\r\n }\r\n\r\n private _getImageLink(): string | null {\r\n const { imageLink, links, actionableRegion } = this.props.config;\r\n if (actionableRegion === region.imageAndLinks) {\r\n if (imageLink?.destinationUrl) {\r\n return imageLink.destinationUrl;\r\n } else if (links && ArrayExtensions.hasElements(links) && links[0].linkUrl) {\r\n return links[0].linkUrl.destinationUrl;\r\n }\r\n return null;\r\n }\r\n return null;\r\n }\r\n \r\n\r\n private _updateIsMobile = () => {\r\n if (msdyn365Commerce.isBrowser) {\r\n this.setState({\r\n isMobile: window.innerWidth < 768\r\n });\r\n }\r\n }\r\n}\r\n\r\nexport default ContentBlock;\r\n","/*!\r\n * Copyright (c) Microsoft Corporation.\r\n * All rights reserved. See LICENSE in the project root for license information.\r\n */\r\n\r\n/* eslint-disable no-duplicate-imports */\r\nimport { Module, Node } from '@msdyn365-commerce-modules/utilities';\r\nimport * as React from 'react';\r\n\r\nimport { IContentBlockAdditionalContentItemViewProps, IContentBlockAdditionalContentViewProps } from './components/additional-content';\r\nimport { IContentBlockViewProps } from './citta-homepage-banner';\r\n\r\n/**\r\n * Render Additional Content.\r\n * @param additionalContent - Additional content view props.\r\n * @returns JSX Element.\r\n */\r\nconst renderAdditionalContent = (additionalContent: IContentBlockAdditionalContentViewProps) => {\r\n return (\r\n \r\n {additionalContent.additionalContentItems?.map((item: IContentBlockAdditionalContentItemViewProps) => {\r\n return (\r\n <>\r\n {item.heading}\r\n \r\n {item.text}\r\n {item.links}\r\n \r\n >\r\n );\r\n })}\r\n \r\n );\r\n};\r\n\r\nconst ContentBlockView: React.FC = props => {\r\n const {\r\n contentBlockContainer,\r\n imageContainer,\r\n detailsContainer,\r\n title,\r\n text,\r\n links,\r\n image,\r\n contentBlockAnchorTag,\r\n imageLink,\r\n imageAriaLabel,\r\n additionalContent\r\n } = props;\r\n\r\n if (imageLink) {\r\n return (\r\n \r\n \r\n {image}\r\n \r\n {title}\r\n {text}\r\n {links}\r\n {additionalContent && renderAdditionalContent(additionalContent)}\r\n \r\n \r\n \r\n \r\n );\r\n }\r\n return (\r\n \r\n {image}\r\n \r\n {title}\r\n {text}\r\n {links}\r\n {additionalContent && renderAdditionalContent(additionalContent)}\r\n \r\n \r\n );\r\n};\r\n\r\nexport default ContentBlockView;\r\n","/*!\r\n * Copyright (c) Microsoft Corporation.\r\n * All rights reserved. See LICENSE in the project root for license information.\r\n */\r\nimport { Module, Node } from '@msdyn365-commerce-modules/utilities';\r\nimport * as React from 'react';\r\nimport { ICittaAccountSubscriptionViewProps } from './citta-account-subscription';\r\n\r\nconst CittaAccountSubscriptionView: React.FC = props => {\r\n const {\r\n AccountSubscriptionWrapper,\r\n AccountSubscriptionAttribute,\r\n AccountSubscriptionProcessing,\r\n AccountSubscriptionUnSubscribe,\r\n subscribeResponse,\r\n subUnsubButtton,\r\n isProcessing,\r\n hasAccountDetails,\r\n processingMessage,\r\n subscribeAlert,\r\n subscribeNote } = props;\r\n return (\r\n \r\n {subscribeResponse}\r\n {hasAccountDetails &&\r\n \r\n {isProcessing ?\r\n \r\n {processingMessage}\r\n :\r\n \r\n {subUnsubButtton}\r\n {subscribeAlert}\r\n {subscribeNote}\r\n }\r\n \r\n }\r\n \r\n );\r\n};\r\n\r\nexport default CittaAccountSubscriptionView;\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CacheType, createObservableDataAction, IAction, IActionContext, IActionInput } from '@msdyn365-commerce/core';\r\nimport { dXC_SubscribeEmailAsync } from '../generated/DataActionExtension.g';\r\nimport { IDXC_SubscribeNewsletterRealtimeResponse } from '../generated/DataServiceEntities.g';\r\n\r\n/**\r\n * SubmitSubscribeFormDataActionInput Input Action\r\n */\r\n\r\nexport class SubscribeEmailDataActionInput implements IActionInput {\r\n public emailAddress: string;\r\n public subscribe: boolean;\r\n\r\n // Construct the input needed to run the action\r\n constructor(emailAddress: string, subscribe: boolean) {\r\n this.emailAddress = emailAddress;\r\n this.subscribe = subscribe;\r\n }\r\n\r\n // TODO: Determine if the results of this get action should cache the results and if so provide\r\n // a cache object type and an appropriate cache key\r\n public getCacheKey = () => 'SubscribeEmail2020';\r\n public getCacheObjectType = () => 'SubscribeEmail';\r\n public dataCacheType = (): CacheType => 'request';\r\n}\r\n\r\n/**\r\n * TODO: Use this function to create the input required to make the action call\r\n */\r\nconst createInput = (args: SubscribeEmailDataActionInput): IActionInput => {\r\n return args;\r\n};\r\n\r\n/**\r\n * TODO: Use this function to call your action and process the results as needed\r\n */\r\nexport async function subscribeEmailAction(\r\n input: SubscribeEmailDataActionInput,\r\n ctx: IActionContext\r\n): Promise {\r\n // Input only needs token\r\n let result: IDXC_SubscribeNewsletterRealtimeResponse = {};\r\n try {\r\n result = await dXC_SubscribeEmailAsync({ callerContext: ctx }, input.emailAddress, input.subscribe);\r\n } catch (error) {\r\n console.log(error);\r\n }\r\n return Array.isArray(result) ? result[0] : result;\r\n}\r\n\r\nexport const ISubscribeEmailDataActionAction = createObservableDataAction({\r\n action: >subscribeEmailAction,\r\n input: createInput\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Button, Heading, IModuleProps } from '@msdyn365-commerce-modules/utilities';\r\nimport * as React from 'react';\r\nimport { IDXC_SubscribeNewsletterRealtimeResponse } from '../../data-actions/generated/DataServiceEntities.g';\r\nimport { subscribeEmailAction, SubscribeEmailDataActionInput } from './../../data-actions/subscribe-email/subscribe-email-data';\r\nimport { ICittaUnsubscribeData } from './citta-unsubscribe.data';\r\nimport { ICittaUnsubscribeProps } from './citta-unsubscribe.props.autogenerated';\r\n\r\nexport interface ICittaUnsubscribeViewProps extends ICittaUnsubscribeProps {\r\n unsubscribeContainer: IModuleProps;\r\n alertMessage?: React.ReactNode;\r\n unsubscribeHeading?: React.ReactNode;\r\n unsubscribeInput?: React.ReactNode;\r\n unsubscribeButton?: React.ReactNode ;\r\n}\r\n\r\ninterface ICittaUnsubscribeState {\r\n alertMessage: string;\r\n alertClass: string;\r\n inputEmail: string;\r\n}\r\n\r\n/**\r\n *\r\n * CittaUnsubscribe component\r\n * @extends {React.PureComponent>}\r\n */\r\nclass CittaUnsubscribe extends React.PureComponent, ICittaUnsubscribeState> {\r\n constructor(props: ICittaUnsubscribeViewProps) {\r\n super(props);\r\n this._handleButtonClick = this._handleButtonClick.bind(this);\r\n this._handleInputChange = this._handleInputChange.bind(this);\r\n\r\n this.state = {\r\n alertMessage: '',\r\n alertClass: '',\r\n inputEmail: ''\r\n };\r\n }\r\n\r\n public render(): JSX.Element | null {\r\n const viewProps: ICittaUnsubscribeViewProps = {\r\n ...(this.props as ICittaUnsubscribeProps),\r\n unsubscribeContainer: {\r\n moduleProps: this.props,\r\n className: 'container citta-unsubscribe'\r\n },\r\n alertMessage: this._renderAlertMessage(),\r\n unsubscribeHeading: this._renderUnsubscribeHeading(),\r\n unsubscribeInput: this._renderUnsubscribeInput(),\r\n unsubscribeButton: this._renderUnsubscribeButton()\r\n };\r\n return this.props.renderView(viewProps);\r\n }\r\n\r\n // tslint:disable-next-line: no-any\r\n private _handleInputChange = (event: any) => {\r\n this.setState({\r\n inputEmail: event.target.value\r\n });\r\n }\r\n\r\n private _handleButtonClick = async () => {\r\n const response = await this._callUnsubscribeAPI(this.state.inputEmail);\r\n if (response.Result && response.Message) {\r\n this.setState({\r\n alertMessage: `${response.Message}`,\r\n alertClass: response.Message === 'Unsubscribed successfully.' ? 'alert-green' : 'alert-yellow'\r\n });\r\n }\r\n }\r\n\r\n private async _callUnsubscribeAPI(email: string): Promise {\r\n try {\r\n return await subscribeEmailAction(new SubscribeEmailDataActionInput(email, false), this.props.context.actionContext);\r\n } catch (e) {\r\n throw this.props.telemetry.error(`Something went wrong ------${e}`);\r\n }\r\n }\r\n\r\n private _renderUnsubscribeHeading(): React.ReactNode {\r\n const { unsubscribeHeading } = this.props.config;\r\n return (\r\n \r\n );\r\n }\r\n\r\n private _renderAlertMessage(): React.ReactNode {\r\n const { alertMessage, alertClass } = this.state;\r\n const displayAlert: boolean = (alertMessage ? alertMessage !== '' : false);\r\n return (\r\n <>\r\n {displayAlert ? : null}\r\n >\r\n );\r\n }\r\n\r\n private _renderUnsubscribeInput(): React.ReactNode {\r\n return (\r\n \r\n \r\n
\r\n );\r\n }\r\n\r\n private _renderUnsubscribeButton(): React.ReactNode {\r\n const { resources } = this.props;\r\n return (\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default CittaUnsubscribe;"],"sourceRoot":""}