Implement fetching blog cards and blog entries
This commit is contained in:
parent
d4a963b162
commit
961a4cda5d
|
|
@ -12,6 +12,7 @@
|
|||
"@babel/core": "^7.24.4",
|
||||
"@babel/preset-env": "^7.24.4",
|
||||
"@babel/preset-react": "^7.24.1",
|
||||
"dompurify": "^3.1.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
|
|
@ -3336,6 +3337,11 @@
|
|||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.2.tgz",
|
||||
"integrity": "sha512-hLGGBI1tw5N8qTELr3blKjAML/LY4ANxksbS612UiJyDfyf/2D092Pvm+S7pmeTGJRqvlJkFzBoHBQKgQlOQVg=="
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
"@babel/core": "^7.24.4",
|
||||
"@babel/preset-env": "^7.24.4",
|
||||
"@babel/preset-react": "^7.24.1",
|
||||
"dompurify": "^3.1.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import NavbarButton from "./components/NavbarButton.tsx";
|
|||
import NavbarUserInfo from "./components/NavbarUserInfo.tsx";
|
||||
|
||||
import Home from "./pages/Home.tsx";
|
||||
import Blog from "./pages/Blog.tsx";
|
||||
import Login from "./pages/Login.tsx";
|
||||
import Logout from "./pages/Logout.tsx";
|
||||
import About from "./pages/About.tsx";
|
||||
|
|
@ -73,6 +74,7 @@ export default function App() {
|
|||
<Routes>
|
||||
<Route path="/" exact element={<Home></Home>} />
|
||||
<Route path="/home" exact element={<Home></Home>} />
|
||||
<Route path="/blog/*" exact element={<Blog></Blog>} />
|
||||
<Route path="/about" exact element={<About></About>} />
|
||||
<Route
|
||||
path="/blogeditor"
|
||||
|
|
|
|||
|
|
@ -1,31 +1,37 @@
|
|||
import * as React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
interface Props {
|
||||
blogID: number;
|
||||
blogImage: string; // This needs a placeholder/default variable
|
||||
blogTitle: string;
|
||||
blogDatePosted: string;
|
||||
blogAuthor: string;
|
||||
blogDescription: string;
|
||||
}
|
||||
|
||||
export default function BlogEntryCard({
|
||||
blogID,
|
||||
blogImage,
|
||||
blogTitle,
|
||||
blogDatePosted,
|
||||
blogAuthor,
|
||||
blogDescription,
|
||||
}: Props) {
|
||||
return (
|
||||
<>
|
||||
<div className="blogEntryCard">
|
||||
<a href="#">
|
||||
<Link to={"/blog?ID=" + blogID.toString()}>
|
||||
<div className="blogEntry">
|
||||
<img src={blogImage} className="blogEntryImage" alt="..."></img>
|
||||
<div className="blogEntryBody">
|
||||
<h4 className="blogEntryTitle">{blogTitle}</h4>
|
||||
<p className="blogEntryDatePosted">{blogDatePosted}</p>
|
||||
<p className="blogEntryDatePosted">{blogAuthor}</p>
|
||||
<p className="blogEntryDescription">{blogDescription}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ body,
|
|||
font-family: "consolas", sans-serif;
|
||||
background-color: white;
|
||||
|
||||
--background-image: url(https://source.unsplash.com/random/1920x1080/?blurry);
|
||||
/*--background-image: url(https://source.unsplash.com/random/1920x1080/?blurry);*/
|
||||
--background-image: url(https://images.unsplash.com/photo-1542254503-d802f00c2342?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=1080&ixid=MnwxfDB8MXxyYW5kb218MHx8Ymx1cnJ5fHx8fHx8MTcxNTE3MDY0OQ&ixlib=rb-4.0.3&q=80&w=1920);
|
||||
--nav-bar-height: 25px;
|
||||
--blog-card-width: 18rem;
|
||||
--blog-card-height: 20rem;
|
||||
|
|
|
|||
|
|
@ -1,38 +1,50 @@
|
|||
import * as React from "react";
|
||||
import * as DOMPurify from "dompurify";
|
||||
|
||||
import BlogEntryCard from "./../components/BlogEntryCard.tsx";
|
||||
import { Navigate } from "react-router-dom";
|
||||
|
||||
import TilingItem from "../components/TilingItem.tsx";
|
||||
|
||||
export default function Home() {
|
||||
// A mock of what the data from the getBlogEntries JSON return would look like
|
||||
const blogEntries = [
|
||||
{
|
||||
blogImage:
|
||||
"https://git.cspark.dev/avatars/1c230bfe7494b1a62932d94ed8558dc61189437b1b6e0cecdb0c45c3d899bea4?size=512",
|
||||
blogTitle: "Test Blog Entry 1",
|
||||
blogDatePosted: "12/04/2024 4PM", // In reality this would probably be an actual correct format/standardised timestamp
|
||||
blogDescription: "This is a first blog entry test", // If no description, we'd want to get a small snippet of the intro of the blog
|
||||
},
|
||||
{
|
||||
blogImage:
|
||||
"https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png",
|
||||
blogTitle: "Test Blog Entry 2",
|
||||
blogDatePosted: "8/04/2024 6PM", // In reality this would probably be an actual correct format/standardised timestamp
|
||||
blogDescription: "This is a test blog entry number 2", // If no description, we'd want to get a small snippet of the intro of the blog
|
||||
},
|
||||
];
|
||||
const [blogContents, setBlogContents] = React.useState(
|
||||
"Fetching blog contents...",
|
||||
);
|
||||
const blogQuery = new URLSearchParams(window.location.search);
|
||||
const blogID = blogQuery.get("ID");
|
||||
|
||||
React.useEffect(() => {
|
||||
if (blogID) {
|
||||
fetch(
|
||||
"http://localhost:8000/api/blog/contents/HTML/" + blogID.toString(),
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((responseParsed: Object) => {
|
||||
if (responseParsed.success) {
|
||||
setBlogContents(responseParsed.contents);
|
||||
} else {
|
||||
setBlogContents(responseParsed.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="blogEntryGrid">
|
||||
{blogEntries.map((item, index) => (
|
||||
<BlogEntryCard
|
||||
key={index}
|
||||
blogImage={item["blogImage"]}
|
||||
blogTitle={item["blogTitle"]}
|
||||
blogDatePosted={item["blogDatePosted"]}
|
||||
blogDescription={item["blogDescription"]}
|
||||
></BlogEntryCard>
|
||||
))}
|
||||
<div className="standardHorizontalTilingGrid">
|
||||
<TilingItem>
|
||||
<h1>Now on blog page!</h1>
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: DOMPurify.sanitize(blogContents),
|
||||
}}
|
||||
/>
|
||||
</TilingItem>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,34 +3,39 @@ import * as React from "react";
|
|||
import BlogEntryCard from "./../components/BlogEntryCard.tsx";
|
||||
|
||||
export default function Home() {
|
||||
// A mock of what the data from the getBlogEntries JSON return would look like
|
||||
const blogEntries = [
|
||||
{
|
||||
blogImage:
|
||||
"https://git.cspark.dev/avatars/1c230bfe7494b1a62932d94ed8558dc61189437b1b6e0cecdb0c45c3d899bea4?size=512",
|
||||
blogTitle: "Test Blog Entry 1",
|
||||
blogDatePosted: "12/04/2024 4PM", // In reality this would probably be an actual correct format/standardised timestamp
|
||||
blogDescription: "This is a first blog entry test", // If no description, we'd want to get a small snippet of the intro of the blog
|
||||
},
|
||||
{
|
||||
blogImage:
|
||||
"https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png",
|
||||
blogTitle: "Test Blog Entry 2",
|
||||
blogDatePosted: "8/04/2024 6PM", // In reality this would probably be an actual correct format/standardised timestamp
|
||||
blogDescription: "This is a test blog entry number 2", // If no description, we'd want to get a small snippet of the intro of the blog
|
||||
},
|
||||
];
|
||||
const [blogEntries, setBlogEntries] = React.useState({});
|
||||
|
||||
React.useEffect(() => {
|
||||
fetch(
|
||||
"http://127.0.0.1:8000/api/user/blog/cardInfo/?rangeStart=1&rangeEnd=25&sortByLatest=true",
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((responseParsed: Object) => {
|
||||
if (responseParsed["0"].success) {
|
||||
delete responseParsed["0"];
|
||||
setBlogEntries(responseParsed);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="blogEntryGrid">
|
||||
{blogEntries.map((item, index) => (
|
||||
{Object.entries(blogEntries).map((item, index) => (
|
||||
<BlogEntryCard
|
||||
key={index}
|
||||
blogImage={item["blogImage"]}
|
||||
blogTitle={item["blogTitle"]}
|
||||
blogDatePosted={item["blogDatePosted"]}
|
||||
blogDescription={item["blogDescription"]}
|
||||
blogID={item["1"]["blogID"]}
|
||||
blogImage={item["1"]["image"]}
|
||||
blogTitle={item["1"]["title"]}
|
||||
blogDatePosted={item["1"]["datePosted"]}
|
||||
blogAuthor={item["1"]["authorInfo"]["username"]}
|
||||
blogDescription={item["1"]["description"]}
|
||||
></BlogEntryCard>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export default function Login({ authTokenStorageHandler }: Props) {
|
|||
rememberMe: formDataObject.rememberMe ? true : false,
|
||||
};
|
||||
|
||||
fetch("http://127.0.0.1:8000/api/login", {
|
||||
fetch("http://127.0.0.1:8000/api/user/login", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
|
|
|||
Loading…
Reference in New Issue