Skip to content

Commit 9314ef7

Browse files
Matus Kasakclaude
andcommitted
ZCU-PUB/feat(community): show "Články" collection 3rd, after "Kapitoly v knihách" (#953)
Hardcode the display order for the ZCU publications community so that the "Články" collection appears in 3rd position, immediately after "Kapitoly v knihách", while all other collections keep their existing alphabetical order. Approach: the base sub-collection-list component gains a no-op `applyCustomCollectionOrder` seam applied to each fetched page, keeping behavior identical for every other theme/customer. The custom theme overrides it to pin the two named collections via a small, unit-tested pure `reorderCollections` helper. Assumption: only the "Články -> 3rd" constraint is encoded here; a full configurable custom ordering would be the separate Option B feature. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent a29ed78 commit 9314ef7

3 files changed

Lines changed: 165 additions & 2 deletions

File tree

src/app/community-page/sub-collection-list/community-page-sub-collection-list.component.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,24 @@ export class CommunityPageSubCollectionListComponent implements OnInit, OnDestro
8888
});
8989
})
9090
).subscribe((results) => {
91-
this.subCollectionsRDObs.next(results);
91+
this.subCollectionsRDObs.next(this.applyCustomCollectionOrder(results));
9292
}));
9393
}
9494

95+
/**
96+
* Extension point for theme/customer-specific ordering of the current page of collections.
97+
*
98+
* The default implementation is a no-op that returns the RemoteData unchanged, so behavior
99+
* stays identical for every theme and customer. Themes that need a bespoke display order
100+
* (e.g. a hardcoded pinned position for a specific collection) override this method.
101+
*
102+
* @param rd the RemoteData holding the current page of collections
103+
* @returns the RemoteData to emit, potentially with a reordered page
104+
*/
105+
protected applyCustomCollectionOrder(rd: RemoteData<PaginatedList<Collection>>): RemoteData<PaginatedList<Collection>> {
106+
return rd;
107+
}
108+
95109
ngOnDestroy(): void {
96110
this.paginationService.clearPagination(this.config?.id);
97111
this.subscriptions.map((subscription: Subscription) => subscription.unsubscribe());
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { Collection } from '../../../../../app/core/shared/collection.model';
2+
import { CommunityPageSubCollectionListComponent } from './community-page-sub-collection-list.component';
3+
4+
/**
5+
* Builds a minimal Collection-like stub that only exposes the `name` getter used by the
6+
* reordering logic under test.
7+
*
8+
* @param name the collection name (dc.title) to expose
9+
* @returns an object typed as Collection for the purposes of these tests
10+
*/
11+
function fakeCollection(name: string): Collection {
12+
return { get name(): string { return name; } } as Collection;
13+
}
14+
15+
/**
16+
* Maps a list of collections to their names for concise assertions.
17+
*
18+
* @param collections the collections to map
19+
* @returns the ordered list of collection names
20+
*/
21+
function names(collections: Collection[]): string[] {
22+
return collections.map((collection: Collection) => collection.name);
23+
}
24+
25+
const SECOND_COLLECTION_NAME = 'Kapitoly v knihách';
26+
const THIRD_COLLECTION_NAME = 'Články';
27+
28+
describe('CommunityPageSubCollectionListComponent (custom theme) reorderCollections', () => {
29+
let component: CommunityPageSubCollectionListComponent;
30+
31+
const reorder = (collections: Collection[]): Collection[] =>
32+
(component as any).reorderCollections(collections);
33+
34+
beforeEach(() => {
35+
component = new CommunityPageSubCollectionListComponent(null, null, null);
36+
});
37+
38+
it('pins "Články" to the 3rd position, directly after "Kapitoly v knihách"', () => {
39+
const input = [
40+
fakeCollection('Alfa'),
41+
fakeCollection(SECOND_COLLECTION_NAME),
42+
fakeCollection(THIRD_COLLECTION_NAME),
43+
fakeCollection('Zeta'),
44+
];
45+
46+
const result = reorder(input);
47+
48+
expect(names(result)).toEqual(['Alfa', SECOND_COLLECTION_NAME, THIRD_COLLECTION_NAME, 'Zeta']);
49+
expect(result[2].name).toBe(THIRD_COLLECTION_NAME);
50+
expect(result[1].name).toBe(SECOND_COLLECTION_NAME);
51+
expect(names(result).indexOf(THIRD_COLLECTION_NAME))
52+
.toBe(names(result).indexOf(SECOND_COLLECTION_NAME) + 1);
53+
});
54+
55+
it('leaves the list unchanged when "Kapitoly v knihách" is missing', () => {
56+
const input = [
57+
fakeCollection('Alfa'),
58+
fakeCollection(THIRD_COLLECTION_NAME),
59+
fakeCollection('Zeta'),
60+
];
61+
62+
expect(names(reorder(input))).toEqual(['Alfa', THIRD_COLLECTION_NAME, 'Zeta']);
63+
});
64+
65+
it('leaves the list unchanged when "Články" is missing', () => {
66+
const input = [
67+
fakeCollection('Alfa'),
68+
fakeCollection(SECOND_COLLECTION_NAME),
69+
fakeCollection('Zeta'),
70+
];
71+
72+
expect(names(reorder(input))).toEqual(['Alfa', SECOND_COLLECTION_NAME, 'Zeta']);
73+
});
74+
75+
it('leaves the list unchanged when there are no other collections', () => {
76+
const input = [
77+
fakeCollection(SECOND_COLLECTION_NAME),
78+
fakeCollection(THIRD_COLLECTION_NAME),
79+
];
80+
81+
expect(names(reorder(input))).toEqual([SECOND_COLLECTION_NAME, THIRD_COLLECTION_NAME]);
82+
});
83+
84+
it('uses the exact diacritic collection names', () => {
85+
expect(SECOND_COLLECTION_NAME).toBe('Kapitoly v knihách');
86+
expect(THIRD_COLLECTION_NAME).toBe('Články');
87+
88+
const input = [
89+
fakeCollection('Alfa'),
90+
fakeCollection('Kapitoly v knihach'),
91+
fakeCollection('Clanky'),
92+
fakeCollection('Zeta'),
93+
];
94+
95+
expect(names(reorder(input))).toEqual(['Alfa', 'Kapitoly v knihach', 'Clanky', 'Zeta']);
96+
});
97+
});
Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
import { Component } from '@angular/core';
22
import { CommunityPageSubCollectionListComponent as BaseComponent }
33
from '../../../../../app/community-page/sub-collection-list/community-page-sub-collection-list.component';
4+
import { RemoteData } from '../../../../../app/core/data/remote-data';
5+
import { PaginatedList } from '../../../../../app/core/data/paginated-list.model';
6+
import { Collection } from '../../../../../app/core/shared/collection.model';
7+
8+
/**
9+
* Name of the collection pinned to the 2nd position for the ZCU publications community.
10+
*/
11+
const SECOND_COLLECTION_NAME = 'Kapitoly v knihách';
12+
13+
/**
14+
* Name of the collection pinned to the 3rd position for the ZCU publications community.
15+
*/
16+
const THIRD_COLLECTION_NAME = 'Články';
417

518
@Component({
619
selector: 'ds-community-page-sub-collection-list',
@@ -9,4 +22,43 @@ import { CommunityPageSubCollectionListComponent as BaseComponent }
922
// templateUrl: './community-page-sub-collection-list.component.html',
1023
templateUrl: '../../../../../app/community-page/sub-collection-list/community-page-sub-collection-list.component.html'
1124
})
12-
export class CommunityPageSubCollectionListComponent extends BaseComponent {}
25+
export class CommunityPageSubCollectionListComponent extends BaseComponent {
26+
27+
/**
28+
* Reorders the current page of collections so that "Kapitoly v knihách" is shown 2nd and
29+
* "Články" 3rd, while all other collections keep their existing alphabetical order.
30+
*
31+
* @param rd the RemoteData holding the current page of collections
32+
* @returns the RemoteData with a reordered page, or unchanged when the page is empty
33+
*/
34+
protected applyCustomCollectionOrder(rd: RemoteData<PaginatedList<Collection>>): RemoteData<PaginatedList<Collection>> {
35+
const page = rd?.payload?.page;
36+
if (Array.isArray(page) && page.length > 0) {
37+
rd.payload.page = this.reorderCollections(page);
38+
}
39+
return rd;
40+
}
41+
42+
/**
43+
* Pure helper that reorders a list of collections to pin "Kapitoly v knihách" to the 2nd
44+
* position and "Články" to the 3rd, keeping every other collection in its original order.
45+
*
46+
* The rule only applies when both pinned collections are present and there is at least one
47+
* other collection; otherwise the list is returned unchanged. The result is
48+
* `[others[0], second, third, ...others.slice(1)]`.
49+
*
50+
* @param collections the collections of the current page (alphabetical by dc.title)
51+
* @returns a new, reordered array, or the original array when the rule does not apply
52+
*/
53+
protected reorderCollections(collections: Collection[]): Collection[] {
54+
const second = collections.find((collection: Collection) => collection.name === SECOND_COLLECTION_NAME);
55+
const third = collections.find((collection: Collection) => collection.name === THIRD_COLLECTION_NAME);
56+
const others = collections.filter((collection: Collection) => collection !== second && collection !== third);
57+
58+
if (second && third && others.length >= 1) {
59+
return [others[0], second, third, ...others.slice(1)];
60+
}
61+
return collections;
62+
}
63+
64+
}

0 commit comments

Comments
 (0)