Skip to content

Commit 64bfe80

Browse files
committed
feat: notification page
1 parent b9c388d commit 64bfe80

File tree

8 files changed

+310
-73
lines changed

8 files changed

+310
-73
lines changed

app/(protected)/layout.tsx

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
11
import { NavUser } from '@/components/nav-user'
2-
import { IsLoggedIn } from '@/lib/firebase/firebase'
2+
import { getMe } from '@/lib/api/user'
3+
import { Verify } from '@/lib/firebase/firebase'
4+
import Link from 'next/link'
35

46
export default async function ProtectedLayout({
57
children,
68
}: Readonly<{ children: React.ReactNode }>) {
7-
const claim = await IsLoggedIn()
9+
// const claim = await IsLoggedIn()
10+
11+
const headers = await Verify({ from: '', forceRedirect: false })
12+
13+
const res = await getMe(
14+
{
15+
include_unread_notifications_count: true,
16+
},
17+
{
18+
headers,
19+
}
20+
)
21+
22+
if ('error' in res) {
23+
console.log('Error getting user', res.error)
24+
return <div>Something went wrong</div>
25+
}
26+
827
return (
928
<div className="container mx-auto px-4 my-4">
1029
<nav className="flex items-center justify-between">
11-
<div>LibrarEase</div>
12-
{claim && (
13-
<NavUser
14-
user={{
15-
id: claim.librarease.id,
16-
avatar: 'https://github.com/agmmtoo.png',
17-
email: claim.email ?? '',
18-
name: claim.librarease.role,
19-
}}
20-
/>
21-
)}
30+
<Link href="/" className="uppercase font-semibold tracking-wider">
31+
Librarease
32+
</Link>
33+
{res.data && <NavUser user={res.data} />}
2234
</nav>
2335

2436
{children}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import {
2+
Breadcrumb,
3+
BreadcrumbItem,
4+
BreadcrumbLink,
5+
BreadcrumbList,
6+
BreadcrumbPage,
7+
BreadcrumbSeparator,
8+
} from '@/components/ui/breadcrumb'
9+
import { Button } from '@/components/ui/button'
10+
import {
11+
Pagination,
12+
PaginationContent,
13+
PaginationItem,
14+
PaginationNext,
15+
PaginationPrevious,
16+
} from '@/components/ui/pagination'
17+
18+
import { Verify } from '@/lib/firebase/firebase'
19+
import { BellOff } from 'lucide-react'
20+
import Link from 'next/link'
21+
import type { Metadata } from 'next'
22+
import { SITE_NAME } from '@/lib/consts'
23+
import { getListNotifications } from '@/lib/api/notification'
24+
25+
export const metadata: Metadata = {
26+
title: `Notifications · ${SITE_NAME}`,
27+
}
28+
29+
export default async function Notifications({
30+
searchParams,
31+
}: {
32+
searchParams: Promise<{
33+
skip?: number
34+
limit?: number
35+
}>
36+
}) {
37+
const sp = await searchParams
38+
const skip = Number(sp?.skip ?? 0)
39+
const limit = Number(sp?.limit ?? 20)
40+
41+
const headers = await Verify({
42+
from: '/notifications',
43+
})
44+
45+
const res = await getListNotifications(
46+
{
47+
limit: limit,
48+
skip: skip,
49+
},
50+
{
51+
headers,
52+
}
53+
)
54+
55+
if ('error' in res) {
56+
return <div>{JSON.stringify(res.error)}</div>
57+
}
58+
59+
const prevSkip = skip - limit > 0 ? skip - limit : 0
60+
61+
const nextURL = `/notifications?skip=${skip + limit}&limit=${limit}`
62+
const prevURL = `/notifications?skip=${prevSkip}&limit=${limit}`
63+
64+
return (
65+
<div className="space-y-4">
66+
<nav className="backdrop-blur-sm sticky top-0 z-10">
67+
<h1 className="text-2xl font-semibold">Notifications</h1>
68+
<div className="flex justify-between items-center">
69+
<Breadcrumb>
70+
<BreadcrumbList>
71+
<BreadcrumbItem>
72+
<Link href="/" passHref legacyBehavior>
73+
<BreadcrumbLink>Home</BreadcrumbLink>
74+
</Link>
75+
</BreadcrumbItem>
76+
<BreadcrumbSeparator />
77+
78+
<BreadcrumbItem>
79+
<BreadcrumbPage>Notifications</BreadcrumbPage>
80+
</BreadcrumbItem>
81+
</BreadcrumbList>
82+
</Breadcrumb>
83+
<Button>
84+
<BellOff className="mr-2 size-4" />
85+
Mark All as Read
86+
</Button>
87+
</div>
88+
</nav>
89+
<ul className="space-y-2">
90+
{res.data.map((notification) => (
91+
<li key={notification.id} className="p-4 border rounded-md">
92+
<div className="flex items-center justify-between">
93+
<div>
94+
<h2 className="text-lg font-semibold">{notification.title}</h2>
95+
<p className="text-sm text-gray-500">{notification.message}</p>
96+
</div>
97+
<span className="text-xs text-gray-400">
98+
{new Date(notification.created_at).toLocaleDateString()}
99+
</span>
100+
</div>
101+
</li>
102+
))}
103+
</ul>
104+
105+
<Pagination>
106+
<PaginationContent>
107+
<PaginationItem>
108+
<PaginationPrevious href={prevURL} />
109+
</PaginationItem>
110+
<PaginationItem>
111+
<PaginationNext href={nextURL} />
112+
</PaginationItem>
113+
</PaginationContent>
114+
</Pagination>
115+
</div>
116+
)
117+
}

components/nav-user.tsx

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
'use client'
22

3-
import {
4-
BellIcon,
5-
CreditCardIcon,
6-
LogOutIcon,
7-
UserCircleIcon,
8-
} from 'lucide-react'
3+
import { BellIcon, LogOutIcon, UserCircleIcon } from 'lucide-react'
94

10-
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
5+
import { Avatar, AvatarFallback } from '@/components/ui/avatar'
116
import {
127
DropdownMenu,
138
DropdownMenuContent,
@@ -21,17 +16,17 @@ import { Button } from './ui/button'
2116
import { useEffect } from 'react'
2217
import { useToast } from './hooks/use-toast'
2318
import { Notification } from '@/lib/types/notification'
24-
import { streamNoti } from '@/lib/api/noti'
19+
import { streamNotification } from '@/lib/api/notification'
2520
import { logoutAction } from '@/lib/actions/logout'
21+
import { User } from '@/lib/types/user'
22+
import { Badge } from './ui/badge'
23+
import Link from 'next/link'
2624

2725
export function NavUser({
2826
user,
2927
}: {
30-
user: {
31-
id: string
32-
name: string
33-
email: string
34-
avatar: string
28+
user: User & {
29+
unread_notifications_count: number
3530
}
3631
}) {
3732
const { toast } = useToast()
@@ -52,7 +47,7 @@ export function NavUser({
5247
})
5348
}
5449

55-
const cleanup = streamNoti(user.id, {
50+
const cleanup = streamNotification(user.id, {
5651
onMessage: onMessage,
5752
onError: onError,
5853
onConnect: console.log,
@@ -62,11 +57,13 @@ export function NavUser({
6257

6358
return (
6459
<DropdownMenu>
65-
<DropdownMenuTrigger asChild>
60+
<DropdownMenuTrigger asChild className="cursor-pointer">
6661
<Button variant="ghost" className="relative h-8 w-8 rounded-full">
6762
<Avatar className="w-8 h-8">
68-
<AvatarImage src={user.avatar} alt={user.name} />
69-
<AvatarFallback className="rounded-lg">AO</AvatarFallback>
63+
{/* <AvatarImage src={user.avatar} alt={user.name} /> */}
64+
<AvatarFallback className="rounded-lg">
65+
{user.name.slice(0, 2)}
66+
</AvatarFallback>
7067
</Avatar>
7168
</Button>
7269
</DropdownMenuTrigger>
@@ -80,8 +77,9 @@ export function NavUser({
8077
<DropdownMenuLabel className="p-0 font-normal">
8178
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
8279
<Avatar className="h-8 w-8 rounded-lg">
83-
<AvatarImage src={user.avatar} alt={user.name} />
84-
<AvatarFallback className="rounded-lg">AO</AvatarFallback>
80+
<AvatarFallback className="rounded-lg">
81+
{user.name.slice(0, 2)}
82+
</AvatarFallback>
8583
</Avatar>
8684
<div className="grid flex-1 text-left text-sm leading-tight">
8785
<span className="truncate font-medium">{user.name}</span>
@@ -97,17 +95,20 @@ export function NavUser({
9795
<UserCircleIcon />
9896
Account
9997
</DropdownMenuItem>
100-
<DropdownMenuItem>
101-
<CreditCardIcon />
102-
Billing
103-
</DropdownMenuItem>
104-
<DropdownMenuItem>
105-
<BellIcon />
106-
Notifications
98+
<DropdownMenuItem asChild>
99+
<Link href="/notifications">
100+
<BellIcon />
101+
Notifications
102+
{user.unread_notifications_count > 0 && (
103+
<Badge className="" variant="outline">
104+
{user.unread_notifications_count}
105+
</Badge>
106+
)}
107+
</Link>
107108
</DropdownMenuItem>
108109
</DropdownMenuGroup>
109110
<DropdownMenuSeparator />
110-
<DropdownMenuItem onClick={logoutAction}>
111+
<DropdownMenuItem onClick={logoutAction} variant="destructive">
111112
<LogOutIcon />
112113
Log out
113114
</DropdownMenuItem>

lib/api/noti.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)