Summary
When a user submits a time that conflicts with an existing appointment/event, the form should block submission and show the designated conflict message. Instead, the form submits and the console shows a 500 error. The hasConflict variable calculated in book-appointment-form.component.ts is not bound/used by the HTML template to disable the submit and render the error state.
Affected components/files
- book-appointment-form.component.ts
- book-appointment-form.component.html
- Backend endpoint: POST /api/appointments
Steps to Reproduce
- Open the Book Appointment form.
- Pick a date/time that is known to conflict (overlap/adjacent per buffer rules).
- Click Submit.
- Observe the console and UI.
Expected Behavior
- The form should not submit while hasConflict === true.
- The UI should display the designated conflict error message (and/or toast).
- The submit button should be disabled when a conflict is present.
Actual Behavior
- The form submits despite a detected conflict.
- Console shows:
book-appointment-form.component.ts:352 POST http://localhost:4200/api/appointments 500 (Internal Server Error)
book-appointment-form.component.ts:365 HttpErrorResponse { status: 500, statusText: 'Internal Server Error', url: 'http://localhost:4200/api/appointments', ... }
- No conflict error message is shown to the user.
Notes & Suspected Cause
- hasConflict is set in TS but not bound in the template:
- Submit button isn’t disabled based on hasConflict.
- Template does not conditionally render the conflict error block.
- As a result, the request reaches the backend and fails (server returns 500 due to conflict/business rules).
Acceptance Criteria
- hasConflict is reactively bound in the template.
- Submit button is disabled when hasConflict is true or when conflict check is pending.
- A clear, accessible inline error (and/or toast) appears when a conflict is detected.
- Form does not call POST /api/appointments while a conflict exists.
- Unit tests cover:
- Conflict state disables submit.
- Conflict message rendering.
- No HTTP call when hasConflict === true.
- E2E test covers end-to-end conflict scenario (optional but recommended).
Proposed Fix (Frontend)
- Bind conflict state to UI
- In template, disable submit:
[disabled]="form.invalid || hasConflict || isSubmitting"
- Show inline error:
*ngIf="hasConflict" → “This time conflicts with another appointment/event. Please choose a different time.”
- Optionally show a toast when conflict toggles to true.
- Guard submit handler
- Early return in
onSubmit() if hasConflict === true.
- Ensure conflict check timing
- Re-run conflict check on date/time changes (datepicker/timepicker) and after manual edits.
- Debounce if needed to reduce API calls.
- UX polish
- Announce error via
aria-live="assertive" for accessibility.
Environment
- Frontend: Angular 19 (standalone components)
- Affected page: Booking flow (Book Appointment Form)
- Browser: Chrome 140
- Local dev: http://localhost:4200
Labels: bug, high-priority, booking, UI/UX, validation
Summary
When a user submits a time that conflicts with an existing appointment/event, the form should block submission and show the designated conflict message. Instead, the form submits and the console shows a 500 error. The hasConflict variable calculated in book-appointment-form.component.ts is not bound/used by the HTML template to disable the submit and render the error state.
Affected components/files
Steps to Reproduce
Expected Behavior
Actual Behavior
Notes & Suspected Cause
Acceptance Criteria
Proposed Fix (Frontend)
[disabled]="form.invalid || hasConflict || isSubmitting"*ngIf="hasConflict" → “This time conflicts with another appointment/event. Please choose a different time.”onSubmit()ifhasConflict === true.aria-live="assertive"for accessibility.Environment
Labels: bug, high-priority, booking, UI/UX, validation