feat(frontend): add createGroup API method and update AddDmMemberModal branching
- Add CreateGroupDmRequest to API client imports, type declaration, and implementation (POST /dm/group) - Update AddDmMemberModal to branch on channel type: 1-on-1 DMs call createGroup and navigate to new channel, group DMs call addMember directly - Remove legacy getApiForOrigin/channelOriginMap usage — S2S federation relay is now entirely server-side
This commit is contained in:
@@ -23,6 +23,7 @@ import type {
|
|||||||
UpdateMemberRequest,
|
UpdateMemberRequest,
|
||||||
LiveKitTokenResponse,
|
LiveKitTokenResponse,
|
||||||
CreateDmRequest,
|
CreateDmRequest,
|
||||||
|
CreateGroupDmRequest,
|
||||||
CreateDmMessageRequest,
|
CreateDmMessageRequest,
|
||||||
Friend,
|
Friend,
|
||||||
FriendRequest,
|
FriendRequest,
|
||||||
@@ -135,6 +136,7 @@ export class BackspaceApiClient {
|
|||||||
readonly dm: {
|
readonly dm: {
|
||||||
list: () => Promise<DmChannel[]>;
|
list: () => Promise<DmChannel[]>;
|
||||||
create: (data: CreateDmRequest) => Promise<DmChannel>;
|
create: (data: CreateDmRequest) => Promise<DmChannel>;
|
||||||
|
createGroup: (data: CreateGroupDmRequest) => Promise<DmChannel>;
|
||||||
close: (id: string) => Promise<{ success: boolean }>;
|
close: (id: string) => Promise<{ success: boolean }>;
|
||||||
messages: (id: string, before?: string, limit?: number) => Promise<DmMessageWithUser[]>;
|
messages: (id: string, before?: string, limit?: number) => Promise<DmMessageWithUser[]>;
|
||||||
messagesAround: (id: string, messageId: string) => Promise<DmMessageWithUser[]>;
|
messagesAround: (id: string, messageId: string) => Promise<DmMessageWithUser[]>;
|
||||||
@@ -480,6 +482,7 @@ export class BackspaceApiClient {
|
|||||||
this.dm = {
|
this.dm = {
|
||||||
list: () => request<DmChannel[]>('GET', '/dm'),
|
list: () => request<DmChannel[]>('GET', '/dm'),
|
||||||
create: (data: CreateDmRequest) => request<DmChannel>('POST', '/dm', data),
|
create: (data: CreateDmRequest) => request<DmChannel>('POST', '/dm', data),
|
||||||
|
createGroup: (data: CreateGroupDmRequest) => request<DmChannel>('POST', '/dm/group', data),
|
||||||
close: (id: string) => request<{ success: boolean }>('DELETE', `/dm/${id}`),
|
close: (id: string) => request<{ success: boolean }>('DELETE', `/dm/${id}`),
|
||||||
messages: (id: string, before?: string, limit = 50) => {
|
messages: (id: string, before?: string, limit = 50) => {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { Modal } from '../ui/Modal';
|
import { Modal } from '../ui/Modal';
|
||||||
import { Avatar } from '../ui/Avatar';
|
import { Avatar } from '../ui/Avatar';
|
||||||
import { useUIStore } from '../../stores/uiStore';
|
import { useUIStore } from '../../stores/uiStore';
|
||||||
import { useSpaceStore, getApiForOrigin } from '../../stores/spaceStore';
|
import { useSpaceStore } from '../../stores/spaceStore';
|
||||||
|
import { useAuthStore } from '../../stores/authStore';
|
||||||
import { api } from '../../api/client';
|
import { api } from '../../api/client';
|
||||||
import type { User } from '@backspace/shared';
|
import type { User } from '@backspace/shared';
|
||||||
|
|
||||||
@@ -16,7 +18,8 @@ export function AddDmMemberModal() {
|
|||||||
const modalData = useUIStore((s) => s.modalData);
|
const modalData = useUIStore((s) => s.modalData);
|
||||||
const closeModal = useUIStore((s) => s.closeModal);
|
const closeModal = useUIStore((s) => s.closeModal);
|
||||||
const dmChannels = useSpaceStore((s) => s.dmChannels);
|
const dmChannels = useSpaceStore((s) => s.dmChannels);
|
||||||
const channelOriginMap = useSpaceStore((s) => s.channelOriginMap);
|
const navigate = useNavigate();
|
||||||
|
const myUserId = useAuthStore((s) => s.user?.id);
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const searchTimer = useRef<ReturnType<typeof setTimeout>>();
|
const searchTimer = useRef<ReturnType<typeof setTimeout>>();
|
||||||
|
|
||||||
@@ -64,14 +67,24 @@ export function AddDmMemberModal() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectUser = async (user: User) => {
|
const handleSelectUser = async (user: User) => {
|
||||||
if (!dmChannelId || isAdding) return;
|
if (!dmChannelId || !dmChannel || isAdding) return;
|
||||||
setError('');
|
setError('');
|
||||||
setIsAdding(true);
|
setIsAdding(true);
|
||||||
try {
|
try {
|
||||||
const origin = channelOriginMap.get(dmChannelId) || '';
|
if (!dmChannel.ownerId) {
|
||||||
const targetApi = getApiForOrigin(origin);
|
// 1-on-1 DM → create a new group DM with all 3 users
|
||||||
await targetApi.dm.addMember(dmChannelId, { userId: user.id });
|
const otherMember = dmChannel.members.find(m => m.id !== myUserId);
|
||||||
|
if (!otherMember) return;
|
||||||
|
const newChannel = await api.dm.createGroup({ userIds: [otherMember.id, user.id] });
|
||||||
closeModal();
|
closeModal();
|
||||||
|
navigate(`/channels/@me/${newChannel.id}`);
|
||||||
|
} else {
|
||||||
|
// Group DM → add to existing group
|
||||||
|
// Always call the home instance — S2S federation handles relay.
|
||||||
|
// Only the owner can add members, and the owner is always on the home instance.
|
||||||
|
await api.dm.addMember(dmChannelId, { userId: user.id });
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError((err as Error).message || 'Failed to add member');
|
setError((err as Error).message || 'Failed to add member');
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user