import { groupService } from '../services/groupService'; import { CursorPaginationResponse, GroupMemberResponse } from '../types/dto'; export const GROUP_MEMBER_LIST_PAGE_SIZE = 50; export type GroupMemberListSourceKind = 'cursor' | 'offset'; export interface IGroupMemberListPagedSource { restart(): void; loadNext(): Promise>; readonly hasMore: boolean; } export class NetworkCursorGroupMemberListPagedSource implements IGroupMemberListPagedSource { private nextCursor: string | null = null; private hasMoreAfterLastLoad = false; private loadedOnce = false; private readonly groupId: string; private readonly pageSize: number; constructor(groupId: string, pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE) { this.groupId = groupId; this.pageSize = pageSize; } restart(): void { this.nextCursor = null; this.hasMoreAfterLastLoad = false; this.loadedOnce = false; } get hasMore(): boolean { return this.loadedOnce && this.hasMoreAfterLastLoad; } async loadNext(): Promise> { const response = await groupService.getGroupMembersCursor( this.groupId, this.nextCursor == null ? { page_size: this.pageSize } : { cursor: this.nextCursor, page_size: this.pageSize } ); this.nextCursor = response.next_cursor ?? null; this.hasMoreAfterLastLoad = Boolean(response.has_more && response.next_cursor != null); this.loadedOnce = true; return { list: response.list || [], next_cursor: response.next_cursor ?? null, prev_cursor: response.prev_cursor ?? null, has_more: response.has_more ?? false, }; } } export class NetworkOffsetGroupMemberListPagedSource implements IGroupMemberListPagedSource { private nextPage = 1; private hasMoreAfterLastLoad = false; private loadedOnce = false; private readonly groupId: string; private readonly pageSize: number; constructor(groupId: string, pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE) { this.groupId = groupId; this.pageSize = pageSize; } restart(): void { this.nextPage = 1; this.hasMoreAfterLastLoad = false; this.loadedOnce = false; } get hasMore(): boolean { return this.loadedOnce && this.hasMoreAfterLastLoad; } async loadNext(): Promise> { const response = await groupService.getMembers(this.groupId, this.nextPage, this.pageSize); const list = response.list || []; const currentPage = response.page ?? this.nextPage; const totalPages = response.total_pages ?? currentPage; const hasMore = currentPage < totalPages; const nextPageCursor = hasMore ? String(currentPage + 1) : null; const prevPageCursor = currentPage > 1 ? String(currentPage - 1) : null; this.nextPage = currentPage + 1; this.hasMoreAfterLastLoad = hasMore; this.loadedOnce = true; return { list, next_cursor: nextPageCursor, prev_cursor: prevPageCursor, has_more: hasMore, }; } } export function createRemoteGroupMemberListSource( kind: GroupMemberListSourceKind, groupId: string, pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE ): IGroupMemberListPagedSource { return kind === 'offset' ? new NetworkOffsetGroupMemberListPagedSource(groupId, pageSize) : new NetworkCursorGroupMemberListPagedSource(groupId, pageSize); }