From fe6a3977f87fb2d963b4e7dc6a1ba685c0ca97fd Mon Sep 17 00:00:00 2001
From: Douglas Lim <97420966+dlimyy@users.noreply.github.com>
Date: Mon, 25 Sep 2023 07:24:13 +0800
Subject: [PATCH] [#12571] Instructors Edit Feedback Session: Instructor is
able to edit submission opening time to an earlier timing (#12580)
* Fix submission opening time bug
* Fix bug where save button is disabled
* Add method in DateTimeService to compare dates
* Change to triggerModelChange
---------
Co-authored-by: Cedric Ong <67156011+cedricongjh@users.noreply.github.com>
---
.../session-edit-form.component.html | 2 +-
.../session-edit-form.component.spec.ts | 23 ++++++
.../session-edit-form.component.ts | 30 ++++++++
.../instructor-session-edit-page.component.ts | 1 +
src/web/services/datetime.service.spec.ts | 73 +++++++++++++++++++
src/web/services/datetime.service.ts | 50 +++++++++++++
6 files changed, 178 insertions(+), 1 deletion(-)
diff --git a/src/web/app/components/session-edit-form/session-edit-form.component.html b/src/web/app/components/session-edit-form/session-edit-form.component.html
index ea8d26cf803..7f7a7f9e435 100644
--- a/src/web/app/components/session-edit-form/session-edit-form.component.html
+++ b/src/web/app/components/session-edit-form/session-edit-form.component.html
@@ -135,7 +135,7 @@
-
diff --git a/src/web/app/components/session-edit-form/session-edit-form.component.spec.ts b/src/web/app/components/session-edit-form/session-edit-form.component.spec.ts
index 21bce10a45d..3ee97b6f228 100644
--- a/src/web/app/components/session-edit-form/session-edit-form.component.spec.ts
+++ b/src/web/app/components/session-edit-form/session-edit-form.component.spec.ts
@@ -1,6 +1,7 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
+import { TimeFormat } from 'src/web/types/datetime-const';
import { TeammatesRouterModule } from '../teammates-router/teammates-router.module';
import { SessionEditFormComponent } from './session-edit-form.component';
import { SessionEditFormModule } from './session-edit-form.module';
@@ -30,4 +31,26 @@ describe('SessionEditFormComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
+
+ it('should configure the time to be 23:59 if the hour is 23 and minute is greater than 0', () => {
+ const time : TimeFormat = { hour: 23, minute: 5 };
+ component.configureSubmissionOpeningTime(time);
+ expect(time.hour).toEqual(23);
+ expect(time.minute).toEqual(59);
+ });
+
+ it('should configure the time correctly if the hour is less than 23 and minute is greater than 0', () => {
+ const time : TimeFormat = { hour: 22, minute: 5 };
+ component.configureSubmissionOpeningTime(time);
+ expect(time.hour).toEqual(23);
+ expect(time.minute).toEqual(0);
+ });
+
+ it('should configure the time correctly if the minute is 0', () => {
+ const time : TimeFormat = { hour: 21, minute: 0 };
+ component.configureSubmissionOpeningTime(time);
+ expect(time.hour).toEqual(21);
+ expect(time.minute).toEqual(0);
+ });
+
});
diff --git a/src/web/app/components/session-edit-form/session-edit-form.component.ts b/src/web/app/components/session-edit-form/session-edit-form.component.ts
index 1a90937b16e..56e5dfb96f8 100644
--- a/src/web/app/components/session-edit-form/session-edit-form.component.ts
+++ b/src/web/app/components/session-edit-form/session-edit-form.component.ts
@@ -134,6 +134,36 @@ export class SessionEditFormComponent {
});
}
+ /**
+ * Triggers the change of the model when the submission opening date changes.
+ */
+ triggerSubmissionOpeningDateModelChange(field: string, date: DateFormat): void {
+ const minDate: DateFormat = this.minDateForSubmissionStart;
+ const minTime: TimeFormat = this.minTimeForSubmissionStart;
+
+ // Case where date is same as earliest date and time is earlier than earliest possible time
+ if (DateTimeService.compareDateFormat(date, minDate) === 0
+ && DateTimeService.compareTimeFormat(this.model.submissionStartTime, minTime) === -1) {
+ this.configureSubmissionOpeningTime(minTime);
+ this.model.submissionStartTime = minTime;
+ }
+
+ this.triggerModelChange(field, date);
+ }
+
+ /**
+ * Configures the time for the submission opening time.
+ */
+ configureSubmissionOpeningTime(time : TimeFormat) : void {
+ if (time.hour === 23 && time.minute > 0) {
+ time.minute = 59;
+ } else if (time.hour < 23 && time.minute > 0) {
+ // Case where minutes is not 0 since the earliest time with 0 minutes is the hour before
+ time.hour += 1;
+ time.minute = 0;
+ }
+ }
+
/**
* Handles course Id change event.
*
diff --git a/src/web/app/pages-instructor/instructor-session-edit-page/instructor-session-edit-page.component.ts b/src/web/app/pages-instructor/instructor-session-edit-page/instructor-session-edit-page.component.ts
index 921fc82419d..4cc6488ff15 100644
--- a/src/web/app/pages-instructor/instructor-session-edit-page/instructor-session-edit-page.component.ts
+++ b/src/web/app/pages-instructor/instructor-session-edit-page/instructor-session-edit-page.component.ts
@@ -419,6 +419,7 @@ export class InstructorSessionEditPageComponent extends InstructorSessionBasePag
this.statusMessageService.showSuccessToast('The feedback session has been updated.');
},
error: (resp: ErrorMessageOutput) => {
+ this.sessionEditFormModel.isEditable = true;
this.statusMessageService.showErrorToast(resp.error.message);
},
});
diff --git a/src/web/services/datetime.service.spec.ts b/src/web/services/datetime.service.spec.ts
index b97421b4986..1dee9dfb5b5 100644
--- a/src/web/services/datetime.service.spec.ts
+++ b/src/web/services/datetime.service.spec.ts
@@ -1,5 +1,6 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
+import { DateFormat, TimeFormat } from '../types/datetime-const';
import { DateTimeService } from './datetime.service';
import { TimezoneService } from './timezone.service';
@@ -77,4 +78,76 @@ describe('DateTimeService', () => {
expect(result.minute).toEqual(59);
});
+ it('should return 1 if the first date\'s year is later than the second date\'s year', () => {
+ const firstDate : DateFormat = { year: 2023, month: 8, day: 23 };
+ const secondDate: DateFormat = { year: 2022, month: 8, day: 23 };
+ expect(DateTimeService.compareDateFormat(firstDate, secondDate)).toEqual(1);
+ });
+
+ it('should return -1 if the first date\'s year is earlier than the second date\'s year', () => {
+ const firstDate : DateFormat = { year: 2022, month: 8, day: 23 };
+ const secondDate: DateFormat = { year: 2023, month: 8, day: 23 };
+ expect(DateTimeService.compareDateFormat(firstDate, secondDate)).toEqual(-1);
+ });
+
+ it('should return 1 if year is the same and first date\'s month is later than second date\'s month', () => {
+ const firstDate : DateFormat = { year: 2023, month: 9, day: 23 };
+ const secondDate: DateFormat = { year: 2023, month: 8, day: 23 };
+ expect(DateTimeService.compareDateFormat(firstDate, secondDate)).toEqual(1);
+ });
+
+ it('should return -1 if if year is the same and first date\'s month is earlier than second date\'s month', () => {
+ const firstDate : DateFormat = { year: 2023, month: 8, day: 23 };
+ const secondDate: DateFormat = { year: 2023, month: 9, day: 23 };
+ expect(DateTimeService.compareDateFormat(firstDate, secondDate)).toEqual(-1);
+ });
+
+ it('should return 1 if year and month are the same and first date\'s day is later than second date\'s day', () => {
+ const firstDate : DateFormat = { year: 2023, month: 9, day: 28 };
+ const secondDate: DateFormat = { year: 2023, month: 9, day: 23 };
+ expect(DateTimeService.compareDateFormat(firstDate, secondDate)).toEqual(1);
+ });
+
+ it('should return -1 if year and month are same and first date\'s day is earlier than second date\'s day', () => {
+ const firstDate : DateFormat = { year: 2023, month: 9, day: 23 };
+ const secondDate: DateFormat = { year: 2023, month: 9, day: 28 };
+ expect(DateTimeService.compareDateFormat(firstDate, secondDate)).toEqual(-1);
+ });
+
+ it('should return 0 if both dates have the same year and month and day', () => {
+ const firstDate : DateFormat = { year: 2023, month: 9, day: 28 };
+ const secondDate: DateFormat = { year: 2023, month: 9, day: 28 };
+ expect(DateTimeService.compareDateFormat(firstDate, secondDate)).toEqual(0);
+ });
+
+ it('should return 1 if the first timing\'s hour is later than the second timing\'s hour', () => {
+ const firstTime : TimeFormat = { hour: 21, minute: 0 };
+ const secondTime : TimeFormat = { hour: 19, minute: 0 };
+ expect(DateTimeService.compareTimeFormat(firstTime, secondTime)).toEqual(1);
+ });
+
+ it('should return -1 if the first timing\'s hour is earlier than the second timing\'s hour', () => {
+ const firstTime : TimeFormat = { hour: 20, minute: 0 };
+ const secondTime : TimeFormat = { hour: 21, minute: 0 };
+ expect(DateTimeService.compareTimeFormat(firstTime, secondTime)).toEqual(-1);
+ });
+
+ it('should return 1 if hour is the same and first timing\'s minute is later than second timing\'s minute', () => {
+ const firstTime : TimeFormat = { hour: 21, minute: 30 };
+ const secondTime : TimeFormat = { hour: 21, minute: 0 };
+ expect(DateTimeService.compareTimeFormat(firstTime, secondTime)).toEqual(1);
+ });
+
+ it('should return -1 if hour is same and first timing\'s minute is earlier than second timing\'s minute', () => {
+ const firstTime : TimeFormat = { hour: 21, minute: 0 };
+ const secondTime : TimeFormat = { hour: 21, minute: 30 };
+ expect(DateTimeService.compareTimeFormat(firstTime, secondTime)).toEqual(-1);
+ });
+
+ it('should return 0 if both timings have the same hour and minute', () => {
+ const firstTime : TimeFormat = { hour: 21, minute: 30 };
+ const secondTime : TimeFormat = { hour: 21, minute: 30 };
+ expect(DateTimeService.compareTimeFormat(firstTime, secondTime)).toEqual(0);
+ });
+
});
diff --git a/src/web/services/datetime.service.ts b/src/web/services/datetime.service.ts
index 9baef02632c..b6d86fcd290 100644
--- a/src/web/services/datetime.service.ts
+++ b/src/web/services/datetime.service.ts
@@ -123,4 +123,54 @@ export class DateTimeService {
minute: mmt.minute(),
};
}
+
+ /**
+ * Compares the first date with the second date and checks whether the first
+ * date is earlier, same or later than the second date.
+ * Returns 1 if the first date is later than second date, 0 if the first date is the
+ * same as the second date and -1 if the first date is earlier than the second date.
+ */
+ static compareDateFormat(firstDate : DateFormat, secondDate : DateFormat) : number {
+ if (firstDate.year > secondDate.year) {
+ return 1;
+ }
+ if (firstDate.year < secondDate.year) {
+ return -1;
+ }
+ if (firstDate.month > secondDate.month) {
+ return 1;
+ }
+ if (firstDate.month < secondDate.month) {
+ return -1;
+ }
+ if (firstDate.day > secondDate.day) {
+ return 1;
+ }
+ if (firstDate.day < secondDate.day) {
+ return -1;
+ }
+ return 0;
+ }
+
+ /**
+ * Compares the first timing with the second timing and checks whether the first
+ * timing is earlier, same or later than the second timing.
+ * Returns 1 if the first timing is later than second timing, 0 if the first timing is the
+ * same as the second timing and -1 if the first timing is earlier than the second timing.
+ */
+ static compareTimeFormat(firstTiming : TimeFormat, secondTiming : TimeFormat) : number {
+ if (firstTiming.hour > secondTiming.hour) {
+ return 1;
+ }
+ if (firstTiming.hour < secondTiming.hour) {
+ return -1;
+ }
+ if (firstTiming.minute > secondTiming.minute) {
+ return 1;
+ }
+ if (firstTiming.minute < secondTiming.minute) {
+ return -1;
+ }
+ return 0;
+ }
}