149 lines
5.5 KiB
TypeScript
149 lines
5.5 KiB
TypeScript
import { CHAT_PERMISSIONS, type ChatNotificationPreference } from "@hivegrid/chat";
|
|
import { listDiscoverablePublicGroupChats } from "@hivegrid/chat/discovery.server";
|
|
import { joinPublicGroupChat } from "@hivegrid/chat/lifecycle.server";
|
|
import { setChatMemberPreferences } from "@hivegrid/chat/member-preferences.server";
|
|
import { getMemberChannelDetail, listMemberChannels, sendTopLevelChatMessage } from "@hivegrid/chat/repository.server";
|
|
import type { ChatChannelDetailVM, ChatChannelListFilterState, ChatChannelListVM, ChatResolvedAuthorVM } from "@hivegrid/view-models";
|
|
import { tenantHasModule } from "~/utils/connector/tenantConnector.server";
|
|
|
|
import { requireChatPermission, type ChatRouteContext } from "../routes/chatAccess.server";
|
|
import { buildMemberChatChannelDetailVM, buildMemberChatChannelListVM, buildChatResolvedAuthors, type ChatViewModelLabels } from "./chatViewModel.server";
|
|
|
|
export async function loadMemberChatChannels(input: {
|
|
readonly context: ChatRouteContext;
|
|
readonly tenantSlug: string;
|
|
readonly filter: ChatChannelListFilterState;
|
|
readonly afterCursor?: string;
|
|
readonly limit?: number;
|
|
readonly labels: ChatViewModelLabels;
|
|
}): Promise<ChatChannelListVM> {
|
|
const context = requireChatPermission(input.context, CHAT_PERMISSIONS.readOwnChannels);
|
|
const [result, discover] = await Promise.all([
|
|
listMemberChannels({
|
|
tenantId: context.tenantId,
|
|
userId: context.userId,
|
|
permissions: context.permissions,
|
|
query: input.filter.query,
|
|
view: input.filter.view,
|
|
includeArchived: input.filter.showArchived,
|
|
afterCursor: input.afterCursor,
|
|
limit: input.limit,
|
|
}),
|
|
input.afterCursor
|
|
? Promise.resolve(undefined)
|
|
: listDiscoverablePublicGroupChats({
|
|
tenantId: context.tenantId,
|
|
userId: context.userId,
|
|
permissions: context.permissions,
|
|
query: input.filter.query,
|
|
}),
|
|
]);
|
|
|
|
return buildMemberChatChannelListVM({
|
|
channels: result.channels,
|
|
tenantSlug: input.tenantSlug,
|
|
currentUserId: context.userId,
|
|
permissions: context.permissions,
|
|
filter: input.filter,
|
|
nextCursor: result.nextCursor,
|
|
discoverChannels: discover?.channels,
|
|
labels: input.labels,
|
|
});
|
|
}
|
|
|
|
export async function joinPublicChatChannel(input: {
|
|
readonly context: ChatRouteContext;
|
|
readonly chatId: string;
|
|
readonly requestId: string;
|
|
}) {
|
|
const context = requireChatPermission(input.context, CHAT_PERMISSIONS.readOwnChannels);
|
|
return joinPublicGroupChat({
|
|
tenantId: context.tenantId,
|
|
userId: context.userId,
|
|
permissions: context.permissions,
|
|
chatId: input.chatId,
|
|
requestId: input.requestId,
|
|
});
|
|
}
|
|
|
|
export async function updateOwnChatChannelPreferences(input: {
|
|
readonly context: ChatRouteContext;
|
|
readonly chatId: string;
|
|
readonly requestId: string;
|
|
readonly isPinned?: boolean;
|
|
readonly notificationPreference?: ChatNotificationPreference;
|
|
}) {
|
|
const context = requireChatPermission(input.context, CHAT_PERMISSIONS.readOwnChannels);
|
|
return setChatMemberPreferences({
|
|
tenantId: context.tenantId,
|
|
userId: context.userId,
|
|
permissions: context.permissions,
|
|
chatId: input.chatId,
|
|
requestId: input.requestId,
|
|
...(input.isPinned === undefined ? {} : { isPinned: input.isPinned }),
|
|
...(input.notificationPreference === undefined ? {} : { notificationPreference: input.notificationPreference }),
|
|
});
|
|
}
|
|
|
|
export async function loadMemberChatChannel(input: {
|
|
readonly context: ChatRouteContext;
|
|
readonly tenantSlug: string;
|
|
readonly chatId: string;
|
|
readonly beforeMessageCursor?: string;
|
|
readonly focusMessageId?: string;
|
|
readonly labels: ChatViewModelLabels;
|
|
}): Promise<{
|
|
readonly vm: ChatChannelDetailVM;
|
|
readonly eventCursor: string;
|
|
readonly authors: readonly ChatResolvedAuthorVM[];
|
|
}> {
|
|
const context = requireChatPermission(input.context, CHAT_PERMISSIONS.readOwnChannels);
|
|
const [detail, filesEnabled, tasksEnabled] = await Promise.all([
|
|
getMemberChannelDetail({
|
|
tenantId: context.tenantId,
|
|
userId: context.userId,
|
|
permissions: context.permissions,
|
|
chatId: input.chatId,
|
|
...(input.beforeMessageCursor ? { beforeMessageCursor: input.beforeMessageCursor } : {}),
|
|
...(input.focusMessageId ? { focusMessageId: input.focusMessageId } : {}),
|
|
}),
|
|
tenantHasModule({ tenantId: context.tenantId, userId: context.userId, moduleKey: "files" }),
|
|
tenantHasModule({ tenantId: context.tenantId, userId: context.userId, moduleKey: "tasks" }),
|
|
]);
|
|
|
|
return {
|
|
vm: buildMemberChatChannelDetailVM({
|
|
detail,
|
|
tenantSlug: input.tenantSlug,
|
|
currentUserId: context.userId,
|
|
permissions: context.permissions,
|
|
nowIso: new Date().toISOString(),
|
|
featureAvailability: { files: filesEnabled, tasks: tasksEnabled },
|
|
labels: input.labels,
|
|
}),
|
|
eventCursor: detail.eventCursor,
|
|
authors: buildChatResolvedAuthors(detail.channel.participants, context.userId),
|
|
};
|
|
}
|
|
|
|
export async function sendMemberChatMessage(input: {
|
|
readonly context: ChatRouteContext;
|
|
readonly chatId: string;
|
|
readonly clientMessageId: string;
|
|
readonly requestId: string;
|
|
readonly body: string;
|
|
readonly attachmentFileIds: readonly string[];
|
|
}) {
|
|
const context = requireChatPermission(input.context, CHAT_PERMISSIONS.write);
|
|
return sendTopLevelChatMessage({
|
|
tenantId: context.tenantId,
|
|
userId: context.userId,
|
|
permissions: context.permissions,
|
|
chatId: input.chatId,
|
|
clientMessageId: input.clientMessageId,
|
|
requestId: input.requestId,
|
|
body: input.body,
|
|
attachmentFileIds: input.attachmentFileIds,
|
|
});
|
|
}
|