initial
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import type { ProfileBrief } from '../friends/index.js';
|
||||
import type { AppSupabaseClient } from '../supabase/client.js';
|
||||
import type { ConversationSummary } from './types.js';
|
||||
|
||||
const PROFILE_BRIEF_COLS = 'user_id, username, display_name, avatar_url';
|
||||
|
||||
function mapBrief(row: {
|
||||
user_id: string;
|
||||
username: string;
|
||||
display_name: string;
|
||||
avatar_url: string | null;
|
||||
}): ProfileBrief {
|
||||
return {
|
||||
userId: row.user_id,
|
||||
username: row.username,
|
||||
displayName: row.display_name,
|
||||
avatarUrl: row.avatar_url,
|
||||
};
|
||||
}
|
||||
|
||||
async function currentUserId(client: AppSupabaseClient): Promise<string> {
|
||||
const { data, error } = await client.auth.getUser();
|
||||
if (error) throw error;
|
||||
if (!data.user) throw new Error('not authenticated');
|
||||
return data.user.id;
|
||||
}
|
||||
|
||||
export async function listConversations(client: AppSupabaseClient): Promise<ConversationSummary[]> {
|
||||
const myId = await currentUserId(client);
|
||||
|
||||
// 1. Caller's memberships
|
||||
const { data: myMembers, error: mErr } = await client
|
||||
.from('conversation_members')
|
||||
.select('conversation_id, role, accepted')
|
||||
.eq('user_id', myId);
|
||||
if (mErr) throw mErr;
|
||||
const myMembersList = myMembers ?? [];
|
||||
if (myMembersList.length === 0) return [];
|
||||
|
||||
const convIds = myMembersList.map((m) => m.conversation_id);
|
||||
|
||||
// 2. Conversations
|
||||
const { data: convs, error: cErr } = await client
|
||||
.from('conversations')
|
||||
.select('id, type, name, avatar_url, created_at')
|
||||
.in('id', convIds);
|
||||
if (cErr) throw cErr;
|
||||
|
||||
// 3. All members across these conversations
|
||||
const { data: allMembers, error: aErr } = await client
|
||||
.from('conversation_members')
|
||||
.select('conversation_id, user_id, role, accepted')
|
||||
.in('conversation_id', convIds);
|
||||
if (aErr) throw aErr;
|
||||
|
||||
// 4. Profiles for ALL distinct member user ids (including self — the
|
||||
// member list in GroupInfoPanel needs our own display name too).
|
||||
const memberIdsAll = Array.from(new Set((allMembers ?? []).map((m) => m.user_id)));
|
||||
const profileMap = new Map<string, ProfileBrief>();
|
||||
if (memberIdsAll.length > 0) {
|
||||
const { data: profiles, error: pErr } = await client
|
||||
.from('profiles')
|
||||
.select(PROFILE_BRIEF_COLS)
|
||||
.in('user_id', memberIdsAll);
|
||||
if (pErr) throw pErr;
|
||||
for (const p of profiles ?? []) {
|
||||
const b = mapBrief(p);
|
||||
profileMap.set(b.userId, b);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Latest message per conversation
|
||||
const { data: latest, error: lErr } = await client
|
||||
.from('messages')
|
||||
.select('conversation_id, created_at')
|
||||
.in('conversation_id', convIds)
|
||||
.order('created_at', { ascending: false });
|
||||
if (lErr) throw lErr;
|
||||
const lastSeen = new Map<string, string>();
|
||||
for (const m of latest ?? []) {
|
||||
if (!lastSeen.has(m.conversation_id)) {
|
||||
lastSeen.set(m.conversation_id, m.created_at);
|
||||
}
|
||||
}
|
||||
|
||||
const myMap = new Map(myMembersList.map((m) => [m.conversation_id, m]));
|
||||
const memberMap = new Map<string, typeof allMembers>();
|
||||
for (const m of allMembers ?? []) {
|
||||
const list = memberMap.get(m.conversation_id) ?? [];
|
||||
list.push(m);
|
||||
memberMap.set(m.conversation_id, list);
|
||||
}
|
||||
|
||||
return (convs ?? []).map<ConversationSummary>((c) => {
|
||||
const mine = myMap.get(c.id);
|
||||
const members = (memberMap.get(c.id) ?? []).map((m) => ({
|
||||
userId: m.user_id,
|
||||
role: m.role,
|
||||
accepted: m.accepted,
|
||||
profile: profileMap.get(m.user_id) ?? null,
|
||||
}));
|
||||
const peer =
|
||||
c.type === 'dm'
|
||||
? (members.find((m) => m.userId !== myId)?.profile ?? null)
|
||||
: null;
|
||||
return {
|
||||
id: c.id,
|
||||
type: c.type,
|
||||
name: c.name,
|
||||
avatarUrl: c.avatar_url,
|
||||
createdAt: c.created_at,
|
||||
peer,
|
||||
acceptedByMe: mine?.accepted ?? false,
|
||||
myRole: mine?.role ?? 'member',
|
||||
members,
|
||||
lastMessageAt: lastSeen.get(c.id) ?? null,
|
||||
};
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user