Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finishes the notification task #31

Merged
merged 1 commit into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 48 additions & 16 deletions src/components/navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import React, { useState, useEffect } from 'react';
import { NavLink, useNavigate } from 'react-router-dom';
import React, { useRef, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { DesktopNav, PopularCategory } from '../../containers/nav/NavbarComponents';
import WishNav from './wishNav/WishNav';
import CartNav from './cartNav/CartNav';
import { LuBell } from 'react-icons/lu';
import Notifications from './notifications/Notifications';
import { cn } from '../../utils';

const Navbar: React.FC = () => {
const [cartOpen, setCartOpen] = useState(false);
const [notificationOpen, setNotificationOpen] = useState<boolean>(false);
const navbarRef = useRef<HTMLDivElement>(null);
const [navbarHeight, setNavbarHeight] = useState<number>(20);
const [cartOpen, SetCartOpen] = useState(false);
const [wish, setWish] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const navigate = useNavigate();
Expand Down Expand Up @@ -34,7 +40,6 @@ const Navbar: React.FC = () => {
container?.classList.remove('-translate-x-full');
hideScrollbar();
});

overlay?.addEventListener('click', e => {
if (e.target !== e.currentTarget) {
return;
Expand All @@ -45,21 +50,34 @@ const Navbar: React.FC = () => {
});
}, []);

const handleSearch = (e: React.FormEvent) => {
useEffect(() => {
const updateNavbarHeight = () => {
setNavbarHeight(navbarRef.current?.offsetHeight as number);
};
updateNavbarHeight();
// setTimeout(updateNavbarHeight, 0);
window.addEventListener('resize', updateNavbarHeight);
return () => {
window.removeEventListener('resize', updateNavbarHeight);
};
}, []);

const handleSearch = (e: any) => {
e.preventDefault();
navigate(`/search?searchQuery=${searchQuery}`);
};

return (
<>
{(wish || cartOpen) && (
{(wish || cartOpen || notificationOpen) && (
<div
onClick={e => {
if (e.target !== e.currentTarget) {
return;
}
setWish(false);
setCartOpen(false);
SetCartOpen(false);
setNotificationOpen(false);
}}
className='absolute bg-[#00000000] top-0 w-full border h-full'
style={{ zIndex: 10 }}
Expand All @@ -70,7 +88,10 @@ const Navbar: React.FC = () => {
wish || cartOpen ? 'sticky' : ''
} z-10`}
>
<div className='flex justify-between gap-2 flex-wrap p-3 md:p-4 xl:px-10 2xl:w-[1440px] relative'>
<div
className='flex justify-between gap-2 flex-wrap p-3 md:p-4 xl:px-10 2xl:w-[1440px] relative'
ref={navbarRef}
>
<div className='flex items-center gap-3 order-1'>
<div
id='humbergurBtn'
Expand Down Expand Up @@ -131,11 +152,12 @@ const Navbar: React.FC = () => {
</div>
)}
</div>
<NavLink
to='shoppingcart'
className='rounded-full transition-all ease-in-out delay-100 hover:bg-grayColor active:bg-greenColor p-1 active:text-blackColor hover:text-blackColor relative'
{/* Favorite */}
<a
className='rounded-full transition-all ease-in-out delay-100 hover:bg-grayColor active:bg-greenColor p-1 active:text-blackColor hover:text-blackColor relative'
onClick={() => setNotificationOpen(!notificationOpen)}
>
<svg
{/* <svg
xmlns='http://www.w3.org/2000/svg'
fill='none'
viewBox='0 0 24 24'
Expand All @@ -148,11 +170,12 @@ const Navbar: React.FC = () => {
strokeLinejoin='round'
d='M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12Z'
/>
</svg>
</svg> */}
<LuBell strokeWidth={1} stroke='currentColor' className='size-6 md:size-8' />
<span className='absolute top-1 right-1 w-2 h-2 rounded-full bg-redColor'></span>
</NavLink>
</a>
<div
onClick={() => setCartOpen(state => !state)}
onClick={() => SetCartOpen(state => !state)}
className='rounded-full transition-all ease-in-out delay-100 hover:bg-grayColor active:bg-greenColor active:text-blackColor hover:text-blackColor p-1 select-none'
>
<div className='relative'>
Expand All @@ -178,7 +201,7 @@ const Navbar: React.FC = () => {
<div
onClick={e => {
if (e.target !== e.currentTarget) {
setCartOpen(false);
SetCartOpen(false);
return;
}
}}
Expand Down Expand Up @@ -253,6 +276,15 @@ const Navbar: React.FC = () => {
</div>
</div>
</div>
<div
className={cn(
'max-w-[500px] w-11/12 absolute right-2 z-[100] transition-all',
!notificationOpen ? 'h-0 scale-0 origin-top' : 'h-fit scale-100 origin-top'
)}
style={{ top: `${navbarHeight}px` }}
>
<Notifications />
</div>
</div>
</>
);
Expand Down
122 changes: 122 additions & 0 deletions src/components/navbar/notifications/NotificationComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { BiDotsVertical } from 'react-icons/bi';
import { cn } from '../../../utils';
import { useEffect, useRef, useState } from 'react';
import {
useMarkNotificationAsReadMutation,
useDeleteSingleNotificationsMutation,
} from '../../../services/notificationsAPI';
import { FaSpinner } from 'react-icons/fa6';

interface NotificationProps {
id: string;
message: string;
time: string;
date: string;
isRead: boolean;
onDelete: (id: string) => void;
onReadChange: (isRead: boolean) => void;
}
const NotificationComponent = ({
message,
time,
date,
isRead: initialIsRead,
id,
onDelete,
onReadChange,
}: NotificationProps) => {
const [isMenuClicked, setIsMenuClicked] = useState(false);
const [isRead, setIsRead] = useState(initialIsRead);
const menubarRef = useRef<HTMLDivElement>(null);
const [markNotificationAsRead, { isLoading }] = useMarkNotificationAsReadMutation();
const [deleteNotification, { isLoading: isDeleting }] = useDeleteSingleNotificationsMutation();
const markAsRead = async () => {
const { data } = await markNotificationAsRead({ isRead: !isRead, id });
setIsRead(data.data.isRead);
onReadChange(data.data.isRead);
};
const notificationDelete = () => {
deleteNotification(id);
onDelete(id);
};
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (menubarRef.current && !menubarRef.current.contains(event.target as Node)) {
setIsMenuClicked(false);
}
};

if (isMenuClicked) {
document.addEventListener('mousedown', handleClickOutside);
} else {
document.removeEventListener('mousedown', handleClickOutside);
}

return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [isMenuClicked]);

return (
<div
className={cn(
'w-full gap-2 flex items-center relative p-2',
isRead
? 'bg-blackColor md:bg-grayColor md:text-blackColor text-whiteColor text-opacity-50 md:text-opacity-40 '
: 'bg-blackColor md:bg-grayColor md:text-blackColor text-whiteColor'
)}
key={id}
>
<span className='w-full'>
<span className='flex justify-between'>
<p className='text-sm'>{message}</p>
<p
className={cn('text-xs font-medium italic text-skyBlueText hidden', isRead ? 'hidden' : 'hidden md:block')}
>
Unread
</p>
<div
className={cn('w-3 h-3 rounded-full bg-skyBlueText md:hidden', isRead ? 'hidden' : 'block md:hidden')}
></div>
</span>
<span className='w-full text-xs flex justify-between items-center italic'>
<p className='italic font-light'>{date} </p>
<p className='italic font-light'>{time}</p>
</span>
</span>
<button
onClick={e => {
e.preventDefault();
setIsMenuClicked(!isMenuClicked);
}}
>
<BiDotsVertical className=' aspect-square max-w-8 w-20 ' />
</button>
{isMenuClicked && (
<div
ref={menubarRef}
className={cn(
'absolute top-10 right-0 bg-white shadow-customShadow border text-sm text-greenColor font-medium flex flex-col gap-2 items-start rounded-xl transition-all z-20 bg-whiteColor overflow-hidden',
isMenuClicked ? 'scale-1 origin-top' : 'h-0 scale-0 origin-top'
)}
>
<button
onClick={notificationDelete}
className=' hover:bg-greenColor hover:text-whiteColor bg-whiteColor text-greenColor p-2 w-full text-left'
>
<FaSpinner className={cn('w-3 h-3 ', isDeleting ? 'block animate-spin ' : 'hidden')} /> Delete
</button>
<button
onClick={markAsRead}
className=' hover:bg-greenColor hover:text-whiteColor bg-whiteColor text-greenColor p-2 w-full text-left'
>
<FaSpinner className={cn('w-3 h-3 ', isLoading ? 'block animate-spin ' : 'hidden')} />{' '}
{isRead ? 'Mark as Unread' : 'Mark as Read'}
</button>
</div>
)}
</div>
);
};

export default NotificationComponent;
Loading
Loading