Appearance
Overview
- File: src/components/app/chat/chatNotification.svelte
The Chat Notification component manages real-time chat notifications in the HVC Web application, displaying incoming messages with user avatars and providing quick actions for message interaction.
Type Definitions
Message Interface
ts
interface IMessage {
fromId: number; // Sender's ID
from: string; // Sender's name
groupId: number; // Chat group ID
groupName: string; // Chat group name
filename?: string; // File name (for file messages)
content: string; // Message content
lines: string[]; // Message lines (for multiple messages)
contentType: "text" | "file"; // Message type
date: Date; // Message timestamp
expires: Date; // Notification expiry
id: number; // Message ID
profileImageUrl?: string; // Sender's profile image
initials: string; // Sender's initials
}Component Configuration
State Management
svelte
let expirySeconds = 6; // Notification display duration
let refreshRate = 2000; // Status check interval
let newMessages: IMessage[] = []; // Active notifications
let intervalHandle: number; // Timer referenceEvent System
Event Subscriptions
svelte
// Subscribe to new messages
subscribe("onNewMessage", onNewMessage);
// Cleanup subscription
onDestroy(() => {
unsubscribe("onNewMessage", onNewMessage);
});Message Handler
svelte
async function onNewMessage(data) {
if (!data?.content || !hasPermission(Permissions.canChat)) {
return;
}
data.expires = dayjs().add(expirySeconds, "s").toDate();
data.initials = getInitials(data.from);
// Skip if in current chat group
if ($activeChatGroupId === data.groupId) {
return;
}
// Handle different notification scenarios
if ($showChat) {
showInfo({title: "New Message", text: data.content});
addNotice("chat", data);
return;
}
// Update or add new message
const existing = newMessages.find(x =>
x.fromId === data.fromId && x.groupId === data.groupId
);
if (existing) {
existing.lines = [...existing.lines, data.content];
existing.expires = data.expires;
newMessages = [...newMessages];
} else {
newMessages = [...newMessages, {...data, lines: [data.content]}];
}
dispatch("newMessage", data);
}User Interactions
Message Actions
svelte
// Close notification
function closeMessage(msg: IMessage) {
newMessages = newMessages.filter(x => x.id !== msg.id);
dispatch("closeMessage", msg);
}
// Open chat group
function openMessage(msg: IMessage) {
newMessages = newMessages.filter(x => x.id !== msg.id);
activateChatGroup(msg.groupId);
dispatch("openMessage", msg);
}UI Implementation
Notification Container
svelte
<div aria-live="assertive" class="pointer-events-none fixed inset-0 flex items-end px-4 py-6 sm:items-start sm:p-6 z-[100]">
<div class="flex w-full flex-col items-center space-y-4 sm:items-end"
class:hidden={$showChat}>
{#each newMessages as msg}
<!-- Message notification card -->
{/each}
</div>
</div>Message Card Template
svelte
<div class="pointer-events-auto flex w-full max-w-md rounded-lg divide-x bg-white shadow-lg">
<!-- Message Content -->
<div class="w-0 flex-1 p-4">
<div class="flex items-start">
<!-- User Avatar -->
<div class="flex-shrink-0 pt-0.5">
{#if msg.profileImageUrl}
<div class="avatar mt-2 placeholder">
<img src={msg.profileImageUrl} alt=""/>
</div>
{:else}
<div class="avatar mt-2 placeholder">
<span>{msg.initials}</span>
</div>
{/if}
</div>
<!-- Message Details -->
<div class="ml-3 w-0 flex-1">
<p class="text-sm font-medium">{msg.from}</p>
<p class="mt-1 text-sm text-gray-500">
{#if msg.contentType === "file"}
<span>{msg.content}</span>
{:else if msg?.lines?.length === 1}
<span>{msg.content}</span>
{:else}
<ul>
{#each msg.lines as line}
<li>{line}</li>
{/each}
</ul>
{/if}
</p>
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="flex">
<button on:click={_ => openMessage(msg)}>Open</button>
<button on:click={_ => closeMessage(msg)}>Close</button>
</div>
</div>Lifecycle Management
Component Initialization
svelte
onMount(() => {
intervalHandle = setInterval(() => {
if (newMessages.find(x => x.expires < new Date())) {
newMessages = newMessages.filter(x => x.expires > new Date());
}
}, refreshRate);
});Cleanup
svelte
onDestroy(() => {
clearInterval(intervalHandle);
unsubscribe("onNewMessage", onNewMessage);
});Usage Guide
Basic Implementation
svelte
<script>
import ChatNotification from './components/app/chat/chatNotification.svelte';
</script>
<ChatNotification />Event Handling
svelte
<ChatNotification
on:newMessage={handleNewMessage}
on:closeMessage={handleCloseMessage}
on:openMessage={handleOpenMessage}
/>