From 1553958a7a21932e0dcaf8be75a46f37af670c59 Mon Sep 17 00:00:00 2001 From: Victor Vogel Date: Mon, 19 Oct 2026 22:14:46 -0500 Subject: [PATCH 1/2] fix(mobile): accept comma decimals in scheduled task intervals Normalize decimal commas before converting interval minutes so decimal-pad input can be saved. Share the parser with the minimum-interval hint and show the hint for nonnumeric input. Co-Authored-By: GPT-6.1 Sol --- .../features/settings/SettingsScheduledTasksRouteScreen.tsx | 3 ++- .../mobile/src/features/settings/scheduledTaskDraft.test.ts | 4 +++- apps/mobile/src/features/settings/scheduledTaskDraft.ts | 6 +++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/mobile/src/features/settings/SettingsScheduledTasksRouteScreen.tsx b/apps/mobile/src/features/settings/SettingsScheduledTasksRouteScreen.tsx index 8913502da919e..a838eb81cf601 100644 --- a/apps/mobile/src/features/settings/SettingsScheduledTasksRouteScreen.tsx +++ b/apps/mobile/src/features/settings/SettingsScheduledTasksRouteScreen.tsx @@ -66,6 +66,7 @@ import { SettingsSection } from "./components/SettingsSection"; import { useSettingsEnvironmentFilter, type SettingsTarget } from "./settings-environment-filter"; import { editDraft, + parseIntervalMinutes, scheduledTaskDefaultModel, scheduleFromDraft, type ScheduledTaskDraft as Draft, @@ -977,7 +978,7 @@ function TaskForm({ setDraft({ ...draft, schedule: { ...draft.schedule, intervalMinutes } }) } /> - {Number(draft.schedule.intervalMinutes) < 1 ? ( + {!(parseIntervalMinutes(draft.schedule.intervalMinutes) >= 1) ? ( Intervals must be at least 1 minute. Update this interval before saving. diff --git a/apps/mobile/src/features/settings/scheduledTaskDraft.test.ts b/apps/mobile/src/features/settings/scheduledTaskDraft.test.ts index 69532b3fd264e..0c435d0c8ca2d 100644 --- a/apps/mobile/src/features/settings/scheduledTaskDraft.test.ts +++ b/apps/mobile/src/features/settings/scheduledTaskDraft.test.ts @@ -196,6 +196,8 @@ describe("scheduleFromDraft", () => { it.each([ ["1.5", 90_000], + ["2,5", 150_000], + [" 2,5 ", 150_000], ["1000001", 60_000_060_000], [String(60_001 / 60_000), 60_001], [String(65_000 / 60_000), 65_000], @@ -207,7 +209,7 @@ describe("scheduleFromDraft", () => { }); }); - it.each(["NaN", "Infinity", "9007199254740991", "0.5"])( + it.each(["NaN", "Infinity", "9007199254740991", "0.5", "0,5", "2,5,0"])( "rejects intervals that cannot be written as safe whole milliseconds: %s", (intervalMinutes) => { expect( diff --git a/apps/mobile/src/features/settings/scheduledTaskDraft.ts b/apps/mobile/src/features/settings/scheduledTaskDraft.ts index eff6674aacc93..eaa8ba7718fef 100644 --- a/apps/mobile/src/features/settings/scheduledTaskDraft.ts +++ b/apps/mobile/src/features/settings/scheduledTaskDraft.ts @@ -90,6 +90,10 @@ export function scheduleDraftForTask(task: Pick): Sch } } +export function parseIntervalMinutes(value: string): number { + return Number(value.trim().replace(",", ".")); +} + export function scheduleFromDraft(draft: ScheduleDraft): ScheduledTaskUpsertSchedule | null { if (draft.mode === "webhook") { const maxDeliveryAgeMinutes = parseMaxDeliveryAge(draft.maxDeliveryAgeMinutes); @@ -109,7 +113,7 @@ export function scheduleFromDraft(draft: ScheduleDraft): ScheduledTaskUpsertSche }; } if (draft.mode === "interval") { - const minutes = Number(draft.intervalMinutes); + const minutes = parseIntervalMinutes(draft.intervalMinutes); const everyMs = Math.round(minutes * 60_000); return minutes >= 1 && Number.isSafeInteger(everyMs) ? { type: "interval", everyMs } : null; } From 15214832d6be9587b607fcb437b7e720dcf2f9f1 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Fri, 30 Oct 2026 04:56:54 +0000 Subject: [PATCH 2/2] test(mobile): cover invalid scheduled interval input --- apps/mobile/src/features/settings/scheduledTaskDraft.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mobile/src/features/settings/scheduledTaskDraft.test.ts b/apps/mobile/src/features/settings/scheduledTaskDraft.test.ts index a8cae2446a033..7359403a67dce 100644 --- a/apps/mobile/src/features/settings/scheduledTaskDraft.test.ts +++ b/apps/mobile/src/features/settings/scheduledTaskDraft.test.ts @@ -99,8 +99,8 @@ describe("scheduleFromDraft", () => { }); }); - it.each(["0,5", "2,5,0"])( - "rejects intervals that cannot be written as safe whole milliseconds: %s", + it.each(["0,5", "2,5,0", "Infinity", "150119987580", ""])( + "rejects invalid interval minutes: %s", (intervalMinutes) => { expect( scheduleFromDraft({ ...DEFAULT_SCHEDULE, mode: "interval", intervalMinutes }),