Skip to content

Commit

Permalink
Details page sections
Browse files Browse the repository at this point in the history
  • Loading branch information
RoyEJohnson committed Nov 4, 2024
1 parent e650384 commit dd14a5d
Show file tree
Hide file tree
Showing 22 changed files with 400 additions and 157 deletions.
2 changes: 0 additions & 2 deletions src/app/models/book-toc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ import memoize from 'lodash/memoize';
export function bookToc(slug: string) {
return cmsFetch(slug)
.then((bi) => {
const isRex = true;
const webviewLink = bi.webview_rex_link;

return {
isRex,
webviewLink,
cnxId: bi.cnx_id
};
Expand Down
32 changes: 13 additions & 19 deletions src/app/models/table-of-contents-html.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
import fetchRexRelease from '~/models/rex-release';

export function cnxFetch({isRex, cnxId, webviewLink}) {
if (isRex) {
return fetchRexRelease(webviewLink, cnxId);
}
return fetch(`${process.env.API_ORIGIN}/contents/${cnxId}.json`)
.then((r) => r.json())
.catch((err) => {throw new Error(`Fetching table of contents: ${err}`);})
;
export function cnxFetch({cnxId, webviewLink}) {
return fetchRexRelease(webviewLink, cnxId);
}

export default function tableOfContentsHtml({isRex, cnxId, webviewLink}) {
export default function tableOfContentsHtml({cnxId, webviewLink}) {
function pageLink(entry) {
const rexRoot = webviewLink.replace(/\/pages\/.*/, '');

return isRex ?
`${rexRoot}/pages/${entry.slug || entry.shortId}` :
`${webviewLink}:${entry.shortId}`;
return `${rexRoot}/pages/${entry.slug || entry.shortId}`;
}

function buildTableOfContents(contents, tag) {
Expand All @@ -25,22 +17,24 @@ export default function tableOfContentsHtml({isRex, cnxId, webviewLink}) {
contents.forEach((entry) => {
if (entry.contents) {
htmlEntities.push(`${entry.title}<ul class="no-bullets">`);
buildTableOfContents(entry.contents, 'li')
.forEach((e) => {
htmlEntities.push(e);
});
buildTableOfContents(entry.contents, 'li').forEach((e) => {
htmlEntities.push(e);
});
htmlEntities.push('</ul>');
} else {
htmlEntities.push(
`<${tag}><a href="${pageLink(entry)}">${entry.title}</a></${tag}>`
`<${tag}><a href="${pageLink(entry)}">${
entry.title
}</a></${tag}>`
);
}
});
return htmlEntities;
}

return cnxFetch({isRex, cnxId, webviewLink}).then(
(cnxData) => buildTableOfContents(cnxData.tree.contents, 'div').join(''),
return cnxFetch({cnxId, webviewLink}).then(
(cnxData) =>
buildTableOfContents(cnxData.tree.contents, 'div').join(''),
(err) => {
console.warn(`Error fetching TOC for ${cnxId}: ${err}`);
}
Expand Down
47 changes: 29 additions & 18 deletions src/app/pages/details/common/authors.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,47 @@
import React from 'react';
import {useIntl} from 'react-intl';
import groupBy from 'lodash/groupBy';
import useDetailsContext from '../context';
import $ from '~/helpers/$';

function Authors({heading, className, authors=[]}) {
function Authors({
heading,
className,
authors = []
}: {
heading: string;
className: string;
authors: ReturnType<typeof useDetailsContext>['authors'];
}) {
if (authors.length === 0) {
return null;
}
return (
<div>
<h3 className="author-heading">{heading}</h3>
{
authors.map((author) =>
<div className={className} key={author.name}>
{author.name}
{author.university ? `, ${author.university}` : ''}
</div>
)
}
{authors.map((author) => (
<div className={className} key={author.name}>
{author.name}
{author.university ? `, ${author.university}` : ''}
</div>
))}
</div>
);
}

export default function AuthorsSection({model, polish}) {
export default function AuthorsSection() {
const {authors, title} = useDetailsContext();
const polish = $.isPolish(title);
const intl = useIntl();
const headings = polish ? [
'Główni autorzy', 'Autorzy współpracujący'
] : [
intl.formatMessage({id: 'authors.senior'}),
intl.formatMessage({id: 'authors.contributing'})
];
const groupFn = (author) => author.seniorAuthor ? 'senior' : 'regular';
const groupedAuthors = groupBy(model.authors, groupFn);
const headings = polish
? ['Główni autorzy', 'Autorzy współpracujący']
: [
intl.formatMessage({id: 'authors.senior'}),
intl.formatMessage({id: 'authors.contributing'})
];
const groupFn = (author: (typeof authors)[0]) =>
author.seniorAuthor ? 'senior' : 'regular';
const groupedAuthors = groupBy(authors, groupFn);

return (
<React.Fragment>
Expand Down
44 changes: 28 additions & 16 deletions src/app/pages/details/common/errata.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,69 @@
import React from 'react';
import RawHTML from '~/components/jsx-helpers/raw-html';
import {FormattedMessage, useIntl} from 'react-intl';
import useDetailsContext from '../context';
import $ from '~/helpers/$';

function EnglishButtonGroup({title}) {
function EnglishButtonGroup({title}: {title: string}) {
return (
<div className="button-group">
<a
href={`/errata/form?book=${encodeURIComponent(title)}`}
className="btn secondary medium"
>
<FormattedMessage id="errata.suggest" defaultMessage="Suggest a correction" />
<FormattedMessage
id="errata.suggest"
defaultMessage="Suggest a correction"
/>
</a>
<a
href={`/errata/?book=${encodeURIComponent(title)}`}
className="btn default medium"
>
<FormattedMessage id="errata.list" defaultMessage="Errata list" />
<FormattedMessage
id="errata.list"
defaultMessage="Errata list"
/>
</a>
</div>
);
}

function ButtonGroup({polish, title}) {
function ButtonGroup({title}: {title: string}) {
const PolishButtonGroup = () => (
<div className="button-group">
<a
href="https://openstax.pl/pl/errata"
className="btn secondary medium">Zgłoś poprawkę</a>
className="btn secondary medium"
>
Zgłoś poprawkę
</a>
</div>
);

return polish ? <PolishButtonGroup /> : <EnglishButtonGroup title={title} />;
return $.isPolish(title) ? (
<PolishButtonGroup />
) : (
<EnglishButtonGroup title={title} />
);
}

export function ErrataContents({model, polish}) {
const title = model.title;
const blurb = model.errataContent;
export function ErrataContents() {
const {title, errataContent: blurb, bookState} = useDetailsContext();

return (
<React.Fragment>
<RawHTML Tag="p" html={blurb} />
{
model.bookState !== 'deprecated' &&
<ButtonGroup polish={polish} title={title} />
}
{bookState !== 'deprecated' && <ButtonGroup title={title} />}
</React.Fragment>
);
}

export default function ErrataSection({model, polish=false}) {
export default function ErrataSection() {
const intl = useIntl();
const {bookState} = useDetailsContext();

if (!['live', 'new_edition_available', 'deprecated'].includes(model.bookState)) {
if (!['live', 'new_edition_available', 'deprecated'].includes(bookState)) {
return null;
}

Expand All @@ -64,7 +76,7 @@ export default function ErrataSection({model, polish=false}) {
<h3>
<FormattedMessage id="errata.header" defaultMessage="Errata" />
</h3>
<ErrataContents model={model} polish={polish} />
<ErrataContents />
</div>
);
}
54 changes: 28 additions & 26 deletions src/app/pages/details/common/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,26 @@ import tableOfContentsHtml from '~/models/table-of-contents-html';
import partnerFeaturePromise, {tooltipText} from '~/models/salesforce-partners';
import shuffle from 'lodash/shuffle';
import {camelCaseKeys} from '~/helpers/page-data-utils';
import useDetailsContext from '../context';

export function useTableOfContents(model) {
const webviewLink = model.webviewRexLink || model.webviewLink;
const isRex = Boolean(model.webviewRexLink);
const [tocHtml, setTocHtml] = useState('');
export function useTableOfContents() {
const model = useDetailsContext();
const webviewLink = model.webviewRexLink;
const [tocHtml, setTocHtml] = useState<string | void>('');

tableOfContentsHtml({
isRex,
cnxId: model.cnxId,
bookSlug: model.slug,
webviewLink
}).then(
setTocHtml,
(err) => {
console.warn(`Failed to generate table of contents HTML for ${model.cnxId}: ${err}`);
}
);
}).then(setTocHtml, (err) => {
console.warn(
`Failed to generate table of contents HTML for ${model.cnxId}: ${err}`
);
});

return tocHtml;
return tocHtml as string;
}

function toBlurb(partner) {
function toBlurb(partner: object) {
const pData = camelCaseKeys(partner);

return {
Expand All @@ -36,28 +34,32 @@ function toBlurb(partner) {
type: pData.partnerType,
url: `/partners?${pData.partnerName}`,
verifiedFeatures: pData.verifiedByInstructor ? tooltipText : false,
rating: pData.averageRating.ratingAvg,
rating: pData.averageRating?.ratingAvg,
ratingCount: pData.ratingCount
};
}

export function usePartnerFeatures(bookAbbreviation) {
const [blurbs, setBlurbs] = useState([]);
type PartnerData = {
books: string;
}

export function usePartnerFeatures(bookAbbreviation: string) {
const [blurbs, setBlurbs] = useState<object[]>([]);
const [includePartners, setIncludePartners] = useState('');

useEffect(() => {
partnerFeaturePromise.then((pd) =>
pd.filter((p) => {
partnerFeaturePromise
.then((pd: PartnerData[]) => pd.filter((p) => {
const books = (p.books || '').split(';');

return books.includes(bookAbbreviation);
})
).then((pd) => {
if (pd.length > 0) {
setIncludePartners('include-partners');
}
setBlurbs(shuffle(pd).map(toBlurb));
});
}))
.then((pd) => {
if (pd.length > 0) {
setIncludePartners('include-partners');
}
setBlurbs(shuffle(pd).map(toBlurb));
});
}, [bookAbbreviation]);

return [blurbs, includePartners];
Expand Down
19 changes: 9 additions & 10 deletions src/app/pages/details/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type WebinarContent = {
link: string;
content: string;
};
}
};
type StuffContent = {
content: {
id: number;
Expand All @@ -20,17 +20,17 @@ type StuffContent = {
contentLoggedIn: string;
heading: string;
};

}
};
type VideoContent = {
title: string;
description: string;
embed: string;
}
};
type Author = {
name: string;
university: string;
}
seniorAuthor?: boolean;
};

export type ContextValues = {
slug: string;
Expand Down Expand Up @@ -60,8 +60,10 @@ export type ContextValues = {
updated: string;
coverUrl: string;
digitalIsbn13: string;
rexWebviewLink: string;
webviewRexLink: string;
webviewLink: string;
errataContent: string;
cnxId: string;
};

function useContextValue({data}: {data: ContextValues}) {
Expand All @@ -74,7 +76,4 @@ function useContextValue({data}: {data: ContextValues}) {

const {useContext, ContextProvider} = buildContext({useContextValue});

export {
useContext as default,
ContextProvider as DetailsContextProvider
};
export {useContext as default, ContextProvider as DetailsContextProvider};
8 changes: 4 additions & 4 deletions src/app/pages/details/desktop-view/details-tab/details-tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ function PolishTab({model}) {
<h3>Podsumowanie</h3>
<RawHTML html={model.description} />
</div>
<Authors model={model} polish={true} />
<ErrataSection model={model} polish={true} />
<Authors />
<ErrataSection />
<PublicationInfo model={model} polish={true} />
</div>
</div>
Expand Down Expand Up @@ -55,8 +55,8 @@ function EnglishTab({model}) {
</h3>
<RawHTML html={model.description} />
</div>
<Authors model={model} />
<ErrataSection model={model} />
<Authors />
<ErrataSection />
<div className="publication-info">
<PublicationInfo model={model} url={null} />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import FeaturedResourcesSection from '../../common/featured-resources/featured-resources';
import {resourceBoxModel, useResources} from '../../common/resource-box/old-resource-box';
import {resourceBoxModel, useResources} from '../../common/resource-box/resource-box-utils';
import ResourceBoxes from '../../common/resource-box/resource-boxes';
import VideoResourceBoxes from '../../common/resource-box/video-resource-box';
import Partners from './partners/partners';
Expand Down
Loading

0 comments on commit dd14a5d

Please sign in to comment.