@happyvertical/smrt-events 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +20 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +151 -0
- package/dist/__smrt-register__.d.ts +2 -0
- package/dist/__smrt-register__.d.ts.map +1 -0
- package/dist/collections/EventAssetCollection.d.ts +16 -0
- package/dist/collections/EventAssetCollection.d.ts.map +1 -0
- package/dist/collections/EventCollection.d.ts +108 -0
- package/dist/collections/EventCollection.d.ts.map +1 -0
- package/dist/collections/EventParticipantCollection.d.ts +42 -0
- package/dist/collections/EventParticipantCollection.d.ts.map +1 -0
- package/dist/collections/EventSeriesCollection.d.ts +62 -0
- package/dist/collections/EventSeriesCollection.d.ts.map +1 -0
- package/dist/collections/EventTypeCollection.d.ts +53 -0
- package/dist/collections/EventTypeCollection.d.ts.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1419 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.json +4067 -0
- package/dist/models/Event.d.ts +92 -0
- package/dist/models/Event.d.ts.map +1 -0
- package/dist/models/EventAsset.d.ts +17 -0
- package/dist/models/EventAsset.d.ts.map +1 -0
- package/dist/models/EventParticipant.d.ts +65 -0
- package/dist/models/EventParticipant.d.ts.map +1 -0
- package/dist/models/EventSeries.d.ts +73 -0
- package/dist/models/EventSeries.d.ts.map +1 -0
- package/dist/models/EventType.d.ts +44 -0
- package/dist/models/EventType.d.ts.map +1 -0
- package/dist/playground.d.ts +2 -0
- package/dist/playground.d.ts.map +1 -0
- package/dist/playground.js +47 -0
- package/dist/playground.js.map +1 -0
- package/dist/smrt-knowledge.json +1662 -0
- package/dist/svelte/components/MeetingView.svelte +321 -0
- package/dist/svelte/components/MeetingView.svelte.d.ts +9 -0
- package/dist/svelte/components/MeetingView.svelte.d.ts.map +1 -0
- package/dist/svelte/i18n.d.ts +10 -0
- package/dist/svelte/i18n.d.ts.map +1 -0
- package/dist/svelte/i18n.js +11 -0
- package/dist/svelte/index.d.ts +11 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +18 -0
- package/dist/svelte/playground.d.ts +40 -0
- package/dist/svelte/playground.d.ts.map +1 -0
- package/dist/svelte/playground.js +43 -0
- package/dist/svelte/types.d.ts +37 -0
- package/dist/svelte/types.d.ts.map +1 -0
- package/dist/svelte/types.js +6 -0
- package/dist/types.d.ts +127 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui.d.ts +10 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +28 -0
- package/dist/ui.js.map +1 -0
- package/dist/utils.d.ts +93 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +127 -0
- package/dist/utils.js.map +1 -0
- package/package.json +102 -0
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ModuleUISlot, SmrtModuleMeta } from '@happyvertical/smrt-types';
|
|
2
|
+
/**
|
|
3
|
+
* Events module UI slots
|
|
4
|
+
*/
|
|
5
|
+
export declare const EVENTS_UI_SLOTS: Record<string, ModuleUISlot>;
|
|
6
|
+
/**
|
|
7
|
+
* Events module metadata
|
|
8
|
+
*/
|
|
9
|
+
export declare const EVENTS_MODULE_META: SmrtModuleMeta;
|
|
10
|
+
//# sourceMappingURL=ui.d.ts.map
|
package/dist/ui.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE9E;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAUxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,cAWhC,CAAC"}
|
package/dist/ui.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const EVENTS_UI_SLOTS = {
|
|
2
|
+
"meeting-view": {
|
|
3
|
+
id: "meeting-view",
|
|
4
|
+
label: "Meeting View",
|
|
5
|
+
description: "Full meeting details with documents and resources",
|
|
6
|
+
icon: "calendar",
|
|
7
|
+
category: "detail",
|
|
8
|
+
order: 1,
|
|
9
|
+
propsInterface: "MeetingViewProps"
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const EVENTS_MODULE_META = {
|
|
13
|
+
name: "@happyvertical/smrt-events",
|
|
14
|
+
displayName: "Events",
|
|
15
|
+
description: "Hierarchical event management with participant tracking",
|
|
16
|
+
uiSlots: EVENTS_UI_SLOTS,
|
|
17
|
+
models: ["Event", "EventParticipant", "EventSeries", "Meeting", "Deadline"],
|
|
18
|
+
collections: [
|
|
19
|
+
"EventCollection",
|
|
20
|
+
"EventParticipantCollection",
|
|
21
|
+
"EventSeriesCollection"
|
|
22
|
+
]
|
|
23
|
+
};
|
|
24
|
+
export {
|
|
25
|
+
EVENTS_MODULE_META,
|
|
26
|
+
EVENTS_UI_SLOTS
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=ui.js.map
|
package/dist/ui.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sources":["../src/ui.ts"],"sourcesContent":["/**\n * Events Module UI Slot Declarations\n *\n * This file defines the UI extension points for the events module.\n * UI components are implemented in the ./svelte subpath.\n */\n\nimport type { ModuleUISlot, SmrtModuleMeta } from '@happyvertical/smrt-types';\n\n/**\n * Events module UI slots\n */\nexport const EVENTS_UI_SLOTS: Record<string, ModuleUISlot> = {\n 'meeting-view': {\n id: 'meeting-view',\n label: 'Meeting View',\n description: 'Full meeting details with documents and resources',\n icon: 'calendar',\n category: 'detail',\n order: 1,\n propsInterface: 'MeetingViewProps',\n },\n};\n\n/**\n * Events module metadata\n */\nexport const EVENTS_MODULE_META: SmrtModuleMeta = {\n name: '@happyvertical/smrt-events',\n displayName: 'Events',\n description: 'Hierarchical event management with participant tracking',\n uiSlots: EVENTS_UI_SLOTS,\n models: ['Event', 'EventParticipant', 'EventSeries', 'Meeting', 'Deadline'],\n collections: [\n 'EventCollection',\n 'EventParticipantCollection',\n 'EventSeriesCollection',\n ],\n};\n"],"names":[],"mappings":"AAYO,MAAM,kBAAgD;AAAA,EAC3D,gBAAgB;AAAA,IACd,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OAAO;AAAA,IACP,gBAAgB;AAAA,EAAA;AAEpB;AAKO,MAAM,qBAAqC;AAAA,EAChD,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa;AAAA,EACb,SAAS;AAAA,EACT,QAAQ,CAAC,SAAS,oBAAoB,eAAe,WAAW,UAAU;AAAA,EAC1E,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { EventStatus, RecurrencePattern } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Validate event status transition
|
|
4
|
+
*
|
|
5
|
+
* @param currentStatus - Current event status
|
|
6
|
+
* @param newStatus - Proposed new status
|
|
7
|
+
* @returns True if transition is valid
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateEventStatus(currentStatus: EventStatus, newStatus: EventStatus): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Format event date range as string
|
|
12
|
+
*
|
|
13
|
+
* @param startDate - Event start date
|
|
14
|
+
* @param endDate - Event end date (optional)
|
|
15
|
+
* @returns Formatted date range string
|
|
16
|
+
*/
|
|
17
|
+
export declare function formatEventDateRange(startDate: Date, endDate?: Date | null): string;
|
|
18
|
+
/**
|
|
19
|
+
* Generate unique slug for an event
|
|
20
|
+
*
|
|
21
|
+
* @param name - Event name
|
|
22
|
+
* @param date - Event date
|
|
23
|
+
* @returns URL-friendly slug
|
|
24
|
+
*/
|
|
25
|
+
export declare function generateEventSlug(name: string, date: Date): string;
|
|
26
|
+
/**
|
|
27
|
+
* Check if events have scheduling conflict
|
|
28
|
+
*
|
|
29
|
+
* @param event1Start - First event start
|
|
30
|
+
* @param event1End - First event end
|
|
31
|
+
* @param event2Start - Second event start
|
|
32
|
+
* @param event2End - Second event end
|
|
33
|
+
* @returns True if events overlap
|
|
34
|
+
*/
|
|
35
|
+
export declare function checkSchedulingConflict(event1Start: Date, event1End: Date | null, event2Start: Date, event2End: Date | null): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Parse recurrence pattern from various formats
|
|
38
|
+
*
|
|
39
|
+
* @param pattern - Recurrence pattern (object or string)
|
|
40
|
+
* @returns Parsed RecurrencePattern or null
|
|
41
|
+
*/
|
|
42
|
+
export declare function parseRecurrencePattern(pattern: RecurrencePattern | string | null): RecurrencePattern | null;
|
|
43
|
+
/**
|
|
44
|
+
* Calculate next occurrence for a recurring event
|
|
45
|
+
*
|
|
46
|
+
* @param pattern - Recurrence pattern
|
|
47
|
+
* @param fromDate - Date to calculate from
|
|
48
|
+
* @returns Next occurrence date or null
|
|
49
|
+
*/
|
|
50
|
+
export declare function calculateNextOccurrence(pattern: RecurrencePattern, fromDate: Date): Date | null;
|
|
51
|
+
/**
|
|
52
|
+
* Calculate duration between two dates
|
|
53
|
+
*
|
|
54
|
+
* @param startDate - Start date
|
|
55
|
+
* @param endDate - End date
|
|
56
|
+
* @returns Duration in milliseconds
|
|
57
|
+
*/
|
|
58
|
+
export declare function calculateDuration(startDate: Date, endDate: Date): number;
|
|
59
|
+
/**
|
|
60
|
+
* Format duration as human-readable string
|
|
61
|
+
*
|
|
62
|
+
* @param durationMs - Duration in milliseconds
|
|
63
|
+
* @returns Formatted duration string
|
|
64
|
+
*/
|
|
65
|
+
export declare function formatDuration(durationMs: number): string;
|
|
66
|
+
/**
|
|
67
|
+
* Check if an event is happening now
|
|
68
|
+
*
|
|
69
|
+
* @param startDate - Event start date
|
|
70
|
+
* @param endDate - Event end date (optional)
|
|
71
|
+
* @returns True if event is currently in progress
|
|
72
|
+
*/
|
|
73
|
+
export declare function isEventNow(startDate: Date, endDate?: Date | null): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Get event status based on dates
|
|
76
|
+
*
|
|
77
|
+
* @param startDate - Event start date
|
|
78
|
+
* @param endDate - Event end date (optional)
|
|
79
|
+
* @param currentStatus - Current status (optional)
|
|
80
|
+
* @returns Suggested event status
|
|
81
|
+
*/
|
|
82
|
+
export declare function getEventStatusFromDates(startDate: Date, endDate?: Date | null, currentStatus?: EventStatus): EventStatus;
|
|
83
|
+
/**
|
|
84
|
+
* Sort events by start date
|
|
85
|
+
*
|
|
86
|
+
* @param events - Array of objects with startDate property
|
|
87
|
+
* @param ascending - Sort ascending (default: true)
|
|
88
|
+
* @returns Sorted array
|
|
89
|
+
*/
|
|
90
|
+
export declare function sortEventsByDate<T extends {
|
|
91
|
+
startDate: Date | null;
|
|
92
|
+
}>(events: T[], ascending?: boolean): T[];
|
|
93
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE9D;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,WAAW,EAC1B,SAAS,EAAE,WAAW,GACrB,OAAO,CAWT;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,IAAI,EACf,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GACpB,MAAM,CAcR;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CASlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,IAAI,EACjB,SAAS,EAAE,IAAI,GAAG,IAAI,EACtB,WAAW,EAAE,IAAI,EACjB,SAAS,EAAE,IAAI,GAAG,IAAI,GACrB,OAAO,CAOT;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,GACzC,iBAAiB,GAAG,IAAI,CAY1B;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,IAAI,GACb,IAAI,GAAG,IAAI,CA8Bb;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,MAAM,CAExE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAgBzD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAO1E;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,IAAI,EACf,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,EACrB,aAAa,CAAC,EAAE,WAAW,GAC1B,WAAW,CAiBb;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS;IAAE,SAAS,EAAE,IAAI,GAAG,IAAI,CAAA;CAAE,EACnE,MAAM,EAAE,CAAC,EAAE,EACX,SAAS,GAAE,OAAc,GACxB,CAAC,EAAE,CASL"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
function validateEventStatus(currentStatus, newStatus) {
|
|
2
|
+
const validTransitions = {
|
|
3
|
+
scheduled: ["in_progress", "cancelled", "postponed"],
|
|
4
|
+
in_progress: ["completed", "cancelled"],
|
|
5
|
+
completed: [],
|
|
6
|
+
// Cannot transition from completed
|
|
7
|
+
cancelled: ["scheduled"],
|
|
8
|
+
// Can reschedule
|
|
9
|
+
postponed: ["scheduled", "cancelled"]
|
|
10
|
+
};
|
|
11
|
+
return validTransitions[currentStatus]?.includes(newStatus) || false;
|
|
12
|
+
}
|
|
13
|
+
function formatEventDateRange(startDate, endDate) {
|
|
14
|
+
const start = startDate.toLocaleDateString();
|
|
15
|
+
if (!endDate) {
|
|
16
|
+
return start;
|
|
17
|
+
}
|
|
18
|
+
if (startDate.toDateString() === endDate.toDateString()) {
|
|
19
|
+
return `${start} ${startDate.toLocaleTimeString()} - ${endDate.toLocaleTimeString()}`;
|
|
20
|
+
}
|
|
21
|
+
return `${start} - ${endDate.toLocaleDateString()}`;
|
|
22
|
+
}
|
|
23
|
+
function generateEventSlug(name, date) {
|
|
24
|
+
const namePart = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
25
|
+
const datePart = date.toISOString().split("T")[0];
|
|
26
|
+
return `${namePart}-${datePart}`;
|
|
27
|
+
}
|
|
28
|
+
function checkSchedulingConflict(event1Start, event1End, event2Start, event2End) {
|
|
29
|
+
const e1End = event1End || event1Start;
|
|
30
|
+
const e2End = event2End || event2Start;
|
|
31
|
+
return event1Start < e2End && e1End > event2Start;
|
|
32
|
+
}
|
|
33
|
+
function parseRecurrencePattern(pattern) {
|
|
34
|
+
if (!pattern) return null;
|
|
35
|
+
if (typeof pattern === "string") {
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(pattern);
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return pattern;
|
|
43
|
+
}
|
|
44
|
+
function calculateNextOccurrence(pattern, fromDate) {
|
|
45
|
+
const { frequency, interval = 1, until, count } = pattern;
|
|
46
|
+
if (until && fromDate >= until) return null;
|
|
47
|
+
const nextDate = new Date(fromDate);
|
|
48
|
+
switch (frequency) {
|
|
49
|
+
case "daily":
|
|
50
|
+
nextDate.setDate(nextDate.getDate() + interval);
|
|
51
|
+
break;
|
|
52
|
+
case "weekly":
|
|
53
|
+
nextDate.setDate(nextDate.getDate() + interval * 7);
|
|
54
|
+
break;
|
|
55
|
+
case "monthly":
|
|
56
|
+
nextDate.setMonth(nextDate.getMonth() + interval);
|
|
57
|
+
break;
|
|
58
|
+
case "yearly":
|
|
59
|
+
nextDate.setFullYear(nextDate.getFullYear() + interval);
|
|
60
|
+
break;
|
|
61
|
+
default:
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (until && nextDate > until) return null;
|
|
65
|
+
return nextDate;
|
|
66
|
+
}
|
|
67
|
+
function calculateDuration(startDate, endDate) {
|
|
68
|
+
return endDate.getTime() - startDate.getTime();
|
|
69
|
+
}
|
|
70
|
+
function formatDuration(durationMs) {
|
|
71
|
+
const seconds = Math.floor(durationMs / 1e3);
|
|
72
|
+
const minutes = Math.floor(seconds / 60);
|
|
73
|
+
const hours = Math.floor(minutes / 60);
|
|
74
|
+
const days = Math.floor(hours / 24);
|
|
75
|
+
if (days > 0) {
|
|
76
|
+
return `${days}d ${hours % 24}h`;
|
|
77
|
+
}
|
|
78
|
+
if (hours > 0) {
|
|
79
|
+
return `${hours}h ${minutes % 60}m`;
|
|
80
|
+
}
|
|
81
|
+
if (minutes > 0) {
|
|
82
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
83
|
+
}
|
|
84
|
+
return `${seconds}s`;
|
|
85
|
+
}
|
|
86
|
+
function isEventNow(startDate, endDate) {
|
|
87
|
+
const now = /* @__PURE__ */ new Date();
|
|
88
|
+
if (now < startDate) return false;
|
|
89
|
+
if (endDate && now > endDate) return false;
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
function getEventStatusFromDates(startDate, endDate, currentStatus) {
|
|
93
|
+
if (currentStatus === "cancelled" || currentStatus === "postponed") {
|
|
94
|
+
return currentStatus;
|
|
95
|
+
}
|
|
96
|
+
const now = /* @__PURE__ */ new Date();
|
|
97
|
+
if (now < startDate) {
|
|
98
|
+
return "scheduled";
|
|
99
|
+
}
|
|
100
|
+
if (endDate && now > endDate) {
|
|
101
|
+
return "completed";
|
|
102
|
+
}
|
|
103
|
+
return "in_progress";
|
|
104
|
+
}
|
|
105
|
+
function sortEventsByDate(events, ascending = true) {
|
|
106
|
+
return events.sort((a, b) => {
|
|
107
|
+
if (!a.startDate && !b.startDate) return 0;
|
|
108
|
+
if (!a.startDate) return 1;
|
|
109
|
+
if (!b.startDate) return -1;
|
|
110
|
+
const diff = a.startDate.getTime() - b.startDate.getTime();
|
|
111
|
+
return ascending ? diff : -diff;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
export {
|
|
115
|
+
calculateDuration,
|
|
116
|
+
calculateNextOccurrence,
|
|
117
|
+
checkSchedulingConflict,
|
|
118
|
+
formatDuration,
|
|
119
|
+
formatEventDateRange,
|
|
120
|
+
generateEventSlug,
|
|
121
|
+
getEventStatusFromDates,
|
|
122
|
+
isEventNow,
|
|
123
|
+
parseRecurrencePattern,
|
|
124
|
+
sortEventsByDate,
|
|
125
|
+
validateEventStatus
|
|
126
|
+
};
|
|
127
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["/**\n * Utility functions for @have/events package\n */\n\nimport type { EventStatus, RecurrencePattern } from './types';\n\n/**\n * Validate event status transition\n *\n * @param currentStatus - Current event status\n * @param newStatus - Proposed new status\n * @returns True if transition is valid\n */\nexport function validateEventStatus(\n currentStatus: EventStatus,\n newStatus: EventStatus,\n): boolean {\n // Define valid transitions\n const validTransitions: Record<EventStatus, EventStatus[]> = {\n scheduled: ['in_progress', 'cancelled', 'postponed'],\n in_progress: ['completed', 'cancelled'],\n completed: [], // Cannot transition from completed\n cancelled: ['scheduled'], // Can reschedule\n postponed: ['scheduled', 'cancelled'],\n };\n\n return validTransitions[currentStatus]?.includes(newStatus) || false;\n}\n\n/**\n * Format event date range as string\n *\n * @param startDate - Event start date\n * @param endDate - Event end date (optional)\n * @returns Formatted date range string\n */\nexport function formatEventDateRange(\n startDate: Date,\n endDate?: Date | null,\n): string {\n const start = startDate.toLocaleDateString();\n\n if (!endDate) {\n return start;\n }\n\n // Same day\n if (startDate.toDateString() === endDate.toDateString()) {\n return `${start} ${startDate.toLocaleTimeString()} - ${endDate.toLocaleTimeString()}`;\n }\n\n // Multi-day\n return `${start} - ${endDate.toLocaleDateString()}`;\n}\n\n/**\n * Generate unique slug for an event\n *\n * @param name - Event name\n * @param date - Event date\n * @returns URL-friendly slug\n */\nexport function generateEventSlug(name: string, date: Date): string {\n const namePart = name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n\n const datePart = date.toISOString().split('T')[0]; // YYYY-MM-DD\n\n return `${namePart}-${datePart}`;\n}\n\n/**\n * Check if events have scheduling conflict\n *\n * @param event1Start - First event start\n * @param event1End - First event end\n * @param event2Start - Second event start\n * @param event2End - Second event end\n * @returns True if events overlap\n */\nexport function checkSchedulingConflict(\n event1Start: Date,\n event1End: Date | null,\n event2Start: Date,\n event2End: Date | null,\n): boolean {\n // If either event has no end date, assume it's instantaneous\n const e1End = event1End || event1Start;\n const e2End = event2End || event2Start;\n\n // Check for overlap\n return event1Start < e2End && e1End > event2Start;\n}\n\n/**\n * Parse recurrence pattern from various formats\n *\n * @param pattern - Recurrence pattern (object or string)\n * @returns Parsed RecurrencePattern or null\n */\nexport function parseRecurrencePattern(\n pattern: RecurrencePattern | string | null,\n): RecurrencePattern | null {\n if (!pattern) return null;\n\n if (typeof pattern === 'string') {\n try {\n return JSON.parse(pattern) as RecurrencePattern;\n } catch {\n return null;\n }\n }\n\n return pattern;\n}\n\n/**\n * Calculate next occurrence for a recurring event\n *\n * @param pattern - Recurrence pattern\n * @param fromDate - Date to calculate from\n * @returns Next occurrence date or null\n */\nexport function calculateNextOccurrence(\n pattern: RecurrencePattern,\n fromDate: Date,\n): Date | null {\n const { frequency, interval = 1, until, count } = pattern;\n\n // Check if recurrence has ended\n if (until && fromDate >= until) return null;\n\n // Calculate next date based on frequency\n const nextDate = new Date(fromDate);\n\n switch (frequency) {\n case 'daily':\n nextDate.setDate(nextDate.getDate() + interval);\n break;\n case 'weekly':\n nextDate.setDate(nextDate.getDate() + interval * 7);\n break;\n case 'monthly':\n nextDate.setMonth(nextDate.getMonth() + interval);\n break;\n case 'yearly':\n nextDate.setFullYear(nextDate.getFullYear() + interval);\n break;\n default:\n return null;\n }\n\n // Check if we've exceeded until date\n if (until && nextDate > until) return null;\n\n return nextDate;\n}\n\n/**\n * Calculate duration between two dates\n *\n * @param startDate - Start date\n * @param endDate - End date\n * @returns Duration in milliseconds\n */\nexport function calculateDuration(startDate: Date, endDate: Date): number {\n return endDate.getTime() - startDate.getTime();\n}\n\n/**\n * Format duration as human-readable string\n *\n * @param durationMs - Duration in milliseconds\n * @returns Formatted duration string\n */\nexport function formatDuration(durationMs: number): string {\n const seconds = Math.floor(durationMs / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days}d ${hours % 24}h`;\n }\n if (hours > 0) {\n return `${hours}h ${minutes % 60}m`;\n }\n if (minutes > 0) {\n return `${minutes}m ${seconds % 60}s`;\n }\n return `${seconds}s`;\n}\n\n/**\n * Check if an event is happening now\n *\n * @param startDate - Event start date\n * @param endDate - Event end date (optional)\n * @returns True if event is currently in progress\n */\nexport function isEventNow(startDate: Date, endDate?: Date | null): boolean {\n const now = new Date();\n\n if (now < startDate) return false;\n if (endDate && now > endDate) return false;\n\n return true;\n}\n\n/**\n * Get event status based on dates\n *\n * @param startDate - Event start date\n * @param endDate - Event end date (optional)\n * @param currentStatus - Current status (optional)\n * @returns Suggested event status\n */\nexport function getEventStatusFromDates(\n startDate: Date,\n endDate?: Date | null,\n currentStatus?: EventStatus,\n): EventStatus {\n // Don't override cancelled or postponed status\n if (currentStatus === 'cancelled' || currentStatus === 'postponed') {\n return currentStatus;\n }\n\n const now = new Date();\n\n if (now < startDate) {\n return 'scheduled';\n }\n\n if (endDate && now > endDate) {\n return 'completed';\n }\n\n return 'in_progress';\n}\n\n/**\n * Sort events by start date\n *\n * @param events - Array of objects with startDate property\n * @param ascending - Sort ascending (default: true)\n * @returns Sorted array\n */\nexport function sortEventsByDate<T extends { startDate: Date | null }>(\n events: T[],\n ascending: boolean = true,\n): T[] {\n return events.sort((a, b) => {\n if (!a.startDate && !b.startDate) return 0;\n if (!a.startDate) return 1;\n if (!b.startDate) return -1;\n\n const diff = a.startDate.getTime() - b.startDate.getTime();\n return ascending ? diff : -diff;\n });\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@happyvertical/smrt-events",
|
|
3
|
+
"version": "0.30.0",
|
|
4
|
+
"description": "Hierarchical event management with participant tracking and SMRT framework support",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"CLAUDE.md",
|
|
11
|
+
"AGENTS.md"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./utils": {
|
|
19
|
+
"types": "./dist/utils.d.ts",
|
|
20
|
+
"default": "./dist/utils.js"
|
|
21
|
+
},
|
|
22
|
+
"./ui": {
|
|
23
|
+
"types": "./dist/ui.d.ts",
|
|
24
|
+
"import": "./dist/ui.js"
|
|
25
|
+
},
|
|
26
|
+
"./manifest": "./dist/manifest.json",
|
|
27
|
+
"./manifest.json": "./dist/manifest.json",
|
|
28
|
+
"./playground": {
|
|
29
|
+
"types": "./dist/playground.d.ts",
|
|
30
|
+
"import": "./dist/playground.js"
|
|
31
|
+
},
|
|
32
|
+
"./svelte": {
|
|
33
|
+
"types": "./dist/svelte/index.d.ts",
|
|
34
|
+
"svelte": "./dist/svelte/index.js",
|
|
35
|
+
"import": "./dist/svelte/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"svelte": "^5.0.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependenciesMeta": {
|
|
42
|
+
"svelte": {
|
|
43
|
+
"optional": true
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@happyvertical/ai": "^0.74.7",
|
|
48
|
+
"@happyvertical/files": "^0.74.7",
|
|
49
|
+
"@happyvertical/logger": "^0.74.7",
|
|
50
|
+
"@happyvertical/sql": "^0.74.7",
|
|
51
|
+
"@happyvertical/utils": "^0.74.7",
|
|
52
|
+
"@happyvertical/smrt-assets": "0.30.0",
|
|
53
|
+
"@happyvertical/smrt-core": "0.30.0",
|
|
54
|
+
"@happyvertical/smrt-places": "0.30.0",
|
|
55
|
+
"@happyvertical/smrt-profiles": "0.30.0",
|
|
56
|
+
"@happyvertical/smrt-tenancy": "0.30.0",
|
|
57
|
+
"@happyvertical/smrt-types": "0.30.0",
|
|
58
|
+
"@happyvertical/smrt-ui": "0.30.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@sveltejs/package": "^2.5.7",
|
|
62
|
+
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
63
|
+
"@types/node": "25.0.9",
|
|
64
|
+
"fast-glob": "^3.3.3",
|
|
65
|
+
"svelte": "^5.46.4",
|
|
66
|
+
"svelte-check": "^4.3.5",
|
|
67
|
+
"typescript": "^5.9.3",
|
|
68
|
+
"vite": "^7.3.1",
|
|
69
|
+
"vitest": "^4.0.17",
|
|
70
|
+
"@happyvertical/smrt-vitest": "0.30.0"
|
|
71
|
+
},
|
|
72
|
+
"keywords": [
|
|
73
|
+
"events",
|
|
74
|
+
"calendar",
|
|
75
|
+
"scheduling",
|
|
76
|
+
"participants",
|
|
77
|
+
"smrt",
|
|
78
|
+
"typescript"
|
|
79
|
+
],
|
|
80
|
+
"author": "HappyVertical",
|
|
81
|
+
"license": "MIT",
|
|
82
|
+
"repository": {
|
|
83
|
+
"type": "git",
|
|
84
|
+
"url": "https://github.com/happyvertical/smrt.git",
|
|
85
|
+
"directory": "packages/events"
|
|
86
|
+
},
|
|
87
|
+
"publishConfig": {
|
|
88
|
+
"registry": "https://registry.npmjs.org",
|
|
89
|
+
"access": "public"
|
|
90
|
+
},
|
|
91
|
+
"scripts": {
|
|
92
|
+
"build": "vite build --mode library && svelte-package -i src/svelte -o dist/svelte --tsconfig tsconfig.svelte.json",
|
|
93
|
+
"build:watch": "vite build --mode library --watch",
|
|
94
|
+
"clean": "rm -rf dist",
|
|
95
|
+
"dev": "vite",
|
|
96
|
+
"check": "pnpm exec svelte-check --tsconfig ./tsconfig.svelte.json",
|
|
97
|
+
"test": "vitest run",
|
|
98
|
+
"test:watch": "vitest",
|
|
99
|
+
"typecheck": "tsc --noEmit && node ../../scripts/svelte-check-a11y.mjs --tsconfig ./tsconfig.svelte.json",
|
|
100
|
+
"verify:pack": "node ../../scripts/verify-package-types-exports.js ."
|
|
101
|
+
}
|
|
102
|
+
}
|