Skip to content

Commit 073031a

Browse files
fix: default full / part day alarm
Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
1 parent c9ab558 commit 073031a

19 files changed

Lines changed: 608 additions & 148 deletions

lib/Controller/SettingsController.php

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ public function setConfig(string $key,
7272
return $this->setSlotDuration($value);
7373
case 'defaultReminder':
7474
return $this->setDefaultReminder($value);
75+
case 'defaultReminderPartDay':
76+
return $this->setDefaultReminderPartDay($value);
77+
case 'defaultReminderFullDay':
78+
return $this->setDefaultReminderFullDay($value);
7579
case 'showTasks':
7680
return $this->setShowTasks($value);
7781
case 'tasksSidebar':
@@ -346,16 +350,31 @@ private function setSlotDuration(string $value):JSONResponse {
346350
return new JSONResponse();
347351
}
348352

353+
/**
354+
* validates reminder values
355+
*
356+
* @param string $value User-selected reminder value
357+
* @param bool $allowPositive Whether positive trigger offsets are allowed
358+
* @return bool
359+
*/
360+
private function isValidReminderValue(string $value, bool $allowPositive = false): bool {
361+
if ($value === 'none') {
362+
return true;
363+
}
364+
365+
$options = $allowPositive ? [] : ['options' => ['max_range' => 0]];
366+
367+
return filter_var($value, FILTER_VALIDATE_INT, $options) !== false;
368+
}
369+
349370
/**
350371
* sets defaultReminder for user
351372
*
352373
* @param string $value User-selected option for default_reminder in agenda view
353374
* @return JSONResponse
354375
*/
355376
private function setDefaultReminder(string $value):JSONResponse {
356-
if ($value !== 'none'
357-
&& filter_var($value, FILTER_VALIDATE_INT,
358-
['options' => ['max_range' => 0]]) === false) {
377+
if (!$this->isValidReminderValue($value)) {
359378
return new JSONResponse([], Http::STATUS_UNPROCESSABLE_ENTITY);
360379
}
361380

@@ -372,4 +391,54 @@ private function setDefaultReminder(string $value):JSONResponse {
372391

373392
return new JSONResponse();
374393
}
394+
395+
/**
396+
* sets defaultReminderPartDay for user
397+
*
398+
* @param string $value User-selected option for the part-day default reminder
399+
* @return JSONResponse
400+
*/
401+
private function setDefaultReminderPartDay(string $value):JSONResponse {
402+
if (!$this->isValidReminderValue($value)) {
403+
return new JSONResponse([], Http::STATUS_UNPROCESSABLE_ENTITY);
404+
}
405+
406+
try {
407+
$this->config->setUserValue(
408+
$this->userId,
409+
$this->appName,
410+
'defaultReminderPartDay',
411+
$value
412+
);
413+
} catch (\Exception $e) {
414+
return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
415+
}
416+
417+
return new JSONResponse();
418+
}
419+
420+
/**
421+
* sets defaultReminderFullDay for user
422+
*
423+
* @param string $value User-selected option for the full-day default reminder
424+
* @return JSONResponse
425+
*/
426+
private function setDefaultReminderFullDay(string $value):JSONResponse {
427+
if (!$this->isValidReminderValue($value, true)) {
428+
return new JSONResponse([], Http::STATUS_UNPROCESSABLE_ENTITY);
429+
}
430+
431+
try {
432+
$this->config->setUserValue(
433+
$this->userId,
434+
$this->appName,
435+
'defaultReminderFullDay',
436+
$value
437+
);
438+
} catch (\Exception $e) {
439+
return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
440+
}
441+
442+
return new JSONResponse();
443+
}
375444
}

lib/Service/CalendarInitialStateService.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ public function run(): void {
6262
$attachmentsFolder = $this->config->getUserValue($this->userId, 'dav', 'attachmentsFolder', '/Calendar');
6363
$slotDuration = $this->config->getUserValue($this->userId, $this->appName, 'slotDuration', $defaultSlotDuration);
6464
$defaultReminder = $this->config->getUserValue($this->userId, $this->appName, 'defaultReminder', $defaultDefaultReminder);
65+
$defaultReminderPartDay = $this->config->getUserValue($this->userId, $this->appName, 'defaultReminderPartDay', $defaultReminder);
66+
$defaultReminderFullDay = $this->config->getUserValue($this->userId, $this->appName, 'defaultReminderFullDay', $defaultReminder);
6567
$showTasks = $this->config->getUserValue($this->userId, $this->appName, 'showTasks', $defaultShowTasks) === 'yes';
6668
$tasksSidebar = $this->config->getUserValue($this->userId, $this->appName, 'tasksSidebar', $defaultTasksSidebar) === 'yes';
6769
$hideEventExport = $this->config->getAppValue($this->appName, 'hideEventExport', 'no') === 'yes';
@@ -104,6 +106,8 @@ public function run(): void {
104106
$this->initialStateService->provideInitialState('attachments_folder', $attachmentsFolder);
105107
$this->initialStateService->provideInitialState('slot_duration', $slotDuration);
106108
$this->initialStateService->provideInitialState('default_reminder', $defaultReminder);
109+
$this->initialStateService->provideInitialState('default_reminder_part_day', $defaultReminderPartDay);
110+
$this->initialStateService->provideInitialState('default_reminder_full_day', $defaultReminderFullDay);
107111
$this->initialStateService->provideInitialState('show_tasks', $showTasks);
108112
$this->initialStateService->provideInitialState('tasks_sidebar', $tasksSidebar);
109113
$this->initialStateService->provideInitialState('tasks_enabled', $tasksEnabled);

package-lock.json

Lines changed: 15 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"@nextcloud/axios": "^2.5.2",
4949
"@nextcloud/calendar-availability-vue": "^3.0.0",
5050
"@nextcloud/calendar-js": "^8.1.6",
51-
"@nextcloud/cdav-library": "^2.2.0",
51+
"@nextcloud/cdav-library": "^2.4.0",
5252
"@nextcloud/dialogs": "^7.3.0",
5353
"@nextcloud/event-bus": "^3.3.3",
5454
"@nextcloud/initial-state": "^3.0.0",
@@ -106,8 +106,8 @@
106106
"ts-loader": "^9.5.4",
107107
"typescript": "^6.0.2",
108108
"vitest": "^4.1.2",
109-
"vue-template-compiler": "^2.7.16",
110-
"vue-style-loader": "^4.1.3"
109+
"vue-style-loader": "^4.1.3",
110+
"vue-template-compiler": "^2.7.16"
111111
},
112112
"optionalDependencies": {
113113
"fsevents": "^2.3.3"

src/components/AppNavigation/EditCalendarModal.vue

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,32 @@
4545
</template>
4646
<template v-if="!calendar.isSharedWithMe && isAfterVersion">
4747
<div class="edit-calendar-modal__default-alarm">
48-
<label for="default-alarm-select" class="edit-calendar-modal__default-alarm__label">
49-
{{ $t('calendar', 'Default reminder') }}
48+
<label for="default-alarm-partday-select" class="edit-calendar-modal__default-alarm__label">
49+
{{ $t('calendar', 'Default reminder for part-day events') }}
5050
</label>
5151
<NcSelect
52-
id="default-alarm-select"
53-
v-model="selectedDefaultAlarm"
54-
:options="defaultAlarmOptions"
52+
id="default-alarm-partday-select"
53+
v-model="selectedDefaultAlarmPartDay"
54+
:options="defaultAlarmPartDayOptions"
55+
:clearable="false"
56+
:placeholder="$t('calendar', 'Select default reminder')"
57+
class="edit-calendar-modal__default-alarm__select"
58+
@update:modelValue="defaultAlarmChanged = true" />
59+
</div>
60+
<div class="edit-calendar-modal__default-alarm">
61+
<label for="default-alarm-fullday-select" class="edit-calendar-modal__default-alarm__label">
62+
{{ $t('calendar', 'Default reminder for full-day events') }}
63+
</label>
64+
<NcSelect
65+
id="default-alarm-fullday-select"
66+
v-model="selectedDefaultAlarmFullDay"
67+
:options="defaultAlarmFullDayOptions"
5568
:clearable="false"
5669
:placeholder="$t('calendar', 'Select default reminder')"
5770
class="edit-calendar-modal__default-alarm__select"
5871
@update:modelValue="defaultAlarmChanged = true" />
5972
<p class="edit-calendar-modal__default-alarm__hint">
60-
{{ $t('calendar', 'This reminder will be automatically added to all new events created in this calendar') }}
73+
{{ $t('calendar', 'These reminders will be automatically added to new events created in this calendar') }}
6174
</p>
6275
</div>
6376
</template>
@@ -159,7 +172,8 @@ export default {
159172
isTransparent: false,
160173
calendarName: undefined,
161174
calendarNameChanged: false,
162-
selectedDefaultAlarm: null,
175+
selectedDefaultAlarmPartDay: null,
176+
selectedDefaultAlarmFullDay: null,
163177
defaultAlarmChanged: false,
164178
}
165179
},
@@ -251,11 +265,11 @@ export default {
251265
},
252266
253267
/**
254-
* Get the default alarm options for the select dropdown
268+
* Get the default alarm options for part-day (timed) events
255269
*
256270
* @return {Array}
257271
*/
258-
defaultAlarmOptions() {
272+
defaultAlarmPartDayOptions() {
259273
const settingsStore = useSettingsStore()
260274
const currentUserTimezone = settingsStore.getResolvedTimezone
261275
const locale = settingsStore.momentLocale
@@ -267,7 +281,6 @@ export default {
267281
},
268282
]
269283
270-
// Add standard alarm options for timed events
271284
const alarms = getDefaultAlarms(false)
272285
for (const alarm of alarms) {
273286
const alarmObject = this.getAlarmObjectFromTriggerTime(alarm)
@@ -280,6 +293,35 @@ export default {
280293
return options
281294
},
282295
296+
/**
297+
* Get the default alarm options for full-day (all-day) events
298+
*
299+
* @return {Array}
300+
*/
301+
defaultAlarmFullDayOptions() {
302+
const settingsStore = useSettingsStore()
303+
const currentUserTimezone = settingsStore.getResolvedTimezone
304+
const locale = settingsStore.momentLocale
305+
306+
const options = [
307+
{
308+
label: this.$t('calendar', 'None'),
309+
value: null,
310+
},
311+
]
312+
313+
const alarms = getDefaultAlarms(true)
314+
for (const alarm of alarms) {
315+
const alarmObject = this.getAlarmObjectFromTriggerTime(alarm)
316+
options.push({
317+
label: alarmFormat(alarmObject, true, currentUserTimezone, locale),
318+
value: alarm,
319+
})
320+
}
321+
322+
return options
323+
},
324+
283325
/**
284326
* Whether the default alarm feature is supported (Nextcloud 34+)
285327
*
@@ -302,13 +344,22 @@ export default {
302344
this.calendarColorChanged = false
303345
this.isTransparent = calendar.transparency === 'transparent'
304346
305-
// Initialize default alarm
306-
if (calendar.defaultAlarm === null) {
307-
this.selectedDefaultAlarm = this.defaultAlarmOptions[0]
347+
// Initialize default alarm for part-day events
348+
if (calendar.defaultAlarmPartDay === null) {
349+
this.selectedDefaultAlarmPartDay = this.defaultAlarmPartDayOptions[0]
350+
} else {
351+
const value = parseInt(calendar.defaultAlarmPartDay)
352+
const option = this.defaultAlarmPartDayOptions.find((opt) => opt.value === value)
353+
this.selectedDefaultAlarmPartDay = option || this.defaultAlarmPartDayOptions[0]
354+
}
355+
356+
// Initialize default alarm for full-day events
357+
if (calendar.defaultAlarmFullDay === null) {
358+
this.selectedDefaultAlarmFullDay = this.defaultAlarmFullDayOptions[0]
308359
} else {
309-
const value = parseInt(calendar.defaultAlarm)
310-
const option = this.defaultAlarmOptions.find((opt) => opt.value === value)
311-
this.selectedDefaultAlarm = option || this.defaultAlarmOptions[0]
360+
const value = parseInt(calendar.defaultAlarmFullDay)
361+
const option = this.defaultAlarmFullDayOptions.find((opt) => opt.value === value)
362+
this.selectedDefaultAlarmFullDay = option || this.defaultAlarmFullDayOptions[0]
312363
}
313364
this.defaultAlarmChanged = false
314365
},
@@ -377,19 +428,20 @@ export default {
377428
},
378429
379430
/**
380-
* Save the calendar default alarm.
431+
* Save the calendar default alarms.
381432
*/
382433
async saveDefaultAlarm() {
383434
try {
384-
const defaultAlarmValue = this.selectedDefaultAlarm ? this.selectedDefaultAlarm.value : null
385-
await this.calendarsStore.changeCalendarDefaultAlarm({
435+
const pdayValue = this.selectedDefaultAlarmPartDay ? this.selectedDefaultAlarmPartDay.value : null
436+
const fdayValue = this.selectedDefaultAlarmFullDay ? this.selectedDefaultAlarmFullDay.value : null
437+
await this.calendarsStore.changeCalendarDefaultAlarms({
386438
calendar: this.calendar,
387-
defaultAlarm: defaultAlarmValue,
439+
defaultAlarmPartDay: pdayValue,
440+
defaultAlarmFullDay: fdayValue,
388441
})
389442
} catch (error) {
390-
logger.error('Failed to save calendar default alarm', {
443+
logger.error('Failed to save calendar default alarms', {
391444
calendar: this.calendar,
392-
defaultAlarm: this.selectedDefaultAlarm,
393445
})
394446
throw error
395447
}

0 commit comments

Comments
 (0)