Skip to content

Commit

Permalink
Implement Reschedule Reservations (#111)
Browse files Browse the repository at this point in the history
* Add Reschedule Modal + UI Enhancements + Bug Fixes

* Implement reschedule reservations

* Disable reschedule button while processing
  • Loading branch information
Amnish04 authored Apr 5, 2024
1 parent 09bfee7 commit ff4c289
Show file tree
Hide file tree
Showing 18 changed files with 638 additions and 125 deletions.
4 changes: 4 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ import { ImageCellRendererComponent } from './components/ag-grid/cell-renderers/
import { DateCellRendererComponent } from './components/ag-grid/cell-renderers/date-cell-renderer.component';
import { CurrencyCellRendererComponent } from './components/ag-grid/cell-renderers/currency-cell-renderer.component';
import { ReservationDetailsPageComponent } from './pages/reservations/reservation-details-page/reservation-details-page.component';
import { ReservationDurationFormComponent } from './components/reservations/create-reservation-dialog/reservation-duration-form/reservation-duration-form.component';
import { RescheduleReservationDialogComponent } from './components/reservations/reschedule-reservation-dialog/reschedule-reservation-dialog.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -127,6 +129,8 @@ import { ReservationDetailsPageComponent } from './pages/reservations/reservatio
DateCellRendererComponent,
CurrencyCellRendererComponent,
ReservationDetailsPageComponent,
ReservationDurationFormComponent,
RescheduleReservationDialogComponent,
],
imports: [
BrowserModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,100 +19,11 @@
<h2 class="text-xl font-bold text-color-primary mb-2"
>Reservation Timing</h2
>
<form
[formGroup]="reservationDurationForm"
class="flex flex-wrap gap-5">
<mat-form-field class="w-full lg:flex-1 mb-4">
<mat-label>Reservation Date</mat-label>
<input
formControlName="reservationDate"
autocomplete="off"
matInput
readonly
[min]="startAt"
[value]="startAt"
[matDatepicker]="datePicker" />
<mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle
matIconSuffix
[for]="datePicker"></mat-datepicker-toggle>
<mat-datepicker
[startAt]="startAt"
#datePicker></mat-datepicker>
<reservation-duration-form
[reservationDurationForm]="
reservationDurationForm
"></reservation-duration-form>

<mat-error
*ngIf="
reservationDurationForm.get('reservationDate')
?.errors?.['required']
"
>Reservation Date is Required</mat-error
>
</mat-form-field>

<mat-form-field class="w-full sm:flex-1 mb-4">
<mat-label>Start Time</mat-label>

<input
formControlName="startDateTime"
autocomplete="off"
readonly
matInput
[ngxTimepicker]="startTimePicker" />
<ngx-material-timepicker
[timepickerClass]="'dine-a-night_time-picker'"
#startTimePicker></ngx-material-timepicker>

<mat-hint>HH:MM AM/PM</mat-hint>

<mat-error
*ngIf="
reservationDurationForm.get('startDateTime')
?.errors?.['required']
"
>Start Date is Required</mat-error
>

<mat-error
*ngIf="
reservationDurationForm.get('startDateTime')
?.errors?.['DateBeforeValidator']
"
>Cannot be after end time</mat-error
>
</mat-form-field>

<mat-form-field class="w-full sm:flex-1 mb-4">
<mat-label>End Time</mat-label>

<input
formControlName="endDateTime"
autocomplete="off"
readonly
matInput
[ngxTimepicker]="endTimePicker" />
<ngx-material-timepicker
[timepickerClass]="'dine-a-night_time-picker'"
#endTimePicker></ngx-material-timepicker>

<mat-hint>HH:MM AM/PM</mat-hint>

<mat-error
*ngIf="
reservationDurationForm.get('endDateTime')
?.errors?.['required']
"
>End Date is Required</mat-error
>

<mat-error
*ngIf="
reservationDurationForm.get('endDateTime')
?.errors?.['DateAfterValidator']
"
>Cannot be before Start Time</mat-error
>
</mat-form-field>
</form>
<h2 class="text-xl font-bold mb-2 text-color-primary"
>Seating Scheme</h2
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export class CreateReservationDialogComponent implements OnInit, OnDestroy {

currentUser: ProfileUser | null;

reservationInProcess = false;

constructor(
@Inject(MAT_DIALOG_DATA) public data: CreateReservationDialogParams,
public dialogRef: MatDialogRef<CreateReservationDialogComponent>,
Expand Down Expand Up @@ -179,7 +181,11 @@ export class CreateReservationDialogComponent implements OnInit, OnDestroy {
}

get saveDisabled() {
return this.reservationDurationForm.invalid || !this.selectedTable;
return (
this.reservationDurationForm.invalid ||
!this.selectedTable ||
this.reservationInProcess
);
}

get selectionDisabled() {
Expand Down Expand Up @@ -345,6 +351,8 @@ export class CreateReservationDialogComponent implements OnInit, OnDestroy {
} else {
const reservation = new Reservation(this.reservation);

this.reservationInProcess = true;

this.reservationService
.createReservation(this.restaurant._id, reservation)
.subscribe({
Expand All @@ -358,6 +366,8 @@ export class CreateReservationDialogComponent implements OnInit, OnDestroy {
},
);

this.reservationInProcess = false;

this.router.navigate(['/reservations']);
this.dialogRef.close();
},
Expand All @@ -369,6 +379,8 @@ export class CreateReservationDialogComponent implements OnInit, OnDestroy {
panelClass: ['fail-snackbar'],
},
);

this.reservationInProcess = false;
},
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<form
*ngIf="reservationDurationForm"
[formGroup]="reservationDurationForm"
class="flex flex-wrap gap-5">
<mat-form-field class="w-full lg:flex-1 mb-4">
<mat-label>Reservation Date</mat-label>
<input
formControlName="reservationDate"
autocomplete="off"
matInput
readonly
[min]="startAt"
[value]="startAt"
[matDatepicker]="datePicker" />
<mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle
matIconSuffix
[for]="datePicker"></mat-datepicker-toggle>
<mat-datepicker
[startAt]="startAt"
#datePicker></mat-datepicker>

<mat-error
*ngIf="
reservationDurationForm.get('reservationDate')?.errors?.[
'required'
]
"
>Reservation Date is Required</mat-error
>
</mat-form-field>

<mat-form-field class="w-full sm:flex-1 mb-4">
<mat-label>Start Time</mat-label>

<input
formControlName="startDateTime"
autocomplete="off"
readonly
matInput
[ngxTimepicker]="startTimePicker" />
<ngx-material-timepicker
[timepickerClass]="'dine-a-night_time-picker'"
#startTimePicker></ngx-material-timepicker>

<mat-hint>HH:MM AM/PM</mat-hint>

<mat-error
*ngIf="
reservationDurationForm.get('startDateTime')?.errors?.[
'required'
]
"
>Start Date is Required</mat-error
>

<mat-error
*ngIf="
reservationDurationForm.get('startDateTime')?.errors?.[
'DateBeforeValidator'
]
"
>Cannot be after end time</mat-error
>
</mat-form-field>

<mat-form-field class="w-full sm:flex-1 mb-4">
<mat-label>End Time</mat-label>

<input
formControlName="endDateTime"
autocomplete="off"
readonly
matInput
[ngxTimepicker]="endTimePicker" />
<ngx-material-timepicker
[timepickerClass]="'dine-a-night_time-picker'"
#endTimePicker></ngx-material-timepicker>

<mat-hint>HH:MM AM/PM</mat-hint>

<mat-error
*ngIf="
reservationDurationForm.get('endDateTime')?.errors?.['required']
"
>End Date is Required</mat-error
>

<mat-error
*ngIf="
reservationDurationForm.get('endDateTime')?.errors?.[
'DateAfterValidator'
]
"
>Cannot be before Start Time</mat-error
>
</mat-form-field>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ReservationDurationFormComponent } from './reservation-duration-form.component';

describe('ReservationDurationFormComponent', () => {
let component: ReservationDurationFormComponent;
let fixture: ComponentFixture<ReservationDurationFormComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ReservationDurationFormComponent],
});
fixture = TestBed.createComponent(ReservationDurationFormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';

@Component({
selector: 'reservation-duration-form',
templateUrl: './reservation-duration-form.component.html',
styleUrls: ['./reservation-duration-form.component.scss'],
})
export class ReservationDurationFormComponent {
@Input() reservationDurationForm: FormGroup;

@Input() startAt: Date = new Date(Date.now());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<h2 class="text-3xl font-bold text-center py-5 bg-slate-950 text-color-light"
>Reschedule Reservation<mat-icon class="mx-2">date_range</mat-icon>
</h2>

<mat-dialog-content class="h-full">
<reservation-duration-form
[reservationDurationForm]="reservationDurationForm"
[startAt]="startAt"></reservation-duration-form>

<div
*ngIf="slotUnavailable"
class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 my-2 rounded relative"
role="alert">
<strong class="font-bold">Oops! </strong>
<span class="block sm:inline"
>This slot is already reserved. Please choose a different
time.</span
>
</div>

<restaurant-layout
[selectionDisabled]="true"
[restaurant]="restaurant"
[unavailableTableIds]="
getUnavailableTableIds(
currentReservations,
startDateTime,
endDateTime
)
"
[selectedTable]="reservation.tables[0]"></restaurant-layout>
</mat-dialog-content>

<mat-dialog-actions
class="absolute right-0 bottom-0 flex flex-wrap"
[align]="'end'">
<button
[disableRipple]="true"
mat-dialog-close
mat-raised-button>
<mat-icon>cancel</mat-icon>
Cancel
</button>

<button
[disabled]="saveDisabled"
[disableRipple]="true"
mat-raised-button
(click)="onRescheduleClick()"
color="accent">
<mat-icon>today</mat-icon>
Reschedule
</button>
</mat-dialog-actions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { RescheduleReservationDialogComponent } from './reschedule-reservation-dialog.component';

describe('RescheduleReservationDialogComponent', () => {
let component: RescheduleReservationDialogComponent;
let fixture: ComponentFixture<RescheduleReservationDialogComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [RescheduleReservationDialogComponent],
});
fixture = TestBed.createComponent(RescheduleReservationDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Loading

0 comments on commit ff4c289

Please sign in to comment.