fix(notifications): add per-row mark as read
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
36ab2eba9b
commit
3d8655aa8a
1 changed files with 39 additions and 21 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { BellIcon } from "lucide-react";
|
import { BellIcon, CheckIcon } from "lucide-react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
|
@ -83,9 +83,8 @@ export function NotificationsBell() {
|
||||||
};
|
};
|
||||||
}, [fetchNotifications]);
|
}, [fetchNotifications]);
|
||||||
|
|
||||||
async function handleItemClick(item: NotificationItem) {
|
async function handleMarkOne(item: NotificationItem) {
|
||||||
if (marking) return;
|
if (item.read || marking) return;
|
||||||
if (!item.read) {
|
|
||||||
setMarking(true);
|
setMarking(true);
|
||||||
setActionError(null);
|
setActionError(null);
|
||||||
try {
|
try {
|
||||||
|
|
@ -103,6 +102,9 @@ export function NotificationsBell() {
|
||||||
setMarking(false);
|
setMarking(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleItemClick(item: NotificationItem) {
|
||||||
|
if (!item.read) await handleMarkOne(item);
|
||||||
if (item.link) {
|
if (item.link) {
|
||||||
router.push(item.link);
|
router.push(item.link);
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
|
@ -194,10 +196,26 @@ export function NotificationsBell() {
|
||||||
)}
|
)}
|
||||||
{item.title}
|
{item.title}
|
||||||
</span>
|
</span>
|
||||||
<span className="shrink-0 text-[10px] text-muted-foreground">
|
<span className="flex shrink-0 items-center gap-1.5">
|
||||||
|
{!item.read && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
title="Mark as read"
|
||||||
|
aria-label={`Mark "${item.title}" as read`}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
void handleMarkOne(item);
|
||||||
|
}}
|
||||||
|
className="rounded-sm p-0.5 text-muted-foreground/60 transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
||||||
|
>
|
||||||
|
<CheckIcon className="size-3.5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<span className="text-[10px] text-muted-foreground">
|
||||||
{timeAgo(item.createdAt)}
|
{timeAgo(item.createdAt)}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
</span>
|
||||||
{item.message && (
|
{item.message && (
|
||||||
<span className="line-clamp-3 w-full text-xs text-muted-foreground">
|
<span className="line-clamp-3 w-full text-xs text-muted-foreground">
|
||||||
{item.message}
|
{item.message}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue