amocrm-client
Version:
JS Library for AmoCRM
152 lines (136 loc) • 4.73 kB
text/typescript
import { IClientRequest } from "../common/ClientRequest";
import {
IEntityAttributes,
IPaginatedResponse,
IPaginationLinks, IResourceEntity, IResourceFactory,
IResourcePagination,
IResourcePaginationParams
} from "../interfaces/api";
import { ResourceCollection } from "./ResourceCollection";
/**
* Постраничная навигация вывода сущностей
* */
export default class ResourcePagination<T extends IResourceEntity<IResourceFactory<T>>> implements IResourcePagination<T> {
protected readonly request: IClientRequest;
protected readonly params: IResourcePaginationParams<T>;
protected data: T[] = [];
protected links: IPaginationLinks = {};
protected page = 1;
constructor(request: IClientRequest, params: IResourcePaginationParams<T>) {
this.request = request;
this.params = params;
}
/**
* Загружает данные первой страницы
* */
fetch() {
return this.fetchUrl(this.params.url);
}
/**
* Обновляет данные на текущей странице
* */
async refresh() {
if (!this.links.current) {
return false;
}
return await this.fetchUrl(this.links.current);
}
/**
* Делает запрос на получение данных по заданному адресу
* @param url адрес запроса
* */
protected async fetchUrl(url: string) {
const { criteria, options } = this.params;
const apiResponse = await this.request.get<IPaginatedResponse>(url, criteria, options);
const { data } = apiResponse;
this.page = data?._page || 1;
this.parseData(data);
this.parseLinks(data);
this.links.current = url;
return this.data;
}
/**
* @returns есть ли следующая страница
* */
hasNext() {
return this.links.next !== undefined;
}
/**
* @returns есть ли возможность загрузки первой страницы
* */
hasFirst() {
return this.links.first !== undefined;
}
/**
* @returns есть ли предыдущая страница
* */
hasPrev() {
return this.links.prev !== undefined;
}
/**
* Загружает данные следующей страницы, если это возможно
* */
async next() {
if (!this.hasNext()) {
return false;
}
return await this.fetchUrl(<string>this.links.next);
}
/**
* Загружает данные первой страницы, если это возможно
* */
async first() {
if (!this.hasFirst()) {
return false;
}
return await this.fetchUrl(<string>this.links.first);
}
/**
* Загружает данные предыдущей страницы, если это возможно
* */
async prev() {
if (!this.hasPrev()) {
return false;
}
return await this.fetchUrl(<string>this.links.prev);
}
/**
* Обрабатывает объект ссылок на первую, предыдущую и следущие страницы
* */
protected parseLinks(response?: IPaginatedResponse) {
const links = response?._links || {};
this.links = {
next: links.next?.href,
prev: links.prev?.href,
first: links.first?.href
};
return this;
}
/**
* Преобразовывает массив атрибутов сущностей в объекты-сущностей
* */
protected parseData(response?: IPaginatedResponse) {
const { embedded, factory } = this.params;
if (response && !response._embedded) return [];
const data: IEntityAttributes[] | undefined = <IEntityAttributes[] | undefined>response?._embedded[embedded!] || [];
if (!Array.isArray(data)) {
return;
}
this.data = data.map(attributes => {
return factory.from(attributes);
});
return this;
}
/**
* Возвращает номер текущей страницы
* */
getPage() {
return this.page;
}
/**
* Возвращает массив сущностей на текущей странице
* */
getData() {
return new ResourceCollection(this.data);
}
}