From 5ded54f9d8558d92fc25baec8c4dc771bdb681fc Mon Sep 17 00:00:00 2001 From: Happy Felix Chukwuma Date: Mon, 5 Aug 2024 23:59:50 +0100 Subject: [PATCH] refactor: Restructured the client codebase for maintainability and readability --- client/src/App.js | 4 +- .../components/ArticleDetail/ArticleApi.js | 11 +++++ .../{ => ArticleDetail}/ArticleDetail.js | 46 ++++--------------- .../components/ArticleDetail/ArticleUtils.js | 23 ++++++++++ .../src/components/ArticleList/ArticleApi.js | 11 +++++ .../{ => ArticleList}/ArticleList.js | 17 ++----- client/src/components/Utils/Config.js | 2 + .../{ => Utils}/DateTimeFormatter.js | 11 +++-- 8 files changed, 71 insertions(+), 54 deletions(-) create mode 100644 client/src/components/ArticleDetail/ArticleApi.js rename client/src/components/{ => ArticleDetail}/ArticleDetail.js (58%) create mode 100644 client/src/components/ArticleDetail/ArticleUtils.js create mode 100644 client/src/components/ArticleList/ArticleApi.js rename client/src/components/{ => ArticleList}/ArticleList.js (88%) create mode 100644 client/src/components/Utils/Config.js rename client/src/components/{ => Utils}/DateTimeFormatter.js (50%) diff --git a/client/src/App.js b/client/src/App.js index 1b1f53f..3cef286 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -5,8 +5,8 @@ import { Routes, Navigate, } from "react-router-dom"; -import ArticleList from "./components/ArticleList"; -import ArticleDetail from "./components/ArticleDetail"; +import ArticleList from "./components/ArticleList/ArticleList"; +import ArticleDetail from "./components/ArticleDetail/ArticleDetail"; import Header from "./components/Header"; import Footer from "./components/Footer"; import { ThemeProviderComponent } from "./components/ThemeContext"; diff --git a/client/src/components/ArticleDetail/ArticleApi.js b/client/src/components/ArticleDetail/ArticleApi.js new file mode 100644 index 0000000..b9b2f99 --- /dev/null +++ b/client/src/components/ArticleDetail/ArticleApi.js @@ -0,0 +1,11 @@ +import axios from 'axios'; +import { apiUrl } from "../Utils/Config"; + +export const fetchArticle = async (id) => { + try { + const response = await axios.get(`${apiUrl}${id}/`); + return response.data.data; + } catch (err) { + console.log("Error fetching article: ", err); + } +}; \ No newline at end of file diff --git a/client/src/components/ArticleDetail.js b/client/src/components/ArticleDetail/ArticleDetail.js similarity index 58% rename from client/src/components/ArticleDetail.js rename to client/src/components/ArticleDetail/ArticleDetail.js index 04edbbd..743de09 100644 --- a/client/src/components/ArticleDetail.js +++ b/client/src/components/ArticleDetail/ArticleDetail.js @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; import { useParams } from "react-router-dom"; -import axios from "axios"; + import { Container, Typography, @@ -10,49 +10,21 @@ import { CardContent, CardMedia, } from "@mui/material"; +import "../../styles/styles.css"; import DOMPurify from "dompurify"; -import formatDate from "./DateTimeFormatter"; -import "../styles/styles.css"; - -const backendBaseUrl = "http://127.0.0.1:8000"; // Backend URL +import formatDate from "../Utils/DateTimeFormatter"; +import { fetchArticle } from "./ArticleApi"; +import { formatArticleData } from "./ArticleUtils"; function ArticleDetail() { const { id } = useParams(); const [article, setArticle] = useState(null); useEffect(() => { - const fetchArticle = async () => { - try { - const response = await axios.get( - `${backendBaseUrl}/api/articles/${id}/` - ); - const data = response.data; - - // Clean up unwanted HTML tags - const cleanedContent = data.content.replace(/

 <\/p>/g, ''); - - // Replace image URLs in content - const updatedContent = cleanedContent.replace( - /src="\/media\//g, - `src="${backendBaseUrl}/media/` - ); - - // Ensure thumb URL is correctly formatted - const updatedThumb = data.thumb - ? `${data.thumb}` - : "/static/images/cards/contemplative-reptile.jpg"; - - setArticle({ - ...data, - content: updatedContent, // Replace content with updated image URLs and cleaned HTML - thumb: updatedThumb, // Ensure thumb path is correct - }); - } catch (err) { - console.log("Error fetching article: ", err); - } - }; - - fetchArticle(); + fetchArticle(id).then((data) => { + const formattedArticle = formatArticleData(data); + setArticle(formattedArticle); + }); }, [id]); return ( diff --git a/client/src/components/ArticleDetail/ArticleUtils.js b/client/src/components/ArticleDetail/ArticleUtils.js new file mode 100644 index 0000000..73d5f7d --- /dev/null +++ b/client/src/components/ArticleDetail/ArticleUtils.js @@ -0,0 +1,23 @@ +import { backendBaseUrl } from "../Utils/Config"; + +// clean up unwanted HTML tags +export const cleanContent = (content) => { + return ( + content + ?.replace(/

 <\/p>/g, "") + .replace(/src="\/media\//g, `src="${backendBaseUrl}/media/`) || "" + ); +}; + +// get thumb URL or default image +export const getThumbUrl = (thumb) => { + return thumb ? `${thumb}` : "/static/images/cards/contemplative-reptile.jpg"; +}; + +// format article data +export const formatArticleData = (data) => { + const updatedContent = cleanContent(data.content); + const updatedThumb = getThumbUrl(data.thumb); + + return { ...data, content: updatedContent, thumb: updatedThumb }; +}; diff --git a/client/src/components/ArticleList/ArticleApi.js b/client/src/components/ArticleList/ArticleApi.js new file mode 100644 index 0000000..59029cb --- /dev/null +++ b/client/src/components/ArticleList/ArticleApi.js @@ -0,0 +1,11 @@ +import axios from 'axios'; +import { apiUrl } from "../Utils/Config"; + +export const fetchArticles = async () => { + try { + const response = await axios.get(`${apiUrl}`); + return response.data; + } catch (err) { + console.log("Error fetching articles: ", err); + } +}; \ No newline at end of file diff --git a/client/src/components/ArticleList.js b/client/src/components/ArticleList/ArticleList.js similarity index 88% rename from client/src/components/ArticleList.js rename to client/src/components/ArticleList/ArticleList.js index 52bab97..1379728 100644 --- a/client/src/components/ArticleList.js +++ b/client/src/components/ArticleList/ArticleList.js @@ -1,6 +1,5 @@ import React, { useState, useEffect } from "react"; import { Link } from "react-router-dom"; -import axios from "axios"; import { Container, Typography, @@ -12,22 +11,16 @@ import { CardMedia, Box, } from "@mui/material"; -import formatDate from "./DateTimeFormatter"; - -const backendBaseUrl = "http://127.0.0.1:8000"; //backend URL +import formatDate from "../Utils/DateTimeFormatter"; +import { fetchArticles } from "./ArticleApi"; function ArticleList() { const [articles, setArticles] = useState([]); useEffect(() => { - axios - .get(`${backendBaseUrl}/api/articles/`) - .then((res) => { - setArticles(res.data); - }) - .catch((err) => { - console.log("Error fetching article: ", err); - }); + fetchArticles().then((data) => { + setArticles(data); + }); }, []); return ( diff --git a/client/src/components/Utils/Config.js b/client/src/components/Utils/Config.js new file mode 100644 index 0000000..9c544c9 --- /dev/null +++ b/client/src/components/Utils/Config.js @@ -0,0 +1,2 @@ +export const backendBaseUrl = "http://127.0.0.1:8000"; +export const apiUrl = `${backendBaseUrl}/api/articles/`; \ No newline at end of file diff --git a/client/src/components/DateTimeFormatter.js b/client/src/components/Utils/DateTimeFormatter.js similarity index 50% rename from client/src/components/DateTimeFormatter.js rename to client/src/components/Utils/DateTimeFormatter.js index 0947d3c..88fd5c3 100644 --- a/client/src/components/DateTimeFormatter.js +++ b/client/src/components/Utils/DateTimeFormatter.js @@ -3,12 +3,17 @@ import { format } from "date-fns"; function formatDate(dateString) { const date = new Date(dateString); + // Check if the date is valid + if (isNaN(date.getTime())) { + return "Invalid date"; // or a default value + } + // Format the date and time - const formattedDate = format(date, "MMMM dd, yyyy"); // Example: July 20, 2024 - const formattedTime = format(date, "hh:mm a"); // Example: 01:45 pm + const formattedDate = format(date, "MMMM dd, yyyy"); + const formattedTime = format(date, "hh:mm a"); const formattedDateTime = `Published: ${formattedDate} at ${formattedTime}`; return formattedDateTime; } -export default formatDate; +export default formatDate; \ No newline at end of file