Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stories page articles from Content API #11387

Merged
merged 5 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 28 additions & 32 deletions content/webapp/components/FeaturedCard/FeaturedCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@ import styled from 'styled-components';
import { ImageType } from '@weco/common/model/image';
import { Label } from '@weco/common/model/labels';
import linkResolver from '@weco/common/services/prismic/link-resolver';
import { transformImage } from '@weco/common/services/prismic/transformers/images';
import { font, grid } from '@weco/common/utils/classnames';
import LabelsList from '@weco/common/views/components/LabelsList/LabelsList';
import PrismicImage from '@weco/common/views/components/PrismicImage/PrismicImage';
import Space from '@weco/common/views/components/styled/Space';
import { PaletteColor } from '@weco/common/views/themes/config';
import DateRange from '@weco/content/components/DateRange/DateRange';
import PartNumberIndicator from '@weco/content/components/PartNumberIndicator/PartNumberIndicator';
import StatusIndicator from '@weco/content/components/StatusIndicator/StatusIndicator';
import {
ArticleBasic,
getArticleColor,
getPartNumberInSeries,
} from '@weco/content/types/articles';
import { Article } from '@weco/content/services/wellcome/content/types/api';
import { ArticleBasic } from '@weco/content/types/articles';
import { BookBasic } from '@weco/content/types/books';
import { Card } from '@weco/content/types/card';
import { EventSeries } from '@weco/content/types/event-series';
Expand Down Expand Up @@ -89,44 +86,29 @@ export function convertItemToFeaturedCardProps(
}

type FeaturedCardArticleProps = {
article: ArticleBasic;
article: Article;
background: PaletteColor;
textColor: PaletteColor;
};

type FeaturedCardArticleBodyProps = {
article: ArticleBasic;
article: Article;
};

// TODO: make this e.g. just `CardArticleBody` and work it back into the existing promos/cards
const FeaturedCardArticleBody: FunctionComponent<
FeaturedCardArticleBodyProps
> = ({ article }) => {
const partNumber = getPartNumberInSeries(article);
const seriesColor = getArticleColor(article);
return (
<>
{partNumber && (
<PartNumberIndicator
number={partNumber}
backgroundColor={seriesColor}
/>
)}
<h2 className={font('wb', 2)}>{article.title}</h2>
{article.promo?.caption && (
<p className={font('intr', 5)}>{article.promo?.caption}</p>
)}
{article.series.length > 0 && (
{article.caption && <p className={font('intr', 5)}>{article.caption}</p>}
{article.seriesTitle && (
<Space $v={{ size: 'l', properties: ['margin-top'] }}>
{article.series.map(series => (
<p
key={series.title}
className={font('intb', 6)}
style={{ marginBottom: 0 }}
>
<span className={font('intr', 6)}>Part of</span> {series.title}
</p>
))}
<p className={font('intb', 6)} style={{ marginBottom: 0 }}>
<span className={font('intr', 6)}>Part of</span>{' '}
{article.seriesTitle}
</p>
</Space>
)}
</>
Expand Down Expand Up @@ -303,10 +285,24 @@ const FeaturedCard: FunctionComponent<PropsWithChildren<Props>> = ({
export const FeaturedCardArticle: FunctionComponent<
FeaturedCardArticleProps
> = ({ article, background, textColor }) => {
const props = convertItemToFeaturedCardProps(article);

const promoImage = article.image?.['16:9'] || article.image;
const image = promoImage && {
...transformImage(promoImage),
alt: '',
};
const link = {
url: linkResolver({ type: 'articles', uid: article.uid }),
text: article.title,
};
const labels = [{ text: article.format.label }];
return (
<FeaturedCard {...props} background={background} textColor={textColor}>
<FeaturedCard
image={image}
link={link}
labels={labels}
background={background}
textColor={textColor}
>
<FeaturedCardArticleBody article={article} />
</FeaturedCard>
);
Expand Down
43 changes: 22 additions & 21 deletions content/webapp/pages/stories/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { pageDescriptions } from '@weco/common/data/microcopy';
import { StoriesLandingDocument as RawStoriesLandingDocument } from '@weco/common/prismicio-types';
import { getServerData } from '@weco/common/server-data';
import { AppErrorProps } from '@weco/common/services/app';
import { transformImage } from '@weco/common/services/prismic/transformers/images';
import { serialiseProps } from '@weco/common/utils/json';
import { createPrismicLink } from '@weco/common/views/components/ApiToolbar';
import { JsonLdObj } from '@weco/common/views/components/JsonLd/JsonLd';
Expand All @@ -27,26 +28,24 @@ import { FeaturedCardArticle } from '@weco/content/components/FeaturedCard/Featu
import FeaturedText from '@weco/content/components/FeaturedText/FeaturedText';
import { defaultSerializer } from '@weco/content/components/HTMLSerializers/HTMLSerializers';
import SectionHeader from '@weco/content/components/SectionHeader/SectionHeader';
import StoryPromo from '@weco/content/components/StoryPromo/StoryPromo';
import StoryPromoContentApi from '@weco/content/components/StoryPromo/StoryPromoContentApi';
import { ArticleFormatIds } from '@weco/content/data/content-format-ids';
import { createClient } from '@weco/content/services/prismic/fetch';
import { fetchArticles } from '@weco/content/services/prismic/fetch/articles';
import { fetchStoriesLanding } from '@weco/content/services/prismic/fetch/stories-landing';
import {
transformArticle,
transformArticleToArticleBasic,
} from '@weco/content/services/prismic/transformers/articles';
import { articleLd } from '@weco/content/services/prismic/transformers/json-ld';
import { transformArticle as transformPrismicArticle } from '@weco/content/services/prismic/transformers/articles';
import { articleLdContentApi } from '@weco/content/services/prismic/transformers/json-ld';
import { transformQuery } from '@weco/content/services/prismic/transformers/paginated-results';
import { transformSeriesToSeriesBasic } from '@weco/content/services/prismic/transformers/series';
import { transformStoriesLanding } from '@weco/content/services/prismic/transformers/stories-landing';
import { ArticleBasic } from '@weco/content/types/articles';
import { getArticles } from '@weco/content/services/wellcome/content/articles';
import { Article } from '@weco/content/services/wellcome/content/types/api';
import { Series, SeriesBasic } from '@weco/content/types/series';
import { StoriesLanding } from '@weco/content/types/stories-landing';
import { setCacheControl } from '@weco/content/utils/setCacheControl';

type Props = {
articles: ArticleBasic[];
articles: Article[];
comicSeries: SeriesBasic[];
storiesLanding: StoriesLanding;
jsonLd: JsonLdObj[];
Expand Down Expand Up @@ -97,31 +96,34 @@ export const getServerSideProps: GetServerSideProps<
setCacheControl(context.res);
const serverData = await getServerData(context);
const client = createClient(context);
const articlesQueryPromise = fetchArticles(client, {
filters: prismic.filter.not('my.articles.format', ArticleFormatIds.Comic),
});

const comicsQueryPromise = fetchArticles(client, {
pageSize: 100, // we need enough comics to make sure we have at least one from three different series
filters: prismic.filter.at('my.articles.format', ArticleFormatIds.Comic),
});

const storiesLandingPromise = fetchStoriesLanding(client);
const articlesResponsePromise = getArticles({
params: {},
pageSize: 11,
toggles: serverData.toggles,
});

const [articlesQuery, storiesLandingDoc, comicsQuery] = await Promise.all([
articlesQueryPromise,
const [articlesResponse, storiesLandingDoc, comicsQuery] = await Promise.all([
articlesResponsePromise,
storiesLandingPromise,
comicsQueryPromise,
]);

const articles = transformQuery(articlesQuery, transformArticle);
const articles =
articlesResponse.type === 'ResultList' ? articlesResponse.results : [];

// In order to avoid the case where we end up with an empty comic series,
// rather than querying for the series itself we query for the individual
// comics, then group them by series and stop once we've got to three. That
// way we can be confident each of the three series that we have contains at
// least one comic.
const comics = transformQuery(comicsQuery, transformArticle);
const comics = transformQuery(comicsQuery, transformPrismicArticle);
const comicSeries = new Map<string, Series>();
for (const comic of comics.results) {
const series = comic.series[0];
Expand All @@ -137,16 +139,15 @@ export const getServerSideProps: GetServerSideProps<
transformSeriesToSeriesBasic
);

const jsonLd = articles.results.map(articleLd);
const basicArticles = articles.results.map(transformArticleToArticleBasic);
const jsonLd = articles.map(articleLdContentApi);
const storiesLanding =
storiesLandingDoc &&
transformStoriesLanding(storiesLandingDoc as RawStoriesLandingDocument);

if (articles && articles.results) {
if (articles) {
return {
props: serialiseProps({
articles: basicArticles,
articles,
comicSeries: basicComicSeries,
serverData,
jsonLd,
Expand Down Expand Up @@ -175,7 +176,7 @@ const StoriesPage: FunctionComponent<Props> = ({
jsonLd={jsonLd}
openGraphType="website"
siteSection="stories"
image={firstArticle && firstArticle.image}
image={firstArticle && transformImage(firstArticle.image)}
rssUrl="https://rss.wellcomecollection.org/stories"
apiToolbarLinks={[createPrismicLink(storiesLanding.id)]}
>
Expand Down Expand Up @@ -217,7 +218,7 @@ const StoriesPage: FunctionComponent<Props> = ({
return (
<div className="grid__cell" key={article.id}>
<Space $v={{ size: 'm', properties: ['margin-bottom'] }}>
<StoryPromo article={article} />
<StoryPromoContentApi article={article} />
</Space>
</div>
);
Expand Down