MOBILE-3909 calendar: Allow setting reminders for offline events
parent
56596ad30e
commit
b31b0764a5
|
@ -521,12 +521,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
|||
* @param eventId Event to load.
|
||||
*/
|
||||
gotoEvent(eventId: number): void {
|
||||
if (eventId < 0) {
|
||||
// It's an offline event, go to the edit page.
|
||||
this.openEdit(eventId);
|
||||
} else {
|
||||
CoreNavigator.navigateToSitePath(`/calendar/event/${eventId}`);
|
||||
}
|
||||
CoreNavigator.navigateToSitePath(`/calendar/event/${eventId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -564,7 +564,10 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave {
|
|||
if (event) {
|
||||
CoreEvents.trigger(
|
||||
AddonCalendarProvider.NEW_EVENT_EVENT,
|
||||
{ eventId: event.id },
|
||||
{
|
||||
eventId: event.id,
|
||||
oldEventId: this.eventId,
|
||||
},
|
||||
this.currentSite.getId(),
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
[priority]="400" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(undefined, $event, true)"
|
||||
[iconAction]="syncIcon" [closeOnClick]="false">
|
||||
</core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="!canEdit || !event || !event.canedit || event.deleted" [priority]="300"
|
||||
[content]="'core.edit' | translate" (action)="openEdit()" iconAction="fas-edit">
|
||||
<core-context-menu-item [hidden]="!event || !event.canedit || event.deleted || (!canEdit && event.id > 0)"
|
||||
[priority]="300" [content]="'core.edit' | translate" (action)="openEdit()" iconAction="fas-edit">
|
||||
</core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="!event || !event.candelete || event.deleted" [priority]="200"
|
||||
[content]="'core.delete' | translate" (action)="deleteEvent()"
|
||||
|
|
|
@ -52,6 +52,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
|
||||
protected eventId!: number;
|
||||
protected siteHomeId: number;
|
||||
protected newEventObserver: CoreEventObserver;
|
||||
protected editEventObserver: CoreEventObserver;
|
||||
protected syncObserver: CoreEventObserver;
|
||||
protected manualSyncObserver: CoreEventObserver;
|
||||
|
@ -88,7 +89,16 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
|
||||
// Listen for event edited. If current event is edited, reload the data.
|
||||
this.editEventObserver = CoreEvents.on(AddonCalendarProvider.EDIT_EVENT_EVENT, (data) => {
|
||||
if (data && data.eventId == this.eventId) {
|
||||
if (data && data.eventId === this.eventId) {
|
||||
this.eventLoaded = false;
|
||||
this.refreshEvent(true, false);
|
||||
}
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Listen for event created. If user edits the data of a new offline event or it's sent to server, this event is triggered.
|
||||
this.newEventObserver = CoreEvents.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => {
|
||||
if (this.eventId < 0 && data && (data.eventId === this.eventId || data.oldEventId === this.eventId)) {
|
||||
this.eventId = data.eventId;
|
||||
this.eventLoaded = false;
|
||||
this.refreshEvent(true, false);
|
||||
}
|
||||
|
@ -173,53 +183,22 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
async fetchEvent(sync = false, showErrors = false): Promise<void> {
|
||||
let deleted = false;
|
||||
|
||||
this.isOnline = CoreApp.isOnline();
|
||||
|
||||
if (sync) {
|
||||
// Try to synchronize offline events.
|
||||
try {
|
||||
const result = await AddonCalendarSync.syncEvents();
|
||||
if (result.warnings && result.warnings.length) {
|
||||
CoreDomUtils.showErrorModal(result.warnings[0]);
|
||||
}
|
||||
const deleted = await this.syncEvents(showErrors);
|
||||
|
||||
if (result.deleted && result.deleted.indexOf(this.eventId) != -1) {
|
||||
// This event was deleted during the sync.
|
||||
deleted = true;
|
||||
}
|
||||
|
||||
if (result.updated) {
|
||||
// Trigger a manual sync event.
|
||||
result.source = 'event';
|
||||
|
||||
CoreEvents.trigger(
|
||||
AddonCalendarSyncProvider.MANUAL_SYNCED,
|
||||
result,
|
||||
this.currentSiteId,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (showErrors) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.errorsync', true);
|
||||
}
|
||||
if (deleted) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (deleted) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the event data.
|
||||
const event = await AddonCalendar.getEventById(this.eventId);
|
||||
const formattedEvent = await AddonCalendarHelper.formatEventData(event);
|
||||
this.event = formattedEvent;
|
||||
|
||||
// Load reminders, and re-schedule them if needed (maybe the event time has changed).
|
||||
this.loadReminders();
|
||||
AddonCalendar.scheduleEventsNotifications([this.event]);
|
||||
if (this.eventId >= 0) {
|
||||
const event = await AddonCalendar.getEventById(this.eventId);
|
||||
this.event = await AddonCalendarHelper.formatEventData(event);
|
||||
}
|
||||
|
||||
try {
|
||||
const offlineEvent = AddonCalendarHelper.formatOfflineEventData(
|
||||
|
@ -228,13 +207,28 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
|
||||
// There is offline data, apply it.
|
||||
this.hasOffline = true;
|
||||
|
||||
this.event = Object.assign(this.event, offlineEvent);
|
||||
this.event = Object.assign(this.event || {}, offlineEvent);
|
||||
} catch {
|
||||
// No offline data.
|
||||
this.hasOffline = false;
|
||||
|
||||
if (this.eventId < 0) {
|
||||
// It's an offline event, but it wasn't found. Shouldn't happen.
|
||||
CoreDomUtils.showErrorModal('Event not found.');
|
||||
CoreNavigator.back();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.event) {
|
||||
return; // At this point we should always have the event, adding this check to avoid TS errors.
|
||||
}
|
||||
|
||||
// Load reminders, and re-schedule them if needed (maybe the event time has changed).
|
||||
this.loadReminders();
|
||||
AddonCalendar.scheduleEventsNotifications([this.event]);
|
||||
|
||||
// Reset some of the calculated data.
|
||||
this.categoryPath = '';
|
||||
this.courseName = '';
|
||||
|
@ -253,6 +247,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
const promises: Promise<void>[] = [];
|
||||
const event = this.event;
|
||||
|
||||
const courseId = this.event.courseid;
|
||||
if (courseId != this.siteHomeId) {
|
||||
|
@ -266,16 +261,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
|
||||
// If it's a group event, get the name of the group.
|
||||
if (courseId && this.event.groupid) {
|
||||
promises.push(CoreGroups.getUserGroupsInCourse(courseId).then((groups) => {
|
||||
const group = groups.find((group) => group.id == formattedEvent.groupid);
|
||||
|
||||
this.groupName = group ? group.name : '';
|
||||
|
||||
return;
|
||||
}).catch(() => {
|
||||
// Error getting groups, just don't show the group name.
|
||||
this.groupName = '';
|
||||
}));
|
||||
promises.push(this.loadGroupName(this.event, courseId));
|
||||
}
|
||||
|
||||
if (this.event.iscategoryevent && this.event.category) {
|
||||
|
@ -290,14 +276,14 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
|
||||
// Check if event was deleted in offine.
|
||||
promises.push(AddonCalendarOffline.isEventDeleted(this.eventId).then((deleted) => {
|
||||
formattedEvent.deleted = deleted;
|
||||
event.deleted = deleted;
|
||||
|
||||
return;
|
||||
}));
|
||||
|
||||
// Re-calculate the formatted time so it uses the device date.
|
||||
promises.push(AddonCalendar.getCalendarTimeFormat().then(async (timeFormat) => {
|
||||
formattedEvent.formattedtime = await AddonCalendar.formatEventTime(formattedEvent, timeFormat);
|
||||
event.formattedtime = await AddonCalendar.formatEventTime(event, timeFormat);
|
||||
|
||||
return;
|
||||
}));
|
||||
|
@ -311,6 +297,69 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
this.syncIcon = CoreConstants.ICON_SYNC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync offline events.
|
||||
*
|
||||
* @param showErrors Whether to show sync errors to the user.
|
||||
* @return Promise resolved with boolean: whether event was deleted on sync.
|
||||
*/
|
||||
protected async syncEvents(showErrors = false): Promise<boolean> {
|
||||
let deleted = false;
|
||||
|
||||
// Try to synchronize offline events.
|
||||
try {
|
||||
const result = await AddonCalendarSync.syncEvents();
|
||||
if (result.warnings && result.warnings.length) {
|
||||
CoreDomUtils.showErrorModal(result.warnings[0]);
|
||||
}
|
||||
|
||||
if (result.deleted && result.deleted.indexOf(this.eventId) != -1) {
|
||||
// This event was deleted during the sync.
|
||||
deleted = true;
|
||||
} else if (this.eventId < 0 && result.offlineIdMap[this.eventId]) {
|
||||
// Event was created, use the online ID.
|
||||
this.eventId = result.offlineIdMap[this.eventId];
|
||||
}
|
||||
|
||||
if (result.updated) {
|
||||
// Trigger a manual sync event.
|
||||
result.source = 'event';
|
||||
|
||||
CoreEvents.trigger(
|
||||
AddonCalendarSyncProvider.MANUAL_SYNCED,
|
||||
result,
|
||||
this.currentSiteId,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (showErrors) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.errorsync', true);
|
||||
}
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load group name.
|
||||
*
|
||||
* @param event Event.
|
||||
* @param courseId Course ID.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async loadGroupName(event: AddonCalendarEventToDisplay, courseId: number): Promise<void> {
|
||||
try {
|
||||
const groups = await CoreGroups.getUserGroupsInCourse(courseId);
|
||||
|
||||
const group = groups.find((group) => group.id == event.groupid);
|
||||
this.groupName = group ? group.name : '';
|
||||
|
||||
} catch {
|
||||
// Error getting groups, just don't show the group name.
|
||||
this.groupName = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a reminder for this event.
|
||||
*/
|
||||
|
@ -392,7 +441,9 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
promises.push(AddonCalendar.invalidateEvent(this.eventId));
|
||||
if (this.eventId > 0) {
|
||||
promises.push(AddonCalendar.invalidateEvent(this.eventId));
|
||||
}
|
||||
promises.push(AddonCalendar.invalidateTimeFormat());
|
||||
|
||||
await CoreUtils.allPromisesIgnoringErrors(promises);
|
||||
|
@ -459,9 +510,14 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
const modal = await CoreDomUtils.showModalLoading('core.sending', true);
|
||||
|
||||
try {
|
||||
const sent = await AddonCalendar.deleteEvent(this.event.id, this.event.name, deleteAll);
|
||||
let onlineEventDeleted = false;
|
||||
if (this.event.id < 0) {
|
||||
await AddonCalendarOffline.deleteEvent(this.event.id);
|
||||
} else {
|
||||
onlineEventDeleted = await AddonCalendar.deleteEvent(this.event.id, this.event.name, deleteAll);
|
||||
}
|
||||
|
||||
if (sent) {
|
||||
if (onlineEventDeleted) {
|
||||
// Event deleted, invalidate right days & months.
|
||||
try {
|
||||
await AddonCalendarHelper.refreshAfterChangeEvent(this.event, deleteAll ? this.event.eventcount : 1);
|
||||
|
@ -471,12 +527,16 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
// Trigger an event.
|
||||
CoreEvents.trigger(AddonCalendarProvider.DELETED_EVENT_EVENT, {
|
||||
eventId: this.eventId,
|
||||
sent: sent,
|
||||
}, CoreSites.getCurrentSiteId());
|
||||
if (this.event.id < 0) {
|
||||
CoreEvents.trigger(AddonCalendarProvider.NEW_EVENT_DISCARDED_EVENT, {}, CoreSites.getCurrentSiteId());
|
||||
} else {
|
||||
CoreEvents.trigger(AddonCalendarProvider.DELETED_EVENT_EVENT, {
|
||||
eventId: this.eventId,
|
||||
sent: onlineEventDeleted,
|
||||
}, CoreSites.getCurrentSiteId());
|
||||
}
|
||||
|
||||
if (sent) {
|
||||
if (onlineEventDeleted || this.event.id < 0) {
|
||||
CoreDomUtils.showToast('addon.calendar.eventcalendareventdeleted', true, 3000);
|
||||
|
||||
// Event deleted, close the view.
|
||||
|
@ -537,11 +597,21 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
// Event was deleted, close the view.
|
||||
CoreNavigator.back();
|
||||
} else if (data.events && (!isManual || data.source != 'event')) {
|
||||
const event = data.events.find((ev) => ev.id == this.eventId);
|
||||
if (this.eventId < 0) {
|
||||
if (data.offlineIdMap[this.eventId]) {
|
||||
// Event was created, use the online ID.
|
||||
this.eventId = data.offlineIdMap[this.eventId];
|
||||
|
||||
if (event) {
|
||||
this.eventLoaded = false;
|
||||
this.refreshEvent();
|
||||
this.eventLoaded = false;
|
||||
this.refreshEvent();
|
||||
}
|
||||
} else {
|
||||
const event = data.events.find((ev) => ev.id == this.eventId);
|
||||
|
||||
if (event) {
|
||||
this.eventLoaded = false;
|
||||
this.refreshEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -550,10 +620,11 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
* Page destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.editEventObserver?.off();
|
||||
this.syncObserver?.off();
|
||||
this.manualSyncObserver?.off();
|
||||
this.onlineObserver?.unsubscribe();
|
||||
this.editEventObserver.off();
|
||||
this.syncObserver.off();
|
||||
this.manualSyncObserver.off();
|
||||
this.onlineObserver.unsubscribe();
|
||||
this.newEventObserver.off();
|
||||
clearInterval(this.updateCurrentTime);
|
||||
}
|
||||
|
||||
|
|
|
@ -301,12 +301,7 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
|
|||
* @param eventId Event to load.
|
||||
*/
|
||||
gotoEvent(eventId: number): void {
|
||||
if (eventId < 0) {
|
||||
// It's an offline event, go to the edit page.
|
||||
this.openEdit(eventId);
|
||||
} else {
|
||||
CoreNavigator.navigateToSitePath(`/calendar/event/${eventId}`);
|
||||
}
|
||||
CoreNavigator.navigateToSitePath(`/calendar/event/${eventId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -245,6 +245,8 @@ export class AddonCalendarHelperProvider {
|
|||
format: 1,
|
||||
visible: 1,
|
||||
offline: true,
|
||||
canedit: event.id < 0,
|
||||
candelete: event.id < 0,
|
||||
timeduration: 0,
|
||||
};
|
||||
|
||||
|
|
|
@ -124,6 +124,7 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider<AddonCalenda
|
|||
const result: AddonCalendarSyncEvents = {
|
||||
warnings: [],
|
||||
events: [],
|
||||
offlineIdMap: {},
|
||||
deleted: [],
|
||||
toinvalidate: [],
|
||||
updated: false,
|
||||
|
@ -256,10 +257,13 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider<AddonCalenda
|
|||
); // Clone the object because it will be modified in the submit function.
|
||||
|
||||
try {
|
||||
const newEvent = await AddonCalendar.submitEventOnline(eventId > 0 ? eventId : 0, data, siteId);
|
||||
const newEvent = await AddonCalendar.submitEventOnline(eventId, data, siteId);
|
||||
|
||||
result.updated = true;
|
||||
result.events.push(newEvent);
|
||||
if (eventId < 0) {
|
||||
result.offlineIdMap[eventId] = newEvent.id;
|
||||
}
|
||||
|
||||
// Add data to invalidate.
|
||||
const numberOfRepetitions = data.repeat ? data.repeats :
|
||||
|
@ -298,6 +302,7 @@ export const AddonCalendarSync = makeSingleton(AddonCalendarSyncProvider);
|
|||
export type AddonCalendarSyncEvents = {
|
||||
warnings: string[];
|
||||
events: AddonCalendarEvent[];
|
||||
offlineIdMap: Record<number, number>; // Map offline ID with online ID for created events.
|
||||
deleted: number[];
|
||||
toinvalidate: AddonCalendarSyncInvalidateEvent[];
|
||||
updated: boolean;
|
||||
|
|
|
@ -1687,7 +1687,7 @@ export class AddonCalendarProvider {
|
|||
/**
|
||||
* Submit an event, either to create it or to edit it. It will fail if offline or cannot connect.
|
||||
*
|
||||
* @param eventId ID of the event. If undefined/null, create a new event.
|
||||
* @param eventId ID of the event. If undefined/null or negative number, create a new event.
|
||||
* @param formData Form data.
|
||||
* @param siteId Site ID. If not provided, current site.
|
||||
* @return Promise resolved when done.
|
||||
|
@ -1700,7 +1700,7 @@ export class AddonCalendarProvider {
|
|||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
// Add data that is "hidden" in web.
|
||||
formData.id = eventId;
|
||||
formData.id = eventId > 0 ? eventId : 0;
|
||||
formData.userid = site.getUserId();
|
||||
formData.visible = 1;
|
||||
formData.instance = 0;
|
||||
|
@ -1724,6 +1724,13 @@ export class AddonCalendarProvider {
|
|||
});
|
||||
}
|
||||
|
||||
if (eventId < 0) {
|
||||
// Offline event has been sent. Change reminders eventid if any.
|
||||
await CoreUtils.ignoreErrors(
|
||||
site.getDb().updateRecords(REMINDERS_TABLE, { eventid: result.event.id }, { eventid: eventId }),
|
||||
);
|
||||
}
|
||||
|
||||
return result.event;
|
||||
}
|
||||
|
||||
|
@ -2240,6 +2247,7 @@ export type AddonCalendarEventToDisplay = Partial<AddonCalendarCalendarEvent> &
|
|||
*/
|
||||
export type AddonCalendarUpdatedEventEvent = {
|
||||
eventId: number;
|
||||
oldEventId?: number; // Old event ID. Used when an offline event is sent.
|
||||
sent?: boolean;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue