Created
October 14, 2019 16:43
-
-
Save angelo510/c749c9addfcf271408dc2e11f987b7bd to your computer and use it in GitHub Desktop.
Example of Angular component for best rxjs practice
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Component, forwardRef, Input } from "@angular/core"; | |
import { NG_VALUE_ACCESSOR } from "@angular/forms"; | |
import { DateTime } from "luxon"; | |
import { BehaviorSubject, combineLatest, of } from "rxjs"; | |
import { filter, map, shareReplay, startWith, switchMap } from "rxjs/operators"; | |
import { AppointmentsService } from "src/appointments/appointments.service"; | |
import { AppointmentSlot } from "src/appointments/fields/appointment-slot.model"; | |
import { Day } from "src/core/day.model"; | |
import { BaseFieldComponent } from "src/core/forms/base-field.component"; | |
import { SitesService } from "src/core/sites"; | |
import { ClosuresService } from "src/settings/closures"; | |
import { Dock } from "src/settings/docks/dock.model"; | |
import { DocksService } from "src/settings/docks/docks.service"; | |
import { DoorGroup } from "src/settings/door-groups/door-group.model"; | |
import { DoorGroupsService } from "src/settings/door-groups/door-groups.service"; | |
import { DoorsService } from "src/settings/doors/doors.service"; | |
import { ReservationsService } from "src/settings/reservations/reservations.service"; | |
import { isExistent } from "src/utils"; | |
@Component({ | |
selector: "mr-schedule-field", | |
templateUrl: "./schedule-field.component.html", | |
styleUrls: ["./schedule-field.component.scss"], | |
providers: [ | |
{ | |
provide: NG_VALUE_ACCESSOR, | |
multi: true, | |
useExisting: forwardRef(() => ScheduleFieldComponent), | |
}, | |
], | |
}) | |
export class ScheduleFieldComponent extends BaseFieldComponent< | |
AppointmentSlot | |
> { | |
public constructor( | |
private readonly sites: SitesService, | |
private readonly appointments: AppointmentsService, | |
private readonly closures: ClosuresService, | |
private readonly reservations: ReservationsService, | |
private readonly doors: DoorsService, | |
private readonly doorGroups: DoorGroupsService, | |
private readonly docks: DocksService, | |
) { | |
super(); | |
} | |
@Input() public readonly isDaySelectable = false; | |
@Input() public set day(value: Day | null) { | |
this.selectedDaySubject.next(value); | |
} | |
private readonly selectedDaySubject = new BehaviorSubject<Day | null>(null); | |
public readonly selectedDayChanges = this.selectedDaySubject.pipe( | |
filter(isExistent), | |
); | |
private readonly selectedDateChanges = combineLatest([ | |
this.selectedDayChanges, | |
this.sites.selectedChanges, | |
]).pipe(map(([day, site]) => day.toDateTime(Day.startOfDay, site.timeZone))); | |
private readonly isReceivingDayChanges = this.selectedDateChanges.pipe( | |
// If the selected date is the same day as the current moment in time | |
// (automatically compared against the date's time zone, which is the | |
// site's time zone) then it's receiving/game day. | |
map(date => date.hasSame(DateTime.utc(), "day")), | |
); | |
public readonly closuresChanges = combineLatest([ | |
this.isReceivingDayChanges.pipe( | |
switchMap(isReceivingDay => | |
this.closures.getListChanges({ isReceivingDay }), | |
), | |
filter(isExistent), | |
), | |
this.selectedDayChanges, | |
]).pipe( | |
map(([closures, day]) => | |
closures.filter(closure => closure.includesDay(day)), | |
), | |
); | |
public readonly reservationsChanges = combineLatest([ | |
this.reservations.changes.pipe(filter(isExistent)), | |
this.selectedDayChanges, | |
]).pipe( | |
map(([reservations, day]) => | |
reservations.filter( | |
reservation => reservation.isActive && reservation.includesDay(day), | |
), | |
), | |
); | |
@Input() public set hideAppointments(value: boolean) { | |
this.hideAppointmentsSubject.next(value); | |
} | |
private readonly hideAppointmentsSubject = new BehaviorSubject(false); | |
@Input() public readonly appointmentDuration: number | null = null; | |
private readonly selectedDocksSubject = new BehaviorSubject<Dock[]>([]); | |
private readonly selectedDoorGroupsSubject = new BehaviorSubject<DoorGroup[]>( | |
[], | |
); | |
public readonly appointmentsChanges = combineLatest([ | |
this.hideAppointmentsSubject, | |
this.selectedDateChanges.pipe( | |
map(date => date.until(date.plus({ days: 1 }))), | |
), | |
]).pipe( | |
switchMap(([hide, dateRange]) => | |
hide | |
? of([]) | |
: this.appointments.getListChanges({ | |
dateRange, | |
areCancelledExcluded: true, | |
}), | |
), | |
shareReplay(1), | |
); | |
public readonly docksChanges = this.docks.changes; | |
public readonly doorGroupsChanges = this.doorGroups.changes; | |
public readonly doorsChanges = combineLatest([ | |
this.doors.changes, | |
this.selectedDocksSubject, | |
this.selectedDoorGroupsSubject, | |
]).pipe( | |
map( | |
([doors, docks, doorGroups]) => | |
doors && | |
doors.filter( | |
door => | |
(!docks.length || docks.includes(door.dock)) && | |
(!doorGroups.length || doorGroups.includes(door.doorGroup)), | |
), | |
), | |
shareReplay(1), | |
); | |
public readonly isLoadedChanges = combineLatest([ | |
this.appointmentsChanges, | |
this.doorsChanges, | |
]).pipe( | |
map(([appointments, doors]) => !!appointments && !!doors), | |
startWith(false), | |
); | |
public selectedHours = 16; | |
public setSelectedDay(day: Day): void { | |
this.selectedDaySubject.next(day); | |
} | |
public setSelectedHours(selectedHours: number): void { | |
this.selectedHours = selectedHours; | |
} | |
public setSelectedDocks(selectedDocks: Dock[]): void { | |
this.selectedDocksSubject.next(selectedDocks); | |
} | |
public setSelectedDoorGroups(selectedDoorGroups: DoorGroup[]): void { | |
this.selectedDoorGroupsSubject.next(selectedDoorGroups); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment