Skip to content

Commit 7d5705a

Browse files
Merge pull request #61 from CivicDataLab/60-fix-stories-page-data-fetch
Fix data fetching issue in stories page
2 parents 9eca166 + c727266 commit 7d5705a

File tree

5 files changed

+77
-54
lines changed

5 files changed

+77
-54
lines changed

components/stories/StoriesCard.tsx

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,46 @@ import Link from 'next/link';
33
import { getMediumBanner } from 'utils/index';
44
import { truncate } from 'lodash';
55

6-
// strip html tags
6+
// Strip HTML tags
77
function strip(html) {
88
const doc = new DOMParser().parseFromString(html, 'text/html');
99
return doc.body.textContent || '';
1010
}
1111

12-
function getReadTime(text: string) {
12+
function getReadTime(text) {
1313
const wpm = 250;
1414
const words = text.trim().split(/\s+/).length;
1515
return Math.ceil(words / wpm);
1616
}
1717

18-
const StoriesCard: React.FC<{ data: any; length: number }> = ({
19-
data,
20-
length,
21-
}) => {
18+
const StoriesCard: React.FC<{ data: any; length: number }> = ({ data, length }) => {
2219
const [paraLen, setParaLen] = useState(length);
23-
const [content, setContent] = useState(null);
20+
const [content, setContent] = useState('');
2421

2522
useEffect(() => {
2623
if (window.innerWidth < 720) {
27-
paraLen > 150 ? setParaLen(150) : null;
24+
setParaLen(150);
2825
}
2926

30-
setContent(strip(data['content']));
31-
}, []);
27+
const textContent = data['content:encoded'] ? strip(data['content:encoded']) : '';
28+
setContent(textContent);
29+
}, [data]);
30+
3231
return (
3332
<article className="stories-card">
34-
<Link href={data.link}>
33+
<Link href={data.link[0]}>
3534
<a>
36-
<img src={getMediumBanner(data['content'])} alt="" />
35+
<img src={getMediumBanner(data['content:encoded'])} alt="" />
3736
</a>
3837
</Link>
3938

4039
<div className="stories-card__content">
41-
<Link href={data.link}>
40+
<Link href={data.link[0]}>
4241
<a>
4342
<h3>{data.title}</h3>
4443

4544
<p>
46-
{truncate(content ? content : data['content'], {
45+
{truncate(content, {
4746
length: paraLen,
4847
})}
4948
</p>
@@ -52,11 +51,8 @@ const StoriesCard: React.FC<{ data: any; length: number }> = ({
5251

5352
<div className="stories-card__footer">
5453
<div>
55-
<small className="stories-card__author">{data.author}</small>
56-
<small>
57-
{`${data.pubDate} .
58-
${getReadTime(data['content'])} mins read`}
59-
</small>
54+
<small className="stories-card__author">{data['dc:creator']}</small>
55+
<small>{`${data.pubDate} · ${getReadTime(content)} mins read`}</small>
6056
</div>
6157
</div>
6258
</div>

package-lock.json

Lines changed: 17 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@
5151
"sonner": "^1.4.3",
5252
"tailwind-merge": "^1.14.0",
5353
"tailwindcss-animate": "^1.0.7",
54-
"typescript": "^4.5.4"
54+
"typescript": "^4.5.4",
55+
"xml2js": "^0.6.2"
5556
},
5657
"devDependencies": {
5758
"@testing-library/jest-dom": "^5.8.0",

pages/stories/index.tsx

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ import { GetServerSideProps } from 'next';
33
import Head from 'next/head';
44
import MegaHeader from 'components/_shared/MegaHeader';
55
import StoriesCard from 'components/stories/StoriesCard';
6+
import fetch from 'node-fetch';
7+
import { parseStringPromise } from 'xml2js';
68

79
const Stories = ({ data }) => {
810
const headerData = {
911
title: 'Data Stories',
1012
content:
11-
'This page contains different researches, case studies, explainers and other public resources using procurement data.',
13+
'This page contains different researches, case studies, explainers and other public resources using procurement data.',
1214
};
15+
1316
return (
1417
<>
1518
<Head>
@@ -20,24 +23,17 @@ const Stories = ({ data }) => {
2023
<MegaHeader data={headerData} />
2124

2225
<div className="container">
23-
{data.items.length > 0 && (
26+
{data?.rss?.channel[0]?.item?.length > 0 && (
2427
<>
25-
<StoriesCard data={data.items[0]} length={700} />
28+
<StoriesCard data={data.rss.channel[0].item[0]} length={700} />
2629
<section className="stories__team">
2730
<div className="stories__header">
2831
<h3 className="heading-w-line">Stories from our team</h3>
2932
</div>
3033
<div className="stories__wrapper">
31-
{data.items.map((story, index) => {
32-
if (index == 0) return;
33-
return (
34-
<StoriesCard
35-
key={`story-${index}`}
36-
data={story}
37-
length={125}
38-
/>
39-
);
40-
})}
34+
{data.rss.channel[0].item.slice(1).map((story, index) => (
35+
<StoriesCard key={`story-${index}`} data={story} length={125} />
36+
))}
4137
</div>
4238
</section>
4339
</>
@@ -49,20 +45,33 @@ const Stories = ({ data }) => {
4945
};
5046

5147
export const getServerSideProps: GetServerSideProps = async ({ res }) => {
52-
res.setHeader(
53-
'Cache-Control',
54-
'public, s-maxage=86400, stale-while-revalidate=59'
55-
);
48+
res.setHeader('Cache-Control', 'public, s-maxage=86400, stale-while-revalidate=59');
5649

57-
const data = await fetch(
58-
'https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/civicdatalab/tagged/open-contracting'
59-
).then((res) => res.json());
50+
try {
51+
const response = await fetch(
52+
'https://medium.com/feed/civicdatalab/tagged/open-contracting'
53+
);
6054

61-
return {
62-
props: {
63-
data,
64-
},
65-
};
55+
if (!response.ok) {
56+
throw new Error('Network response was not ok');
57+
}
58+
59+
const xmlData = await response.text();
60+
const jsonData = await parseStringPromise(xmlData);
61+
62+
return {
63+
props: {
64+
data: jsonData,
65+
},
66+
};
67+
} catch (error) {
68+
console.error('Fetch error:', error);
69+
return {
70+
props: {
71+
data: null,
72+
},
73+
};
74+
}
6675
};
6776

6877
export default Stories;

utils/index.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ import { config } from '../config';
22

33
// fetch medium post banner URL
44
export function getMediumBanner(postContent) {
5-
const srcIndex = postContent.indexOf('src=');
6-
const srcStart = srcIndex + 5;
7-
const srcEnd = postContent.substring(srcStart).indexOf('"') + srcStart;
8-
const src = postContent.substring(srcStart, srcEnd);
9-
return src;
5+
if (!postContent || typeof postContent !== 'string') {
6+
return null;
7+
}
8+
9+
const srcRegex = /<img[^>]+src="([^">]+)"/;
10+
const match = postContent.match(srcRegex);
11+
12+
return match && match[1] ? match[1] : null;
1013
}
1114

15+
1216
export function getOrgLogo(url) {
1317
return `http://${config.CKAN_URL}/uploads/group/${url}`;
1418
}

0 commit comments

Comments
 (0)