diff --git a/src/app/app-module.ts b/src/app/app-module.ts
index ec14d8c..970fd36 100644
--- a/src/app/app-module.ts
+++ b/src/app/app-module.ts
@@ -1,9 +1,10 @@
import { CommonModule } from '@angular/common';
import { NgModule, provideBrowserGlobalErrorListeners } from '@angular/core';
-import { FormsModule } from '@angular/forms';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
+
import { AppRoutingModule } from './app-routing-module';
import { App } from './app';
@@ -12,7 +13,11 @@ import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSnackBarModule } from '@angular/material/snack-bar';
-
+import { MatAutocompleteModule } from '@angular/material/autocomplete';
+import { MatInputModule } from '@angular/material/input';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatIconButton } from '@angular/material/button';
+import { MatDividerModule } from '@angular/material/divider';
import { HeaderComponent } from './header/header.component';
import { HomeComponent } from './home/home.component';
@@ -34,8 +39,10 @@ import { Header2Component } from './header-2/header-2.component';
import { TheaterOverlayComponent } from './theater-overlay/theater-overlay.component';
import { SeatComponent } from './seat/seat.component';
import { SeatRowComponent } from './seat-row/seat-row.component';
-import {MatIconButton} from '@angular/material/button';
import { TheaterLayoutComponent } from './theater-layout/theater-layout.component';
+import { MovieSearchComponent } from './movie-search/movie-search.component';
+import { ScheduleHeaderComponent } from './schedule-header/schedule-header.component';
+import { MovieScheduleNoSearchResultComponent } from './movie-schedule-no-search-result/movie-schedule-no-search-result.component';
@NgModule({
@@ -60,11 +67,15 @@ import { TheaterLayoutComponent } from './theater-layout/theater-layout.componen
TheaterOverlayComponent,
SeatComponent,
SeatRowComponent,
- TheaterLayoutComponent
+ TheaterLayoutComponent,
+ MovieSearchComponent,
+ ScheduleHeaderComponent,
+ MovieScheduleNoSearchResultComponent
],
imports: [
AppRoutingModule,
BrowserModule,
+ ReactiveFormsModule,
CommonModule,
FormsModule,
MatIconModule,
@@ -72,7 +83,11 @@ import { TheaterLayoutComponent } from './theater-layout/theater-layout.componen
MatToolbarModule,
MatProgressBarModule,
MatSnackBarModule,
- MatIconButton
+ MatAutocompleteModule,
+ MatInputModule,
+ MatFormFieldModule,
+ MatIconButton,
+ MatDividerModule
],
providers: [
provideBrowserGlobalErrorListeners(),
diff --git a/src/app/header-2/header-2.component.html b/src/app/header-2/header-2.component.html
index 9545660..ce95d56 100644
--- a/src/app/header-2/header-2.component.html
+++ b/src/app/header-2/header-2.component.html
@@ -6,7 +6,7 @@
-
+
Absolut war gestern, Bewegung ist heute!
diff --git a/src/app/http.service.ts b/src/app/http.service.ts
index 5efe788..2429917 100644
--- a/src/app/http.service.ts
+++ b/src/app/http.service.ts
@@ -1,4 +1,4 @@
-import {Kinosaal, Sitzplatz, Vorstellung} from '@infinimotion/model-frontend';
+import { Kinosaal, Sitzplatz, Vorstellung, Film } from '@infinimotion/model-frontend';
import { HttpClient } from "@angular/common/http";
import { inject, Injectable } from "@angular/core";
import { Observable } from "rxjs";
@@ -51,6 +51,11 @@ export class HttpService {
return this.http.get(`${this.baseUrl}vorstellung/${id}`);
}
+ /* POST /api/vorstellung/filter */
+ getPerformaceByFilter(filter: string[]): Observable {
+ return this.http.post(`${this.baseUrl}vorstellung/filter`, filter);
+ }
+
/* POST /api/vorstellung */
addPerformace(vorstellung: Omit): Observable {
return this.http.post(`${this.baseUrl}vorstellung`, vorstellung);
@@ -67,6 +72,13 @@ export class HttpService {
}
+ /* Film APIs */
+
+ /* GET /api/film */
+ getMovies(): Observable {
+ return this.http.get(`${this.baseUrl}film`);
+ }
+
/* Show-Seats APIs*/
diff --git a/src/app/movie-schedule-no-search-result/movie-schedule-no-search-result.component.css b/src/app/movie-schedule-no-search-result/movie-schedule-no-search-result.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/movie-schedule-no-search-result/movie-schedule-no-search-result.component.html b/src/app/movie-schedule-no-search-result/movie-schedule-no-search-result.component.html
new file mode 100644
index 0000000..5685ffe
--- /dev/null
+++ b/src/app/movie-schedule-no-search-result/movie-schedule-no-search-result.component.html
@@ -0,0 +1,5 @@
+
+
search_off
+
Keine Vorstellungen gefunden
+
Für '{{ search() }}' finden am {{ date().toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric'} )}} kein Vorstellunge statt.
+
diff --git a/src/app/movie-schedule-no-search-result/movie-schedule-no-search-result.component.ts b/src/app/movie-schedule-no-search-result/movie-schedule-no-search-result.component.ts
new file mode 100644
index 0000000..4c91a0b
--- /dev/null
+++ b/src/app/movie-schedule-no-search-result/movie-schedule-no-search-result.component.ts
@@ -0,0 +1,12 @@
+import { Component, input } from '@angular/core';
+
+@Component({
+ selector: 'app-movie-schedule-no-search-result',
+ standalone: false,
+ templateUrl: './movie-schedule-no-search-result.component.html',
+ styleUrl: './movie-schedule-no-search-result.component.css'
+})
+export class MovieScheduleNoSearchResultComponent {
+ search = input.required();
+ date = input.required();
+}
diff --git a/src/app/movie-search/movie-search.component.css b/src/app/movie-search/movie-search.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/movie-search/movie-search.component.html b/src/app/movie-search/movie-search.component.html
new file mode 100644
index 0000000..add7471
--- /dev/null
+++ b/src/app/movie-search/movie-search.component.html
@@ -0,0 +1,16 @@
+
diff --git a/src/app/movie-search/movie-search.component.ts b/src/app/movie-search/movie-search.component.ts
new file mode 100644
index 0000000..ad27356
--- /dev/null
+++ b/src/app/movie-search/movie-search.component.ts
@@ -0,0 +1,62 @@
+import { Component, inject, OnInit, output, ViewEncapsulation } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { Observable, of } from 'rxjs';
+import { catchError, map, startWith, tap } from 'rxjs/operators';
+import { HttpService } from '../http.service';
+
+@Component({
+ selector: 'app-movie-search',
+ standalone: false,
+ templateUrl: './movie-search.component.html',
+ styleUrl: './movie-search.component.css',
+ encapsulation: ViewEncapsulation.None
+})
+export class MovieSearchComponent implements OnInit {
+
+ movieSearchResult = output();
+
+ options: string[] = [];
+ filteredOptions: Observable = new Observable();
+
+ searchControl = new FormControl('', (control) => {
+ if (!control.value) return null;
+
+ const value = control.value.toLowerCase();
+ const found = this.options.some(option =>
+ option.toLowerCase().includes(value)
+ );
+ return found ? null : { filmNotFound: true };
+ });
+
+ private http = inject(HttpService)
+
+ ngOnInit() {
+ this.loadMovies();
+ this.filteredOptions = this.searchControl.valueChanges.pipe(
+ startWith(''),
+ tap(value => this.movieSearchResult.emit(value || '')),
+ map(value => this._filter(value || ''))
+ );
+ }
+
+ private _filter(value: string): string[] {
+ const filterValue = value.toLowerCase();
+ return this.options.filter(option =>
+ option.toLowerCase().includes(filterValue)
+ );
+ }
+
+ private loadMovies() {
+ this.http.getMovies().pipe(
+ tap(movies => {
+ this.options = movies
+ .map(movie => movie.title)
+ .sort();
+ }),
+ catchError(err => {
+ console.error('Fehler beim Laden der Filme', err);
+ return of([]);
+ })
+ ).subscribe();
+ }
+}
diff --git a/src/app/navbar/navbar.component.css b/src/app/navbar/navbar.component.css
index 27299ec..7d41e7d 100644
--- a/src/app/navbar/navbar.component.css
+++ b/src/app/navbar/navbar.component.css
@@ -6,7 +6,7 @@ nav {
}
.navbar {
- width: 200px;
+ width: 250px;
background-color: white;
padding: 5px;
transition: color .2s;
diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html
index e738b6b..75353b1 100644
--- a/src/app/navbar/navbar.component.html
+++ b/src/app/navbar/navbar.component.html
@@ -7,7 +7,7 @@
+ class="text-2xl pl-3 hover:bg-gray-200 gradient-text rounded-sm">
{{ item.label }}
diff --git a/src/app/navbar/navbar.component.ts b/src/app/navbar/navbar.component.ts
index ac2bf55..b060804 100644
--- a/src/app/navbar/navbar.component.ts
+++ b/src/app/navbar/navbar.component.ts
@@ -12,7 +12,7 @@ export class NavbarComponent {
*/
navItems:{label:string, path:string}[] = [
- {label: 'Schedule', path: '/schedule'},
+ {label: 'Programm', path: '/schedule'},
{label: 'Kinosaal-test', path: '/theater-overlay'},
]
}
diff --git a/src/app/schedule-header/schedule-header.component.css b/src/app/schedule-header/schedule-header.component.css
new file mode 100644
index 0000000..343f510
--- /dev/null
+++ b/src/app/schedule-header/schedule-header.component.css
@@ -0,0 +1,6 @@
+.schedule-header {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
diff --git a/src/app/schedule-header/schedule-header.component.html b/src/app/schedule-header/schedule-header.component.html
new file mode 100644
index 0000000..cfb017f
--- /dev/null
+++ b/src/app/schedule-header/schedule-header.component.html
@@ -0,0 +1,10 @@
+
+
diff --git a/src/app/schedule-header/schedule-header.component.ts b/src/app/schedule-header/schedule-header.component.ts
new file mode 100644
index 0000000..8ac6849
--- /dev/null
+++ b/src/app/schedule-header/schedule-header.component.ts
@@ -0,0 +1,11 @@
+import { Component, output } from '@angular/core';
+
+@Component({
+ selector: 'app-schedule-header',
+ standalone: false,
+ templateUrl: './schedule-header.component.html',
+ styleUrl: './schedule-header.component.css'
+})
+export class ScheduleHeaderComponent {
+ movieSearchResult = output();
+}
diff --git a/src/app/schedule/schedule.component.html b/src/app/schedule/schedule.component.html
index cfcd93a..f5924df 100644
--- a/src/app/schedule/schedule.component.html
+++ b/src/app/schedule/schedule.component.html
@@ -1,9 +1,17 @@
+
+
@for (dateInfo of dates; track dateInfo.date; let i = $index) {
@if (getMovieCount(i) > 0) {
- @for (group of dateInfo.performances; track group.movie.id) {
-
+ @if (hasSearchResults(i)) {
+ @for (group of dateInfo.performances; track group.movie.id) {
+ @if (group.movie.title.toLowerCase().includes(movieSearchResult.toLowerCase())) {
+
+ }
+ }
+ } @else {
+
}
} @else {
diff --git a/src/app/schedule/schedule.component.ts b/src/app/schedule/schedule.component.ts
index c7bbc7a..aae539d 100644
--- a/src/app/schedule/schedule.component.ts
+++ b/src/app/schedule/schedule.component.ts
@@ -16,20 +16,32 @@ export class ScheduleComponent implements OnInit {
dates: { label: string; date: Date; performances: MovieGroup[] }[] = [];
performaces: Vorstellung[] = [];
+ movieSearchResult: string = '';
+
+ private readonly bookableDays: number = 14;
+
private http = inject(HttpService);
private loading = inject(LoadingService)
constructor() {
- this.generateDates();
+ this.generateDates(this.bookableDays);
}
ngOnInit() {
- this.loadPerformances();
+ this.loadPerformances(this.bookableDays);
}
- generateDates() {
+ hasSearchResults(dateIndex: number): boolean {
+ if (!this.movieSearchResult) return true;
+
+ return this.dates[dateIndex].performances.some(group =>
+ group.movie.title.toLowerCase().includes(this.movieSearchResult.toLowerCase())
+ );
+ }
+
+ generateDates(bookableDays: number) {
const today = new Date();
- for (let i = 0; i < 14; i++) {
+ for (let i = 0; i < bookableDays; i++) {
const date = new Date(today);
date.setDate(today.getDate() + i);
@@ -46,9 +58,10 @@ export class ScheduleComponent implements OnInit {
}
}
- loadPerformances() {
+ loadPerformances(bookableDays: number) {
this.loading.show();
- this.http.getPerformaces().pipe(
+ const filter = this.generateDateFilter(bookableDays);
+ this.http.getPerformaceByFilter(filter).pipe(
map(data => Array.isArray(data) ? data : [data]),
tap(performaces => {
this.performaces = performaces;
@@ -57,12 +70,27 @@ export class ScheduleComponent implements OnInit {
}),
catchError(err => {
this.loading.showError(err);
- console.error('Fehler beim Laden der Vorstellung', err);
+ console.error('Fehler beim Laden der Vorstellungen', err);
return of([]);
})
).subscribe();
}
+private generateDateFilter(bookableDays: number): string[] {
+ const startDate = new Date();
+ const endDate = new Date();
+ endDate.setDate(startDate.getDate() + bookableDays - 1);
+
+ const startStr = startDate.toISOString().split('T')[0] + 'T00:00:00';
+ const endStr = endDate.toISOString().split('T')[0] + 'T23:59:59';
+
+ return [
+ `ge;start;date;${startStr}`,
+ `le;start;date;${endStr}`,
+ ];
+}
+
+
assignPerformancesToDates() {
// Gruppieren nach Datum