diff --git a/src/core/features/course/components/components.module.ts b/src/core/features/course/components/components.module.ts
index a8bbc04f1..f663770b5 100644
--- a/src/core/features/course/components/components.module.ts
+++ b/src/core/features/course/components/components.module.ts
@@ -29,6 +29,7 @@ import { CoreCourseModuleManualCompletionComponent } from './module-manual-compl
import { CoreCourseModuleNavigationComponent } from './module-navigation/module-navigation';
import { CoreCourseModuleSummaryComponent } from './module-summary/module-summary';
import { CoreCourseCourseIndexTourComponent } from './course-index-tour/course-index-tour';
+import { CoreRemindersComponentsModule } from '@features/reminders/components/components.module';
@NgModule({
declarations: [
@@ -48,6 +49,7 @@ import { CoreCourseCourseIndexTourComponent } from './course-index-tour/course-i
],
imports: [
CoreBlockComponentsModule,
+ CoreRemindersComponentsModule,
CoreSharedModule,
],
exports: [
diff --git a/src/core/features/course/components/module-info/core-course-module-info.html b/src/core/features/course/components/module-info/core-course-module-info.html
index b338fc7d1..1e00b23b0 100644
--- a/src/core/features/course/components/module-info/core-course-module-info.html
+++ b/src/core/features/course/components/module-info/core-course-module-info.html
@@ -26,10 +26,9 @@
-
- {{ date.label }}
- {{ date.readableTime }}
-
+
+
diff --git a/src/core/features/course/components/module-info/course-module-info.scss b/src/core/features/course/components/module-info/course-module-info.scss
index bf6e0d5ce..533696aae 100644
--- a/src/core/features/course/components/module-info/course-module-info.scss
+++ b/src/core/features/course/components/module-info/course-module-info.scss
@@ -48,12 +48,6 @@
padding-top: 8px;
}
- .core-module-dates ion-icon {
- margin-left: 4px;
- margin-right: 4px;
- }
-
- .core-module-dates,
.core-module-availabilityinfo {
font-size: 90%;
ion-icon {
@@ -94,8 +88,6 @@
white-space: normal !important;
}
}
-
-
}
:host-context(.core-iframe-fullscreen) {
diff --git a/src/core/features/course/components/module/core-course-module.html b/src/core/features/course/components/module/core-course-module.html
index 8a099383d..5206b6397 100644
--- a/src/core/features/course/components/module/core-course-module.html
+++ b/src/core/features/course/components/module/core-course-module.html
@@ -81,10 +81,9 @@
*ngIf="(showActivityDates && module.dates && module.dates.length) || module.availabilityinfo">
-
- {{ date.label }}
- {{ date.readableTime }}
-
+
+
diff --git a/src/core/features/course/pages/course-summary/course-summary.html b/src/core/features/course/pages/course-summary/course-summary.html
index 0336344b6..56e89e0fa 100644
--- a/src/core/features/course/pages/course-summary/course-summary.html
+++ b/src/core/features/course/pages/course-summary/course-summary.html
@@ -57,16 +57,14 @@
-
-
- {{ 'core.course.startdate' | translate }}
- {{ course.startdate * 1000 | coreFormatDate:'strftimedaydatetime' }}
-
-
-
- {{ 'core.course.enddate' | translate }}
- {{ course.enddate * 1000 | coreFormatDate:'strftimedaydatetime' }}
-
+
+
+
+
diff --git a/src/core/features/course/pages/course-summary/course-summary.module.ts b/src/core/features/course/pages/course-summary/course-summary.module.ts
index daeb7f70c..c925524f7 100644
--- a/src/core/features/course/pages/course-summary/course-summary.module.ts
+++ b/src/core/features/course/pages/course-summary/course-summary.module.ts
@@ -17,6 +17,7 @@ import { RouterModule, Routes } from '@angular/router';
import { CoreSharedModule } from '@/core/shared.module';
import { CoreCourseSummaryPage } from './course-summary';
+import { CoreRemindersComponentsModule } from '@features/reminders/components/components.module';
const routes: Routes = [
{
@@ -27,6 +28,7 @@ const routes: Routes = [
@NgModule({
imports: [
CoreSharedModule,
+ CoreRemindersComponentsModule,
],
declarations: [
CoreCourseSummaryPage,
@@ -39,6 +41,7 @@ export class CoreCoursePreviewPageComponentModule { }
RouterModule.forChild(routes),
CoreSharedModule,
CoreCoursePreviewPageComponentModule,
+ CoreRemindersComponentsModule,
],
exports: [RouterModule],
})
diff --git a/src/core/features/course/services/course-helper.ts b/src/core/features/course/services/course-helper.ts
index 58ae2f26d..65d242603 100644
--- a/src/core/features/course/services/course-helper.ts
+++ b/src/core/features/course/services/course-helper.ts
@@ -27,7 +27,6 @@ import {
CoreCourseModuleCompletionTracking,
CoreCourseModuleCompletionStatus,
CoreCourseGetContentsWSModule,
- CoreCourseGetContentsWSModuleDate,
} from './course';
import { CoreConstants } from '@/core/constants';
import { CoreLogger } from '@singletons/logger';
@@ -1189,7 +1188,7 @@ export class CoreCourseHelperProvider {
* This should be used in 3.6 sites or higher, where the course contents already include the completion.
*
* @param courseId The course to get the completion.
- * @param mmodule The module.
+ * @param module The module.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done.
*/
@@ -2086,20 +2085,12 @@ export type CoreCourseSectionWithStatus = CoreCourseSection & {
/**
* Module with calculated data.
*/
-export type CoreCourseModuleData = Omit & {
+export type CoreCourseModuleData = Omit & {
course: number; // The course id.
isStealth?: boolean;
handlerData?: CoreCourseModuleHandlerData;
completiondata?: CoreCourseModuleCompletionData;
section: number;
- dates?: CoreCourseModuleDate[];
-};
-
-/**
- * Module date with calculated data.
- */
-export type CoreCourseModuleDate = CoreCourseGetContentsWSModuleDate & {
- readableTime: string;
};
/**
diff --git a/src/core/features/course/services/course.ts b/src/core/features/course/services/course.ts
index 16a680440..70b2ca22b 100644
--- a/src/core/features/course/services/course.ts
+++ b/src/core/features/course/services/course.ts
@@ -38,7 +38,7 @@ import {
import { CoreDomUtils } from '@services/utils/dom';
import { CoreWSError } from '@classes/errors/wserror';
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
-import { CoreCourseHelper, CoreCourseModuleData, CoreCourseModuleCompletionData, CoreCourseModuleDate } from './course-helper';
+import { CoreCourseHelper, CoreCourseModuleData, CoreCourseModuleCompletionData } from './course-helper';
import { CoreCourseFormatDelegate } from './format-delegate';
import { CoreCronDelegate } from '@services/cron';
import { CoreCourseLogCronHandler } from './handlers/log-cron';
@@ -53,7 +53,6 @@ import { CoreDatabaseTable } from '@classes/database/database-table';
import { CoreDatabaseCachingStrategy } from '@classes/database/database-table-proxy';
import { SQLiteDB } from '@classes/sqlitedb';
import { CorePlatform } from '@services/platform';
-import { CoreTime } from '@singletons/time';
import { asyncObservable, firstValueFrom } from '@/core/utils/rxjs';
import { map } from 'rxjs/operators';
@@ -678,39 +677,11 @@ export class CoreCourseProvider {
};
}
- let formattedDates: CoreCourseModuleDate[] | undefined;
-
- if (module.dates) {
- formattedDates = module.dates.map(date => {
- let readableTime = '';
- if (!date.relativeto) {
- readableTime = CoreTimeUtils.userDate(date.timestamp * 1000, 'core.strftimedatetime', true);
- } else {
- readableTime = Translate.instant(
- 'core.course.relativedatessubmissionduedate' + (date.timestamp > date.relativeto ? 'after' : 'before'),
- {
- $a: {
- datediffstr: date.relativeto === date.timestamp ?
- '0 ' + Translate.instant('core.secs') :
- CoreTime.formatTime(date.relativeto - date.timestamp, 3),
- },
- },
- );
- }
-
- return {
- ...date,
- readableTime,
- };
- });
- }
-
return {
...module,
course: courseId,
section: sectionId,
completiondata: completionData,
- dates: formattedDates,
};
}
@@ -1775,7 +1746,10 @@ export type CoreCourseGetContentsWSModule = {
completiondata?: CoreCourseModuleWSCompletionData; // Module completion data.
contents?: CoreCourseModuleContentFile[];
downloadcontent?: number; // @since 4.0 The download content value.
- dates?: CoreCourseGetContentsWSModuleDate[]; // @since 3.11. Activity dates.
+ dates?: {
+ label: string;
+ timestamp: number;
+ }[]; // @since 3.11. Activity dates.
contentsinfo?: { // @since v3.7.6 Contents summary information.
filescount: number; // Total number of files.
filessize: number; // Total files size.
@@ -1785,16 +1759,6 @@ export type CoreCourseGetContentsWSModule = {
};
};
-/**
- * Activity date.
- */
-export type CoreCourseGetContentsWSModuleDate = {
- label: string;
- timestamp: number;
- relativeto?: number; // @since 4.1. Relative date timestamp.
- dataid?: string; // @since 4.1. ID to identify the text.
-};
-
/**
* Data returned by core_course_get_contents WS.
*/
diff --git a/src/core/features/reminders/components/components.module.ts b/src/core/features/reminders/components/components.module.ts
index a16051728..c99c2b06a 100644
--- a/src/core/features/reminders/components/components.module.ts
+++ b/src/core/features/reminders/components/components.module.ts
@@ -14,20 +14,26 @@
import { CoreSharedModule } from '@/core/shared.module';
import { NgModule } from '@angular/core';
+import { CoreRemindersDateComponent } from './date/date';
+import { CoreRemindersSetButtonComponent } from './set-button/set-button';
import { CoreRemindersSetReminderCustomComponent } from './set-reminder-custom/set-reminder-custom';
import { CoreRemindersSetReminderMenuComponent } from './set-reminder-menu/set-reminder-menu';
@NgModule({
declarations: [
- CoreRemindersSetReminderMenuComponent,
+ CoreRemindersDateComponent,
+ CoreRemindersSetButtonComponent,
CoreRemindersSetReminderCustomComponent,
+ CoreRemindersSetReminderMenuComponent,
],
imports: [
CoreSharedModule,
],
exports: [
- CoreRemindersSetReminderMenuComponent,
+ CoreRemindersDateComponent,
+ CoreRemindersSetButtonComponent,
CoreRemindersSetReminderCustomComponent,
+ CoreRemindersSetReminderMenuComponent,
],
})
export class CoreRemindersComponentsModule {}
diff --git a/src/core/features/reminders/components/date/date.html b/src/core/features/reminders/components/date/date.html
new file mode 100644
index 000000000..4f75b5422
--- /dev/null
+++ b/src/core/features/reminders/components/date/date.html
@@ -0,0 +1,8 @@
+
+
+ {{ label }} {{ readableTime }}
+
+
+
+
diff --git a/src/core/features/reminders/components/date/date.scss b/src/core/features/reminders/components/date/date.scss
new file mode 100644
index 000000000..e898db6da
--- /dev/null
+++ b/src/core/features/reminders/components/date/date.scss
@@ -0,0 +1,21 @@
+@import "~theme/globals";
+
+:host {
+ display: flex;
+ flex-direction: row;
+}
+
+div {
+ flex-grow: 1;
+ font-size: 14px;
+ margin: 0;
+ align-self: center;
+
+ ion-icon {
+ @include margin-horizontal(0px, 4px);
+ }
+}
+
+core-reminders-date + :host {
+ margin-top: 12px;
+}
diff --git a/src/core/features/reminders/components/date/date.ts b/src/core/features/reminders/components/date/date.ts
new file mode 100644
index 000000000..137d88d4b
--- /dev/null
+++ b/src/core/features/reminders/components/date/date.ts
@@ -0,0 +1,95 @@
+// (C) Copyright 2015 Moodle Pty Ltd.
+//
+// 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 { CoreReminders } from '@features/reminders/services/reminders';
+import { Component, Input, OnInit } from '@angular/core';
+import { CoreTimeUtils } from '@services/utils/time';
+import { Translate } from '@singletons';
+import { CoreTime } from '@singletons/time';
+
+/**
+ * Component that displays a date to remind.
+ */
+@Component({
+ selector: 'core-reminders-date',
+ templateUrl: 'date.html',
+ styleUrls: ['date.scss'],
+})
+export class CoreRemindersDateComponent implements OnInit {
+
+ @Input() component?: string;
+ @Input() instanceId?: number;
+ @Input() type?: string;
+ @Input() label = '';
+ @Input() time = 0;
+ @Input() relativeTo = 0;
+ @Input() title = '';
+ @Input() url = '';
+
+ showReminderButton = false;
+ timebefore?: number; // Undefined means no reminder has been set.
+ readableTime = '';
+
+ /**
+ * @inheritdoc
+ */
+ async ngOnInit(): Promise {
+ this.readableTime = this.getReadableTime(this.time, this.relativeTo);
+
+ // If not set, button won't be shown.
+ if (this.component === undefined || this.instanceId === undefined || this.type === undefined) {
+ return;
+ }
+
+ const remindersEnabled = CoreReminders.isEnabled();
+ this.showReminderButton = remindersEnabled && this.time > CoreTimeUtils.timestamp();
+
+ if (!this.showReminderButton) {
+ return;
+ }
+
+ const reminders = await CoreReminders.getReminders({
+ instanceId: this.instanceId,
+ component: this.component,
+ type: this.type,
+ });
+
+ this.timebefore = reminders[0]?.timebefore;
+ }
+
+ /**
+ * Returns the readable time.
+ *
+ * @param timestamp Timestamp.
+ * @param relativeTo Base timestamp if timestamp is relative to this one.
+ * @return Readable time string.
+ */
+ protected getReadableTime(timestamp: number, relativeTo = 0): string {
+ if (!relativeTo) {
+ return CoreTimeUtils.userDate(timestamp * 1000, 'core.strftimedatetime', true);
+ }
+
+ return Translate.instant(
+ 'core.course.relativedatessubmissionduedate' + (timestamp > relativeTo ? 'after' : 'before'),
+ {
+ $a: {
+ datediffstr: relativeTo === timestamp ?
+ '0 ' + Translate.instant('core.secs') :
+ CoreTime.formatTime(relativeTo - timestamp, 3),
+ },
+ },
+ );
+ }
+
+}
diff --git a/src/core/features/reminders/components/set-button/set-button.html b/src/core/features/reminders/components/set-button/set-button.html
new file mode 100644
index 000000000..fcc693d20
--- /dev/null
+++ b/src/core/features/reminders/components/set-button/set-button.html
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/core/features/reminders/components/set-button/set-button.ts b/src/core/features/reminders/components/set-button/set-button.ts
new file mode 100644
index 000000000..d9fa8f439
--- /dev/null
+++ b/src/core/features/reminders/components/set-button/set-button.ts
@@ -0,0 +1,116 @@
+// (C) Copyright 2015 Moodle Pty Ltd.
+//
+// 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 { CoreReminderData, CoreReminders, CoreRemindersService } from '@features/reminders/services/reminders';
+import { Component, Input } from '@angular/core';
+import { CoreDomUtils } from '@services/utils/dom';
+import { CoreRemindersSetReminderMenuComponent } from '../set-reminder-menu/set-reminder-menu';
+
+/**
+ * Component that displays a button to set a reminder.
+ */
+@Component({
+ selector: 'core-reminders-set-button',
+ templateUrl: 'set-button.html',
+})
+export class CoreRemindersSetButtonComponent {
+
+ @Input() component?: string;
+ @Input() instanceId?: number;
+ @Input() type?: string;
+ @Input() label = '';
+ @Input() timebefore?: number;
+ @Input() time = -1;
+ @Input() title = '';
+ @Input() url = '';
+
+ /**
+ * Set reminder.
+ *
+ * @param ev Click event.
+ */
+ async setReminder(ev: Event): Promise {
+ if (this.component === undefined || this.instanceId === undefined || this.type === undefined) {
+ return;
+ }
+
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ if (this.timebefore === undefined) {
+ // Set it to the time of the event.
+ this.saveReminder(0);
+
+ return;
+ }
+
+ // Open popover.
+ const reminderTime = await CoreDomUtils.openPopover<{timeBefore: number}>({
+ component: CoreRemindersSetReminderMenuComponent,
+ componentProps: {
+ initialValue: this.timebefore,
+ noReminderLabel: 'core.reminders.delete',
+ },
+ event: ev,
+ });
+
+ if (reminderTime === undefined) {
+ // User canceled.
+ return;
+ }
+
+ // Save before.
+ this.saveReminder(reminderTime.timeBefore);
+ }
+
+ /**
+ * Save reminder.
+ *
+ * @param timebefore Time before the event to fire the notification.
+ * @return Promise resolved when done.
+ */
+ protected async saveReminder(timebefore: number): Promise {
+ if (this.component === undefined || this.instanceId === undefined || this.type === undefined) {
+ return;
+ }
+
+ if (timebefore === CoreRemindersService.DISABLED) {
+ // Remove the reminder.
+ await CoreReminders.removeReminders({
+ instanceId: this.instanceId,
+ component: this.component,
+ type: this.type,
+ });
+ this.timebefore = undefined;
+
+ return;
+ }
+
+ this.timebefore = timebefore;
+
+ const reminder: CoreReminderData = {
+ component: this.component,
+ instanceId: this.instanceId,
+ timebefore: this.timebefore,
+ type: this.type,
+ title: this.label + ' ' + this.title,
+ url: this.url,
+ time: this.time,
+ };
+
+ // Save before.
+ await CoreReminders.addReminder(reminder);
+ }
+
+}