Files
frontend/src/stores/groupMemberListSources.ts

111 lines
3.4 KiB
TypeScript
Raw Normal View History

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<CursorPaginationResponse<GroupMemberResponse>>;
readonly hasMore: boolean;
}
export class NetworkCursorGroupMemberListPagedSource implements IGroupMemberListPagedSource {
private nextCursor: string | null = null;
private hasMoreAfterLastLoad = false;
private loadedOnce = false;
private readonly groupId: number | string;
private readonly pageSize: number;
constructor(groupId: number | 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<CursorPaginationResponse<GroupMemberResponse>> {
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: number | string;
private readonly pageSize: number;
constructor(groupId: number | 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<CursorPaginationResponse<GroupMemberResponse>> {
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: number | string,
pageSize: number = GROUP_MEMBER_LIST_PAGE_SIZE
): IGroupMemberListPagedSource {
return kind === 'offset'
? new NetworkOffsetGroupMemberListPagedSource(groupId, pageSize)
: new NetworkCursorGroupMemberListPagedSource(groupId, pageSize);
}