feat: add sorting button for VOD and series

This commit is contained in:
Serkan committed 2024-09-29 05:12:34 +03:00
1 parent 35d83149eb
commit 81cbc1e5d6
10 files changed
+111 -15

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
import { Injectable, Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'sortBy',
standalone: true,
})
@Injectable()
export class SortPipe implements PipeTransform {
transform(array: any[], sortType: string): any {
if (!array || !sortType) {
return array;
}
return array.sort((a, b) => {
if (sortType === 'date') {
return parseInt(b.added) - parseInt(a.added);
} else if (sortType === 'rating') {
const ratingA = isNaN(parseFloat(a.rating)) ? 0 : parseFloat(a.rating);
const ratingB = isNaN(parseFloat(b.rating)) ? 0 : parseFloat(b.rating);
return ratingB - ratingA;
} else if (sortType === 'alpha') {
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
} else {
return 0;
}
});
}
}
@@ -1,6 +1,6 @@
@if (items?.length > 0) {
<div class="grid">
@for (item of items | filterBy: searchPhrase() : 'name'; track $index) {
@for (item of items | filterBy: searchPhrase() : 'name' | sortBy: sortType(); track $index) {
<mat-card (click)="itemClicked.emit(item)">
<mat-card-content>
@if (item.stream_icon || item.cover || item.logo) {
@@ -6,6 +6,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { XtreamItem } from '../../../../shared/xtream-item.interface';
import { FilterPipe } from '../../shared/pipes/filter.pipe';
import { SortPipe } from '../../shared/pipes/sort.pipe';
import { PlaylistErrorViewComponent } from '../playlist-error-view/playlist-error-view.component';
import { PortalStore } from '../portal.store';
@@ -16,6 +17,7 @@ import { PortalStore } from '../portal.store';
standalone: true,
imports: [
FilterPipe,
SortPipe,
MatCardModule,
MatIconModule,
MatTooltipModule,
@@ -30,4 +32,5 @@ export class CategoryContentViewComponent {
portalStore = inject(PortalStore);
searchPhrase = this.portalStore.searchPhrase;
sortType = this.portalStore.sortType;
}
@@ -50,16 +50,46 @@
>
</div>
</div>
<div class="search" *ngIf="searchVisible">
<mat-form-field class="search-input">
<mat-icon matPrefix>search</mat-icon>
<input
matInput
placeholder="Search by name"
type="search"
[ngModel]="searchPhrase()"
(ngModelChange)="searchPhraseUpdate.next($event)"
/>
</mat-form-field>
<div class="search-container">
<div class="sort" *ngIf="sortVisible">
<button
mat-icon-button
[matTooltip]="'CHANNELS.SORT_BY' | translate"
[matMenuTriggerFor]="sortPlaylistMenu"
data-test-id="sort-playlist"
>
<mat-icon>sort</mat-icon>
</button>
</div>
<div class="search" *ngIf="searchVisible">
<mat-form-field class="search-input">
<mat-icon matPrefix>search</mat-icon>
<input
matInput
placeholder="Search by name"
type="search"
[ngModel]="searchPhrase()"
(ngModelChange)="searchPhraseUpdate.next($event)"
/>
</mat-form-field>
</div>
</div>
<mat-menu #sortPlaylistMenu="matMenu">
<section
(click)="$event.stopPropagation()"
>
<button mat-menu-item (click)="setSortType('date')">
<mat-icon>calendar_today</mat-icon>
<span>{{ 'CHANNELS.SORT_BY_DATE' | translate }}</span>
</button>
<button mat-menu-item (click)="setSortType('rating')">
<mat-icon>star</mat-icon>
<span>{{ 'CHANNELS.SORT_BY_RATING' | translate }}</span>
</button>
<button mat-menu-item (click)="setSortType('alpha')">
<mat-icon>sort_by_alpha</mat-icon>
<span>{{ 'CHANNELS.SORT_BY_NAME' | translate }}</span>
</button>
</section>
</mat-menu>
</div>
@@ -40,6 +40,10 @@
}
}
.search-container {
display: flex;
}
.search {
text-align: center;
}
@@ -17,6 +17,9 @@ import { Breadcrumb } from '../breadcrumb.interface';
import { ContentTypeNavigationItem } from '../content-type-navigation-item.interface';
import { ContentType } from '../content-type.enum';
import { PortalStore } from '../portal.store';
import { MatMenuModule } from '@angular/material/menu';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatTooltipModule } from '@angular/material/tooltip';
@Component({
selector: 'app-navigation-bar',
@@ -34,12 +37,16 @@ import { PortalStore } from '../portal.store';
NgIf,
RouterLink,
TranslateModule,
MatMenuModule,
MatCheckboxModule,
MatTooltipModule
],
})
export class NavigationBarComponent {
@Input({ required: true }) breadcrumbs: Breadcrumb[];
@Input({ required: true }) contentType: ContentType;
@Input() searchVisible = true;
@Input() sortVisible = false;
@Input() contentTypeNavigationItems: ContentTypeNavigationItem[];
@Input() clientSideSearch = true;
@Input() showCategories = false;
@@ -56,6 +63,7 @@ export class NavigationBarComponent {
searchPhrase = this.portalStore.searchPhrase;
searchPhraseUpdate = new Subject<string>();
currentPlaylist = this.store.selectSignal(selectCurrentPlaylist);
sortType = this.portalStore.sortType;
constructor() {
this.searchPhraseUpdate
@@ -76,6 +84,10 @@ export class NavigationBarComponent {
this.breadcrumbClicked.emit(item);
}
setSortType(type: string) {
this.portalStore.setSortType(type);
}
setSearchText(text: string) {
if (this.clientSideSearch) this.portalStore.setSearchPhrase(text);
else this.searchTextChanged.emit(text);
+12 -1
View File
@@ -7,6 +7,7 @@ export interface PortalState {
hideExternalInfoDialog: boolean;
currentVod: any;
currentSerial: any;
sortType: string;
}
@Injectable({ providedIn: 'root' })
@@ -19,6 +20,7 @@ export class PortalStore extends ComponentStore<PortalState> {
content: [],
hideExternalInfoDialog:
localStorage.getItem('hideExternalInfoDialog') === 'true',
sortType: undefined
});
}
@@ -26,11 +28,13 @@ export class PortalStore extends ComponentStore<PortalState> {
readonly searchPhrase = this.selectSignal((state) => state.searchPhrase);
readonly currentSerial = this.selectSignal((state) => state.currentSerial);
readonly currentVod = this.selectSignal((state) => state.currentVod);
readonly hideExternalInfoDialog = this.selectSignal(
(state) => state.hideExternalInfoDialog
);
readonly sortType = this.selectSignal((state) => state.sortType);
readonly getContentById = (id: string) =>
this.selectSignal((state) => state.content.find((i) => i.id === id));
@@ -72,4 +76,11 @@ export class PortalStore extends ComponentStore<PortalState> {
return { ...state, hideExternalInfoDialog };
}
);
readonly setSortType = this.updater(
(state, sortType: string): PortalState => ({
...state,
sortType,
})
);
}
@@ -9,6 +9,7 @@
[searchVisible]="
currentLayout === 'category' || currentLayout === 'category_content'
"
[sortVisible]="currentLayout === 'category_content'"
[contentTypeNavigationItems]="navigationContentTypes"
/>
+5 -1
View File
@@ -155,7 +155,11 @@
"NO_FAVORITES": "No favorites yet",
"USE_STAR_TO_FAVORITE": "Please use 'star' icon to add channels to your favorites.",
"REMOVE_FAVORITE": "Remove from favorites",
"FAVORITES_UPDATED": "Favorites were updated!"
"FAVORITES_UPDATED": "Favorites were updated!",
"SORT_BY": "Sort by",
"SORT_BY_DATE": "Sort by Date Added (Newest First)",
"SORT_BY_RATING": "Sort by Rating",
"SORT_BY_NAME": "Sort by Name (A-Z)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Open channel list",
+5 -1
View File
@@ -155,7 +155,11 @@
"NO_FAVORITES": "Henüz favori yok",
"USE_STAR_TO_FAVORITE": "Kanalları favorilerinize eklemek için lütfen 'yıldız' simgesini kullanın.",
"REMOVE_FAVORITE": "Favorilerden Kaldır",
"FAVORITES_UPDATED": "Favoriler güncellendi!"
"FAVORITES_UPDATED": "Favoriler güncellendi!",
"SORT_BY": "Sırala",
"SORT_BY_DATE": "Eklenme Tarihine Göre Sırala (Önce En Yeni)",
"SORT_BY_RATING": "Puana Göre Sırala",
"SORT_BY_NAME": "İsmine Göre Sırala (A-Z)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Kanal listesini aç",