feat: unread markers for channels and DMs
- Read states store: smarter hasUnread compares against latest message - ConversationList: orange dot + bold name for unread DMs - DMChat: auto-mark-read when viewing conversation - WS handler: mark DM read on new message while active+focused
This commit is contained in:
@@ -4,6 +4,7 @@ import { useConversationStore, type ConversationMessage } from "../stores/conver
|
||||
import { useAuthStore } from "../stores/auth.ts";
|
||||
import { useTypingStore } from "../stores/typing.ts";
|
||||
import { useLayoutStore } from "../stores/layout.ts";
|
||||
import { useReadStatesStore } from "../stores/readStates.ts";
|
||||
import { type Gif } from "./GiphyPicker.tsx";
|
||||
import { EmojiPicker as KaomojiPicker } from "./EmojiPicker.tsx";
|
||||
import Picker, { Theme } from 'emoji-picker-react';
|
||||
@@ -31,6 +32,9 @@ function renderDMContent(content: string) {
|
||||
code: ({ ...props }) => <code {...props} className="bg-gb-bg-t px-1 rounded text-gb-fg-s" />,
|
||||
pre: ({ ...props }) => <pre {...props} className="bg-gb-bg-s p-2 my-1 overflow-x-auto text-gb-fg-s" />,
|
||||
blockquote: ({ ...props }) => <blockquote {...props} className="border-l-2 border-gb-orange pl-2 my-1 text-gb-fg-s" />,
|
||||
h1: ({ ...props }) => <h1 {...props} className="text-lg font-bold my-1" />,
|
||||
h2: ({ ...props }) => <h2 {...props} className="text-base font-bold my-1" />,
|
||||
h3: ({ ...props }) => <h3 {...props} className="text-sm font-bold my-0.5" />,
|
||||
p: ({ ...props }) => <span {...props} className="inline" />,
|
||||
img: ({ src, alt, ...props }) => (
|
||||
<ExpandableImage src={src} alt={alt} {...props} />
|
||||
@@ -149,6 +153,7 @@ export function DMChat() {
|
||||
const fetchMessages = useConversationStore((s) => s.fetchMessages);
|
||||
const fetchOlderMessages = useConversationStore((s) => s.fetchOlderMessages);
|
||||
const isLoadingOlder = useConversationStore((s) => s.isLoadingOlder);
|
||||
const isLoading = useConversationStore((s) => s.isLoading);
|
||||
const sendMessage = useConversationStore((s) => s.sendMessage);
|
||||
const fetchConversations = useConversationStore((s) => s.fetchConversations);
|
||||
const currentUser = useAuthStore((s) => s.user);
|
||||
@@ -162,6 +167,7 @@ export function DMChat() {
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||
const inputRef = useRef<HTMLTextAreaElement>(null);
|
||||
const lastTypingRef = useRef<number>(0);
|
||||
const markConvRead = useReadStatesStore((s) => s.markConvRead);
|
||||
|
||||
const id = conversationId || activeId;
|
||||
const conversation = conversations.find((c) => c.id === id);
|
||||
@@ -207,6 +213,14 @@ export function DMChat() {
|
||||
bottomRef.current?.scrollIntoView({ behavior: "auto" });
|
||||
}, [messages]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!id || messages.length === 0 || isLoading) return;
|
||||
const lastMsg = messages[messages.length - 1];
|
||||
if (lastMsg?.id) {
|
||||
markConvRead(id, lastMsg.id);
|
||||
}
|
||||
}, [id, messages.length, isLoading]);
|
||||
|
||||
const handleGifSelect = async (gif: Gif) => {
|
||||
if (!id) return;
|
||||
const content = ``;
|
||||
|
||||
Reference in New Issue
Block a user