Skip to content

Commit

Permalink
Notification progress
Browse files Browse the repository at this point in the history
  • Loading branch information
andreu-vall committed Dec 15, 2023
1 parent 87011a1 commit d99cc0d
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 123 deletions.
4 changes: 3 additions & 1 deletion src/components/KasulaNavbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ExclamationTriangleFill, PlusLg } from "react-bootstrap-icons";

//Components
import PostRecipe from "./PostRecipe";
import NotificationBell from "./NotificationBell";

//Assets
import logo from "../assets/logo.png";
Expand Down Expand Up @@ -115,7 +116,8 @@ function KasulaNavbar() {
<Nav className="me-auto fs-5">
<Nav.Link href="/">Feed</Nav.Link>
<Nav.Link href="/collections">Collections</Nav.Link>
<Nav.Link href="/notifications">Notifications</Nav.Link>
<NotificationBell />
{/* <Nav.Link href="/notifications">Notifications</Nav.Link> */}
</Nav>
{isLogged() && (
<>
Expand Down
101 changes: 101 additions & 0 deletions src/components/NotificationBell.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//He de fer un fetch a les notificacions de l'usuari i mostrar-les en NotificationsCard cadascuna
//React
import React, { useState, useEffect } from 'react'
import { Container, Row, Col } from "react-bootstrap"
import NotificationCard from "./NotificationCard"
import Dropdown from 'react-bootstrap/Dropdown';
import { BellFill } from 'react-bootstrap-icons';
import styled from 'styled-components';
import "../css/common.css";


const CustomToggle = styled(Dropdown.Toggle)`
&::after {
display: none;
}
`;

//Call the method every x seconds (will be used for checking new notifications on the backend)
function Timer({ method, seconds=30 }) {
const [count, setCount] = useState(0);
useEffect(() => {
const timerId = setInterval(() => {
setCount(count + 1);
console.log("Timer called");
method();
}, seconds*1000);
return () => clearInterval(timerId); // cleanup on unmount
}, []);
return null; // Timer doesn't render anything
}


export default function NotificationBell() {

const [notifications, setNotifications] = useState([])

const [isFocused, setIsFocused] = useState(false);

const currentUserUsername = localStorage.getItem('currentUser')

const handleStatusChange = (id, newStatus) => {
setNotifications(notifications.map(notification =>
notification.id === id ? { ...notification, status: newStatus } : notification
));
};

const getUnreadNotifications = () => {
return notifications.filter(notification => notification.status === "unread").length;
}

const getRecipes = () => {
console.log("Fetching notifications...");
fetch(process.env.REACT_APP_API_URL + `/notification/` + currentUserUsername)
.then((response) => response.json())
.then((data) => {
setNotifications(data)
})
.catch((error) => {
console.error("Error al obtenir notificacions:", error)
});
};

useEffect(() => {
getRecipes()
}, [])

return (
<>

<Timer method={getRecipes} />

<Dropdown>
<CustomToggle variant="success" id="dropdown-basic" style={{backgroundColor: "transparent", border: "none"}}>
<BellFill style={{ color: 'black', marginTop: '10px' }}/>
<span className="badge rounded-pill badge-notification bg-danger">{getUnreadNotifications()}</span>
</CustomToggle>

<Dropdown.Menu style={{ maxHeight: '50vh', overflowY: 'auto', overflowX: 'hidden', backgroundColor: '#ffe7df' }}>
{notifications.map(notification => (
<Dropdown.Item
className="my-dropdown-item"
onClick={(e) => e.stopPropagation()}
href={notification.link}
style={isFocused ? { backgroundColor: 'transparent' } : {}}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
>
<NotificationCard
key={notification.id}
notification={notification}
username={currentUserUsername}
onStatusChange={handleStatusChange}
/>
</Dropdown.Item>
))}
<Dropdown.Item href={"/notifications"}>View all</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</>
);
}
28 changes: 24 additions & 4 deletions src/components/NotificationCard.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
import { Card } from "react-bootstrap";
import moment from 'moment';
import { Link } from 'react-router-dom'
import { Check } from 'react-bootstrap-icons';
import { Check, ArrowRight } from 'react-bootstrap-icons';

export default function NotificationCard({ notification, username, onStatusChange }) {

const updateStatus = (newStatus) => {
fetch(`${process.env.REACT_APP_API_URL}/notification/${username}/${notification.id}?mystatus=${newStatus}`, {
method: 'PUT'
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
onStatusChange(notification.id, newStatus)
})
.catch((error) => {
console.error('Error:', error);
});
};

export default function NotificationCard({ notification }) {
return (
<Card className="mb-3" key={notification.id} style={{ maxWidth: '540px' }}>
<Card className="mb-3" key={notification.id} style={
{ maxWidth: '540px' , backgroundColor: notification.status==="read" ? 'white' : 'lightblue' }}
>
<Card.Body>
<div className="row no-gutters">
<div className="col-md-4">
Expand All @@ -19,7 +36,10 @@ export default function NotificationCard({ notification }) {
<Card.Text>
<small className="text-muted">{moment.utc(notification.date).fromNow()}</small>
</Card.Text>
<button onClick={() => alert("Hello")}><Check /></button>
{notification.status==="unread"
? <button title="Mark as read" onClick={() => updateStatus('read')}><Check /></button>
: <button title="Mark as unread" onClick={() => updateStatus('unread')}><ArrowRight /></button>
}
</div>
</div>
</Card.Body>
Expand Down
148 changes: 31 additions & 117 deletions src/components/Notifications.jsx
Original file line number Diff line number Diff line change
@@ -1,161 +1,75 @@
//He de fer un fetch a les notificacions de l'usuari i mostrar-les en NotificationsCard cadascuna
//React
import { CSSTransition } from "react-transition-group"
import React, { useState, useEffect } from 'react'
import { Link } from "react-router-dom"
import { Container, Row, Col } from "react-bootstrap"
import NotificationCard from "./NotificationCard"
import Dropdown from 'react-bootstrap/Dropdown';
import { BellFill } from 'react-bootstrap-icons';
import styled from 'styled-components';


const CustomToggle = styled(Dropdown.Toggle)`
&::after {
display: none;
}
`;
//Call the method every x seconds (will be used for checking new notifications on the backend)
function Timer({ method, seconds=30 }) {
const [count, setCount] = useState(0);
useEffect(() => {
const timerId = setInterval(() => {
setCount(count + 1);
console.log("Timer called");
method();
}, seconds*1000);
return () => clearInterval(timerId); // cleanup on unmount
}, []);
return null; // Timer doesn't render anything
}


export default function Notifications() {

console.log("Notifications constructor call start")

const [notifications, setNotifications] = useState([])

const currentUserUsername = localStorage.getItem('currentUser')
console.log("Current user: " + currentUserUsername)

const handleStatusChange = (id, newStatus) => {
setNotifications(notifications.map(notification =>
notification.id === id ? { ...notification, status: newStatus } : notification
));
};

// const getUnreadNotifications = () => {
// return notifications.filter(notification => notification.status === "unread").length;
// }

const getRecipes = () => {
console.log("Fetching notifications...");
fetch(process.env.REACT_APP_API_URL + `/notification/` + currentUserUsername)
.then((response) => response.json())
.then((data) => {
console.log(data)
setNotifications(data)
//setLoading(false);
})
.catch((error) => {
console.error("Error al obtenir notificacions:", error)
//setLoading(false)
});
};

useEffect(() => {
console.log("useEffect call")
getRecipes()
}, [])

/*useEffect(() => {
setLoading(true);
if (!isLogged()) {
navigate("/login");
setLoading(false);
} else {
getRecipes();
}
}, [id, name]);*/

console.log("Notifications constructor call end");

const onClick = () => {
alert("notification added");
}

return (
<>
<h1>Notifications</h1>

<Dropdown>
<CustomToggle variant="success" id="dropdown-basic" >
<BellFill />
<span className="badge rounded-pill badge-notification bg-danger">{notifications.length}</span>
</CustomToggle>

<Dropdown.Menu>
{notifications.map(notification => (
<Dropdown.Item
href={"#/"+notification.link}>
<NotificationCard notification={notification} />
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>

<button onClick={onClick} className="add-notification-button">
Add Notification
</button>
<Timer method={getRecipes} />

<Container>
{notifications.map(notification => (
<Row key={notification.id}>
<Col xs={12}>
<NotificationCard notification={notification} />
<NotificationCard
key={notification.id}
notification={notification}
username={currentUserUsername}
onStatusChange={handleStatusChange}
/>
</Col>
</Row>
))}
</Container>
</>
);
}

// <Container className="pb-5 pt-3">
// <Row>
// {notifications && notifications.length > 0 ? (
// notifications.map((notification) => (
// <Col sm={12} md={6} xl={4}>
// <CSSTransition
// in={true}
// timeout={500}
// classNames="slideUp"
// appear
// >
// <div className="position-relative transition-03s">
// <Link
// key={notification._id}
// to={'/'}//{`/RecipeDetail/${recipe._id}`}
// className="text-decoration-none"
// >
// <NotificationCard notification={notification} />
// </Link>
// {/* {canDelete && (
// <span
// className="fs-3 colorless-span-button position-absolute top-0 end-0 mx-2"
// role="button"
// onClick={() => {
// fetch(
// process.env.REACT_APP_API_URL +
// `/collection/${id}/remove_recipe/${recipe._id}`,
// {
// method: "PUT",
// headers: {
// Authorization: `Bearer ${token}`,
// },
// }
// )
// .then((response) => response.json())
// .then((data) => {
// console.log(data);
// //onDeleteRecipe();
// })
// .catch((error) =>
// console.error("Error al obtener recetas:", error)
// );
// }}
// >
// <X className="rounded-circle highlighter" />
// </span>
// )} */}
// </div>
// </CSSTransition>
// </Col>
// ))
// ) : (
// <div className="alert alert-warning" role="alert">
// There are currently no recipes
// </div>
// )}
// </Row>
// </Container>
// );
// }
}
6 changes: 5 additions & 1 deletion src/css/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,8 @@
.user-nav-image {
border-top-right-radius: 25px;
border-bottom-right-radius: 25px;
}
}

.my-dropdown-item:hover {
background-color: transparent !important;
}

0 comments on commit d99cc0d

Please sign in to comment.