393 lines
14 KiB
TypeScript
393 lines
14 KiB
TypeScript
// (C) Copyright 2015 Martin Dougiamas
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import { Component, OnInit, Optional, ViewChild } from '@angular/core';
|
|
import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms';
|
|
import { IonicPage, NavController, NavParams } from 'ionic-angular';
|
|
import { TranslateService } from '@ngx-translate/core';
|
|
import { CoreEventsProvider } from '@providers/events';
|
|
import { CoreGroupsProvider } from '@providers/groups';
|
|
import { CoreSitesProvider } from '@providers/sites';
|
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
|
import { CoreRichTextEditorComponent } from '@components/rich-text-editor/rich-text-editor.ts';
|
|
import { AddonCalendarProvider } from '../../providers/calendar';
|
|
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
|
import { CoreSite } from '@classes/site';
|
|
|
|
/**
|
|
* Page that displays a form to create/edit an event.
|
|
*/
|
|
@IonicPage({ segment: 'addon-calendar-edit-event' })
|
|
@Component({
|
|
selector: 'page-addon-calendar-edit-event',
|
|
templateUrl: 'edit-event.html',
|
|
})
|
|
export class AddonCalendarEditEventPage implements OnInit {
|
|
|
|
@ViewChild(CoreRichTextEditorComponent) descriptionEditor: CoreRichTextEditorComponent;
|
|
|
|
title: string;
|
|
dateFormat: string;
|
|
component = AddonCalendarProvider.COMPONENT;
|
|
loaded = false;
|
|
hasOffline = false;
|
|
eventTypes = [];
|
|
categories = [];
|
|
courses = [];
|
|
groups = [];
|
|
loadingGroups = false;
|
|
courseGroupSet = false;
|
|
advanced = false;
|
|
errors: any;
|
|
|
|
// Form variables.
|
|
eventForm: FormGroup;
|
|
eventTypeControl: FormControl;
|
|
groupControl: FormControl;
|
|
descriptionControl: FormControl;
|
|
|
|
protected eventId: number;
|
|
protected courseId: number;
|
|
protected originalData: any;
|
|
protected currentSite: CoreSite;
|
|
protected types: any; // Object with the supported types.
|
|
protected showAll: boolean;
|
|
|
|
constructor(navParams: NavParams,
|
|
private navCtrl: NavController,
|
|
private translate: TranslateService,
|
|
private domUtils: CoreDomUtilsProvider,
|
|
private timeUtils: CoreTimeUtilsProvider,
|
|
private eventsProvider: CoreEventsProvider,
|
|
private groupsProvider: CoreGroupsProvider,
|
|
sitesProvider: CoreSitesProvider,
|
|
private coursesProvider: CoreCoursesProvider,
|
|
private utils: CoreUtilsProvider,
|
|
private calendarProvider: AddonCalendarProvider,
|
|
private calendarHelper: AddonCalendarHelperProvider,
|
|
private fb: FormBuilder,
|
|
@Optional() private svComponent: CoreSplitViewComponent) {
|
|
|
|
this.eventId = navParams.get('eventId');
|
|
this.courseId = navParams.get('courseId');
|
|
this.title = this.eventId ? 'addon.calendar.editevent' : 'addon.calendar.newevent';
|
|
|
|
this.currentSite = sitesProvider.getCurrentSite();
|
|
this.errors = {
|
|
required: this.translate.instant('core.required')
|
|
};
|
|
|
|
// Calculate format to use. ion-datetime doesn't support escaping characters ([]), so we remove them.
|
|
this.dateFormat = this.timeUtils.convertPHPToMoment(this.translate.instant('core.strftimedatetimeshort'))
|
|
.replace(/[\[\]]/g, '');
|
|
|
|
// Initialize form variables.
|
|
this.eventForm = new FormGroup({});
|
|
this.eventTypeControl = this.fb.control('', Validators.required);
|
|
this.groupControl = this.fb.control('');
|
|
this.descriptionControl = this.fb.control('');
|
|
|
|
this.eventForm.addControl('name', this.fb.control('', Validators.required));
|
|
this.eventForm.addControl('timestart', this.fb.control(new Date().toISOString(), Validators.required));
|
|
this.eventForm.addControl('eventtype', this.eventTypeControl);
|
|
this.eventForm.addControl('categoryid', this.fb.control(''));
|
|
this.eventForm.addControl('courseid', this.fb.control(this.courseId));
|
|
this.eventForm.addControl('groupcourseid', this.fb.control(''));
|
|
this.eventForm.addControl('groupid', this.groupControl);
|
|
this.eventForm.addControl('description', this.descriptionControl);
|
|
this.eventForm.addControl('location', this.fb.control(''));
|
|
this.eventForm.addControl('duration', this.fb.control(0));
|
|
this.eventForm.addControl('timedurationuntil', this.fb.control(new Date().toISOString()));
|
|
this.eventForm.addControl('timedurationminutes', this.fb.control(''));
|
|
this.eventForm.addControl('repeat', this.fb.control(false));
|
|
this.eventForm.addControl('repeats', this.fb.control('1'));
|
|
}
|
|
|
|
/**
|
|
* Component being initialized.
|
|
*/
|
|
ngOnInit(): void {
|
|
this.fetchData().finally(() => {
|
|
this.originalData = this.utils.clone(this.eventForm.value);
|
|
this.loaded = true;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Fetch the data needed to render the form.
|
|
*
|
|
* @return {Promise<any>} Promise resolved when done.
|
|
*/
|
|
protected fetchData(): Promise<any> {
|
|
let accessInfo;
|
|
|
|
// Get access info.
|
|
return this.calendarProvider.getAccessInformation().then((info) => {
|
|
accessInfo = info;
|
|
|
|
return this.calendarProvider.getAllowedEventTypes();
|
|
}).then((types) => {
|
|
this.types = types;
|
|
|
|
const promises = [],
|
|
eventTypes = this.calendarHelper.getEventTypeOptions(types);
|
|
|
|
if (!eventTypes.length) {
|
|
return Promise.reject(this.translate.instant('addon.calendar.nopermissiontoupdatecalendar'));
|
|
}
|
|
|
|
if (types.category) {
|
|
// Get the categories.
|
|
promises.push(this.coursesProvider.getCategories(0, true).then((cats) => {
|
|
this.categories = cats;
|
|
}));
|
|
}
|
|
|
|
this.showAll = this.utils.isTrueOrOne(this.currentSite.getStoredConfig('calendar_adminseesall')) &&
|
|
accessInfo.canmanageentries;
|
|
|
|
if (types.course || types.groups) {
|
|
// Get the courses.
|
|
const promise = this.showAll ? this.coursesProvider.getCoursesByField() : this.coursesProvider.getUserCourses();
|
|
|
|
promises.push(promise.then((courses) => {
|
|
if (this.showAll) {
|
|
// Remove site home from the list of courses.
|
|
const siteHomeId = this.currentSite.getSiteHomeId();
|
|
courses = courses.filter((course) => {
|
|
return course.id != siteHomeId;
|
|
});
|
|
}
|
|
|
|
// Sort courses by name.
|
|
this.courses = courses.sort((a, b) => {
|
|
const compareA = a.fullname.toLowerCase(),
|
|
compareB = b.fullname.toLowerCase();
|
|
|
|
return compareA.localeCompare(compareB);
|
|
});
|
|
}));
|
|
}
|
|
|
|
return Promise.all(promises).then(() => {
|
|
// Set event types. If course is allowed, select it first.
|
|
if (types.course) {
|
|
this.eventTypeControl.setValue(AddonCalendarProvider.TYPE_COURSE);
|
|
} else {
|
|
this.eventTypeControl.setValue(eventTypes[0].value);
|
|
}
|
|
|
|
this.eventTypes = eventTypes;
|
|
});
|
|
|
|
}).catch((error) => {
|
|
this.domUtils.showErrorModalDefault(error, 'Error getting data.');
|
|
this.originalData = null; // Avoid asking for confirmation.
|
|
this.navCtrl.pop();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Pull to refresh.
|
|
*
|
|
* @param {any} refresher Refresher.
|
|
*/
|
|
refreshData(refresher: any): void {
|
|
const promises = [
|
|
this.calendarProvider.invalidateAccessInformation(this.courseId),
|
|
this.calendarProvider.invalidateAllowedEventTypes(this.courseId)
|
|
];
|
|
|
|
if (this.types) {
|
|
if (this.types.category) {
|
|
promises.push(this.coursesProvider.invalidateCategories(0, true));
|
|
}
|
|
if (this.types.course || this.types.groups) {
|
|
if (this.showAll) {
|
|
promises.push(this.coursesProvider.invalidateCoursesByField());
|
|
} else {
|
|
promises.push(this.coursesProvider.invalidateUserCourses());
|
|
}
|
|
}
|
|
}
|
|
|
|
Promise.all(promises).finally(() => {
|
|
this.fetchData().finally(() => {
|
|
refresher.complete();
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* A course was selected, get its groups.
|
|
*
|
|
* @param {number} courseId Course ID.
|
|
*/
|
|
groupCourseSelected(courseId: number): void {
|
|
if (!courseId) {
|
|
return;
|
|
}
|
|
|
|
const modal = this.domUtils.showModalLoading();
|
|
this.loadingGroups = true;
|
|
|
|
this.groupsProvider.getUserGroupsInCourse(courseId).then((groups) => {
|
|
this.groups = groups;
|
|
this.courseGroupSet = true;
|
|
this.groupControl.setValue('');
|
|
}).catch((error) => {
|
|
this.domUtils.showErrorModalDefault(error, 'Error getting data.');
|
|
}).finally(() => {
|
|
this.loadingGroups = false;
|
|
modal.dismiss();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Show or hide advanced form fields.
|
|
*/
|
|
toggleAdvanced(): void {
|
|
this.advanced = !this.advanced;
|
|
}
|
|
|
|
/**
|
|
* Create the event.
|
|
*/
|
|
submit(): void {
|
|
// Validate data.
|
|
const formData = this.eventForm.value,
|
|
timeStartDate = new Date(formData.timestart),
|
|
timeUntilDate = new Date(formData.timedurationuntil),
|
|
timeDurationMinutes = parseInt(formData.timedurationminutes || '', 10);
|
|
let error;
|
|
|
|
if (formData.eventtype == AddonCalendarProvider.TYPE_COURSE && !formData.courseid) {
|
|
error = 'core.selectacourse';
|
|
} else if (formData.eventtype == AddonCalendarProvider.TYPE_GROUP && !formData.groupcourseid) {
|
|
error = 'core.selectacourse';
|
|
} else if (formData.eventtype == AddonCalendarProvider.TYPE_GROUP && !formData.groupid) {
|
|
error = 'core.selectagroup';
|
|
} else if (formData.eventtype == AddonCalendarProvider.TYPE_CATEGORY && !formData.categoryid) {
|
|
error = 'core.selectacategory';
|
|
} else if (formData.duration == 1 && timeStartDate.getTime() > timeUntilDate.getTime()) {
|
|
error = 'addon.calendar.invalidtimedurationuntil';
|
|
} else if (formData.duration == 2 && (isNaN(timeDurationMinutes) || timeDurationMinutes < 1)) {
|
|
error = 'addon.calendar.invalidtimedurationminutes';
|
|
}
|
|
|
|
if (error) {
|
|
// Show error and stop.
|
|
this.domUtils.showErrorModal(this.translate.instant(error));
|
|
|
|
return;
|
|
}
|
|
|
|
// Format the data to send.
|
|
const data: any = {
|
|
name: formData.name,
|
|
eventtype: formData.eventtype,
|
|
timestart: Math.floor(timeStartDate.getTime() / 1000),
|
|
description: {
|
|
text: formData.description,
|
|
format: 1
|
|
},
|
|
location: formData.location,
|
|
duration: formData.duration,
|
|
repeat: formData.repeat
|
|
};
|
|
|
|
if (formData.eventtype == AddonCalendarProvider.TYPE_COURSE) {
|
|
data.courseid = formData.courseid;
|
|
} else if (formData.eventtype == AddonCalendarProvider.TYPE_GROUP) {
|
|
data.groupcourseid = formData.groupcourseid;
|
|
data.groupid = formData.groupid;
|
|
} else if (formData.eventtype == AddonCalendarProvider.TYPE_CATEGORY) {
|
|
data.categoryid = formData.categoryid;
|
|
}
|
|
|
|
if (formData.duration == 1) {
|
|
data.timedurationuntil = Math.floor(timeUntilDate.getTime() / 1000);
|
|
} else if (formData.duration == 2) {
|
|
data.timedurationminutes = formData.timedurationminutes;
|
|
}
|
|
|
|
if (formData.repeat) {
|
|
data.repeats = formData.repeats;
|
|
}
|
|
|
|
// Send the data.
|
|
const modal = this.domUtils.showModalLoading('core.sending');
|
|
|
|
this.calendarProvider.submitEvent(this.eventId, data).then((event) => {
|
|
this.returnToList(event);
|
|
}).catch((error) => {
|
|
this.domUtils.showErrorModalDefault(error, 'Error sending data.');
|
|
}).finally(() => {
|
|
modal.dismiss();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Convenience function to update or return to event list depending on device.
|
|
*
|
|
* @param {number} [event] Event.
|
|
*/
|
|
protected returnToList(event?: any): void {
|
|
const data: any = {
|
|
event: event
|
|
};
|
|
this.eventsProvider.trigger(AddonCalendarProvider.NEW_EVENT_EVENT, data, this.currentSite.getId());
|
|
|
|
if (this.svComponent && this.svComponent.isOn()) {
|
|
// Empty form.
|
|
this.hasOffline = false;
|
|
this.eventForm.reset(this.originalData);
|
|
this.originalData = this.utils.clone(this.eventForm.value);
|
|
} else {
|
|
this.originalData = null; // Avoid asking for confirmation.
|
|
this.navCtrl.pop();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Discard an offline saved discussion.
|
|
*/
|
|
discard(): void {
|
|
this.domUtils.showConfirm(this.translate.instant('core.areyousure')).then(() => {
|
|
// @todo.
|
|
}).catch(() => {
|
|
// Cancelled.
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Check if we can leave the page or not.
|
|
*
|
|
* @return {boolean|Promise<void>} Resolved if we can leave it, rejected if not.
|
|
*/
|
|
ionViewCanLeave(): boolean | Promise<void> {
|
|
|
|
if (this.calendarHelper.hasEventDataChanged(this.eventForm.value, this.originalData)) {
|
|
// Show confirmation if some data has been modified.
|
|
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
|
|
} else {
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
}
|