- add chat_notification_settings table and migration - add chat notifications API (get/update muted) - skip message notifications for muted recipients - add mute/unmute control in chat info panel
This commit is contained in:
@@ -2,6 +2,12 @@ import { http } from "./http";
|
||||
import type { Chat, ChatDetail, ChatMember, ChatMemberRole, ChatType, DiscoverChat, Message, MessageType } from "../chat/types";
|
||||
import axios from "axios";
|
||||
|
||||
export interface ChatNotificationSettings {
|
||||
chat_id: number;
|
||||
user_id: number;
|
||||
muted: boolean;
|
||||
}
|
||||
|
||||
export async function getChats(query?: string): Promise<Chat[]> {
|
||||
const { data } = await http.get<Chat[]>("/chats", {
|
||||
params: query?.trim() ? { query: query.trim() } : undefined
|
||||
@@ -207,3 +213,13 @@ export async function removeChatMember(chatId: number, userId: number): Promise<
|
||||
export async function leaveChat(chatId: number): Promise<void> {
|
||||
await http.post(`/chats/${chatId}/leave`);
|
||||
}
|
||||
|
||||
export async function getChatNotificationSettings(chatId: number): Promise<ChatNotificationSettings> {
|
||||
const { data } = await http.get<ChatNotificationSettings>(`/chats/${chatId}/notifications`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function updateChatNotificationSettings(chatId: number, muted: boolean): Promise<ChatNotificationSettings> {
|
||||
const { data } = await http.put<ChatNotificationSettings>(`/chats/${chatId}/notifications`, { muted });
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,12 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import {
|
||||
addChatMember,
|
||||
getChatNotificationSettings,
|
||||
getChatDetail,
|
||||
leaveChat,
|
||||
listChatMembers,
|
||||
removeChatMember,
|
||||
updateChatNotificationSettings,
|
||||
updateChatMemberRole,
|
||||
updateChatTitle
|
||||
} from "../api/chats";
|
||||
@@ -33,6 +35,8 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) {
|
||||
const [savingTitle, setSavingTitle] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [searchResults, setSearchResults] = useState<UserSearchItem[]>([]);
|
||||
const [muted, setMuted] = useState(false);
|
||||
const [savingMute, setSavingMute] = useState(false);
|
||||
|
||||
const myRole = useMemo(() => members.find((m) => m.user_id === me?.id)?.role, [members, me?.id]);
|
||||
const isGroupLike = chat?.type === "group" || chat?.type === "channel";
|
||||
@@ -65,6 +69,10 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) {
|
||||
if (cancelled) return;
|
||||
setChat(detail);
|
||||
setTitleDraft(detail.title ?? "");
|
||||
const notificationSettings = await getChatNotificationSettings(chatId);
|
||||
if (!cancelled) {
|
||||
setMuted(notificationSettings.muted);
|
||||
}
|
||||
await refreshMembers(chatId);
|
||||
} catch {
|
||||
if (!cancelled) setError("Failed to load chat info");
|
||||
@@ -107,6 +115,27 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) {
|
||||
{chat ? (
|
||||
<>
|
||||
<div className="mb-3 rounded-lg border border-slate-700/70 bg-slate-800/60 p-3">
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<p className="text-xs text-slate-400">Notifications</p>
|
||||
<button
|
||||
className="rounded bg-slate-700 px-2 py-1 text-xs disabled:opacity-60"
|
||||
disabled={savingMute}
|
||||
onClick={async () => {
|
||||
setSavingMute(true);
|
||||
try {
|
||||
const updated = await updateChatNotificationSettings(chatId, !muted);
|
||||
setMuted(updated.muted);
|
||||
} catch {
|
||||
setError("Failed to update notifications");
|
||||
} finally {
|
||||
setSavingMute(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{muted ? "Unmute" : "Mute"}
|
||||
</button>
|
||||
</div>
|
||||
<p className="mb-2 text-xs text-slate-300">{muted ? "Chat notifications are muted." : "Chat notifications are enabled."}</p>
|
||||
<p className="text-xs text-slate-400">Type</p>
|
||||
<p className="text-sm">{chat.type}</p>
|
||||
<p className="mt-2 text-xs text-slate-400">Title</p>
|
||||
|
||||
Reference in New Issue
Block a user