Files
chatroom/resources/js/chat-room/friend-notifications.js
T
2026-04-25 14:02:04 +08:00

189 lines
5.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 聊天室好友与通用大卡片广播通知监听,集中管理 Echo 订阅和弹窗渲染。
import { escapeHtml } from "./html.js";
/**
* 读取页面 CSRF Token。
*
* @returns {string}
*/
function getCsrfToken() {
return document.querySelector('meta[name="csrf-token"]')?.content ?? "";
}
/**
* 等待 Echo 与聊天上下文就绪后再订阅频道。
*
* @param {Function} callback
* @returns {void}
*/
function whenEchoReady(callback) {
if (!window.Echo || !window.chatContext) {
window.setTimeout(() => whenEchoReady(callback), 500);
return;
}
callback();
}
/**
* 同步移除对方好友关系。
*
* @param {string} username
* @returns {Promise<void>}
*/
async function removeFriendBack(username) {
await fetch(`/friend/${encodeURIComponent(username)}/remove`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": getCsrfToken(),
"Accept": "application/json",
},
body: JSON.stringify({
room_id: window.chatContext?.roomId,
}),
});
}
/**
* 显示好友添加居中大卡弹窗。
*
* @param {string} fromUsername
* @param {boolean} hasAddedBack
* @returns {void}
*/
export function showFriendBanner(fromUsername, hasAddedBack) {
if (!window.chatBanner) {
return;
}
if (hasAddedBack) {
window.chatBanner.show({
id: "friend-banner",
icon: "🎉💚🎉",
title: "好友通知",
name: fromUsername,
body: "将你加为好友了!",
sub: "你们现在互为好友 🎊",
gradient: ["#065f46", "#059669", "#10b981"],
titleColor: "#a7f3d0",
autoClose: 5000,
});
return;
}
window.chatBanner.show({
id: "friend-banner",
icon: "💚📩",
title: "好友申请",
name: fromUsername,
body: "将你加为好友了!",
sub: "但你还没有回加对方为好友",
gradient: ["#1e3a5f", "#1d4ed8", "#0891b2"],
titleColor: "#bae6fd",
autoClose: 0,
buttons: [
{
label: " 回加好友",
color: "#10b981",
onClick: async (button, close) => {
await window.quickFriendAction?.("add", fromUsername, button);
if (button.textContent.startsWith("✅")) {
window.setTimeout(close, 1500);
}
},
},
{
label: "稍后再说",
color: "rgba(255,255,255,0.15)",
onClick: (button, close) => close(),
},
],
});
}
/**
* 订阅好友私有频道通知。
*
* @returns {void}
*/
export function setupFriendNotification() {
whenEchoReady(() => {
const myId = window.chatContext.userId;
window.Echo.private(`user.${myId}`)
.listen(".FriendAdded", (event) => {
showFriendBanner(event.from_username, event.has_added_back);
})
.listen(".FriendRemoved", (event) => {
const fromUsername = String(event.from_username ?? "");
const safeUsername = escapeHtml(fromUsername);
if (event.had_added_back) {
window.chatToast?.show?.({
title: "好友通知",
message: `<b>${safeUsername}</b> 已将你从好友列表移除。<br><span style="color:#6b7280; font-size:12px;">你的好友列表中仍保留对方,可点击同步移除。</span>`,
icon: "👥",
color: "#6b7280",
duration: 10000,
action: {
label: `🗑️ 同步移除 ${fromUsername}`,
onClick: async () => removeFriendBack(fromUsername),
},
});
return;
}
window.chatToast?.show?.({
title: "好友通知",
message: `<b>${safeUsername}</b> 已将你从他的好友列表移除。`,
icon: "👥",
color: "#9ca3af",
});
});
});
}
/**
* 订阅通用大卡片通知广播。
*
* @returns {void}
*/
export function setupBannerNotification() {
whenEchoReady(() => {
const myId = window.chatContext.userId;
const roomId = window.chatContext.roomId;
const showBanner = (event) => {
if (event.options && typeof event.options === "object") {
window.chatBanner?.show?.(event.options);
}
};
// 私有频道只推送给指定用户,房间频道推送给当前房间在线用户。
window.Echo.private(`user.${myId}`).listen(".BannerNotification", showBanner);
if (roomId) {
window.Echo.join(`room.${roomId}`).listen(".BannerNotification", showBanner);
}
});
}
/**
* 绑定好友与大卡片通知监听,并暴露旧全局函数。
*
* @returns {void}
*/
export function bindFriendNotificationControls() {
if (typeof window === "undefined") {
return;
}
window.showFriendBanner = showFriendBanner;
window.setupFriendNotification = setupFriendNotification;
window.setupBannerNotification = setupBannerNotification;
setupFriendNotification();
setupBannerNotification();
}