Skip to content

Commit

Permalink
Merge branch 'master' into jsegawa-InstructorResponsesViewBase-coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
domoberzin authored Jul 23, 2024
2 parents 6af82a9 + 67628fb commit 41e76ab
Show file tree
Hide file tree
Showing 9 changed files with 536 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ <h2 class="question-details"><b>Question {{ model.questionNumber }}: </b>{{ mode
<tm-ajax-loading *ngIf="isSavingResponses"></tm-ajax-loading>
<span>{{ isQuestionCountOne ? "Submit Response" : "Submit Response for Question " + model.questionNumber }}</span>
</button>
<button type="button" class="btn btn-warning float-end" (click)="resetForm(); resetTooltip.close();" ngbTooltip="Reset your responses for this question to the last submitted state."
#resetTooltip="ngbTooltip" (mouseenter)="resetTooltip.open()" [disabled]="!hasResponseChanged">{{ "Reset Question " + model.questionNumber }}</button>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export class QuestionSubmissionFormComponent implements DoCheck {

this.model.isTabExpandedForRecipients.set(recipient.recipientIdentifier, true);
});
this.hasResponseChanged = Array.from(this.model.hasResponseChangedForRecipients.values()).some((value) => value);
}

@Input()
Expand All @@ -118,6 +119,12 @@ export class QuestionSubmissionFormComponent implements DoCheck {
@Output()
responsesSave: EventEmitter<QuestionSubmissionFormModel> = new EventEmitter();

@Output()
autoSave: EventEmitter<{ id: string, model: QuestionSubmissionFormModel }> = new EventEmitter();

@Output()
resetFeedback: EventEmitter<QuestionSubmissionFormModel> = new EventEmitter<QuestionSubmissionFormModel>();

@ViewChild(ContributionQuestionConstraintComponent)
private contributionQuestionConstraint!: ContributionQuestionConstraintComponent;

Expand Down Expand Up @@ -168,6 +175,8 @@ export class QuestionSubmissionFormComponent implements DoCheck {
visibilityStateMachine: VisibilityStateMachine;
isEveryRecipientSorted: boolean = false;

autosaveTimeout: any;

constructor(private feedbackQuestionsService: FeedbackQuestionsService,
private feedbackResponseService: FeedbackResponsesService) {
this.visibilityStateMachine =
Expand Down Expand Up @@ -221,6 +230,13 @@ export class QuestionSubmissionFormComponent implements DoCheck {
});
}

resetForm(): void {
this.resetFeedback.emit(this.model);
this.isSaved = true;
this.hasResponseChanged = false;
clearTimeout(this.autosaveTimeout);
}

toggleQuestionTab(): void {
if (this.currentSelectedSessionView === this.allSessionViews.DEFAULT) {
this.model.isTabExpanded = !this.model.isTabExpanded;
Expand Down Expand Up @@ -350,7 +366,6 @@ export class QuestionSubmissionFormComponent implements DoCheck {
*/
triggerRecipientSubmissionFormChange(index: number, field: string, data: any): void {
if (!this.isFormsDisabled) {
this.hasResponseChanged = true;
this.isSubmitAllClickedChange.emit(false);
this.model.hasResponseChangedForRecipients.set(this.model.recipientList[index].recipientIdentifier, true);

Expand All @@ -362,6 +377,12 @@ export class QuestionSubmissionFormComponent implements DoCheck {

this.updateIsValidByQuestionConstraint();
this.formModelChange.emit(this.model);

this.autoSave.emit({ id: this.model.feedbackQuestionId, model: this.model });
clearTimeout(this.autosaveTimeout);
this.autosaveTimeout = setTimeout(() => {
this.hasResponseChanged = true;
}, 100); // 0.1 second to prevent people from trying to immediately reset before autosave kicks in
}
}

Expand Down Expand Up @@ -451,6 +472,7 @@ export class QuestionSubmissionFormComponent implements DoCheck {
* Triggers saving of responses for the specific question.
*/
saveFeedbackResponses(): void {
clearTimeout(this.autosaveTimeout);
this.isSaved = true;
this.hasResponseChanged = false;
this.model.hasResponseChangedForRecipients.forEach(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ <h5>Or</h5>
[date]="model.submissionStartDate"></tm-datepicker>
</div>
<div class="col-md-5">
<tm-timepicker id="submission-start-time" [isDisabled]="!model.isEditable" (timeChange)="triggerModelChange('submissionStartTime', $event)"
<tm-timepicker id="submission-start-time" [isDisabled]="!model.isEditable" (timeChange)="triggerSubmissionOpeningTimeModelChange('submissionStartTime', $event)"
[minDate]="minDateForSubmissionStart" [maxDate]="maxDateForSubmissionStart"
[date]="model.submissionStartDate"
[minTime]="minTimeForSubmissionStart" [maxTime]="maxTimeForSubmissionStart"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ describe('SessionEditFormComponent', () => {
let dateTimeService: DateTimeService;

const submissionStartDateField = 'submissionStartDate';
const submissionStartTimeField = 'submissionStartTime';

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
Expand Down Expand Up @@ -94,6 +95,41 @@ describe('SessionEditFormComponent', () => {
expect(configureSubmissionOpeningTimeSpy).not.toHaveBeenCalled();
});

it('should trigger the change of the model when the submission opening time '
+ 'changes to before the visibility time', () => {
const date: DateFormat = { day: 12, month: 7, year: 2024 };
const time: TimeFormat = { hour: 4, minute: 0 };
const visibilityTime: TimeFormat = { hour: 14, minute: 0 };
const triggerModelChangeSpy = jest.spyOn(component, 'triggerModelChange');
const configureSessionVisibleDateTimeSpy = jest.spyOn(component, 'configureSessionVisibleDateTime');
component.model.customSessionVisibleDate = date;
component.model.submissionStartDate = date;
component.model.customSessionVisibleTime = visibilityTime;
component.triggerSubmissionOpeningTimeModelChange(submissionStartTimeField, time);
expect(triggerModelChangeSpy).toHaveBeenCalledWith(submissionStartTimeField, time);
expect(configureSessionVisibleDateTimeSpy).toHaveBeenCalledWith(date, time);
});

it('should adjust the session visibility date if submission opening date is earlier', () => {
const date: DateFormat = { day: 12, month: 7, year: 2024 };
const time: TimeFormat = { hour: 14, minute: 0 };
component.model.customSessionVisibleDate = { day: 13, month: 7, year: 2024 };
component.model.customSessionVisibleTime = time;
component.configureSessionVisibleDateTime(date, time);
expect(component.model.customSessionVisibleDate).toEqual(date);
expect(component.model.customSessionVisibleTime).toEqual(time);
});

it('should not adjust the session visibility date and time if submission opening date and time are later', () => {
const date: DateFormat = component.minDateForSubmissionStart;
const time: TimeFormat = component.minTimeForSubmissionStart;
component.model.customSessionVisibleDate = dateTimeService.getDateInstance(moment().subtract(1, 'days'));
component.model.customSessionVisibleTime = dateTimeService.getTimeInstance(moment().subtract(1, 'hours'));
component.configureSessionVisibleDateTime(date, time);
expect(component.model.customSessionVisibleDate).not.toEqual(date);
expect(component.model.customSessionVisibleTime).not.toEqual(time);
});

it('should emit a modelChange event with the updated field when triggerModelChange is called', () => {
const field = 'courseId';
const data = 'testId';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,51 @@ export class SessionEditFormComponent {
* Triggers the change of the model for the form.
*/
triggerModelChange(field: string, data: any): void {
if (field === 'submissionStartDate' || field === 'submissionStartTime') {
this.adjustSessionVisibilityTime(data, field);
}
this.modelChange.emit({
...this.model,
[field]: data,
});
}

/**
* Adjusts session visibility time to ensure it does not occur after submission opening time.
*/
adjustSessionVisibilityTime(value: any, field: string): void {
const submissionDateTime = this.combineDateAndTime(
field === 'submissionStartDate' ? value : this.model.submissionStartDate,
field === 'submissionStartTime' ? value : this.model.submissionStartTime,
);

const visibilityDateTime = this.combineDateAndTime(
this.model.customSessionVisibleDate,
this.model.customSessionVisibleTime,
);

if (submissionDateTime.isBefore(visibilityDateTime)) {
if (field === 'submissionStartDate') {
this.model.customSessionVisibleDate = value;
} else {
this.model.customSessionVisibleTime = value;
}
}
}

/**
* Combines date and time into a single moment instance.
*/
combineDateAndTime(date: DateFormat, time: TimeFormat): moment.Moment {
return moment.tz({
year: date.year,
month: date.month - 1,
day: date.day,
hour: time.hour,
minute: time.minute,
}, this.model.timeZone);
}

/**
* Triggers the change of the model when the submission opening date changes.
*/
Expand All @@ -148,6 +187,7 @@ export class SessionEditFormComponent {
this.model.submissionStartTime = minTime;
}

this.adjustSessionVisibilityTime(date, field);
this.triggerModelChange(field, date);
}

Expand All @@ -164,6 +204,37 @@ export class SessionEditFormComponent {
}
}

/**
* Triggers the change of the model when the submission opening time changes.
*/
triggerSubmissionOpeningTimeModelChange(field: string, time: TimeFormat): void {
const date: DateFormat = this.model.submissionStartDate;
const sessionDate: DateFormat = this.model.customSessionVisibleDate;
const sessionTime: TimeFormat = this.model.customSessionVisibleTime;

if (DateTimeService.compareDateFormat(date, sessionDate) === 0
&& DateTimeService.compareTimeFormat(time, sessionTime) === -1) {
this.configureSessionVisibleDateTime(date, time);
}

this.triggerModelChange(field, time);
}

/**
* Configures the session visible date and time to ensure it is not after submission opening time.
*/
configureSessionVisibleDateTime(date: DateFormat, time: TimeFormat): void {
const sessionDate: DateFormat = this.model.customSessionVisibleDate;
const sessionTime: TimeFormat = this.model.customSessionVisibleTime;

if (DateTimeService.compareDateFormat(date, sessionDate) === -1) {
this.model.customSessionVisibleDate = date;
} else if (DateTimeService.compareDateFormat(date, sessionDate) === 0
&& DateTimeService.compareTimeFormat(time, sessionTime) === -1) {
this.model.customSessionVisibleTime = time;
}
}

/**
* Handles course Id change event.
*
Expand Down
Loading

0 comments on commit 41e76ab

Please sign in to comment.