Skip to content

Commit

Permalink
Show iframe for Amazon listing (#2495)
Browse files Browse the repository at this point in the history
* Use Amazon iframe and snippet for order print copy

Fix language selector, too
separate useAmazonIframe

* Fix tests

* Explain commented-out test
  • Loading branch information
RoyEJohnson authored Nov 9, 2023
1 parent eb188ef commit 5f1aa0d
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ export default function (args: LanguageSelectorArgs): React.ReactNode;

export const LanguageLink: LinkPresentationType;

export function useLanguageText(locale: string): () => React.ReactNode;
export function LanguageText({locale}: Pick<LocaleEntry, 'locale'>): React.ReactNode;
2 changes: 1 addition & 1 deletion src/app/components/language-selector/language-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function LanguageLink({locale, slug}) {
}

// Provide a fallback so ancient browsers don't outright fail
function LanguageText({locale}) {
export function LanguageText({locale}) {
if (Intl.DisplayNames) {
return (<LanguageTextUsingIntl locale={locale} />);
}
Expand Down
7 changes: 7 additions & 0 deletions src/app/models/amazon-snippet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import cmsFetch from '~/helpers/cms-fetch';
import {camelCaseKeys} from '~/helpers/page-data-utils';

export default cmsFetch('snippets/amazonbookblurb')
.then((r) => r[0])
.then(camelCaseKeys)
.then((r) => r?.amazonBookBlurb ?? '** no Amazon blurb snippet**') as Promise<string>;
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const buyprintServer = 'https://buyprint.openstax.org';

type AmazonAssociatesLink = {
url?: string;
disclosure?: string;
};

export default function useAmazonAssociatesLink(slug: string) {
Expand Down
24 changes: 0 additions & 24 deletions src/app/pages/details/common/get-this-title-files/options.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faBook} from '@fortawesome/free-solid-svg-icons/faBook';
import {faLaptop} from '@fortawesome/free-solid-svg-icons/faLaptop';
import {faListOl} from '@fortawesome/free-solid-svg-icons/faListOl';
import {faCloudDownloadAlt} from '@fortawesome/free-solid-svg-icons/faCloudDownloadAlt';
Expand All @@ -11,7 +10,6 @@ import $ from '~/helpers/$';
import {treatSpaceOrEnterAsClick} from '~/helpers/events';
import {useIntl, FormattedMessage} from 'react-intl';
import OrderPrintCopy from './order-print-copy/order-print-copy';
import useAmazonAssociatesLink from './amazon-associates-link';
import useTOCContext from '../toc-slideout/context';
import {useDialog} from '~/components/dialog/dialog';
import RecommendedCallout from './recommended-callout/recommended-callout';
Expand Down Expand Up @@ -179,28 +177,6 @@ export function usePrintCopyDialog() {
return {onClick, PCDialog};
}

export function PrintOption({model, icon = faBook}) {
const slug = (model.slug || '').replace('books/', '');
const amazonDataLink = useAmazonAssociatesLink(slug);
const intl = useIntl();
const printText = intl.formatMessage({id: 'getit.print'});
const text = $.isPolish(model.title)
? 'Zamów egzemplarz drukowany'
: printText;
const {onClick, PCDialog} = usePrintCopyDialog({});

return (
<SimpleLinkOption
link={isRealPrintLink(amazonDataLink.url)}
icon={icon}
text={text}
onClick={onClick}
>
<PCDialog text={text} amazonDataLink={amazonDataLink} />
</SimpleLinkOption>
);
}

export function BookshareOption({model}) {
return (
<SimpleLinkOption
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';
import RawHTML from '~/components/jsx-helpers/raw-html';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faUser} from '@fortawesome/free-solid-svg-icons/faUser';
import {faUsers} from '@fortawesome/free-solid-svg-icons/faUsers';
import { useIntl } from 'react-intl';
import {useIntl} from 'react-intl';
import './order-print-copy.scss';
import amazonSnippet from '~/models/amazon-snippet';
import {usePromise} from '~/helpers/use-data';
import useAmazonIframe from './use-amazon-iframe';

function Header({entry}) {
return (
Expand All @@ -21,115 +23,101 @@ function Header({entry}) {
function PhoneBox({entry, closeAfterDelay}) {
return (
<a
className="box"
className='box'
href={entry.buttonUrl}
onClick={closeAfterDelay} data-track="Print"
onClick={closeAfterDelay}
data-track='Print'
>
<Header entry={entry} />
</a>
);
}

function PhoneBoxes({contentArray, ...otherProps}) {
function PhoneBoxes({contentArray}) {
return (
<div className={`phone-version boxes boxes-${contentArray.length}`}>
{contentArray.map((entry) => <PhoneBox {...{entry, ...otherProps}} key={entry} />)}
{contentArray.map((entry) => (
<PhoneBox {...{entry}} key={entry} />
))}
</div>
);
}

function Button({href, text, buttonClass, onClick}) {
return (
<a className={`btn ${buttonClass}`} href={href} onClick={onClick} data-track="Print">
<a
className={`btn ${buttonClass}`}
href={href}
onClick={onClick}
data-track='Print'
>
{text}
</a>
);
}

function DesktopBox({index, entry, closeAfterDelay}) {
function DesktopBox({index, entry}) {
const buttonClass = ['primary', 'secondary'][index];

return (<div className="box" key={entry.headerText}>
<Header entry={entry} />
<Button
buttonClass={buttonClass}
href={entry.buttonUrl}
onClick={closeAfterDelay}
text={entry.buttonText}
/>
</div>);
if (typeof entry === 'string') {
return <RawHTML html={entry} />;
}

return (
<div className='box' key={entry.headerText}>
<Header entry={entry} />
<Button
buttonClass={buttonClass}
href={entry.buttonUrl}
text={entry.buttonText}
/>
</div>
);
}

function DesktopBoxes({contentArray, ...otherProps}) {
function DesktopBoxes({contentArray}) {
return (
<div className={`larger-version boxes boxes-${contentArray.length}`}>
{
contentArray.map((entry, index) =>
<DesktopBox {...{index, entry, ...otherProps}} key={entry} />
)
}
{contentArray.map((entry, index) => (
<DesktopBox {...{index, entry}} key={entry} />
))}
</div>
);
}

export default function OrderPrintCopy({amazonDataLink, hideDialog}) {
const { formatMessage } = useIntl();
const contentArray = React.useMemo(
() => {
const individual = formatMessage({
id: 'printcopy.individual',
defaultMessage: 'Individual'
});
const bookstore = formatMessage({
id: 'printcopy.bookstore',
defaultMessage: 'Bookstore'
});
const disclosure = formatMessage({
id: 'printcopy.disclosure',
defaultMessage: '***'
});
const button1Text = formatMessage({
id: 'printcopy.button1',
defaultMessage: 'Order a personal copy'
});
const button2Text = formatMessage({
id: 'printcopy.button2',
defaultMessage: 'Order options'
});
export default function OrderPrintCopy({slug}) {
const {formatMessage} = useIntl();
const iframeCode = useAmazonIframe(slug);

return [
{
headerText: individual,
headerIcon: faUser,
disclosure: disclosure === '***' ? amazonDataLink.disclosure : disclosure,
buttonText: button1Text,
buttonUrl: amazonDataLink.url
},
{
headerText: bookstore,
headerIcon: faUsers,
buttonText: button2Text,
buttonUrl: 'https://buyprint.openstax.org/bookstore-suppliers'
}
];
},
[amazonDataLink, formatMessage]
);
const otherProps = React.useMemo(
() => ({
closeAfterDelay(event) {
if (event) {
window.requestAnimationFrame(hideDialog);
}
const contentArray = React.useMemo(() => {
const bookstore = formatMessage({
id: 'printcopy.bookstore',
defaultMessage: 'Bookstore'
});
const button2Text = formatMessage({
id: 'printcopy.button2',
defaultMessage: 'Order options'
});

return [
iframeCode,
{
headerText: bookstore,
headerIcon: faUsers,
buttonText: button2Text,
buttonUrl: 'https://buyprint.openstax.org/bookstore-suppliers'
}
}),
[hideDialog]
);
];
}, [formatMessage, iframeCode]);
const blurb = usePromise(amazonSnippet, '');

return (
<nav className="order-print-copy">
<PhoneBoxes {...{contentArray, ...otherProps}} />
<DesktopBoxes {...{contentArray, ...otherProps}} />
<nav className='order-print-copy'>
<div className='blurb'>
{blurb}
</div>
<PhoneBoxes {...{contentArray}} />
<DesktopBoxes {...{contentArray}} />
</nav>
);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
@import 'pattern-library/core/pattern-library/headers';

.order-print-copy {
@include set-font(helper-label);

background-color: ui-color(page-bg);
max-width: 26rem;

.blurb {
padding: 1rem $normal-margin 0;
}

h1 {
@include set-font(h4);
Expand All @@ -23,8 +29,6 @@
@include wider-than($phone-max) {
display: grid;
grid-gap: 2rem;
max-width: 90rem; // Matches dialog width
overflow-x: auto;
}
}

Expand All @@ -38,28 +42,16 @@
display: grid;
grid-gap: 2rem;
justify-items: center;
padding: 2rem;
padding: 2rem 0.5rem;

@include width-up-to($phone-max) {
width: 100%;
}

@include wider-than($phone-max) {
grid-gap: 4rem;
grid-template-columns: auto;
margin: auto;
padding: 4rem;

&.boxes-1 {
grid-template-columns: auto;
}

&.boxes-2 {
grid-template-columns: 1fr 1fr;
}

&.boxes-3 {
grid-template-columns: 1fr 1fr 1fr;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import useDetailsContext from '../../../context';
import useAmazonAssociatesLink from '../amazon-associates-link';
import {IntlShape, useIntl} from 'react-intl';
import {faUser} from '@fortawesome/free-solid-svg-icons/faUser';

export default function useAmazonIframe(slug: string) {
const {amazonIframe} = useDetailsContext();
const amazonDataLink = useAmazonAssociatesLink(slug);
const {formatMessage} = useIntl();

const iframeCode = React.useMemo(
() => amazonIframe?.length > 0 ? (`
${amazonIframe}
<div>
${amazonDataLink.disclosure || 'disclosure: we make money from Amazon sales'}
</div>
`) : null,
[amazonIframe, amazonDataLink.disclosure]
);

return iframeCode ?? amazonButton(amazonDataLink, formatMessage);
}

function amazonButton(
amazonDataLink: ReturnType<typeof useAmazonAssociatesLink>,
formatMessage: IntlShape['formatMessage']
) {
const individual = formatMessage({
id: 'printcopy.individual',
defaultMessage: 'Individual'
});
const disclosure = formatMessage({
id: 'printcopy.disclosure',
defaultMessage: '***'
});
const button1Text = formatMessage({
id: 'printcopy.button1',
defaultMessage: 'Order a personal copy'
});

return ({
headerText: individual,
headerIcon: faUser,
disclosure:
disclosure === '***'
? amazonDataLink.disclosure
: disclosure,
buttonText: button1Text,
buttonUrl: amazonDataLink.url
});
}
Loading

0 comments on commit 5f1aa0d

Please sign in to comment.