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

Add notification center #268

Merged
merged 4 commits into from
Mar 13, 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
62 changes: 62 additions & 0 deletions frontend/components/group/Invitation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Trans } from "@lingui/macro";
import clsx from "clsx";
import Link from "next/link";
import { Check, X } from "react-feather";

import { Button } from "@/components/input/Button";
import { Invitation as InvitationType } from "@/types/Invitation";
import { declineGroupInvitation, sendGroupRequest } from "@/util/api";

import { Text } from "../Text";

interface InvitationProps {
/**
* Invitation
*/
invitation: InvitationType;
/**
* Additional classes
*/
className?: string;
TomRomeo marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Component for displaying a group invitation in the notification center
*/
export const Invitation = ({ invitation, className }: InvitationProps) => {
return (
<div className={clsx("flex flex-row space-x-3", className)}>
<div className="h-8 w-8 flex-none rounded-full bg-kiokuLightBlue" />
<div className="w-full">
<Text textSize="5xs" className="font-semibold text-black">
<Trans>Group Invitation</Trans>
</Text>
<Text textSize="5xs" className="text-gray-500">
<Trans>
You have been invited to join{" "}
<Link
href={`/group/${invitation.groupID}`}
className="underline hover:text-black"
>
{invitation.groupName}
</Link>
</Trans>
</Text>
</div>
<div className="flex flex-row space-x-1">
<Button
buttonSize="px-3"
buttonStyle="tertiary"
buttonIcon={<X strokeWidth={3}></X>}
onClick={() => declineGroupInvitation(invitation.groupID)}
/>
<Button
buttonSize="px-3 py-1"
buttonStyle="secondary"
buttonIcon={<Check strokeWidth={3}></Check>}
onClick={() => sendGroupRequest(invitation.groupID)}
/>
</div>
</div>
);
};
7 changes: 5 additions & 2 deletions frontend/components/input/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const getStyle = {
secondary:
"bg-black font-medium text-white hover:scale-[1.02] hover:bg-neutral-900",
tertiary:
"bg-transparent font-medium text-kiokuDarkBlue hover:scale-105 hover:bg-gray-100",
"bg-transparent font-medium text-black hover:scale-105 hover:bg-gray-100",
cancel: "bg-transparent font-normal text-gray-400 hover:bg-gray-100",
error: "bg-kiokuRed font-medium text-white hover:scale-105",
warning: "bg-kiokuYellow font-medium text-white hover:scale-105",
Expand Down Expand Up @@ -78,12 +78,15 @@ export const Button = ({
</>
);
const classNames = [
"flex items-center space-x-1 rounded-md outline-none transition",
"flex items-center rounded-md outline-none transition",
className,
];
if (buttonStyle) {
classNames.push(getStyle[buttonStyle]);
}
if (buttonIcon && children) {
classNames.push("space-x-1");
}
classNames.push(buttonSize);

return href ? (
Expand Down
68 changes: 68 additions & 0 deletions frontend/components/modal/NotificationCenter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Trans } from "@lingui/macro";
import { useState } from "react";
import { Bell, Info } from "react-feather";

import { Invitation } from "@/components/group/Invitation";
import { Modal, ModalProps } from "@/components/modal/modal";
import { useInvitations } from "@/util/swr";

/**
* Component for displaying an icon that opens the notification center
*/
export const NotificationCenter = () => {
const { invitations } = useInvitations();

const [showNotificationCenter, setShowNotificationCenter] =
useState<boolean>(false);

return (
<>
<NotificationCenterModal
visible={showNotificationCenter}
setVisible={setShowNotificationCenter}
/>
<div className="relative">
<Bell
className="cursor-pointer"
onClick={() => {
setShowNotificationCenter(true);
}}
/>
{invitations && (
<div className="absolute right-[-0.1rem] top-[-0.15rem] h-3 w-3 flex-none rounded-full bg-kiokuRed">
<div className="absolute h-full w-full animate-[ping_0.8s_ease-out_3] rounded-full bg-kiokuRed" />
</div>
)}
</div>
</>
);
};

/**
* Modal for creating decks
*/
export const NotificationCenterModal = ({
className = "",
setVisible,
...props
}: ModalProps) => {
const { invitations } = useInvitations();

return (
<Modal header="Notification Center" setVisible={setVisible} {...props}>
{invitations ? (
invitations.map((invitation) => (
<Invitation
key={invitation.groupName}
invitation={invitation}
/>
))
) : (
<div className="flex items-center justify-center space-x-3 rounded-md border border-dashed border-gray-500 p-10 text-gray-800">
<Info />
<Trans>You have no pending messages</Trans>
</div>
)}
</Modal>
);
};
2 changes: 1 addition & 1 deletion frontend/components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const Modal = ({
<div className="flex w-full justify-between">
<Text
textSize="xs"
className="font-bold"
className="font-bold text-black"
>
{header}
</Text>
Expand Down
30 changes: 18 additions & 12 deletions frontend/components/navigation/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { ArrowRight, LogOut } from "react-feather";

import { Logo } from "@/components/graphics/Logo";
import { Button } from "@/components/input/Button";
import { NotificationCenter } from "@/components/modal/NotificationCenter";
import { postRequest } from "@/util/api";
import { logoutRoute } from "@/util/endpoints";
import { authedFetch } from "@/util/reauth";

interface NavbarProps {
/**
Expand All @@ -21,34 +22,39 @@ interface NavbarProps {
*/
export const Navbar = ({ className = "" }: NavbarProps) => {
const router = useRouter();

const [loggedIn, setLoggedIn] = useState<boolean>();

useEffect(() => {
if (router.pathname == "/login") {
setLoggedIn(undefined);
} else {
setLoggedIn(hasCookie("access_token"));
}
}, [router.pathname]);

if (loggedIn == undefined) {
return <></>;
}

return (
<nav
className={`flex items-center justify-between p-5 md:p-10 ${className}`}
>
<Logo href={loggedIn ? "/" : "/home"} />
{loggedIn == true && (
<LogOut
className="cursor-pointer text-kiokuDarkBlue"
onClick={async () => {
const response = await authedFetch(logoutRoute, {
method: "POST",
});
if (response?.ok) {
router.replace("/home");
}
}}
/>
<div className="flex flex-row space-x-8 text-kiokuDarkBlue">
<NotificationCenter />
<LogOut
className="cursor-pointer"
onClick={async () => {
const response = await postRequest(logoutRoute);
if (response?.ok) {
router.replace("/home");
}
}}
/>
</div>
)}
{loggedIn == false && (
<Button
Expand Down
32 changes: 0 additions & 32 deletions frontend/components/navigation/Tabs/InvitationsTabs.tsx

This file was deleted.

13 changes: 0 additions & 13 deletions frontend/components/navigation/Tabs/TabHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ interface TabHeaderProps {
* Style
*/
icon: IconName;
/**
* Text that should be displayed as notification
*/
notificationBadgeContent?: string;
/**
* Additional classes
*/
Expand All @@ -29,7 +25,6 @@ interface TabHeaderProps {
export const TabHeader = ({
name,
icon,
notificationBadgeContent = "",
className = "",
...props
}: TabHeaderProps) => {
Expand All @@ -41,14 +36,6 @@ export const TabHeader = ({
<Icon icon={icon} />

<div>{name}</div>
{notificationBadgeContent && (
<div className="relative flex h-full text-sm text-eggshell">
<div className="absolute inline-flex h-full w-full animate-[ping_1s_ease-out_3] rounded-full bg-kiokuRed opacity-75" />
<div className="relative flex h-full w-full justify-center rounded-full bg-kiokuRed px-2">
{notificationBadgeContent}
</div>
</div>
)}
</div>
);
};
Loading
Loading