Skip to content

Commit aef5341

Browse files
authored
#30: Implemented Saved Articles form section for the settings
* created saved articles form with modal * added cancel button functionality
1 parent 10d05db commit aef5341

File tree

5 files changed

+249
-4
lines changed

5 files changed

+249
-4
lines changed

frontend/src/Components/Settings/Customizations/CustomizationsEdit.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,6 @@ const TechnologiesOfInterest = ({
237237
onChange,
238238
editable,
239239
setEditable,
240-
setIsDataChanged,
241240
}) => {
242241
return (
243242
<>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Modal, Button, ModalBody } from "react-bootstrap";
2+
3+
//modal for confirming if the user wants to delete selected articles
4+
export default function ConfirmDeleteModal({
5+
isOpen,
6+
handleClose,
7+
submitHandler,
8+
}) {
9+
return (
10+
<Modal show={isOpen} onHide={handleClose} centered>
11+
<Modal.Header closeButton className="border-0" />
12+
<ModalBody>
13+
<h5 className="text-center">
14+
Are you sure you want to remove the article(s) you selected?
15+
</h5>
16+
<div className="d-flex justify-content-between mt-4">
17+
<Button
18+
className="border-0 text-dark fw-medium"
19+
style={{ backgroundColor: "#B9B2B2" }}
20+
onClick={handleClose}
21+
>
22+
Cancel
23+
</Button>
24+
25+
<Button
26+
className="border-0 text-dark fw-medium"
27+
style={{ backgroundColor: "#24BEEF" }}
28+
type="submit"
29+
onClick={() => {
30+
handleClose();
31+
submitHandler();
32+
}}
33+
>
34+
Yes
35+
</Button>
36+
</div>
37+
</ModalBody>
38+
</Modal>
39+
);
40+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Card, Container, Image, Row, Col, Button } from "react-bootstrap";
2+
import { TrashFill, BookmarkPlusFill } from "react-bootstrap-icons";
3+
import "./SavedArticleItem.scss";
4+
export default function SavedArticleItem({
5+
articleImg,
6+
articleTitle,
7+
articleDesc,
8+
toBeDeleted,
9+
deleteToggler,
10+
}) {
11+
return (
12+
<Container
13+
gap={3}
14+
className={`${
15+
toBeDeleted ? "to-be-deleted-article" : "kept-article"
16+
} mb-3 p-3 rounded-4 mx-0`}
17+
>
18+
<Row>
19+
<Col xs={3}>
20+
<Image
21+
src={articleImg}
22+
className="object-fit-contain w-100"
23+
height={100}
24+
/>
25+
</Col>
26+
<Col xs={7}>
27+
<Card.Body>
28+
<Card.Title className="fw-bold">{articleTitle}</Card.Title>
29+
<Card.Text className="mt-2">{articleDesc}</Card.Text>
30+
</Card.Body>
31+
</Col>
32+
<Col xs={2} className="d-flex align-items-start justify-content-end">
33+
<Button className="bg-transparent border-0">
34+
{/*User will be able to either add back or remove the current article depending on article's state */}
35+
{toBeDeleted ? (
36+
<BookmarkPlusFill className="fs-4" onClick={deleteToggler} />
37+
) : (
38+
<TrashFill className="fs-4" onClick={deleteToggler} />
39+
)}
40+
</Button>
41+
</Col>
42+
</Row>
43+
</Container>
44+
);
45+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@import "../../../../scss/variables";
2+
@import "bootstrap/scss/functions";
3+
4+
.kept-article {
5+
background: $primary;
6+
}
7+
8+
//make article lighter if selected to be deleted
9+
.to-be-deleted-article {
10+
background: tint-color($primary, 50%);
11+
12+
& img,
13+
.card-title,
14+
.card-text {
15+
opacity: 0.5;
16+
}
17+
}
Lines changed: 147 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,148 @@
1+
import { useEffect, useState } from "react";
2+
import { Container, Form, Stack, Button } from "react-bootstrap";
3+
import SavedArticleItem from "./SaveArticleItem/SavedArticleItem";
4+
import ConfirmDeleteModal from "./ConfirmDeleteModal";
5+
6+
const test_articles = [
7+
{
8+
id: 0,
9+
image:
10+
"https://builtin.com/cdn-cgi/image/f=auto,quality=80,width=752,height=435/https://builtin.com/sites/www.builtin.com/files/styles/byline_image/public/2021-12/machine-learning-examples-applications.png",
11+
title: "Intro to Machine Learning",
12+
description: "Brief description about this topic...",
13+
},
14+
{
15+
id: 1,
16+
image:
17+
"https://imageio.forbes.com/specials-images/dam/imageserve/966248982/960x0.jpg?height=456&width=711&fit=bounds",
18+
title: "Intro to Machine Learning",
19+
description: "Brief description about this topic...",
20+
},
21+
{
22+
id: 2,
23+
image:
24+
"https://www.mathworks.com/solutions/machine-learning/_jcr_content/mainParsys/band_copy_1919605364/mainParsys/columns/a03cc495-1c23-4402-82ea-1c8fd4d25234/pictogram.adapt.full.medium.svg/1701252724596.svg",
25+
title: "Intro to Machine Learning",
26+
description: "Brief description about this topic...",
27+
},
28+
];
29+
130
export default function SavedArticles() {
2-
return <h1>Saved Articles</h1>;
3-
}
4-
31+
//array all the articles currently not deleted
32+
const [articles, setArticles] = useState([]);
33+
34+
//the state of the articles of whether they are being deleted or not, is object, key = article id, value = whether it is selected orn ot
35+
const [isDeletedArticles, setIsDeletedArticles] = useState({});
36+
37+
//toggler of selected state for a specific article
38+
//this returns a FUNCTION that toggles an article's state with the provided id
39+
const articleToggleHandler = (id) => () =>
40+
setIsDeletedArticles((prevArticles) => {
41+
return { ...prevArticles, [id]: !prevArticles[id] };
42+
});
43+
44+
//deselects all articles from deletion
45+
const resetDeletionHandler = () => {
46+
let resetArticles = {};
47+
articles.forEach(({ id }) => {
48+
resetArticles[id] = false;
49+
});
50+
setIsDeletedArticles(resetArticles);
51+
};
52+
53+
//use effect to get articles upon page load once, also init selected state of every article as false
54+
//just simulating retrieving articles
55+
useEffect(() => {
56+
let initArticles = async () => {
57+
let retrieved_articles = await test_articles;
58+
setArticles(retrieved_articles);
59+
60+
let initIsDeletedArticles = {};
61+
retrieved_articles.forEach(({ id }) => {
62+
initIsDeletedArticles[id] = false;
63+
});
64+
setIsDeletedArticles(initIsDeletedArticles);
65+
};
66+
67+
initArticles();
68+
}, []);
69+
70+
//submit handler (the yes button in modal does not trigger submit event)
71+
//simply removed the selected articles from the displayed articles state
72+
//insert backend actions here
73+
const submitHandler = () => {
74+
//filter out kept articles, replace articles state with them
75+
let keptArticles = articles.filter(
76+
(article) => !isDeletedArticles[article.id]
77+
);
78+
setArticles(keptArticles);
79+
80+
//reset selected state
81+
let initIsDeletedArticles = {};
82+
keptArticles.forEach(({ id }) => {
83+
initIsDeletedArticles[id] = false;
84+
});
85+
setIsDeletedArticles(initIsDeletedArticles);
86+
};
87+
88+
//state for whether delete confirmation modal is displayed or now
89+
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
90+
91+
//show and hide handlers
92+
const showDeleteConfirm = () => setDeleteConfirmOpen(true);
93+
const hideDeleteConfirm = () => setDeleteConfirmOpen(false);
94+
95+
return (
96+
<Container className="my-3">
97+
<Form>
98+
<h4 className="ps-2 py-1 border-start border-4 border-primary">
99+
My Bookmarks
100+
</h4>
101+
<Container className="p-0 pt-4">
102+
{articles.map((article) => (
103+
<SavedArticleItem
104+
key={article.id}
105+
articleImg={article.image}
106+
articleDesc={article.description}
107+
articleTitle={article.title}
108+
toBeDeleted={isDeletedArticles[article.id]}
109+
deleteToggler={articleToggleHandler(article.id)}
110+
/>
111+
))}
112+
</Container>
113+
{/*Remove/Cancel will only show if there are any articles selected to be deleted*/}
114+
{Object.values(isDeletedArticles).some((isDeleted) => isDeleted) && (
115+
<Stack
116+
direction="horizontal"
117+
gap={3}
118+
className="mt-3 justify-content-end"
119+
>
120+
<div>
121+
<Button
122+
className="border-0 text-dark fw-medium"
123+
style={{ backgroundColor: "#24BEEF" }}
124+
onClick={showDeleteConfirm}
125+
>
126+
Remove
127+
</Button>
128+
</div>
129+
<div>
130+
<Button
131+
className="border-0 text-dark fw-medium"
132+
style={{ backgroundColor: "#B9B2B2" }}
133+
onClick={resetDeletionHandler}
134+
>
135+
Cancel
136+
</Button>
137+
</div>
138+
</Stack>
139+
)}
140+
<ConfirmDeleteModal
141+
isOpen={deleteConfirmOpen}
142+
handleClose={hideDeleteConfirm}
143+
submitHandler={submitHandler}
144+
/>
145+
</Form>
146+
</Container>
147+
);
148+
}

0 commit comments

Comments
 (0)