feat: add RRULE parsing to shared package and improve ProposedEventCard UI
- Add rrule library to shared package for RRULE string parsing - Add rruleHelpers.ts with parseRRule() returning freq, until, count, interval, byDay - Add formatters.ts with German date/time formatters for client and server - Extend CreateEventDTO with exceptionDates field for proposals - Extend ChatModel schema with exceptionDates, deleteMode, occurrenceDate - Update proposeUpdateEvent tool to support isRecurring and recurrenceRule params - ProposedEventCard now shows green "Neue Ausnahme" and "Neues Ende" text - Add Sport test scenario with dynamic exception and UNTIL responses - Update CLAUDE.md documentation
This commit is contained in:
49
packages/shared/src/utils/rruleHelpers.ts
Normal file
49
packages/shared/src/utils/rruleHelpers.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { rrulestr, Frequency } from "rrule";
|
||||
|
||||
export interface ParsedRRule {
|
||||
freq: string; // "YEARLY", "MONTHLY", "WEEKLY", "DAILY", etc.
|
||||
until?: Date;
|
||||
count?: number;
|
||||
interval?: number;
|
||||
byDay?: string[]; // ["MO", "WE", "FR"]
|
||||
}
|
||||
|
||||
const FREQ_NAMES: Record<Frequency, string> = {
|
||||
[Frequency.YEARLY]: "YEARLY",
|
||||
[Frequency.MONTHLY]: "MONTHLY",
|
||||
[Frequency.WEEKLY]: "WEEKLY",
|
||||
[Frequency.DAILY]: "DAILY",
|
||||
[Frequency.HOURLY]: "HOURLY",
|
||||
[Frequency.MINUTELY]: "MINUTELY",
|
||||
[Frequency.SECONDLY]: "SECONDLY",
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses an RRULE string and extracts the relevant fields.
|
||||
* Handles both with and without "RRULE:" prefix.
|
||||
*/
|
||||
export function parseRRule(ruleString: string): ParsedRRule | null {
|
||||
if (!ruleString) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Ensure RRULE: prefix is present
|
||||
const normalized = ruleString.startsWith("RRULE:")
|
||||
? ruleString
|
||||
: `RRULE:${ruleString}`;
|
||||
|
||||
const rule = rrulestr(normalized);
|
||||
const options = rule.options;
|
||||
|
||||
return {
|
||||
freq: FREQ_NAMES[options.freq] || "UNKNOWN",
|
||||
until: options.until || undefined,
|
||||
count: options.count || undefined,
|
||||
interval: options.interval > 1 ? options.interval : undefined,
|
||||
byDay: options.byweekday?.map((d) => d.toString()) || undefined,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user