From d99cc0dfd359b4763e482c787db51867c4c01df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreu=20Vall=20Hern=C3=A0ndez?= Date: Fri, 15 Dec 2023 02:36:46 +0100 Subject: [PATCH] Notification progress --- src/components/KasulaNavbar.jsx | 4 +- src/components/NotificationBell.jsx | 101 +++++++++++++++++++ src/components/NotificationCard.jsx | 28 +++++- src/components/Notifications.jsx | 148 ++++++---------------------- src/css/common.css | 6 +- 5 files changed, 164 insertions(+), 123 deletions(-) create mode 100644 src/components/NotificationBell.jsx diff --git a/src/components/KasulaNavbar.jsx b/src/components/KasulaNavbar.jsx index 57f7878..d15e2c8 100644 --- a/src/components/KasulaNavbar.jsx +++ b/src/components/KasulaNavbar.jsx @@ -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"; @@ -115,7 +116,8 @@ function KasulaNavbar() { {isLogged() && ( <> diff --git a/src/components/NotificationBell.jsx b/src/components/NotificationBell.jsx new file mode 100644 index 0000000..b9ec8fc --- /dev/null +++ b/src/components/NotificationBell.jsx @@ -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 ( + <> + + + + + + + {getUnreadNotifications()} + + + + {notifications.map(notification => ( + e.stopPropagation()} + href={notification.link} + style={isFocused ? { backgroundColor: 'transparent' } : {}} + onFocus={() => setIsFocused(true)} + onBlur={() => setIsFocused(false)} + > + + + ))} + View all + + + +); +} diff --git a/src/components/NotificationCard.jsx b/src/components/NotificationCard.jsx index 20b663b..a969555 100644 --- a/src/components/NotificationCard.jsx +++ b/src/components/NotificationCard.jsx @@ -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 ( - +
@@ -19,7 +36,10 @@ export default function NotificationCard({ notification }) { {moment.utc(notification.date).fromNow()} - + {notification.status==="unread" + ? + : + }
diff --git a/src/components/Notifications.jsx b/src/components/Notifications.jsx index 0367b4b..5f4336d 100644 --- a/src/components/Notifications.jsx +++ b/src/components/Notifications.jsx @@ -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 ( <> -

Notifications

- - - - {notifications.length} - - - - {notifications.map(notification => ( - - - - ))} - - - - + {notifications.map(notification => ( - + ))} ); - } - - // - // - // {notifications && notifications.length > 0 ? ( - // notifications.map((notification) => ( - // - // - //
- // - // - // - // {/* {canDelete && ( - // { - // 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) - // ); - // }} - // > - // - // - // )} */} - //
- //
- // - // )) - // ) : ( - //
- // There are currently no recipes - //
- // )} - //
- //
-// ); -// } +} diff --git a/src/css/common.css b/src/css/common.css index 9f8e993..dd52aec 100644 --- a/src/css/common.css +++ b/src/css/common.css @@ -119,4 +119,8 @@ .user-nav-image { border-top-right-radius: 25px; border-bottom-right-radius: 25px; -} \ No newline at end of file +} + +.my-dropdown-item:hover { + background-color: transparent !important; + } \ No newline at end of file