Skip to content

Commit c14f1c0

Browse files
authored
Core 1061 port press page to ts (#2751)
* CORE-1061: Port Press page to TypeScript [CORE-1061] * Prettier
1 parent c0e32d8 commit c14f1c0

File tree

19 files changed

+317
-190
lines changed

19 files changed

+317
-190
lines changed

src/app/components/byline/byline.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@ import React from 'react';
22
import './byline.scss';
33
import {formatDateForBlog} from '~/helpers/data';
44

5-
export default function Byline({
6-
date,
7-
author,
8-
source
9-
}: {
5+
type BylineArgs = {
106
date: string;
11-
author: string;
7+
author?: string;
128
source?: string;
13-
}) {
9+
};
10+
11+
export default function Byline({date, source, author}: BylineArgs) {
1412
return (
1513
<div className="byline">
1614
{source ? (
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import React from 'react';
22
import usePageContext from '../page-context';
33
import RawHTML from '~/components/jsx-helpers/raw-html';
4+
import {ContentBlock} from '../helpers';
5+
import {assertDefined} from '~/helpers/data';
46

57
export default function AboutOpenStax() {
6-
const {about} = usePageContext();
8+
const {about} = assertDefined(usePageContext());
79

810
return (
9-
<div className='content-block'>
10-
<h2>About OpenStax</h2>
11+
<ContentBlock title="About OpenStax">
1112
<RawHTML html={about} />
12-
</div>
13+
</ContentBlock>
1314
);
1415
}

src/app/pages/press/article/article.js

Lines changed: 0 additions & 69 deletions
This file was deleted.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import React from 'react';
2+
import BodyUnit, {UnitType} from '~/components/body-units/body-units';
3+
import Byline from '~/components/byline/byline';
4+
import {formatDateForBlog as formatDate, assertNotNull} from '~/helpers/data';
5+
import '~/pages/blog/article/article.scss';
6+
import usePageData from '~/helpers/use-page-data';
7+
import './article.scss';
8+
9+
function Hero({coverUrl}: {coverUrl: string}) {
10+
return (
11+
<div className="hero" style={{backgroundImage: `url(${coverUrl})`}}>
12+
<img
13+
className="strips"
14+
src="/dist/images/components/strips.svg"
15+
height="10"
16+
alt=""
17+
role="presentation"
18+
/>
19+
</div>
20+
);
21+
}
22+
23+
type ArticleData = {
24+
articleImage: string | null;
25+
subheading: string;
26+
title: string;
27+
author: string;
28+
date: string;
29+
body: UnitType[];
30+
};
31+
32+
function Article({data}: {data: ArticleData}) {
33+
const {
34+
articleImage: coverUrl,
35+
subheading,
36+
title,
37+
author,
38+
date: rawDate,
39+
body: bodyData
40+
} = data;
41+
const date = assertNotNull(formatDate(rawDate));
42+
43+
return (
44+
<div className="article">
45+
{coverUrl !== null && <Hero coverUrl={coverUrl} />}
46+
<article className="text-content">
47+
<h1>{title}</h1>
48+
{Boolean(subheading) && <h2>{subheading}</h2>}
49+
<Byline author={author} date={date} />
50+
<div className="body">
51+
{bodyData.map((unit) => (
52+
<BodyUnit unit={unit} key={unit.value as string} />
53+
))}
54+
</div>
55+
</article>
56+
</div>
57+
);
58+
}
59+
60+
type PageData =
61+
| ArticleData
62+
| {
63+
error: {message: string};
64+
};
65+
66+
export default function ArticleLoader({slug}: {slug: string}) {
67+
const data = usePageData<PageData>(slug, true);
68+
69+
if (!data) {
70+
return null;
71+
}
72+
if ('error' in data) {
73+
return (
74+
<div className="text-content">
75+
<h1>[Article not found]</h1>
76+
<pre>
77+
{data.error.message} {slug}
78+
</pre>
79+
</div>
80+
);
81+
}
82+
83+
return <Article data={data} />;
84+
}

src/app/pages/press/banner/banner.js renamed to src/app/pages/press/banner/banner.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import React from 'react';
22
import usePageContext from '../page-context';
3+
import {assertDefined} from '~/helpers/data';
34
import './banner.scss';
45

56
export default function Banner() {
6-
const {title} = usePageContext();
7+
const {title} = assertDefined(usePageContext());
78

89
return (
9-
<div className='content-block'>
10-
<div className='hero'>
10+
<div className="content-block">
11+
<div className="hero">
1112
<h1>{title}</h1>
1213
</div>
1314
</div>
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import React from 'react';
2+
import {ContentBlock} from '../helpers';
23
import usePageContext from '../page-context';
34
import AccordionGroup from '~/components/accordion-group/accordion-group';
4-
import {htmlToText} from '~/helpers/data';
5+
import {htmlToText, assertDefined} from '~/helpers/data';
56
import RawHTML from '~/components/jsx-helpers/raw-html';
67
import './faq.scss';
78

89
export default function FAQ() {
9-
const {faqs} = usePageContext();
10+
const {faqs} = assertDefined(usePageContext());
1011

1112
const accordionItems = React.useMemo(
1213
() =>
@@ -18,11 +19,10 @@ export default function FAQ() {
1819
);
1920

2021
return (
21-
<div className='content-block'>
22-
<h2>Frequently asked questions</h2>
23-
<div className='articles'>
22+
<ContentBlock title="Frequently asked questions">
23+
<div className="articles">
2424
<AccordionGroup items={accordionItems} noScroll />
2525
</div>
26-
</div>
26+
</ContentBlock>
2727
);
2828
}
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
import React from 'react';
22
import usePageContext from '../page-context';
3+
import {assertDefined} from '~/helpers/data';
4+
import {ContentBlock} from '../helpers';
35
import './featured-in.scss';
46

57
export default function FeaturedIn() {
6-
const {featuredIn} = usePageContext();
8+
const {featuredIn} = assertDefined(usePageContext());
79

810
return (
9-
<div className='content-block'>
10-
<h2>Featured in</h2>
11-
<div className='link-grid'>
11+
<ContentBlock title="Featured in">
12+
<div className="link-grid">
1213
{featuredIn.map((obj) => (
1314
<a key={obj.image} href={obj.url}>
1415
<img src={obj.image} alt={obj.name} />
1516
</a>
1617
))}
1718
</div>
18-
</div>
19+
</ContentBlock>
1920
);
2021
}

src/app/pages/press/helpers.js renamed to src/app/pages/press/helpers.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,36 @@ import Byline from '~/components/byline/byline';
33
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
44
import {faExternalLinkAlt} from '@fortawesome/free-solid-svg-icons/faExternalLinkAlt';
55

6-
export function ContentBlock({title, children}) {
6+
export function ContentBlock({
7+
title,
8+
children
9+
}: React.PropsWithChildren<{title: string}>) {
710
return (
8-
<div className='content-block'>
11+
<div className="content-block">
912
<h2>{title}</h2>
1013
{children}
1114
</div>
1215
);
1316
}
1417

15-
export function asDate(dateStr) {
18+
export function asDate(dateStr: string) {
1619
const [year, month, day] = dateStr.split('-');
1720

18-
return new Date(year, month - 1, day);
21+
return new Date(+year, +month - 1, +day);
1922
}
2023

21-
export function convertedDate(dateStr) {
24+
export function convertedDate(dateStr: string) {
2225
return asDate(dateStr).toLocaleString('en-US', {
2326
month: 'short',
2427
day: 'numeric',
2528
year: 'numeric'
2629
});
2730
}
2831

29-
function OptionalExcerpt({excerpt, url}) {
32+
function OptionalExcerpt({excerpt, url}: {excerpt?: string; url: string}) {
3033
return (
3134
excerpt && (
32-
<div className='excerpt'>
35+
<div className="excerpt">
3336
{excerpt}<a href={url}>Continue reading</a>
3437
</div>
3538
)
@@ -44,6 +47,11 @@ export function PressExcerpt({
4447
url,
4548
headline,
4649
excerpt
50+
}: Parameters<typeof Byline>[0] & {
51+
iconUrl?: string;
52+
url: string;
53+
headline: string;
54+
excerpt?: string;
4755
}) {
4856
const classList = ['press-excerpt'];
4957

@@ -53,9 +61,9 @@ export function PressExcerpt({
5361

5462
return (
5563
<div className={classList.join(' ')}>
56-
{iconUrl && <img src={iconUrl} alt='' />}
64+
{iconUrl && <img src={iconUrl} alt="" />}
5765
<Byline author={author} date={date} source={source} />
58-
<div className='headline'>
66+
<div className="headline">
5967
<a href={url}>
6068
{headline}{' '}
6169
{source && <FontAwesomeIcon icon={faExternalLinkAlt} />}
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import React from 'react';
2+
import {assertDefined} from '~/helpers/data';
23
import usePageContext from '../page-context';
4+
import {ContentBlock} from '../helpers';
35

46
export default function Infographic() {
5-
const {infographicText, infographicImage} = usePageContext();
7+
const {infographicText, infographicImage} = assertDefined(usePageContext());
68

79
return (
8-
<div className='content-block'>
9-
<h2>{infographicText}</h2>
10+
<ContentBlock title={infographicText}>
1011
<img
1112
src={infographicImage.meta.downloadUrl}
1213
alt={infographicImage.title}
1314
/>
14-
</div>
15+
</ContentBlock>
1516
);
1617
}

0 commit comments

Comments
 (0)