Skip to content

Commit bc1ad47

Browse files
committed
chore: display notifications
1 parent 33ebef2 commit bc1ad47

File tree

6 files changed

+112
-7
lines changed

6 files changed

+112
-7
lines changed

apps/web/src/app/context/AuthContext.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import React, { createContext, useContext, useEffect, useState } from "react"
55
import { fetcher } from "@/app/lib/fetcher"
66
// Import the fetch helper
77
import { BACKEND_URL } from "@/utils/constants"
8+
import { Notification } from "@/types/users"
89

910
export type User = {
1011
id: string
1112
handle: string
1213
displayName: string
1314
bio: string
15+
notifications: Notification[]
1416
avatarUrl: string
1517
bannerUrl: string
1618
dateRegistered: string
@@ -38,7 +40,7 @@ type AuthContextType = {
3840
const AuthContext = createContext<AuthContextType>({
3941
user: null,
4042
isLoading: true,
41-
logout: () => {}
43+
logout: () => null
4244
})
4345

4446
export const useAuth = () => useContext(AuthContext)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { USER_DEFAULT_AVATAR } from "@/utils/constants";
2+
import Image from "next/image";
3+
import { LuCheck } from "react-icons/lu";
4+
5+
6+
export default function Notification({ content, createdAt, read, senderAvatar, url, userAvatar }: {
7+
content: string
8+
read: boolean
9+
userAvatar: string | null
10+
senderAvatar: string | null
11+
url: string | null
12+
createdAt: Date
13+
}) {
14+
const date = new Date(createdAt || "")
15+
const now = new Date()
16+
const diff = Math.floor(
17+
(now.getTime() - date.getTime()) / 1000 / 60 / 60 / 24
18+
)
19+
const diffString =
20+
diff > 0 ? `${diff} day${diff > 1 ? "s" : ""} ago` : "Earlier Today"
21+
22+
// TODO: Read implementation
23+
24+
25+
return (
26+
<div className="flex flex-row justify-between items-center gap-x-5 w-full">
27+
<div className="flex flex-row items-center gap-x-6 py-3">
28+
<div className="relative w-[50px] h-[50px]">
29+
<Image
30+
src={userAvatar ?? USER_DEFAULT_AVATAR}
31+
alt="User Profile"
32+
width={60}
33+
height={60}
34+
className="absolute top-0 left-0 rounded-full"
35+
/>
36+
<Image
37+
src={senderAvatar ?? USER_DEFAULT_AVATAR}
38+
alt="User Profile Overlay"
39+
width={30}
40+
height={30}
41+
className="absolute -bottom-1 -right-2 rounded-full border-2 border-white shadow-md"
42+
/>
43+
</div>
44+
<div className="flex flex-col">
45+
<span>{content}</span>
46+
<span>{diffString}</span>
47+
</div>
48+
</div>
49+
<LuCheck size={20} className="text-green-500" />
50+
</div>
51+
)
52+
}

apps/web/src/components/layouts/AppLayout/ActionsLoggedIn.tsx

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import {
77
generateSiteSettingItems
88
} from "@/utils/generateItems"
99
import { Button } from "@mav/ui/components/buttons"
10-
import { LuBell, LuChevronDown, LuPlus } from "react-icons/lu"
10+
import { LuBell, LuCheck, LuChevronDown, LuMinusCircle, LuPlus } from "react-icons/lu"
1111
import { Dropdown, DropdownItem } from "./Dropdown"
12+
import Image from "next/image"
13+
import Notification from "@/components/Notification"
1214

1315
const ICON = (
1416
<>
@@ -59,12 +61,54 @@ export function ActionsLoggedIn({
5961
</>
6062
}
6163
/>
64+
<Dropdown
65+
button={<Button
66+
prefix={<div className="relative">
67+
<LuBell size={22} />
68+
{user.notifications.length > 0 && !user.notifications.some(n => n.read) && (
69+
<span className="absolute -top-1 -right-1 inline-block w-2 h-2 bg-500 rounded-full animate-pulse" />
70+
)}
71+
</div>}
72+
variant="tritery"
73+
/>}
74+
items={
75+
<div className="flex flex-col items-center px-4 w-80">
76+
<div className="flex flex-row items-center justify-between w-full">
77+
<span className="text-xl">Notifications</span>
78+
<div className="flex flex-row">
79+
<Button variant="tritery" size={"big"} icon={<LuMinusCircle />} />
80+
<Button variant="tritery" size={"big"} icon={<LuCheck />} />
81+
</div>
82+
</div>
83+
{user.notifications.length === 0 ? (
84+
<span className="text-gray-500 text-sm">No new notifications</span>
85+
) : (
86+
user.notifications.slice(0, 5).map((notification) => (
87+
<Notification
88+
key={notification.id}
89+
content={notification.content}
90+
createdAt={notification.createdAt}
91+
read={notification.read}
92+
userAvatar={user.avatarUrl || "/UserProfile.png"}
93+
senderAvatar={
94+
notification.sender ? notification.sender.avatarUrl : null
95+
}
96+
url={
97+
notification.artwork
98+
? `/artworks/${notification.artwork.id}`
99+
: notification.character
100+
? `/characters/${notification.character.id}`
101+
: null
102+
}
103+
/>
104+
))
105+
)}
106+
107+
</div>
108+
}
62109

63-
<Button
64-
prefix={<LuBell size={22} />}
65-
className="hover:!bg-100"
66-
variant="tritery"
67110
/>
111+
68112
<Dropdown
69113
button={
70114
<Link href={`/@${user.handle}`}>

apps/web/src/components/layouts/AppLayout/Dropdown/Dropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default function Dropdown({
2222
// @ts-expect-error
2323
className="translate-x-0"
2424
>
25-
<MenuItems className="bg-context-menu border-300 absolute right-0 top-2.5 z-[9] grid rounded-md border p-2 shadow-md">
25+
<MenuItems className="bg-context-menu border-300 absolute right-0 top-7 z-[9] grid rounded-md border p-2 shadow-md">
2626
{items}
2727
</MenuItems>
2828
</Transition>

apps/web/src/types/users.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type Badge = {
1616
rewardDate: Date
1717
}
1818

19+
1920
export interface UserType {
2021
id: string
2122
handle: string
@@ -63,6 +64,7 @@ export interface Notification {
6364
user: UserType
6465
sender: UserType | null
6566
artwork: Artwork | null
67+
character: Character | null
6668
comment: Comments | null
6769
createdAt: Date
6870
}

apps/web/src/utils/api.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ export const fetchUser = async (handle: string) => {
138138
return data
139139
}
140140

141+
export const getNotifications = async () => {
142+
const data = await apiWithAuth<Notification[]>("GET", `/v1/profile/notifications`)
143+
return data
144+
}
145+
141146
export const fetchUserCharacters = async (handle: string) => {
142147
const data = await apiWithoutAuth<CharacterResponse>(
143148
"GET",

0 commit comments

Comments
 (0)