forked from StellarSplit/StellarSplit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNotificationCenter.tsx
More file actions
133 lines (123 loc) · 4.65 KB
/
Copy pathNotificationCenter.tsx
File metadata and controls
133 lines (123 loc) · 4.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { useMemo } from "react";
import { useNotificationsStore } from "../../store/notifications";
import type { NotificationType } from "../../types/notifications";
import { NOTIFICATION_TYPE_LABELS } from "../../types/notifications";
import { NotificationItem } from "./NotificationItem";
import { Button } from "../ui/button";
const DEMO_MESSAGES: Array<{ type: NotificationType; title: string; message: string }> = [
{ type: "split_invitation", title: "Split invitation", message: "You were invited to a new split." },
{ type: "payment_received", title: "Payment received", message: "A payment was received." },
{ type: "system_announcement", title: "Update", message: "New feature available." },
];
const FILTER_OPTIONS: (NotificationType | "all")[] = [
"all",
"split_invitation",
"payment_reminder",
"payment_received",
"split_completed",
"split_cancelled",
"friend_request",
"system_announcement",
];
export function NotificationCenter() {
const notifications = useNotificationsStore((state) => state.notifications);
const typeFilter = useNotificationsStore((state) => state.typeFilter);
const setTypeFilter = useNotificationsStore((state) => state.setTypeFilter);
const markAllAsRead = useNotificationsStore((state) => state.markAllAsRead);
const clearAll = useNotificationsStore((state) => state.clearAll);
const addNotification = useNotificationsStore((state) => state.addNotification);
const filteredList = useMemo(() => {
if (typeFilter === "all") return [...notifications];
return notifications.filter((n) => n.type === typeFilter);
}, [notifications, typeFilter]);
const unreadCount = useMemo(
() => notifications.filter((n) => !n.read).length,
[notifications]
);
const simulateNew = () => {
const item = DEMO_MESSAGES[Math.floor(Math.random() * DEMO_MESSAGES.length)];
addNotification(item);
};
return (
<div className="max-w-2xl mx-auto px-4 py-6 sm:py-8" data-testid="notification-center">
<header className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
<h1 className="text-2xl font-bold text-theme">Notifications</h1>
<div className="flex flex-wrap gap-2">
{unreadCount > 0 && (
<Button
type="button"
onClick={markAllAsRead}
className="!rounded-lg"
data-testid="mark-all-read"
>
Mark all as read
</Button>
)}
{notifications.length > 0 && (
<Button
type="button"
onClick={clearAll}
className="!rounded-lg border border-theme bg-card-theme text-theme hover:bg-surface"
data-testid="clear-all"
>
Clear all
</Button>
)}
</div>
</header>
{import.meta.env.DEV && (
<div className="mb-4 flex flex-wrap items-center gap-4">
<button
type="button"
onClick={simulateNew}
className="text-sm text-accent hover:underline"
data-testid="simulate-notification"
>
Simulate new notification
</button>
</div>
)}
<div className="mb-4">
<p className="text-sm text-muted-theme mb-2">Filter by type</p>
<div className="flex flex-wrap gap-2">
{FILTER_OPTIONS.map((type) => (
<button
key={type}
type="button"
onClick={() => setTypeFilter(type)}
className={`
px-3 py-1.5 rounded-full text-sm font-medium transition-colors
${typeFilter === type
? "bg-accent text-white"
: "bg-card-theme border border-theme text-theme hover:bg-surface"}
`}
data-testid={`filter-${type}`}
>
{type === "all" ? "All" : NOTIFICATION_TYPE_LABELS[type]}
</button>
))}
</div>
</div>
<section className="space-y-2">
{filteredList.length === 0 ? (
<div
className="rounded-xl border border-theme bg-card-theme p-8 text-center text-muted-theme"
data-testid="empty-state"
>
{notifications.length === 0
? "No notifications yet."
: `No ${typeFilter === "all" ? "" : NOTIFICATION_TYPE_LABELS[typeFilter].toLowerCase()} notifications.`}
</div>
) : (
<ul className="space-y-2">
{filteredList.map((n) => (
<li key={n.id}>
<NotificationItem notification={n} />
</li>
))}
</ul>
)}
</section>
</div>
);
}