init
This commit is contained in:
106
frontend/composables/useSupportUnread.ts
Normal file
106
frontend/composables/useSupportUnread.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import type { SupportConversation } from "~/types";
|
||||
|
||||
const toConversationMap = (items: SupportConversation[]) =>
|
||||
Object.fromEntries(items.map((item) => [item.id, item])) as Record<string, SupportConversation>;
|
||||
|
||||
export function useSupportUnread() {
|
||||
const { user, token } = useAuth();
|
||||
const { connect, onConversationUpdated, onMessageCreated } = useSupportRealtime();
|
||||
|
||||
const conversations = useState<Record<string, SupportConversation>>("support-unread-conversations", () => ({}));
|
||||
const unreadCount = useState<number>("support-unread-count", () => 0);
|
||||
const initialized = useState<boolean>("support-unread-initialized", () => false);
|
||||
const loading = useState<boolean>("support-unread-loading", () => false);
|
||||
const offConversationUpdated = useState<(() => void) | null>("support-unread-off-conversation", () => null);
|
||||
const offMessageCreated = useState<(() => void) | null>("support-unread-off-message", () => null);
|
||||
|
||||
const recomputeUnreadCount = () => {
|
||||
const items = Object.values(conversations.value);
|
||||
|
||||
unreadCount.value = user.value?.role === "admin"
|
||||
? items.filter((item) => item.unreadForAdmin).length
|
||||
: items.some((item) => item.unreadForUser) ? 1 : 0;
|
||||
};
|
||||
|
||||
const replaceConversations = (items: SupportConversation[]) => {
|
||||
conversations.value = toConversationMap(items);
|
||||
recomputeUnreadCount();
|
||||
};
|
||||
|
||||
const upsertConversation = (item: SupportConversation) => {
|
||||
conversations.value = {
|
||||
...conversations.value,
|
||||
[item.id]: item
|
||||
};
|
||||
recomputeUnreadCount();
|
||||
};
|
||||
|
||||
const clearState = () => {
|
||||
conversations.value = {};
|
||||
unreadCount.value = 0;
|
||||
initialized.value = false;
|
||||
offConversationUpdated.value?.();
|
||||
offConversationUpdated.value = null;
|
||||
offMessageCreated.value?.();
|
||||
offMessageCreated.value = null;
|
||||
};
|
||||
|
||||
const refreshUnread = async () => {
|
||||
if (!user.value || !token.value || loading.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
if (user.value.role === "admin") {
|
||||
const response = await useChatApi<SupportConversation[]>("/admin/support/conversations");
|
||||
replaceConversations(response);
|
||||
} else {
|
||||
const response = await useChatApi<SupportConversation>("/support/conversation");
|
||||
replaceConversations([response]);
|
||||
}
|
||||
} catch {
|
||||
// Ignore unread refresh failures in shell navigation.
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const ensureRealtime = () => {
|
||||
if (!process.client || !token.value || offConversationUpdated.value || offMessageCreated.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
connect();
|
||||
offConversationUpdated.value = onConversationUpdated(({ conversation }) => {
|
||||
if (conversation) {
|
||||
upsertConversation(conversation);
|
||||
}
|
||||
});
|
||||
offMessageCreated.value = onMessageCreated(({ conversation }) => {
|
||||
if (conversation) {
|
||||
upsertConversation(conversation);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const initializeUnread = async () => {
|
||||
if (initialized.value || !user.value || !token.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
await refreshUnread();
|
||||
ensureRealtime();
|
||||
initialized.value = true;
|
||||
};
|
||||
|
||||
return {
|
||||
unreadCount,
|
||||
initializeUnread,
|
||||
refreshUnread,
|
||||
replaceConversations,
|
||||
upsertConversation,
|
||||
clearState
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user