Skip to content

Commit 2dbffbe

Browse files
authored
feat: add search functionality (#46)
1 parent 1b22eae commit 2dbffbe

2 files changed

Lines changed: 39 additions & 1 deletion

File tree

src/app/home/course/course.page.html

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,19 @@
101101
}
102102
</ion-col>
103103
<ion-col size="12" size-lg [ngClass]="currentVideo ? 'scroll-area' : ''">
104-
@if (list$ | async; as list) {
104+
<ion-searchbar
105+
(ionInput)="onSearchChange($event)"
106+
placeholder="Search videos by title or lecturer..."
107+
debounce="300">
108+
</ion-searchbar>
109+
@if (filteredList$ | async; as list) {
110+
@if (list.length === 0 && searchQuery) {
111+
<ion-card>
112+
<ion-card-content>
113+
No videos found matching "{{ searchQuery }}"
114+
</ion-card-content>
115+
</ion-card>
116+
}
105117
<ion-list>
106118
@for (lecture of list; track lecture.id) {
107119
<ion-item button (click)="viewVideo(lecture)"

src/app/home/course/course.page.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
IonListHeader,
2626
IonProgressBar,
2727
IonRow,
28+
IonSearchbar,
2829
IonText,
2930
IonTitle,
3031
IonToolbar,
@@ -63,6 +64,7 @@ import {ModalEvaluationComponent} from './modal-evaluation.component';
6364
IonLabel,
6465
IonItem,
6566
IonIcon,
67+
IonSearchbar,
6668
NgClass,
6769
IonProgressBar,
6870
AsyncPipe,
@@ -78,10 +80,13 @@ export class CoursePage implements OnInit, AfterViewInit, OnDestroy {
7880
course: string;
7981
courseId?: string;
8082
list$: Observable<Lecture[]>;
83+
filteredList$: Observable<Lecture[]>;
8184
courseProgress = {
8285
viewed: 0,
8386
duration: 0
8487
};
88+
searchQuery = '';
89+
searchQuery$ = new Subject<string>();
8590
isAndroid = /Android/i.test(navigator.userAgent);
8691
isIos = /iPad/i.test(navigator.userAgent) || /iPhone/i.test(navigator.userAgent);
8792
lastPlayedVideoKey: number = null;
@@ -128,6 +133,10 @@ export class CoursePage implements OnInit, AfterViewInit, OnDestroy {
128133
return EMPTY;
129134
})
130135
);
136+
137+
this.filteredList$ = combineLatest([this.list$, this.searchQuery$.pipe(startWith(''))]).pipe(
138+
map(([videos, query]) => this.filterVideos(videos, query))
139+
);
131140
}
132141

133142
ngAfterViewInit() {
@@ -276,6 +285,23 @@ export class CoursePage implements OnInit, AfterViewInit, OnDestroy {
276285
: videoInfo;
277286
}
278287

288+
filterVideos(videos: Lecture[], query: string): Lecture[] {
289+
if (!query.trim()) {
290+
return videos;
291+
}
292+
293+
const lowerQuery = query.toLowerCase();
294+
return videos.filter(video =>
295+
video.title.toLowerCase().includes(lowerQuery) ||
296+
(video.lecturer && video.lecturer.toLowerCase().includes(lowerQuery))
297+
);
298+
}
299+
300+
onSearchChange(event: any) {
301+
this.searchQuery = event.detail.value ?? '';
302+
this.searchQuery$.next(this.searchQuery);
303+
}
304+
279305
viewVideo(video: Lecture) {
280306
video.sources = video.sources.filter(source => {
281307
if (source.type === 'video/youtube') {

0 commit comments

Comments
 (0)