Skip to content

Commit

Permalink
Merge pull request #61 from CivicDataLab/60-fix-stories-page-data-fetch
Browse files Browse the repository at this point in the history
Fix data fetching issue in stories page
  • Loading branch information
Deepthi-Chand authored Jun 17, 2024
2 parents 9eca166 + c727266 commit 7d5705a
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 54 deletions.
34 changes: 15 additions & 19 deletions components/stories/StoriesCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,46 @@ import Link from 'next/link';
import { getMediumBanner } from 'utils/index';
import { truncate } from 'lodash';

// strip html tags
// Strip HTML tags
function strip(html) {
const doc = new DOMParser().parseFromString(html, 'text/html');
return doc.body.textContent || '';
}

function getReadTime(text: string) {
function getReadTime(text) {
const wpm = 250;
const words = text.trim().split(/\s+/).length;
return Math.ceil(words / wpm);
}

const StoriesCard: React.FC<{ data: any; length: number }> = ({
data,
length,
}) => {
const StoriesCard: React.FC<{ data: any; length: number }> = ({ data, length }) => {
const [paraLen, setParaLen] = useState(length);
const [content, setContent] = useState(null);
const [content, setContent] = useState('');

useEffect(() => {
if (window.innerWidth < 720) {
paraLen > 150 ? setParaLen(150) : null;
setParaLen(150);
}

setContent(strip(data['content']));
}, []);
const textContent = data['content:encoded'] ? strip(data['content:encoded']) : '';
setContent(textContent);
}, [data]);

return (
<article className="stories-card">
<Link href={data.link}>
<Link href={data.link[0]}>
<a>
<img src={getMediumBanner(data['content'])} alt="" />
<img src={getMediumBanner(data['content:encoded'])} alt="" />
</a>
</Link>

<div className="stories-card__content">
<Link href={data.link}>
<Link href={data.link[0]}>
<a>
<h3>{data.title}</h3>

<p>
{truncate(content ? content : data['content'], {
{truncate(content, {
length: paraLen,
})}
</p>
Expand All @@ -52,11 +51,8 @@ const StoriesCard: React.FC<{ data: any; length: number }> = ({

<div className="stories-card__footer">
<div>
<small className="stories-card__author">{data.author}</small>
<small>
{`${data.pubDate} .
${getReadTime(data['content'])} mins read`}
</small>
<small className="stories-card__author">{data['dc:creator']}</small>
<small>{`${data.pubDate} · ${getReadTime(content)} mins read`}</small>
</div>
</div>
</div>
Expand Down
21 changes: 17 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"sonner": "^1.4.3",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7",
"typescript": "^4.5.4"
"typescript": "^4.5.4",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.8.0",
Expand Down
59 changes: 34 additions & 25 deletions pages/stories/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import { GetServerSideProps } from 'next';
import Head from 'next/head';
import MegaHeader from 'components/_shared/MegaHeader';
import StoriesCard from 'components/stories/StoriesCard';
import fetch from 'node-fetch';
import { parseStringPromise } from 'xml2js';

const Stories = ({ data }) => {
const headerData = {
title: 'Data Stories',
content:
'This page contains different researches, case studies, explainers and other public resources using procurement data.',
'This page contains different researches, case studies, explainers and other public resources using procurement data.',
};

return (
<>
<Head>
Expand All @@ -20,24 +23,17 @@ const Stories = ({ data }) => {
<MegaHeader data={headerData} />

<div className="container">
{data.items.length > 0 && (
{data?.rss?.channel[0]?.item?.length > 0 && (
<>
<StoriesCard data={data.items[0]} length={700} />
<StoriesCard data={data.rss.channel[0].item[0]} length={700} />
<section className="stories__team">
<div className="stories__header">
<h3 className="heading-w-line">Stories from our team</h3>
</div>
<div className="stories__wrapper">
{data.items.map((story, index) => {
if (index == 0) return;
return (
<StoriesCard
key={`story-${index}`}
data={story}
length={125}
/>
);
})}
{data.rss.channel[0].item.slice(1).map((story, index) => (
<StoriesCard key={`story-${index}`} data={story} length={125} />
))}
</div>
</section>
</>
Expand All @@ -49,20 +45,33 @@ const Stories = ({ data }) => {
};

export const getServerSideProps: GetServerSideProps = async ({ res }) => {
res.setHeader(
'Cache-Control',
'public, s-maxage=86400, stale-while-revalidate=59'
);
res.setHeader('Cache-Control', 'public, s-maxage=86400, stale-while-revalidate=59');

const data = await fetch(
'https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/civicdatalab/tagged/open-contracting'
).then((res) => res.json());
try {
const response = await fetch(
'https://medium.com/feed/civicdatalab/tagged/open-contracting'
);

return {
props: {
data,
},
};
if (!response.ok) {
throw new Error('Network response was not ok');
}

const xmlData = await response.text();
const jsonData = await parseStringPromise(xmlData);

return {
props: {
data: jsonData,
},
};
} catch (error) {
console.error('Fetch error:', error);
return {
props: {
data: null,
},
};
}
};

export default Stories;
14 changes: 9 additions & 5 deletions utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import { config } from '../config';

// fetch medium post banner URL
export function getMediumBanner(postContent) {
const srcIndex = postContent.indexOf('src=');
const srcStart = srcIndex + 5;
const srcEnd = postContent.substring(srcStart).indexOf('"') + srcStart;
const src = postContent.substring(srcStart, srcEnd);
return src;
if (!postContent || typeof postContent !== 'string') {
return null;
}

const srcRegex = /<img[^>]+src="([^">]+)"/;
const match = postContent.match(srcRegex);

return match && match[1] ? match[1] : null;
}


export function getOrgLogo(url) {
return `http://${config.CKAN_URL}/uploads/group/${url}`;
}
Expand Down

0 comments on commit 7d5705a

Please sign in to comment.