superdesk/superdesk-client-core

View on GitHub
scripts/core/helpers/generic-array-list-page-component.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
import React from 'react';
import {
    ICrudManagerFilters,
    ICrudManagerMethods,
    ISortOption,
    ICrudManagerData,
    IPropsGenericArrayListPage,
} from 'superdesk-api';
import {GenericListPageComponent} from 'core/ui/components/ListPage/generic-list-page';
import {omit} from 'lodash';
import {gettext} from 'core/utils';

interface IState {
    activeSortOption: ISortOption;
    activeFilters: {};
}

function computeMeta(items) {
    const itemsCount = items.length;

    return {
        total: itemsCount,
        max_results: itemsCount,
        page: 1,
    };
}

function getItemsWithMeta(_items) {
    return {
        _items: _items,
        _meta: computeMeta(_items),
    };
}

export class GenericArrayListPageComponent<T, P>
    extends React.Component<IPropsGenericArrayListPage<T, P>, IState>
    implements ICrudManagerMethods<T> {
    constructor(props: IPropsGenericArrayListPage<T, P>) {
        super(props);

        this.state = {
            activeSortOption: props.defaultSortOption,
            activeFilters: {},
        };

        this.create = this.create.bind(this);
        this.read = this.read.bind(this);
        this.update = this.update.bind(this);
        this.delete = this.delete.bind(this);
        this.refresh = this.refresh.bind(this);
        this.sort = this.sort.bind(this);
        this.removeFilter = this.removeFilter.bind(this);
        this.goToPage = this.goToPage.bind(this);

        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(value: Array<T>) {
        this.props.onChange(value);
    }

    create(item: T): Promise<T> {
        const i = this.props.newItemIndex ?? this.props.value.length;

        const result: Array<T> = [
            ...this.props.value.slice(0, i),
            item,
            ...this.props.value.slice(i),
        ];

        return new Promise((resolve) => {
            resolve(item);

            setTimeout(() => {
                this.handleChange(result);
            });
        });
    }

    read(
        page: number,
        sort: ISortOption,
        filterValues?: ICrudManagerFilters,
    ): Promise<ICrudManagerData<T>> {
        return Promise.resolve(getItemsWithMeta(this.props.value));
    }

    update(_item: T, nextItem: T): Promise<T> {
        this.handleChange(this.props.value.map(
            (item) => this.props.getId(item) === this.props.getId(nextItem) ? nextItem : item),
        );

        return Promise.resolve(nextItem);
    }

    delete(item: T): Promise<void> {
        this.handleChange(this.props.value.filter((current) => this.props.getId(current) !== this.props.getId(item)));

        return Promise.resolve();
    }

    refresh(): Promise<ICrudManagerData<T>> {
        return Promise.resolve(getItemsWithMeta(this.props.value));
    }

    sort(sortOption: ISortOption): Promise<ICrudManagerData<T>> {
        return Promise.resolve(getItemsWithMeta(this.props.value));
    }

    removeFilter(fieldName: string): Promise<ICrudManagerData<T>> {
        let nextFilters = {...this.state.activeFilters};

        delete nextFilters[fieldName];

        return this.read(1, this.state.activeSortOption, nextFilters);
    }

    goToPage(nextPage: number) {
        return this.read(nextPage, this.props.defaultSortOption, this.state.activeFilters);
    }

    render() {
        return (
            <GenericListPageComponent
                {...omit(this.props, ['value', 'onChange', 'newItemIndex'])} // omit own props
                labelForItemSaveButton={gettext('Apply')}
                crudManager={{
                    read: this.read,
                    update: this.update,
                    create: this.create,
                    delete: this.delete,
                    refresh: this.refresh,
                    sort: this.sort,
                    removeFilter: this.removeFilter,
                    goToPage: this.goToPage,
                    activeFilters: {},
                    activeSortOption: this.props.defaultSortOption,
                    _items: this.props.value,
                    _meta: computeMeta(this.props.value),
                }}
            />
        );
    }
}