[AAE-6376] Adding Sort by Category service (#7502)

* [AAE-6376] Adding Sort by Category service

* indentation fix

* fix

* fix

* indentation fix

* fix CR

* fix lint

* missing semicolon

* fix name

* fix CR and added unit tests

* small fix
This commit is contained in:
Ketevani Kvirikashvili 2022-02-18 19:45:21 +02:00 committed by GitHub
parent 6ccc39d0f4
commit 0365143e33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 215 additions and 0 deletions

View File

@ -68,3 +68,4 @@ export * from './language.service';
export * from './identity-user.service.interface';
export * from './identity-group.interface';
export * from './language-item.interface';
export * from './sort-by-category.service';

View File

@ -0,0 +1,111 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { SortableByCategoryItem, SortByCategoryMapperService } from './sort-by-category.service';
interface TestSortableByCategoryItem extends SortableByCategoryItem {
id: string;
}
describe('SortByCategoryMapperService', () => {
let mapper: SortByCategoryMapperService<TestSortableByCategoryItem>;
const DEFAULT_CATEGORIES = [
'',
'DefaultCategory1',
'DefaultCategory2',
'DefaultCategory3'
];
beforeEach(() => {
mapper = new SortByCategoryMapperService();
});
it('should map items by categories', () => {
const items: TestSortableByCategoryItem[] = [
{ id: 'id1', name: 'firstCategory_222', category: 'category1' },
{ id: 'id2', name: 'secondCategory_AA', category: 'category2' },
{ id: 'id3', name: 'firstCategory_111', category: 'category1' },
{ id: 'id4', name: 'secondCategory_BB', category: 'category2' },
{ id: 'id5', name: 'Default_a', category: DEFAULT_CATEGORIES[1] },
{ id: 'id6', name: 'Default_b', category: DEFAULT_CATEGORIES[0] }
];
const expectedItemsByCategory = [
{ category: 'category1', items: [items[2], items[0]] },
{ category: 'category2', items: [items[1], items[3]] },
{ category: '', items: [items[4], items[5]] }
];
const result = mapper.mapItems(items, DEFAULT_CATEGORIES);
expect(result).toEqual(expectedItemsByCategory);
});
it('should set all items under default category', () => {
const defaulValues: TestSortableByCategoryItem[] = [{
name: 'name-a',
id: 'id',
category: DEFAULT_CATEGORIES[1]
}, {
name: 'name-b',
id: 'id2',
category: DEFAULT_CATEGORIES[2]
}, {
name: 'name-c',
id: 'id3',
category: DEFAULT_CATEGORIES[0]
}];
const result = mapper.mapItems(defaulValues, DEFAULT_CATEGORIES);
expect(result.length).toBe(1);
expect(result[0].category).toBe('');
expect(result[0].items.length).toBe(defaulValues.length);
});
it('should work if no items are present', () => {
const result = mapper.mapItems([], DEFAULT_CATEGORIES);
expect(result.length).toBe(0);
});
it('should work if the default categories are empty', () => {
const result = mapper.mapItems([{id: 'id', name: 'name', category: ''}], []);
expect(result.length).toBe(1);
expect(result[0].category).toBe('');
});
it('should set items in ascending order in appropriate category', () => {
const contents = [
{ id: 'id1', name: 'item-b', category: 'cat1' },
{ id: 'id2', name: 'item2', category: 'cat2' },
{ id: 'id3', name: 'item-a', category: 'cat1' }
];
const result = mapper.mapItems(contents, DEFAULT_CATEGORIES);
expect(result.length).toBe(2);
expect(result[0].category).toBe('cat1');
expect(result[0].items[0]).toEqual({ id: 'id3', name: 'item-a', category: 'cat1' });
expect(result[0].items[1]).toEqual({ id: 'id1', name: 'item-b', category: 'cat1' });
expect(result[1].category).toBe('cat2');
expect(result[1].items[0]).toEqual({ id: 'id2', name: 'item2', category: 'cat2' });
});
});

View File

@ -0,0 +1,103 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Injectable } from '@angular/core';
export interface SortableByCategoryItem {
name: string;
category?: string;
}
export interface ItemsByCategory<T> {
category: string;
items: T[];
}
@Injectable({
providedIn: 'root'
})
export class SortByCategoryMapperService<T extends SortableByCategoryItem = SortableByCategoryItem> {
private defaultCategories: string[] = [];
mapItems(items: T[], defaultCategories: string[]): ItemsByCategory<T>[] {
this.defaultCategories = defaultCategories;
const sortedItems = this.sortItems(items);
const itemsByCategory = this.mapItemsByCategory(sortedItems);
const itemsSortedByCategory = this.sortCategories(itemsByCategory);
return itemsSortedByCategory;
}
private mapItemsByCategory(items: T[]): ItemsByCategory<T>[] {
const itemsByCategoryObject: { [category: string]: T[] } = {};
items.forEach((item) => {
const category = this.mapItemDefaultCategory(item);
if (!itemsByCategoryObject[category]) {
itemsByCategoryObject[category] = [];
}
itemsByCategoryObject[category].push(item);
});
const itemsByCategory: ItemsByCategory<T>[] = Object.keys(itemsByCategoryObject).map((key) => {
const category = key;
return { category, items: itemsByCategoryObject[category] };
});
return itemsByCategory;
}
private sortItems(items: T[]): T[] {
return items.sort((itemA, itemB) => itemA.name.localeCompare(itemB.name));
}
private sortCategories(itemsByCategory: ItemsByCategory<T>[]): ItemsByCategory<T>[] {
return itemsByCategory.sort((itemA, itemB) => {
if (itemB.category === '' && itemA.category === '') {
return 0;
}
if (itemA.category === '') {
return 1;
}
if (itemB.category === '') {
return -1;
}
return itemA.category.localeCompare(itemB.category);
}
);
}
private mapItemDefaultCategory(listItem: SortableByCategoryItem): string {
const itemCategory = listItem.category;
if (!this.isDefaultCategory(itemCategory)) {
return (itemCategory ?? '');
}
return '';
}
private isDefaultCategory(category?: string): boolean {
return category ? this.defaultCategories.includes(category) : false;
}
}