Messenger/packages/web/src/features/conversations/model.ts
Заид Омар Медхат | Zaid Omar Medhat 71e018d802 init presence
2026-07-10 16:54:40 +05:00

81 lines
2.6 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react';
import type { Conversation } from '@altricade/core';
import { userChannel } from '@altricade/core';
import { listConversations, createDirect, createGroup } from '@altricade/core/api';
import { apiConfig } from '../../shared/api';
import { useRealtime } from '../realtime';
export interface UseConversations {
conversations: Conversation[];
loading: boolean;
startDirect: (username: string) => Promise<Conversation>;
createGroupChat: (title: string, members: string[]) => Promise<Conversation>;
}
const isConversationNew = (
data: unknown,
): data is { type: 'conversation.new'; conversation: Conversation } => {
if (typeof data !== 'object' || data === null) {
return false;
}
return 'type' in data && data.type === 'conversation.new' && 'conversation' in data;
};
const upsert = (list: Conversation[], conversation: Conversation): Conversation[] => {
const rest = list.filter((item) => item.id !== conversation.id);
return [conversation, ...rest];
};
export const useConversations = (userId: string): UseConversations => {
const { subscribe } = useRealtime();
const [conversations, setConversations] = useState<Conversation[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
const load = async (): Promise<void> => {
try {
const list = await listConversations(apiConfig);
if (!cancelled) {
setConversations(list);
}
} finally {
if (!cancelled) {
setLoading(false);
}
}
};
void load();
return () => {
cancelled = true;
};
}, []);
// New conversations (a DM someone started with me, or a group I was added to)
// arrive on my personal channel.
useEffect(() => {
return subscribe(userChannel(userId), (event) => {
if (isConversationNew(event.data)) {
const { conversation } = event.data;
setConversations((prev) => upsert(prev, conversation));
}
});
}, [subscribe, userId]);
const startDirect = useCallback(async (username: string): Promise<Conversation> => {
const conversation = await createDirect(apiConfig, { username });
setConversations((prev) => upsert(prev, conversation));
return conversation;
}, []);
const createGroupChat = useCallback(
async (title: string, members: string[]): Promise<Conversation> => {
const conversation = await createGroup(apiConfig, { title, members });
setConversations((prev) => upsert(prev, conversation));
return conversation;
},
[],
);
return { conversations, loading, startDirect, createGroupChat };
};