MOBILE-3936 reminders: Avoid creating reminders in the past

main
Pau Ferrer Ocaña 2022-11-08 17:33:50 +01:00
parent 5d910ea5b4
commit 69d2530bb8
7 changed files with 74 additions and 24 deletions

View File

@ -43,7 +43,6 @@ import { CoreError } from '@classes/errors/error';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CanLeave } from '@guards/can-leave'; import { CanLeave } from '@guards/can-leave';
import { CoreForms } from '@singletons/form'; import { CoreForms } from '@singletons/form';
import { CoreLocalNotifications } from '@services/local-notifications';
import { CoreReminders, CoreRemindersService, CoreRemindersUnits } from '@features/reminders/services/reminders'; import { CoreReminders, CoreRemindersService, CoreRemindersUnits } from '@features/reminders/services/reminders';
import { CoreRemindersSetReminderMenuComponent } from '@features/reminders/components/set-reminder-menu/set-reminder-menu'; import { CoreRemindersSetReminderMenuComponent } from '@features/reminders/components/set-reminder-menu/set-reminder-menu';
@ -671,8 +670,14 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave {
* Add a reminder. * Add a reminder.
*/ */
async addReminder(): Promise<void> { async addReminder(): Promise<void> {
const formData = this.form.value;
const eventTime = CoreTimeUtils.convertToTimestamp(formData.timestart, true);
const reminderTime = await CoreDomUtils.openPopover<{timeBefore: number}>({ const reminderTime = await CoreDomUtils.openPopover<{timeBefore: number}>({
component: CoreRemindersSetReminderMenuComponent, component: CoreRemindersSetReminderMenuComponent,
componentProps: {
eventTime,
},
// TODO: Add event to open the popover in place. // TODO: Add event to open the popover in place.
}); });

View File

@ -28,7 +28,6 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; import { CoreDomUtils, ToastDuration } from '@services/utils/dom';
import { CoreTextUtils } from '@services/utils/text'; import { CoreTextUtils } from '@services/utils/text';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreLocalNotifications } from '@services/local-notifications';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreTimeUtils } from '@services/utils/time'; import { CoreTimeUtils } from '@services/utils/time';
import { CoreGroups } from '@services/groups'; import { CoreGroups } from '@services/groups';
@ -389,6 +388,9 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
const reminderTime = await CoreDomUtils.openPopover<{timeBefore: number}>({ const reminderTime = await CoreDomUtils.openPopover<{timeBefore: number}>({
component: CoreRemindersSetReminderMenuComponent, component: CoreRemindersSetReminderMenuComponent,
componentProps: {
eventTime: this.event.timestart,
},
// TODO: Add event to open the popover in place. // TODO: Add event to open the popover in place.
}); });

View File

@ -1,4 +1,6 @@
<ion-button fill="clear" size="small" (click)="setReminder($event)"> <ion-button fill="clear" size="small" (click)="setReminder($event)"
<ion-icon name="fas-bell" slot="icon-only" *ngIf="timebefore !== undefined"></ion-icon> [attr.aria-label]="'core.reminders.setareminderfor' | translate : { title: title, label: labelClean }"
<ion-icon name="far-bell-slash" slot="icon-only" *ngIf="timebefore === undefined"></ion-icon> [attr.aria-checked]="timebefore !== undefined">
<ion-icon name="fas-bell" slot="icon-only" *ngIf="timebefore !== undefined" aria-hidden="true"></ion-icon>
<ion-icon name="far-bell-slash" slot="icon-only" *ngIf="timebefore === undefined" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { CoreReminderData, CoreReminders, CoreRemindersService } from '@features/reminders/services/reminders'; import { CoreReminderData, CoreReminders, CoreRemindersService } from '@features/reminders/services/reminders';
import { Component, Input } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreRemindersSetReminderMenuComponent } from '../set-reminder-menu/set-reminder-menu'; import { CoreRemindersSetReminderMenuComponent } from '../set-reminder-menu/set-reminder-menu';
@ -24,7 +24,7 @@ import { CoreRemindersSetReminderMenuComponent } from '../set-reminder-menu/set-
selector: 'core-reminders-set-button', selector: 'core-reminders-set-button',
templateUrl: 'set-button.html', templateUrl: 'set-button.html',
}) })
export class CoreRemindersSetButtonComponent { export class CoreRemindersSetButtonComponent implements OnInit {
@Input() component?: string; @Input() component?: string;
@Input() instanceId?: number; @Input() instanceId?: number;
@ -35,6 +35,15 @@ export class CoreRemindersSetButtonComponent {
@Input() title = ''; @Input() title = '';
@Input() url = ''; @Input() url = '';
labelClean = '';
/**
* @inheritdoc
*/
ngOnInit(): void {
this.labelClean = this.label.replace(':', '');
}
/** /**
* Set reminder. * Set reminder.
* *
@ -60,6 +69,7 @@ export class CoreRemindersSetButtonComponent {
component: CoreRemindersSetReminderMenuComponent, component: CoreRemindersSetReminderMenuComponent,
componentProps: { componentProps: {
initialValue: this.timebefore, initialValue: this.timebefore,
eventTime: this.time,
noReminderLabel: 'core.reminders.delete', noReminderLabel: 'core.reminders.delete',
}, },
event: ev, event: ev,
@ -85,7 +95,7 @@ export class CoreRemindersSetButtonComponent {
return; return;
} }
if (timebefore === CoreRemindersService.DISABLED) { if (timebefore === undefined || timebefore === CoreRemindersService.DISABLED) {
// Remove the reminder. // Remove the reminder.
await CoreReminders.removeReminders({ await CoreReminders.removeReminders({
instanceId: this.instanceId, instanceId: this.instanceId,

View File

@ -9,14 +9,15 @@
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<div class="flex-row"> <div class="flex-row">
<!-- Input to enter the value. --> <!-- Input to enter the value. -->
<ion-input type="number" name="customvalue" [(ngModel)]="customValue" placeholder="10"> <ion-input id="reminderValue" type="number" name="customvalue" [(ngModel)]="customValue" placeholder="10"
[attr.aria-label]="'core.reminders.value' | translate">
</ion-input> </ion-input>
<!-- Units. --> <!-- Units. -->
<label class="accesshide" for="reminderUnits">{{ 'core.reminders.units' | translate }}</label> <span class="accesshide" id="reminderUnits_label">{{ 'core.reminders.units' | translate }}</span>
<ion-select id="reminderUnits" name="customunits" [(ngModel)]="customUnits" interface="action-sheet" slot="end" <ion-select aria-labelledby="reminderUnits_label" name="customunits" [(ngModel)]="customUnits" interface="action-sheet"
[interfaceOptions]="{header: 'core.reminders.units' | translate}"> slot="end" [interfaceOptions]="{header: 'core.reminders.units' | translate}">
<ion-select-option *ngFor="let option of customUnitsOptions" [value]="option.value"> <ion-select-option *ngFor=" let option of customUnitsOptions" [value]="option.value">
{{ option.label | translate }} {{ option.label | translate }}
</ion-select-option> </ion-select-option>
</ion-select> </ion-select>
@ -29,7 +30,7 @@
</ion-col> </ion-col>
<ion-col> <ion-col>
<ion-button expand="block" (click)="set()"> <ion-button expand="block" (click)="set()">
{{ 'core.done' | translate }} {{ 'core.reminders.setreminder' | translate }}
</ion-button> </ion-button>
</ion-col> </ion-col>
</ion-row> </ion-row>

View File

@ -8,27 +8,31 @@
<ion-content> <ion-content>
<ion-content> <ion-content>
<!-- Preset options. --> <!-- Preset options. -->
<ion-item button class="ion-text-wrap" (click)="setReminder(option.radioValue)" detail="false" *ngFor="let option of presetOptions"> <ng-container *ngFor="let option of presetOptions">
<ion-label> <ion-item button class="ion-text-wrap" (click)="setReminder(option.radioValue)" detail="false" *ngIf="option.enabled"
<p class="item-heading">{{ option.label }}</p> [attr.aria-selected]="currentValue === option.radioValue">
</ion-label> <ion-label>
<ion-icon name="fas-check" *ngIf="currentValue === option.radioValue" slot="end"></ion-icon> <p class="item-heading">{{ option.label }}</p>
</ion-item> </ion-label>
<ion-icon name="fas-check" *ngIf="currentValue === option.radioValue" slot="end" aria-hidden="true"></ion-icon>
</ion-item>
</ng-container>
<!-- Custom value. --> <!-- Custom value. -->
<ion-item button class="ion-text-wrap" (click)="setCustom($event)" detail="false"> <ion-item button class="ion-text-wrap" (click)="setCustom($event)" detail="false" [attr.aria-selected]="currentValue === 'custom'">
<ion-label> <ion-label>
<p class="item-heading">{{ 'core.reminders.custom' | translate }}</p> <p class="item-heading">{{ 'core.reminders.custom' | translate }}</p>
<p>{{ customLabel }}</p> <p>{{ customLabel }}</p>
</ion-label> </ion-label>
<ion-icon name="fas-check" *ngIf="currentValue === 'custom'" slot="end"></ion-icon> <ion-icon name="fas-check" *ngIf="currentValue === 'custom'" slot="end" aria-hidden="true"></ion-icon>
</ion-item> </ion-item>
<ion-item *ngIf="noReminderLabel" button class="ion-text-wrap text-danger border-top" (click)="disableReminder()" detail="false"> <ion-item *ngIf="noReminderLabel" button class="ion-text-wrap text-danger border-top" (click)="disableReminder()" detail="false"
[attr.aria-selected]="currentValue === 'disabled'">
<ion-label> <ion-label>
<p class="item-heading">{{ noReminderLabel | translate }}</p> <p class="item-heading">{{ noReminderLabel | translate }}</p>
</ion-label> </ion-label>
<ion-icon name="fas-check" *ngIf="currentValue === 'disabled'" slot="end"></ion-icon> <ion-icon name="fas-check" *ngIf="currentValue === 'disabled'" slot="end" aria-hidden="true"></ion-icon>
</ion-item> </ion-item>
</ion-content> </ion-content>

View File

@ -34,6 +34,7 @@ import { CoreRemindersSetReminderCustomComponent } from '../set-reminder-custom/
export class CoreRemindersSetReminderMenuComponent implements OnInit { export class CoreRemindersSetReminderMenuComponent implements OnInit {
@Input() initialValue?: number; @Input() initialValue?: number;
@Input() eventTime?: number;
@Input() noReminderLabel = ''; @Input() noReminderLabel = '';
currentValue = '0m'; currentValue = '0m';
@ -48,24 +49,28 @@ export class CoreRemindersSetReminderMenuComponent implements OnInit {
value: 0, value: 0,
unit: CoreRemindersUnits.MINUTE, unit: CoreRemindersUnits.MINUTE,
label: '', label: '',
enabled: true,
}, },
{ {
radioValue: '1h', radioValue: '1h',
value: 1, value: 1,
unit: CoreRemindersUnits.HOUR, unit: CoreRemindersUnits.HOUR,
label: '', label: '',
enabled: true,
}, },
{ {
radioValue: '12h', radioValue: '12h',
value: 12, value: 12,
unit: CoreRemindersUnits.HOUR, unit: CoreRemindersUnits.HOUR,
label: '', label: '',
enabled: true,
}, },
{ {
radioValue: '1d', radioValue: '1d',
value: 1, value: 1,
unit: CoreRemindersUnits.DAY, unit: CoreRemindersUnits.DAY,
label: '', label: '',
enabled: true,
}, },
]; ];
@ -75,6 +80,7 @@ export class CoreRemindersSetReminderMenuComponent implements OnInit {
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
this.presetOptions.forEach((option) => { this.presetOptions.forEach((option) => {
option.label = CoreReminders.getUnitValueLabel(option.value, option.unit); option.label = CoreReminders.getUnitValueLabel(option.value, option.unit);
option.enabled = this.isValidTime(option.unit, option.value);
}); });
const initialValue = CoreRemindersService.convertSecondsToValueAndUnit(this.initialValue); const initialValue = CoreRemindersService.convertSecondsToValueAndUnit(this.initialValue);
@ -106,7 +112,10 @@ export class CoreRemindersSetReminderMenuComponent implements OnInit {
*/ */
setReminder(value?: string): void { setReminder(value?: string): void {
const option = this.presetOptions.find(option => option.radioValue === value); const option = this.presetOptions.find(option => option.radioValue === value);
if (!option) { if (!option) {
PopoverController.dismiss();
return; return;
} }
@ -120,6 +129,23 @@ export class CoreRemindersSetReminderMenuComponent implements OnInit {
PopoverController.dismiss({ timeBefore: undefined }); PopoverController.dismiss({ timeBefore: undefined });
} }
/**
* Check the time is on the future.
*
* @param unit Time unit.
* @param value Time value.
* @return Wether is a valid time or not.
*/
protected isValidTime(unit: number, value: number): boolean {
if (!this.eventTime) {
return true;
}
const timebefore = unit * value;
return (this.eventTime - timebefore) * 1000 > Date.now();
}
/** /**
* Custom value input clicked. * Custom value input clicked.
* *