feat(recurrence): Daily tab is "every day at <time>" — drop weekday choice
The Daily tab had two radios: "Every day" vs "Every weekday (Mon–Fri)".
That's confusing — Mon-Fri-only is a weekly pattern, not a daily one,
and it overlapped exactly with what the Weekly tab can already do
(select Mon, Tue, Wed, Thu, Fri).
So Daily now means literally every day. The tab body is just the time
picker plus a one-liner ("Fires once a day at the time below.").
Legacy reminders that stored "MM HH * * 1-5" still load fine — the
parser maps any DOW list (including the 1-5 range) onto a Weekly draft
with Mon-Fri pre-selected. So a saved "weekday" daily reminder shows
up as Weekly with the right days checked, no data loss.
RadioRow component went unused after this — removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
08435988c2
commit
657fa71bf9
@ -34,7 +34,6 @@ type RuleType = "daily" | "weekly" | "monthly" | "yearly";
|
||||
|
||||
interface Draft {
|
||||
type: RuleType;
|
||||
dailyMode: "every_day" | "weekdays";
|
||||
/** Cron weekday list (0=Sun..6=Sat). */
|
||||
weekdays: number[];
|
||||
monthDay: number;
|
||||
@ -50,7 +49,6 @@ const MAX_RULES = 8;
|
||||
function defaultDraft(firstFire: DateTime): Draft {
|
||||
return {
|
||||
type: "daily",
|
||||
dailyMode: "every_day",
|
||||
weekdays: [isoWeekdayToCron(firstFire.weekday)],
|
||||
monthDay: firstFire.day,
|
||||
month: firstFire.month,
|
||||
@ -87,7 +85,7 @@ function draftToCron(d: Draft): string | null {
|
||||
const h = clamp(d.hour, 0, 23);
|
||||
switch (d.type) {
|
||||
case "daily":
|
||||
return d.dailyMode === "weekdays" ? `${m} ${h} * * 1-5` : `${m} ${h} * * *`;
|
||||
return `${m} ${h} * * *`;
|
||||
case "weekly":
|
||||
if (!d.weekdays.length) return null;
|
||||
return `${m} ${h} * * ${d.weekdays.slice().sort((a, b) => a - b).join(",")}`;
|
||||
@ -102,9 +100,7 @@ function describeDraft(d: Draft): string {
|
||||
const t = `${pad2(clamp(d.hour, 0, 23))}:${pad2(clamp(d.minute, 0, 59))}`;
|
||||
switch (d.type) {
|
||||
case "daily":
|
||||
return d.dailyMode === "weekdays"
|
||||
? `Every weekday at ${t}`
|
||||
: `Every day at ${t}`;
|
||||
return `Every day at ${t}`;
|
||||
case "weekly": {
|
||||
if (!d.weekdays.length) return "Pick at least one weekday";
|
||||
const labels = d.weekdays
|
||||
@ -137,12 +133,11 @@ function draftFromCronExpr(expr: string, firstFire: DateTime): Draft {
|
||||
const rest = head[3]!.trim();
|
||||
|
||||
let m: RegExpMatchArray | null;
|
||||
if (rest === "* * 1-5") {
|
||||
return { ...base, type: "daily", dailyMode: "weekdays", hour, minute };
|
||||
}
|
||||
if (rest === "* * *") {
|
||||
return { ...base, type: "daily", dailyMode: "every_day", hour, minute };
|
||||
return { ...base, type: "daily", hour, minute };
|
||||
}
|
||||
// Any DOW list (including the legacy "1-5" weekday-only daily rule)
|
||||
// round-trips as a Weekly draft.
|
||||
if ((m = rest.match(/^\* \* ([0-9,\-]+)$/))) {
|
||||
const days = m[1]!
|
||||
.split(",")
|
||||
@ -357,18 +352,9 @@ function RuleEditor({ draft, onChange }: RuleEditorProps) {
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="daily" className="space-y-3 pt-3">
|
||||
<RadioRow
|
||||
name={`daily-${draft.type}`}
|
||||
checked={draft.dailyMode === "every_day"}
|
||||
onChange={() => onChange({ dailyMode: "every_day" })}
|
||||
label="Every day"
|
||||
/>
|
||||
<RadioRow
|
||||
name={`daily-${draft.type}`}
|
||||
checked={draft.dailyMode === "weekdays"}
|
||||
onChange={() => onChange({ dailyMode: "weekdays" })}
|
||||
label="Every weekday (Mon – Fri)"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Fires once a day at the time below.
|
||||
</p>
|
||||
<TimeField draft={draft} onChange={onChange} />
|
||||
</TabsContent>
|
||||
|
||||
@ -485,24 +471,3 @@ function TimeField({ draft, onChange }: TimeFieldProps) {
|
||||
);
|
||||
}
|
||||
|
||||
interface RadioRowProps {
|
||||
name: string;
|
||||
checked: boolean;
|
||||
onChange: () => void;
|
||||
label: string;
|
||||
}
|
||||
|
||||
function RadioRow({ name, checked, onChange, label }: RadioRowProps) {
|
||||
return (
|
||||
<label className="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="radio"
|
||||
name={name}
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
className="size-4 accent-primary"
|
||||
/>
|
||||
<span className="text-sm">{label}</span>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user