feat: track unread NIP-17 group conversations
This commit is contained in:
parent
9aab761a08
commit
7f0524978c
2 changed files with 18 additions and 2 deletions
|
|
@ -80,8 +80,10 @@ function GroupPreview({ conversation }: { conversation: Conversation }) {
|
|||
const { t } = useTranslation();
|
||||
const participants = conversation.participants ?? [];
|
||||
const { user } = useCurrentUser();
|
||||
const { getLastRead } = useDMRead();
|
||||
const last = conversation.lastMessage;
|
||||
const isFromMe = last?.pubkey === user?.pubkey;
|
||||
const unread = !!last && !isFromMe && last.createdAt > getLastRead(conversation.pubkey);
|
||||
const timeAgo = last
|
||||
? formatDistanceToNow(new Date(last.createdAt * 1000), { addSuffix: true })
|
||||
: '';
|
||||
|
|
@ -90,6 +92,7 @@ function GroupPreview({ conversation }: { conversation: Conversation }) {
|
|||
<Link to={`/messages/group/${participants.join(',')}`}>
|
||||
<Card className={cn(
|
||||
'hover:bg-gray-900/50 transition-colors cursor-pointer border-gray-800',
|
||||
unread && 'border-[#ff0040]/40 bg-[#ff0040]/[0.04]',
|
||||
'hover:border-[#ccff00]/50 active:scale-[0.99]',
|
||||
)}>
|
||||
<CardContent className="p-3">
|
||||
|
|
@ -99,7 +102,10 @@ function GroupPreview({ conversation }: { conversation: Conversation }) {
|
|||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h3 className="truncate font-bold text-white">{t('socialUi.dms.peopleCount', { count: participants.length })}</h3>
|
||||
<h3 className={cn('truncate font-bold text-white', unread && 'font-black')}>
|
||||
{t('socialUi.dms.peopleCount', { count: participants.length })}
|
||||
{unread && <span className="ml-2 inline-block h-1.5 w-1.5 rounded-full bg-[#ff0040]" aria-label={t('socialUi.dms.unreadMessages')} />}
|
||||
</h3>
|
||||
<span className="shrink-0 text-xs text-gray-500">{timeAgo}</span>
|
||||
</div>
|
||||
<p className="mt-0.5 truncate text-xs text-gray-500">
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ import { useTranslation } from '@/contexts/language';
|
|||
import { useToast } from '@/hooks/useToast';
|
||||
import { useNostrLogin } from '@nostrify/react/login';
|
||||
import { hasNip44 as checkNip44 } from '@/lib/signerCapabilities';
|
||||
import { useGroupConversation, useSendDirectMessage } from '@/hooks/useDirectMessages';
|
||||
import { useGroupConversation, useSendDirectMessage, getGroupId } from '@/hooks/useDirectMessages';
|
||||
import { useDMRead } from '@/hooks/useDMRead';
|
||||
import { useAuthor } from '@/hooks/useAuthor';
|
||||
import { genUserName } from '@/lib/genUserName';
|
||||
import { formatDistanceToNow } from '@/lib/dateFnsI18n';
|
||||
|
|
@ -54,11 +55,20 @@ export default function GroupConversationPage() {
|
|||
useSeoMeta({ title: t('socialUi.groupConversation.seoTitle') });
|
||||
|
||||
const { data: messages, isLoading, refetch, isRefetching } = useGroupConversation(allParticipants);
|
||||
const { markRead } = useDMRead();
|
||||
const groupId = useMemo(() => getGroupId(allParticipants), [allParticipants]);
|
||||
|
||||
useEffect(() => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
}, [messages]);
|
||||
|
||||
// Opening a group marks it read up to its newest message, same as 1:1 DMs.
|
||||
useEffect(() => {
|
||||
if (!messages || messages.length === 0) return;
|
||||
const newest = messages.reduce((max, message) => Math.max(max, message.createdAt), 0);
|
||||
markRead(groupId, newest);
|
||||
}, [groupId, markRead, messages]);
|
||||
|
||||
if (!participantsParam || otherPubkeys.length === 0) {
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
Loading…
Reference in a new issue