Add recurring series to events
A Series checkbox under When opens a panel for the schedule: weekly on chosen weekdays, monthly by date, or monthly by weekday position, every N weeks or months, with meeting times and an optional meeting count. starts_on anchors the schedule and ends_on bounds it, so effective_status needs no change. Occurrences are derived, not stored. src/lib/eventSeries.ts builds the schedule label shown on cards and the event page, and the upcoming dates listed on the event page. Migration 016 adds the columns; the CRUD engine gains a time type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
aebc1c302b
commit
5ed7994a64
11 changed files with 500 additions and 3 deletions
|
|
@ -34,6 +34,7 @@ export class HttpError extends Error {
|
|||
|
||||
const SLUG = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
||||
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
||||
const CLOCK_TIME = /^([01]\d|2[0-3]):[0-5]\d$/;
|
||||
|
||||
/* Not a value the caller can ever send, so it can mean "leave this
|
||||
column out of the statement" without colliding with real data. */
|
||||
|
|
@ -98,6 +99,13 @@ function coerceValue(column, raw, errors, prefix = "") {
|
|||
if (!ISO_DATE.test(value)) errors[key] = "Use YYYY-MM-DD.";
|
||||
return ISO_DATE.test(value) ? value : null;
|
||||
}
|
||||
case "time": {
|
||||
// <input type="time"> sends HH:MM, or HH:MM:SS when a step
|
||||
// asks for seconds. Nothing here does, so seconds are dropped.
|
||||
const value = String(raw).trim().slice(0, 5);
|
||||
if (!CLOCK_TIME.test(value)) errors[key] = "Use HH:MM, 24-hour.";
|
||||
return CLOCK_TIME.test(value) ? value : null;
|
||||
}
|
||||
default: {
|
||||
const value = String(raw).trim();
|
||||
return value === "" ? null : value;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue