Skip to content

Commit

Permalink
notification model and utils added
Browse files Browse the repository at this point in the history
  • Loading branch information
sinanptm committed Sep 22, 2024
1 parent 006c5cd commit a9ea8b5
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 80 deletions.
44 changes: 44 additions & 0 deletions client/components/button/PatientNotificationButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use client";

import { Bell } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { ButtonV2 } from "@/components/common/ButtonV2";
import NotificationModal from "@/components/models/NotificationModel";
import { useState } from "react";
import { useGetAllPatientNotifications } from "@/lib/hooks/notification/useSlotPatient";
import { INotification } from "@/types";

const NotificationButton = () => {
const [isNotificationModalOpen, setIsNotificationModalOpen] = useState(false);
const { data: notifications, isLoading } = useGetAllPatientNotifications();

const notificationCount = notifications?.length || 0;

const handleNotificationClick = () => {
setIsNotificationModalOpen(true);
};

return (
<>
<ButtonV2 variant="ghost" size="icon" className="relative" onClick={handleNotificationClick}>
<Bell className="h-5 w-5" />
{notificationCount > 0 && (
<Badge
variant="destructive"
className="absolute -right-1 -top-1 h-5 w-5 rounded-full p-0 text-xs flex items-center justify-center"
>
{notificationCount}
</Badge>
)}
<span className="sr-only">View notifications</span>
</ButtonV2>
<NotificationModal
open={isNotificationModalOpen}
setOpen={setIsNotificationModalOpen}
notifications={notifications as INotification[] || []}
/>
</>
);
};

export default NotificationButton;
53 changes: 5 additions & 48 deletions client/components/layout/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// NavBar.tsx
"use client";

import Link from "next/link";
import { Sheet, SheetTrigger, SheetContent, SheetTitle, SheetDescription } from "@/components/ui/sheet";
import { Button } from "@/components/ui/button";
import { Package2, Bell } from "lucide-react";
import { Package2 } from "lucide-react";
import {
DropdownMenu,
DropdownMenuTrigger,
Expand All @@ -21,8 +22,7 @@ import { toast } from "../ui/use-toast";
import { useState } from "react";
import LogoutModel from "../models/LogoutModel";
import { ButtonV2 } from "../common/ButtonV2";
import { Badge } from "@/components/ui/badge";
import NotificationModal from "@/components/models/NotificationModel";
import NotificationButton from "../button/PatientNotificationButton";

export const NavBar = () => {
const path = usePathname();
Expand All @@ -31,29 +31,6 @@ export const NavBar = () => {
const { patientToken, setCredentials, logout } = useAuth();
const [isLogoutModelOpen, setLogoutModelOpen] = useState(false);
const [isSheetOpen, setIsSheetOpen] = useState(false);
const [isNotificationModalOpen, setIsNotificationModalOpen] = useState(false);
const [notificationCount, setNotificationCount] = useState(3);

const notifications = [
{
id: "1",
title: "New message",
description: "You have a new message from Dr. Smith",
icon: "/assets/icons/email.svg",
},
{
id: "2",
title: "Appointment reminder",
description: "Your appointment is tomorrow at 2 PM",
icon: "/assets/icons/calendar.svg",
},
{
id: "3",
title: "Lab results ready",
description: "Your recent lab results are now available",
icon: "/assets/icons/utils/droplet.svg",
},
];

if (path.includes("signup") || path.includes("admin") || path.includes("signin") || path.includes("doctor")) {
return null;
Expand Down Expand Up @@ -99,10 +76,6 @@ export const NavBar = () => {
setIsSheetOpen(false);
};

const handleNotificationClick = () => {
setIsNotificationModalOpen(true);
};

return (
<header className="sticky top-0 flex h-16 items-center justify-between gap-4 border-b bg-dark-300 bg-opacity-55 px-4 md:px-6 z-50">
<nav className="hidden flex-col gap-6 text-lg font-medium md:flex md:flex-row md:items-center md:gap-5 md:text-sm lg:gap-6">
Expand Down Expand Up @@ -159,18 +132,7 @@ export const NavBar = () => {
</SheetContent>
</Sheet>
<div className="flex items-center gap-4">
<ButtonV2 variant="ghost" size="icon" className="relative" onClick={handleNotificationClick}>
<Bell className="h-5 w-5" />
{notificationCount > 0 && (
<Badge
variant="destructive"
className="absolute -right-1 -top-1 h-5 w-5 rounded-full p-0 text-xs flex items-center justify-center"
>
{notificationCount}
</Badge>
)}
<span className="sr-only">View notifications</span>
</ButtonV2>
<NotificationButton />
<DropdownMenu>
<DropdownMenuTrigger asChild>
<ButtonV2 variant="ghost" size="icon" className="rounded-full">
Expand Down Expand Up @@ -209,14 +171,9 @@ export const NavBar = () => {
setOpen={setLogoutModelOpen}
handleLogoutConfirm={handleLogoutConfirm}
/>
<NotificationModal
open={isNotificationModalOpen}
setOpen={setIsNotificationModalOpen}
notifications={notifications}
/>
</div>
</header>
);
};

export default NavBar;
export default NavBar;
58 changes: 28 additions & 30 deletions client/components/models/NotificationModel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,26 @@ import {
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";

type Notification = {
id: string;
title: string;
description: string;
icon: string;
};
import { INotification, NotificationTypes } from "@/types";
import getNotificationDetails from "@/lib/utils/getNotificationDetails";

type Props = {
open: boolean;
setOpen: Dispatch<SetStateAction<boolean>>;
notifications: Notification[];
notifications: INotification[];
};

const NotificationModal = ({ open, setOpen, notifications }: Props)=> {
const NotificationModal = ({ open, setOpen, notifications }: Props) => {
const closeModal = () => {
setOpen(false);
};

return (
<AlertDialog open={open} onOpenChange={setOpen}>
<AlertDialogContent className="max-w-3xl">
<AlertDialogContent className="max-w-3xl bg-dark-200">
<AlertDialogHeader>
<AlertDialogTitle className="flex items-center justify-between">
<h2 className="text-2xl font-semibold">Notifications</h2>
<AlertDialogTitle className="flex items-center justify-between text-2xl font-semibold">
Notifications
<Button variant="ghost" size="icon" onClick={closeModal}>
<Image
src="/assets/icons/close.svg"
Expand All @@ -48,23 +43,26 @@ const NotificationModal = ({ open, setOpen, notifications }: Props)=> {
</AlertDialogHeader>
<AlertDialogDescription></AlertDialogDescription>
<div className="space-y-4">
{notifications.map((notification) => (
<Card key={notification.id}>
<CardContent className="flex items-center space-x-4 p-4">
<Image
src={notification.icon}
width={24}
height={24}
alt={notification.title}
className="h-6 w-6"
/>
<div>
<h3 className="font-semibold">{notification.title}</h3>
<p className="text-sm text-muted-foreground">{notification.description}</p>
</div>
</CardContent>
</Card>
))}
{notifications.map((notification) => {
const { icon, title } = getNotificationDetails(notification.type!);
return (
<Card key={notification._id}>
<CardContent className="flex items-center space-x-4 p-4">
<Image
src={icon}
width={24}
height={24}
alt={title}
className="h-6 w-6"
/>
<div>
<h3 className="font-semibold">{title}</h3>
<p className="text-sm text-muted-foreground">{notification.message}</p>
</div>
</CardContent>
</Card>
);
})}
</div>
<AlertDialogFooter>
<Button onClick={closeModal}>Close</Button>
Expand All @@ -74,4 +72,4 @@ const NotificationModal = ({ open, setOpen, notifications }: Props)=> {
);
}

export default NotificationModal
export default NotificationModal;
26 changes: 26 additions & 0 deletions client/lib/utils/getNotificationDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NotificationTypes } from "@/types";

export default function getNotificationDetails(type: NotificationTypes) {
switch (type) {
case NotificationTypes.APPOINTMENT_CANCELED:
return {
icon: '/assets/icons/utils/calendar-cancel.svg',
title: 'Appointment Canceled'
};
case NotificationTypes.APPOINTMENT_CONFIRMED:
return {
icon: '/assets/icons/utils/verified.svg',
title: 'Appointment Confirmed'
};
case NotificationTypes.APPOINTMENT_REMINDER:
return {
icon: '/assets/icons/utils/alarm-plus.svg',
title: 'Appointment Reminder'
};
default:
return {
icon: '/assets/icons/notification.svg',
title: 'Notification'
};
}
}
1 change: 1 addition & 0 deletions client/public/assets/icons/utils/alarm-plus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions client/public/assets/icons/utils/calendar-cancel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion client/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export interface INotification {
readonly _id?: string;
readonly patientId?: string;
readonly doctorId?: string;
readonly type?: string;
readonly type?: NotificationTypes;
readonly message?: string;
readonly createdAt?: Date;
readonly updatedAt?: Date;
Expand Down
2 changes: 1 addition & 1 deletion server/src/domain/entities/INotification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default interface INotification {
readonly _id?: string;
readonly patientId?: string;
readonly doctorId?: string;
readonly type?: string;
readonly type?: NotificationTypes;
readonly message?: string;
readonly createdAt?: Date;
readonly updatedAt?: Date;
Expand Down

0 comments on commit a9ea8b5

Please sign in to comment.