Task #45: Tapping a chat notification opens the matching conversation
- notifications.tsx: When a notification is clicked, if it has relatedType === "conversation" and a relatedId, navigate to /chat?c=<conversationId> in addition to marking it read. Other notification types continue to behave as before (just mark read). - chat.tsx: Read the optional `c` query parameter via wouter's useSearch hook. When present and valid, set it as the selectedConvId so the conversation opens automatically, then replace the URL back to /chat so refreshing or navigating away doesn't keep re-opening it. No API or schema changes required; notification records already carry relatedType/relatedId for chat notifications.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect, useRef, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useLocation } from "wouter";
|
||||
import { useLocation, useSearch } from "wouter";
|
||||
import {
|
||||
useListConversations,
|
||||
getListConversationsQueryKey,
|
||||
@@ -135,6 +135,7 @@ type ConvMode = "direct" | "group";
|
||||
export default function ChatPage() {
|
||||
const { t, i18n } = useTranslation();
|
||||
const [, setLocation] = useLocation();
|
||||
const search = useSearch();
|
||||
const { user } = useAuth();
|
||||
const lang = i18n.language;
|
||||
const isRtl = lang === "ar";
|
||||
@@ -231,6 +232,17 @@ export default function ChatPage() {
|
||||
};
|
||||
}, [user, selectedConvId, queryClient]);
|
||||
|
||||
// Open conversation specified via ?c=<id> query param (e.g. from notifications)
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(search);
|
||||
const convParam = params.get("c");
|
||||
if (!convParam) return;
|
||||
const convId = Number(convParam);
|
||||
if (!Number.isFinite(convId) || convId <= 0) return;
|
||||
setSelectedConvId(convId);
|
||||
setLocation("/chat", { replace: true });
|
||||
}, [search, setLocation]);
|
||||
|
||||
// Mark conversation as read when selected
|
||||
useEffect(() => {
|
||||
if (selectedConvId) {
|
||||
|
||||
@@ -49,6 +49,20 @@ export default function NotificationsPage() {
|
||||
);
|
||||
};
|
||||
|
||||
const handleNotificationClick = (n: {
|
||||
id: number;
|
||||
isRead: boolean;
|
||||
relatedType?: string | null;
|
||||
relatedId?: number | null;
|
||||
}) => {
|
||||
if (!n.isRead) {
|
||||
handleMarkOne(n.id);
|
||||
}
|
||||
if (n.relatedType === "conversation" && n.relatedId != null) {
|
||||
setLocation(`/chat?c=${n.relatedId}`);
|
||||
}
|
||||
};
|
||||
|
||||
const unreadCount = notifications?.filter((n) => !n.isRead).length ?? 0;
|
||||
|
||||
return (
|
||||
@@ -103,7 +117,7 @@ export default function NotificationsPage() {
|
||||
return (
|
||||
<div
|
||||
key={n.id}
|
||||
onClick={() => !n.isRead && handleMarkOne(n.id)}
|
||||
onClick={() => handleNotificationClick(n)}
|
||||
className={`glass-panel rounded-2xl p-4 cursor-pointer transition-opacity ${n.isRead ? "opacity-60" : ""}`}
|
||||
>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
|
||||
Reference in New Issue
Block a user