[PULSE-55] In-app notification center, settings tab, and notifications page #28

Merged
uz1mani merged 13 commits from staging into main 2026-02-16 19:46:02 +00:00
8 changed files with 435 additions and 723 deletions
Showing only changes of commit a83f3727b1 - Show all commits

View File

@@ -975,7 +975,7 @@ export default function OrganizationSettings() {
<div className="space-y-8"> <div className="space-y-8">
<div> <div>
<h2 className="text-2xl font-bold text-neutral-900 dark:text-white mb-1">Notification Settings</h2> <h2 className="text-2xl font-bold text-neutral-900 dark:text-white mb-1">Notification Settings</h2>
<p className="text-sm text-neutral-500 dark:text-neutral-400"> <p className="text-sm text-neutral-500 dark:text-neutral-400 mb-6">
Choose which notification types you want to receive. These apply to the notification center for owners and admins. Choose which notification types you want to receive. These apply to the notification center for owners and admins.
</p> </p>
</div> </div>
@@ -985,41 +985,44 @@ export default function OrganizationSettings() {
<div className="w-6 h-6 border-2 border-brand-orange/30 border-t-brand-orange rounded-full animate-spin" /> <div className="w-6 h-6 border-2 border-brand-orange/30 border-t-brand-orange rounded-full animate-spin" />
</div> </div>
) : ( ) : (
<div className="space-y-6"> <div className="space-y-4">
{notificationCategories.map((cat) => ( <h3 className="text-sm font-medium text-neutral-500 uppercase tracking-wider">Notification categories</h3>
<div <div className="bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 rounded-2xl overflow-hidden divide-y divide-neutral-200 dark:divide-neutral-800">
key={cat.id} {notificationCategories.map((cat) => (
className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 p-4 rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-neutral-50/50 dark:bg-neutral-900/50" <div
> key={cat.id}
<div className="flex-1"> className="p-4 flex flex-col sm:flex-row sm:items-center justify-between gap-4 hover:bg-neutral-50 dark:hover:bg-neutral-800/50 transition-colors"
<p className="font-medium text-neutral-900 dark:text-white">{cat.label}</p> >
<p className="text-sm text-neutral-500 dark:text-neutral-400 mt-0.5">{cat.description}</p> <div className="flex-1">
</div> <p className="text-sm font-medium text-neutral-900 dark:text-white">{cat.label}</p>
<div className="flex items-center gap-2"> <p className="text-sm text-neutral-500 dark:text-neutral-400 mt-0.5">{cat.description}</p>
<Checkbox </div>
checked={notificationSettings[cat.id] !== false} <div className="flex items-center gap-2 shrink-0">
onCheckedChange={(checked) => { <Checkbox
const next = { ...notificationSettings, [cat.id]: checked === true } checked={notificationSettings[cat.id] !== false}
setNotificationSettings(next) onCheckedChange={(checked) => {
setIsSavingNotificationSettings(true) const next = { ...notificationSettings, [cat.id]: checked === true }
updateNotificationSettings(next) setNotificationSettings(next)
.then(() => { setIsSavingNotificationSettings(true)
toast.success('Notification settings updated') updateNotificationSettings(next)
}) .then(() => {
.catch((err) => { toast.success('Notification settings updated')
toast.error(getAuthErrorMessage(err) || 'Failed to update settings') })
setNotificationSettings(notificationSettings) .catch((err) => {
}) toast.error(getAuthErrorMessage(err) || 'Failed to update settings')
.finally(() => setIsSavingNotificationSettings(false)) setNotificationSettings(notificationSettings)
})
.finally(() => setIsSavingNotificationSettings(false))
}} }}
disabled={isSavingNotificationSettings} disabled={isSavingNotificationSettings}
/> />
<span className="text-sm text-neutral-500"> <span className="text-sm text-neutral-500 whitespace-nowrap">
{notificationSettings[cat.id] !== false ? 'On' : 'Off'} {notificationSettings[cat.id] !== false ? 'On' : 'Off'}
</span> </span>
</div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
)} )}
</div> </div>