feat(dm): read-only composer notice for Deleted-User 1-on-1 threads (C2)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { formatDmTimestamp, formatDmPreview, formatDmSidebarPreview, formatDmHeaderName, formatDmInputLabel } from './dmFormatters';
|
||||
import { formatDmTimestamp, formatDmPreview, formatDmSidebarPreview, formatDmHeaderName, formatDmInputLabel, isDeletedPartnerDm } from './dmFormatters';
|
||||
import type { DmChannel, DmLastMessagePreview, User } from '@backspace/shared';
|
||||
|
||||
/** Build a local-time Date: new Date(year, month-1, day, hour, minute) as a timestamp. */
|
||||
@@ -417,3 +417,19 @@ describe('formatDmSidebarPreview — icon_changed system message', () => {
|
||||
expect(formatDmSidebarPreview(dm, { id: 'OTHER', username: 'other' })).toBe('Unknown updated the group icon');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isDeletedPartnerDm', () => {
|
||||
const me = { id: 'me', username: 'me' } as User;
|
||||
it('true for a 1-on-1 whose only other member is deleted', () => {
|
||||
const dm = { ownerId: null, members: [me, { id: 'x', username: 'Deleted User', isDeleted: true } as User] };
|
||||
expect(isDeletedPartnerDm(dm as any, me)).toBe(true);
|
||||
});
|
||||
it('false for a live partner', () => {
|
||||
const dm = { ownerId: null, members: [me, { id: 'x', username: 'p', isDeleted: false } as User] };
|
||||
expect(isDeletedPartnerDm(dm as any, me)).toBe(false);
|
||||
});
|
||||
it('false for a group even with a deleted member', () => {
|
||||
const dm = { ownerId: 'me', members: [me, { id: 'x', isDeleted: true } as User] };
|
||||
expect(isDeletedPartnerDm(dm as any, me)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -314,3 +314,14 @@ export function formatDmInputLabel(dm: DmChannel, currentUser: AuthLike): string
|
||||
if (!partner) return '@unknown';
|
||||
return `@${memberDisplayName(partner) || 'unknown'}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* True when `dm` is a 1-on-1 whose only other participant(s) are tombstoned.
|
||||
* Drives the read-only composer — you cannot message a deleted user.
|
||||
*/
|
||||
export function isDeletedPartnerDm(dm: Pick<DmChannel, 'ownerId' | 'members'>, currentUser: AuthLike): boolean {
|
||||
if (dm.ownerId) return false; // group
|
||||
const others = dm.members.filter(m => !isSelf(m, currentUser));
|
||||
if (others.length === 0) return false;
|
||||
return others.every(m => m.isDeleted === true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user