@getmicdrop/svelte-components 5.3.12 → 5.3.13
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/dist/calendar/AboutShow/AboutShow.svelte +172 -172
- package/dist/calendar/Calendar/MiniMonthCalendar.svelte +782 -782
- package/dist/calendar/FAQs/FAQs.svelte +75 -75
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte +126 -126
- package/dist/calendar/OrderSummary/OrderSummary.svelte +367 -367
- package/dist/calendar/PublicCard/PublicCard.svelte +145 -145
- package/dist/calendar/ShowCard/ShowCard.svelte +157 -157
- package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte +61 -61
- package/dist/components/Layout/Grid.svelte +109 -109
- package/dist/components/Layout/Section.svelte +80 -80
- package/dist/components/Layout/Sidebar.svelte +108 -108
- package/dist/components/Layout/Stack.svelte +90 -90
- package/dist/constants/formOptions.js +26 -26
- package/dist/constants/validation.js +91 -91
- package/dist/constants/validation.spec.js +64 -64
- package/dist/datetime/__tests__/format.test.d.ts +2 -0
- package/dist/datetime/__tests__/format.test.d.ts.map +1 -0
- package/dist/datetime/__tests__/format.test.js +268 -0
- package/dist/datetime/__tests__/integration.test.d.ts +2 -0
- package/dist/datetime/__tests__/integration.test.d.ts.map +1 -0
- package/dist/datetime/__tests__/integration.test.js +243 -0
- package/dist/datetime/__tests__/parse.test.d.ts +2 -0
- package/dist/datetime/__tests__/parse.test.d.ts.map +1 -0
- package/dist/datetime/__tests__/parse.test.js +261 -0
- package/dist/datetime/__tests__/timezone.test.d.ts +2 -0
- package/dist/datetime/__tests__/timezone.test.d.ts.map +1 -0
- package/dist/datetime/__tests__/timezone.test.js +214 -0
- package/dist/datetime/constants.d.ts +133 -0
- package/dist/datetime/constants.d.ts.map +1 -0
- package/dist/datetime/constants.js +112 -0
- package/dist/datetime/format.d.ts +158 -0
- package/dist/datetime/format.d.ts.map +1 -0
- package/dist/datetime/format.js +315 -0
- package/dist/datetime/index.d.ts +42 -0
- package/dist/datetime/index.d.ts.map +1 -0
- package/dist/datetime/index.js +44 -0
- package/dist/datetime/parse.d.ts +149 -0
- package/dist/datetime/parse.d.ts.map +1 -0
- package/dist/datetime/parse.js +276 -0
- package/dist/datetime/timezone.d.ts +95 -0
- package/dist/datetime/timezone.d.ts.map +1 -0
- package/dist/datetime/timezone.js +241 -0
- package/dist/datetime/types.d.ts +105 -0
- package/dist/datetime/types.d.ts.map +1 -0
- package/dist/datetime/types.js +31 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +232 -218
- package/dist/patterns/data/DataGrid.svelte +45 -45
- package/dist/patterns/data/DataList.svelte +24 -24
- package/dist/patterns/data/DataTable.svelte +40 -40
- package/dist/patterns/forms/FormActions.spec.js +88 -88
- package/dist/patterns/forms/FormActions.stories.svelte +97 -97
- package/dist/patterns/forms/FormActions.svelte +46 -46
- package/dist/patterns/forms/FormGrid.svelte +33 -33
- package/dist/patterns/forms/FormSection.svelte +32 -32
- package/dist/patterns/forms/FormValidationSummary.spec.js +203 -203
- package/dist/patterns/forms/FormValidationSummary.stories.svelte +97 -97
- package/dist/patterns/forms/FormValidationSummary.svelte +67 -67
- package/dist/patterns/layout/Grid.svelte +35 -35
- package/dist/patterns/layout/Sidebar.svelte +39 -39
- package/dist/patterns/layout/Stack.svelte +45 -45
- package/dist/patterns/navigation/BottomNav.spec.js +130 -130
- package/dist/patterns/navigation/BottomNav.stories.svelte +117 -117
- package/dist/patterns/navigation/BottomNav.svelte +54 -54
- package/dist/patterns/navigation/Header.spec.js +203 -203
- package/dist/patterns/navigation/Header.stories.svelte +77 -77
- package/dist/patterns/navigation/Header.svelte +240 -240
- package/dist/patterns/page/PageHeader.svelte +36 -36
- package/dist/patterns/page/PageLayout.svelte +40 -40
- package/dist/patterns/page/PageLoader.spec.js +54 -54
- package/dist/patterns/page/PageLoader.stories.svelte +137 -137
- package/dist/patterns/page/PageLoader.svelte +41 -41
- package/dist/patterns/page/SectionHeader.svelte +41 -41
- package/dist/presets/badges.js +112 -112
- package/dist/presets/buttons.js +76 -76
- package/dist/presets/index.js +9 -9
- package/dist/primitives/Accordion/Accordion.stories.svelte +75 -75
- package/dist/primitives/Accordion/Accordion.svelte +61 -61
- package/dist/primitives/Accordion/AccordionItem.svelte +95 -95
- package/dist/primitives/Alert/Alert.spec.js +170 -170
- package/dist/primitives/Alert/Alert.stories.svelte +88 -88
- package/dist/primitives/Alert/Alert.svelte +65 -65
- package/dist/primitives/Avatar/Avatar.stories.svelte +94 -94
- package/dist/primitives/Avatar/Avatar.svelte +66 -66
- package/dist/primitives/Badges/Badge.spec.js +103 -103
- package/dist/primitives/Badges/Badge.stories.svelte +86 -86
- package/dist/primitives/Badges/Badge.svelte +142 -142
- package/dist/primitives/BottomSheet/BottomSheet.spec.js +127 -127
- package/dist/primitives/BottomSheet/BottomSheet.stories.svelte +83 -83
- package/dist/primitives/BottomSheet/BottomSheet.svelte +100 -100
- package/dist/primitives/Breadcrumb/Breadcrumb.spec.js +120 -120
- package/dist/primitives/Breadcrumb/Breadcrumb.stories.svelte +23 -23
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte +89 -89
- package/dist/primitives/Button/Button.spec.js +211 -211
- package/dist/primitives/Button/Button.stories.svelte +76 -76
- package/dist/primitives/Button/Button.svelte +301 -301
- package/dist/primitives/Button/ButtonSaveDemo.spec.js +48 -48
- package/dist/primitives/Button/ButtonSaveDemo.svelte +25 -25
- package/dist/primitives/Button/ButtonVariantShowcase.svelte +129 -129
- package/dist/primitives/Card.spec.js +49 -49
- package/dist/primitives/Card.stories.svelte +22 -22
- package/dist/primitives/Card.svelte +28 -28
- package/dist/primitives/Checkbox/Checkbox.stories.svelte +84 -84
- package/dist/primitives/Checkbox/Checkbox.svelte +88 -88
- package/dist/primitives/DarkModeToggle.spec.js +357 -357
- package/dist/primitives/DarkModeToggle.stories.svelte +57 -57
- package/dist/primitives/DarkModeToggle.svelte +136 -136
- package/dist/primitives/Drawer/Drawer.stories.svelte +100 -100
- package/dist/primitives/Drawer/Drawer.svelte +214 -214
- package/dist/primitives/Dropdown/Dropdown.stories.svelte +137 -137
- package/dist/primitives/Dropdown/Dropdown.svelte +148 -148
- package/dist/primitives/Dropdown/DropdownItem.svelte +80 -80
- package/dist/primitives/Icons/ArrowLeft.svelte +20 -20
- package/dist/primitives/Icons/ArrowRight.svelte +20 -20
- package/dist/primitives/Icons/Availability.svelte +26 -26
- package/dist/primitives/Icons/Back.svelte +26 -26
- package/dist/primitives/Icons/CheckCircle.svelte +18 -18
- package/dist/primitives/Icons/CheckCircleOutline.svelte +27 -27
- package/dist/primitives/Icons/ChevronLeft.svelte +16 -16
- package/dist/primitives/Icons/ChevronRight.svelte +16 -16
- package/dist/primitives/Icons/Copy.svelte +27 -27
- package/dist/primitives/Icons/Cross.svelte +17 -17
- package/dist/primitives/Icons/DownArrow.svelte +20 -20
- package/dist/primitives/Icons/ErrorCircle.svelte +18 -18
- package/dist/primitives/Icons/FacebookIcon.svelte +13 -13
- package/dist/primitives/Icons/Home.svelte +27 -27
- package/dist/primitives/Icons/Icon.spec.js +175 -175
- package/dist/primitives/Icons/Icon.stories.svelte +100 -100
- package/dist/primitives/Icons/Icon.svelte +63 -63
- package/dist/primitives/Icons/IconGallery.stories.svelte +235 -235
- package/dist/primitives/Icons/ImageOutline.svelte +19 -19
- package/dist/primitives/Icons/Info.svelte +19 -19
- package/dist/primitives/Icons/InstagramIcon.svelte +19 -19
- package/dist/primitives/Icons/LogoInstagram.svelte +15 -15
- package/dist/primitives/Icons/Message.svelte +27 -27
- package/dist/primitives/Icons/MoonIcon.svelte +16 -16
- package/dist/primitives/Icons/More.svelte +33 -33
- package/dist/primitives/Icons/MoreHori.spec.js +67 -67
- package/dist/primitives/Icons/MoreHori.svelte +34 -34
- package/dist/primitives/Icons/Notification.svelte +26 -26
- package/dist/primitives/Icons/Payment.svelte +26 -26
- package/dist/primitives/Icons/Profile.svelte +33 -33
- package/dist/primitives/Icons/Reload.svelte +41 -41
- package/dist/primitives/Icons/Shows.svelte +33 -33
- package/dist/primitives/Icons/Signout.svelte +33 -33
- package/dist/primitives/Icons/SunIcon.svelte +19 -19
- package/dist/primitives/Icons/TiktokIcon.svelte +13 -13
- package/dist/primitives/Icons/TrashBinOutline.svelte +19 -19
- package/dist/primitives/Icons/TwitterIcon.svelte +13 -13
- package/dist/primitives/Icons/WarningIcon.spec.js +30 -30
- package/dist/primitives/Icons/WarningIcon.svelte +24 -24
- package/dist/primitives/Input/Input.spec.js +573 -573
- package/dist/primitives/Input/Input.stories.svelte +139 -139
- package/dist/primitives/Input/Input.svelte +444 -444
- package/dist/primitives/Input/Select.spec.js +218 -218
- package/dist/primitives/Input/Select.stories.svelte +112 -112
- package/dist/primitives/Input/Select.svelte +232 -232
- package/dist/primitives/Input/Textarea.stories.svelte +137 -137
- package/dist/primitives/Input/Textarea.svelte +79 -79
- package/dist/primitives/Label/Label.svelte +37 -37
- package/dist/primitives/Modal/Modal.spec.js +95 -95
- package/dist/primitives/Modal/Modal.stories.svelte +86 -86
- package/dist/primitives/Modal/Modal.svelte +158 -158
- package/dist/primitives/Pagination/Pagination.stories.svelte +76 -76
- package/dist/primitives/Pagination/Pagination.svelte +261 -261
- package/dist/primitives/Radio/Radio.stories.svelte +80 -80
- package/dist/primitives/Radio/Radio.svelte +67 -67
- package/dist/primitives/Skeleton/CardPlaceholder.svelte +87 -87
- package/dist/primitives/Skeleton/ImagePlaceholder.svelte +59 -59
- package/dist/primitives/Skeleton/ListPlaceholder.svelte +76 -76
- package/dist/primitives/Skeleton/Skeleton.stories.svelte +151 -151
- package/dist/primitives/Skeleton/Skeleton.svelte +52 -52
- package/dist/primitives/Spinner/Spinner.spec.js +75 -75
- package/dist/primitives/Spinner/Spinner.stories.svelte +29 -29
- package/dist/primitives/Spinner/Spinner.svelte +57 -57
- package/dist/primitives/Tabs/TabItem.svelte +51 -51
- package/dist/primitives/Tabs/Tabs.stories.svelte +112 -112
- package/dist/primitives/Tabs/Tabs.svelte +128 -128
- package/dist/primitives/Toggle.spec.js +127 -127
- package/dist/primitives/Toggle.stories.svelte +92 -92
- package/dist/primitives/Toggle.svelte +71 -71
- package/dist/primitives/Typography/Typography.svelte +53 -53
- package/dist/primitives/ValidationError.spec.js +103 -103
- package/dist/primitives/ValidationError.stories.svelte +111 -111
- package/dist/primitives/ValidationError.svelte +29 -29
- package/dist/recipes/CropImage/CropImage.spec.js +216 -216
- package/dist/recipes/CropImage/CropImage.stories.svelte +104 -104
- package/dist/recipes/CropImage/CropImage.svelte +238 -238
- package/dist/recipes/ImageUploader/ImageUploader.stories.svelte +125 -125
- package/dist/recipes/ImageUploader/ImageUploader.svelte +980 -980
- package/dist/recipes/Toaster/Toaster.stories.svelte +62 -62
- package/dist/recipes/feedback/EmptyState/EmptyState.svelte +47 -47
- package/dist/recipes/feedback/ErrorDisplay.spec.js +69 -69
- package/dist/recipes/feedback/ErrorDisplay.stories.svelte +112 -112
- package/dist/recipes/feedback/ErrorDisplay.svelte +38 -38
- package/dist/recipes/feedback/StatusIndicator/StatusIndicator.spec.js +129 -129
- package/dist/recipes/feedback/StatusIndicator/StatusIndicator.svelte +167 -167
- package/dist/recipes/fields/CheckboxField.svelte +85 -85
- package/dist/recipes/fields/FormField.svelte +58 -58
- package/dist/recipes/fields/RadioGroup.svelte +95 -95
- package/dist/recipes/fields/SelectField.svelte +82 -82
- package/dist/recipes/fields/TextareaField.svelte +101 -101
- package/dist/recipes/fields/ToggleField.svelte +60 -60
- package/dist/recipes/fields/index.js +7 -7
- package/dist/recipes/inputs/MultiSelect.spec.js +257 -257
- package/dist/recipes/inputs/MultiSelect.stories.svelte +133 -133
- package/dist/recipes/inputs/MultiSelect.svelte +244 -244
- package/dist/recipes/inputs/OTPInput.spec.js +238 -238
- package/dist/recipes/inputs/OTPInput.stories.svelte +162 -162
- package/dist/recipes/inputs/OTPInput.svelte +102 -102
- package/dist/recipes/inputs/PasswordInput.svelte +100 -100
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.spec.js +173 -173
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte +108 -108
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.spec.js +300 -300
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.stories.svelte +165 -165
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte +337 -337
- package/dist/recipes/inputs/Search.svelte +85 -85
- package/dist/recipes/inputs/SelectDropdown.svelte +161 -161
- package/dist/recipes/modals/AlertModal.svelte +130 -130
- package/dist/recipes/modals/ConfirmationModal.spec.js +191 -191
- package/dist/recipes/modals/ConfirmationModal.stories.svelte +119 -119
- package/dist/recipes/modals/ConfirmationModal.svelte +152 -152
- package/dist/recipes/modals/InputModal.svelte +182 -182
- package/dist/recipes/modals/ModalStateManager.spec.js +100 -100
- package/dist/recipes/modals/ModalStateManager.svelte +77 -77
- package/dist/recipes/modals/ModalTestWrapper.svelte +65 -65
- package/dist/recipes/modals/StatusModal.svelte +206 -206
- package/dist/services/EventService.js +75 -75
- package/dist/services/EventService.spec.js +217 -217
- package/dist/services/ShowService.spec.js +342 -342
- package/dist/stores/auth.js +93 -6
- package/dist/stores/auth.spec.js +310 -2
- package/dist/stores/toaster.js +13 -13
- package/dist/stories/ButtonAuditReview.stories.svelte +14 -14
- package/dist/stories/ButtonAuditReview.svelte +427 -427
- package/dist/stories/PatternsGallery.stories.svelte +19 -19
- package/dist/stories/PatternsGallery.svelte +388 -388
- package/dist/stories/PrimitivesGallery.stories.svelte +19 -19
- package/dist/stories/PrimitivesGallery.svelte +752 -752
- package/dist/stories/RecipesGallery.stories.svelte +19 -19
- package/dist/stories/RecipesGallery.svelte +441 -441
- package/dist/stories/button-audit-manifest.json +11186 -11186
- package/dist/tailwind/preset.cjs +82 -82
- package/dist/telemetry.js +357 -357
- package/dist/tokens/tokens.css +87 -87
- package/dist/utils/apiConfig.js +49 -49
- package/dist/utils/utils.js +9 -1
- package/package.json +233 -191
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DateTime Constants
|
|
3
|
+
*
|
|
4
|
+
* Centralized constants for datetime operations.
|
|
5
|
+
* Use these instead of magic numbers throughout the codebase.
|
|
6
|
+
*
|
|
7
|
+
* @module datetime/constants
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Duration constants in milliseconds.
|
|
11
|
+
*/
|
|
12
|
+
export const DURATIONS = {
|
|
13
|
+
/** One second in milliseconds */
|
|
14
|
+
SECOND: 1000,
|
|
15
|
+
/** One minute in milliseconds */
|
|
16
|
+
MINUTE: 60 * 1000,
|
|
17
|
+
/** One hour in milliseconds */
|
|
18
|
+
HOUR: 60 * 60 * 1000,
|
|
19
|
+
/** One day in milliseconds */
|
|
20
|
+
DAY: 24 * 60 * 60 * 1000,
|
|
21
|
+
/** One week in milliseconds */
|
|
22
|
+
WEEK: 7 * 24 * 60 * 60 * 1000,
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Duration constants in minutes.
|
|
26
|
+
*/
|
|
27
|
+
export const DURATIONS_MINUTES = {
|
|
28
|
+
/** One hour in minutes */
|
|
29
|
+
HOUR: 60,
|
|
30
|
+
/** One day in minutes */
|
|
31
|
+
DAY: 24 * 60,
|
|
32
|
+
/** One week in minutes */
|
|
33
|
+
WEEK: 7 * 24 * 60,
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Date format strings for use with date-fns.
|
|
37
|
+
*/
|
|
38
|
+
export const DATE_FORMATS = {
|
|
39
|
+
/** API format: UTC ISO string */
|
|
40
|
+
API: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
|
41
|
+
/** Date for API without time */
|
|
42
|
+
API_DATE: 'yyyy-MM-dd',
|
|
43
|
+
/** Display date (e.g., "Dec 20, 2025") */
|
|
44
|
+
DISPLAY_DATE: 'MMM d, yyyy',
|
|
45
|
+
/** Display date without year (e.g., "Dec 20") */
|
|
46
|
+
DISPLAY_DATE_SHORT: 'MMM d',
|
|
47
|
+
/** Display time (e.g., "7:00 PM") */
|
|
48
|
+
DISPLAY_TIME: 'h:mm a',
|
|
49
|
+
/** Display time with seconds (e.g., "7:00:00 PM") */
|
|
50
|
+
DISPLAY_TIME_SECONDS: 'h:mm:ss a',
|
|
51
|
+
/** Display datetime (e.g., "Dec 20, 2025 at 7:00 PM") */
|
|
52
|
+
DISPLAY_DATETIME: "MMM d, yyyy 'at' h:mm a",
|
|
53
|
+
/** Display full datetime with day (e.g., "Mon, Dec 20, 2025 at 7:00 PM") */
|
|
54
|
+
DISPLAY_DATETIME_FULL: "EEE, MMM d, yyyy 'at' h:mm a",
|
|
55
|
+
/** Day of week short (e.g., "Mon") */
|
|
56
|
+
DAY_SHORT: 'EEE',
|
|
57
|
+
/** Day of week full (e.g., "Monday") */
|
|
58
|
+
DAY_FULL: 'EEEE',
|
|
59
|
+
/** Month short (e.g., "Dec") */
|
|
60
|
+
MONTH_SHORT: 'MMM',
|
|
61
|
+
/** Month full (e.g., "December") */
|
|
62
|
+
MONTH_FULL: 'MMMM',
|
|
63
|
+
/** Year only (e.g., "2025") */
|
|
64
|
+
YEAR: 'yyyy',
|
|
65
|
+
/** 24-hour time (e.g., "19:00") */
|
|
66
|
+
TIME_24H: 'HH:mm',
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Commonly used US timezones for quick selection.
|
|
70
|
+
*/
|
|
71
|
+
export const COMMON_US_TIMEZONES = [
|
|
72
|
+
{ id: 'America/Los_Angeles', label: 'Pacific Time (PT)', abbr: 'PT' },
|
|
73
|
+
{ id: 'America/Denver', label: 'Mountain Time (MT)', abbr: 'MT' },
|
|
74
|
+
{ id: 'America/Chicago', label: 'Central Time (CT)', abbr: 'CT' },
|
|
75
|
+
{ id: 'America/New_York', label: 'Eastern Time (ET)', abbr: 'ET' },
|
|
76
|
+
{ id: 'America/Phoenix', label: 'Arizona (no DST)', abbr: 'AZ' },
|
|
77
|
+
{ id: 'Pacific/Honolulu', label: 'Hawaii Time (HT)', abbr: 'HT' },
|
|
78
|
+
{ id: 'America/Anchorage', label: 'Alaska Time (AKT)', abbr: 'AKT' },
|
|
79
|
+
];
|
|
80
|
+
/**
|
|
81
|
+
* Default timezone when none is specified (should rarely be used).
|
|
82
|
+
* Prefer explicitly passing timezone in all operations.
|
|
83
|
+
*/
|
|
84
|
+
export const DEFAULT_TIMEZONE = 'America/Los_Angeles';
|
|
85
|
+
/**
|
|
86
|
+
* Relative time thresholds for formatRelativeTime.
|
|
87
|
+
*/
|
|
88
|
+
export const RELATIVE_TIME_THRESHOLDS = {
|
|
89
|
+
/** Under this many seconds, show "just now" */
|
|
90
|
+
JUST_NOW_SECONDS: 60,
|
|
91
|
+
/** Under this many minutes, show "X minutes ago/from now" */
|
|
92
|
+
MINUTES_THRESHOLD: 60,
|
|
93
|
+
/** Under this many hours, show "X hours ago/from now" */
|
|
94
|
+
HOURS_THRESHOLD: 24,
|
|
95
|
+
/** Under this many days, show "X days ago/from now" */
|
|
96
|
+
DAYS_THRESHOLD: 7,
|
|
97
|
+
/** Under this many weeks, show "X weeks ago/from now" */
|
|
98
|
+
WEEKS_THRESHOLD: 4,
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* MicDrop-specific event defaults.
|
|
102
|
+
*/
|
|
103
|
+
export const EVENT_DEFAULTS = {
|
|
104
|
+
/** Default event duration in minutes */
|
|
105
|
+
DEFAULT_DURATION_MINUTES: 120,
|
|
106
|
+
/** Minimum event duration in minutes */
|
|
107
|
+
MIN_DURATION_MINUTES: 15,
|
|
108
|
+
/** Maximum event duration in minutes (24 hours) */
|
|
109
|
+
MAX_DURATION_MINUTES: 24 * 60,
|
|
110
|
+
/** Default doors open time before event start (minutes) */
|
|
111
|
+
DEFAULT_DOORS_BEFORE_MINUTES: 30,
|
|
112
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DateTime Formatting Functions
|
|
3
|
+
*
|
|
4
|
+
* All formatting functions require an explicit timezone parameter.
|
|
5
|
+
* No defaults - timezone must always be provided.
|
|
6
|
+
*
|
|
7
|
+
* @module datetime/format
|
|
8
|
+
*/
|
|
9
|
+
import type { DateParts, FormatOptions, ISODateString, TimezoneId } from './types';
|
|
10
|
+
/**
|
|
11
|
+
* Formats a UTC datetime as a time string in the specified timezone.
|
|
12
|
+
*
|
|
13
|
+
* @param utcIso - UTC ISO datetime string
|
|
14
|
+
* @param timezone - IANA timezone ID
|
|
15
|
+
* @param options - Optional formatting options
|
|
16
|
+
* @returns Formatted time (e.g., "7:00 PM")
|
|
17
|
+
* @throws {DateTimeError} If timezone or ISO string is invalid
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* formatEventTime('2023-12-25T03:00:00Z', 'America/Los_Angeles')
|
|
21
|
+
* // "7:00 PM" (Dec 24 in LA)
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatEventTime(utcIso: ISODateString, timezone: TimezoneId, options?: FormatOptions): string;
|
|
24
|
+
/**
|
|
25
|
+
* Formats a UTC datetime as a date string in the specified timezone.
|
|
26
|
+
*
|
|
27
|
+
* @param utcIso - UTC ISO datetime string
|
|
28
|
+
* @param timezone - IANA timezone ID
|
|
29
|
+
* @param options - Optional formatting options
|
|
30
|
+
* @returns Formatted date (e.g., "Dec 20, 2025")
|
|
31
|
+
* @throws {DateTimeError} If timezone or ISO string is invalid
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* formatEventDate('2023-12-25T03:00:00Z', 'America/Los_Angeles')
|
|
35
|
+
* // "Dec 24, 2023" (still Dec 24 in LA at 7 PM)
|
|
36
|
+
*/
|
|
37
|
+
export declare function formatEventDate(utcIso: ISODateString, timezone: TimezoneId, options?: FormatOptions): string;
|
|
38
|
+
/**
|
|
39
|
+
* Formats a UTC datetime as a full datetime string in the specified timezone.
|
|
40
|
+
*
|
|
41
|
+
* @param utcIso - UTC ISO datetime string
|
|
42
|
+
* @param timezone - IANA timezone ID
|
|
43
|
+
* @param options - Optional formatting options
|
|
44
|
+
* @returns Formatted datetime (e.g., "Dec 20, 2025 at 7:00 PM")
|
|
45
|
+
* @throws {DateTimeError} If timezone or ISO string is invalid
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* formatEventDateTime('2023-12-26T03:00:00Z', 'America/Los_Angeles')
|
|
49
|
+
* // "Dec 25, 2023 at 7:00 PM"
|
|
50
|
+
*/
|
|
51
|
+
export declare function formatEventDateTime(utcIso: ISODateString, timezone: TimezoneId, options?: FormatOptions): string;
|
|
52
|
+
/**
|
|
53
|
+
* Formats a time range in the specified timezone.
|
|
54
|
+
*
|
|
55
|
+
* @param startUtc - Start time as UTC ISO string
|
|
56
|
+
* @param endUtc - End time as UTC ISO string
|
|
57
|
+
* @param timezone - IANA timezone ID
|
|
58
|
+
* @returns Formatted time range (e.g., "7:00 PM - 10:00 PM")
|
|
59
|
+
* @throws {DateTimeError} If timezone or ISO strings are invalid
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* formatTimeRange(
|
|
63
|
+
* '2023-12-25T03:00:00Z',
|
|
64
|
+
* '2023-12-25T06:00:00Z',
|
|
65
|
+
* 'America/Los_Angeles'
|
|
66
|
+
* )
|
|
67
|
+
* // "7:00 PM - 10:00 PM"
|
|
68
|
+
*/
|
|
69
|
+
export declare function formatTimeRange(startUtc: ISODateString, endUtc: ISODateString, timezone: TimezoneId): string;
|
|
70
|
+
/**
|
|
71
|
+
* Formats a date range in the specified timezone.
|
|
72
|
+
* Handles same-day, same-month, and cross-month/year ranges intelligently.
|
|
73
|
+
*
|
|
74
|
+
* @param startUtc - Start date as UTC ISO string
|
|
75
|
+
* @param endUtc - End date as UTC ISO string
|
|
76
|
+
* @param timezone - IANA timezone ID
|
|
77
|
+
* @returns Formatted date range (e.g., "Dec 20 - 22, 2025" or "Dec 20 - Jan 5, 2026")
|
|
78
|
+
* @throws {DateTimeError} If timezone or ISO strings are invalid
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* formatDateRange(
|
|
82
|
+
* '2023-12-20T08:00:00Z',
|
|
83
|
+
* '2023-12-22T08:00:00Z',
|
|
84
|
+
* 'America/Los_Angeles'
|
|
85
|
+
* )
|
|
86
|
+
* // "Dec 20 - 22, 2023"
|
|
87
|
+
*/
|
|
88
|
+
export declare function formatDateRange(startUtc: ISODateString, endUtc: ISODateString, timezone: TimezoneId): string;
|
|
89
|
+
/**
|
|
90
|
+
* Formats a datetime as a relative time string (e.g., "2 hours ago", "in 3 days").
|
|
91
|
+
*
|
|
92
|
+
* @param utcIso - UTC ISO datetime string
|
|
93
|
+
* @param timezone - IANA timezone ID (used for consistency, though relative time is timezone-agnostic)
|
|
94
|
+
* @returns Relative time string
|
|
95
|
+
* @throws {DateTimeError} If timezone or ISO string is invalid
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* formatRelativeTime(new Date(Date.now() - 30 * 60 * 1000).toISOString(), 'America/Los_Angeles')
|
|
99
|
+
* // "30 minutes ago"
|
|
100
|
+
*/
|
|
101
|
+
export declare function formatRelativeTime(utcIso: ISODateString, timezone: TimezoneId): string;
|
|
102
|
+
/**
|
|
103
|
+
* Extracts date parts from a UTC datetime in the specified timezone.
|
|
104
|
+
*
|
|
105
|
+
* @param utcIso - UTC ISO datetime string
|
|
106
|
+
* @param timezone - IANA timezone ID
|
|
107
|
+
* @returns Object with day, month, date, and year
|
|
108
|
+
* @throws {DateTimeError} If timezone or ISO string is invalid
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* getDateParts('2023-12-25T20:00:00Z', 'America/Los_Angeles')
|
|
112
|
+
* // { day: 'Mon', month: 'Dec', date: 25, year: 2023 }
|
|
113
|
+
*/
|
|
114
|
+
export declare function getDateParts(utcIso: ISODateString, timezone: TimezoneId): DateParts;
|
|
115
|
+
/**
|
|
116
|
+
* Formats a datetime for display in notifications.
|
|
117
|
+
* Shows relative time for recent events, date for older ones.
|
|
118
|
+
*
|
|
119
|
+
* @param utcIso - UTC ISO datetime string
|
|
120
|
+
* @param timezone - IANA timezone ID
|
|
121
|
+
* @returns Formatted string suitable for notifications
|
|
122
|
+
*/
|
|
123
|
+
export declare function formatNotificationTime(utcIso: ISODateString, timezone: TimezoneId): string;
|
|
124
|
+
/**
|
|
125
|
+
* Formats the day of week from a UTC datetime.
|
|
126
|
+
*
|
|
127
|
+
* @param utcIso - UTC ISO datetime string
|
|
128
|
+
* @param timezone - IANA timezone ID
|
|
129
|
+
* @param short - If true, returns short form (e.g., "Mon"), otherwise full (e.g., "Monday")
|
|
130
|
+
* @returns Day of week string
|
|
131
|
+
*/
|
|
132
|
+
export declare function formatDayOfWeek(utcIso: ISODateString, timezone: TimezoneId, short?: boolean): string;
|
|
133
|
+
/**
|
|
134
|
+
* Formats the month from a UTC datetime.
|
|
135
|
+
*
|
|
136
|
+
* @param utcIso - UTC ISO datetime string
|
|
137
|
+
* @param timezone - IANA timezone ID
|
|
138
|
+
* @param short - If true, returns short form (e.g., "Dec"), otherwise full (e.g., "December")
|
|
139
|
+
* @returns Month string
|
|
140
|
+
*/
|
|
141
|
+
export declare function formatMonth(utcIso: ISODateString, timezone: TimezoneId, short?: boolean): string;
|
|
142
|
+
/**
|
|
143
|
+
* Gets the hour in the specified timezone (0-23).
|
|
144
|
+
*
|
|
145
|
+
* @param utcIso - UTC ISO datetime string
|
|
146
|
+
* @param timezone - IANA timezone ID
|
|
147
|
+
* @returns Hour (0-23)
|
|
148
|
+
*/
|
|
149
|
+
export declare function getHourInTimezone(utcIso: ISODateString, timezone: TimezoneId): number;
|
|
150
|
+
/**
|
|
151
|
+
* Gets the date string (YYYY-MM-DD) in the specified timezone.
|
|
152
|
+
*
|
|
153
|
+
* @param utcIso - UTC ISO datetime string
|
|
154
|
+
* @param timezone - IANA timezone ID
|
|
155
|
+
* @returns Date string in YYYY-MM-DD format
|
|
156
|
+
*/
|
|
157
|
+
export declare function getDateInTimezone(utcIso: ISODateString, timezone: TimezoneId): string;
|
|
158
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/lib/datetime/format.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EACb,aAAa,EACb,UAAU,EACX,MAAM,SAAS,CAAC;AA4CjB;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAMR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAOR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAiBR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,GACnB,MAAM,CAIR;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,GACnB,MAAM,CA4BR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,GACnB,MAAM,CAoDR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,GACnB,SAAS,CASX;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,GACnB,MAAM,CAkBR;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,EACpB,KAAK,GAAE,OAAc,GACpB,MAAM,CAMR;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,EACpB,KAAK,GAAE,OAAc,GACpB,MAAM,CAMR;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,GACnB,MAAM,CAGR;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,UAAU,GACnB,MAAM,CAGR"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DateTime Formatting Functions
|
|
3
|
+
*
|
|
4
|
+
* All formatting functions require an explicit timezone parameter.
|
|
5
|
+
* No defaults - timezone must always be provided.
|
|
6
|
+
*
|
|
7
|
+
* @module datetime/format
|
|
8
|
+
*/
|
|
9
|
+
import { format } from 'date-fns';
|
|
10
|
+
import { toZonedTime } from 'date-fns-tz';
|
|
11
|
+
import { DATE_FORMATS, DURATIONS, RELATIVE_TIME_THRESHOLDS } from './constants';
|
|
12
|
+
import { isValidTimezone } from './timezone';
|
|
13
|
+
import { DateTimeError, DateTimeErrorCode } from './types';
|
|
14
|
+
/**
|
|
15
|
+
* Validates an ISO date string and returns a Date object.
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
function parseAndValidateISO(utcIso) {
|
|
19
|
+
if (!utcIso || typeof utcIso !== 'string') {
|
|
20
|
+
throw new DateTimeError('ISO date string is required', DateTimeErrorCode.INVALID_ISO_STRING, { value: utcIso });
|
|
21
|
+
}
|
|
22
|
+
const date = new Date(utcIso);
|
|
23
|
+
if (isNaN(date.getTime())) {
|
|
24
|
+
throw new DateTimeError(`Invalid ISO date string: ${utcIso}`, DateTimeErrorCode.INVALID_ISO_STRING, { value: utcIso });
|
|
25
|
+
}
|
|
26
|
+
return date;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validates timezone and returns zoned date.
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
function getZonedDate(utcIso, timezone) {
|
|
33
|
+
if (!isValidTimezone(timezone)) {
|
|
34
|
+
throw new DateTimeError(`Invalid timezone: ${timezone}`, DateTimeErrorCode.INVALID_TIMEZONE, { timezone });
|
|
35
|
+
}
|
|
36
|
+
const date = parseAndValidateISO(utcIso);
|
|
37
|
+
return toZonedTime(date, timezone);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Formats a UTC datetime as a time string in the specified timezone.
|
|
41
|
+
*
|
|
42
|
+
* @param utcIso - UTC ISO datetime string
|
|
43
|
+
* @param timezone - IANA timezone ID
|
|
44
|
+
* @param options - Optional formatting options
|
|
45
|
+
* @returns Formatted time (e.g., "7:00 PM")
|
|
46
|
+
* @throws {DateTimeError} If timezone or ISO string is invalid
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* formatEventTime('2023-12-25T03:00:00Z', 'America/Los_Angeles')
|
|
50
|
+
* // "7:00 PM" (Dec 24 in LA)
|
|
51
|
+
*/
|
|
52
|
+
export function formatEventTime(utcIso, timezone, options) {
|
|
53
|
+
const zonedDate = getZonedDate(utcIso, timezone);
|
|
54
|
+
const formatStr = options?.includeSeconds
|
|
55
|
+
? DATE_FORMATS.DISPLAY_TIME_SECONDS
|
|
56
|
+
: DATE_FORMATS.DISPLAY_TIME;
|
|
57
|
+
return format(zonedDate, formatStr);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Formats a UTC datetime as a date string in the specified timezone.
|
|
61
|
+
*
|
|
62
|
+
* @param utcIso - UTC ISO datetime string
|
|
63
|
+
* @param timezone - IANA timezone ID
|
|
64
|
+
* @param options - Optional formatting options
|
|
65
|
+
* @returns Formatted date (e.g., "Dec 20, 2025")
|
|
66
|
+
* @throws {DateTimeError} If timezone or ISO string is invalid
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* formatEventDate('2023-12-25T03:00:00Z', 'America/Los_Angeles')
|
|
70
|
+
* // "Dec 24, 2023" (still Dec 24 in LA at 7 PM)
|
|
71
|
+
*/
|
|
72
|
+
export function formatEventDate(utcIso, timezone, options) {
|
|
73
|
+
const zonedDate = getZonedDate(utcIso, timezone);
|
|
74
|
+
const formatStr = options?.includeYear === false
|
|
75
|
+
? DATE_FORMATS.DISPLAY_DATE_SHORT
|
|
76
|
+
: DATE_FORMATS.DISPLAY_DATE;
|
|
77
|
+
return format(zonedDate, formatStr);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Formats a UTC datetime as a full datetime string in the specified timezone.
|
|
81
|
+
*
|
|
82
|
+
* @param utcIso - UTC ISO datetime string
|
|
83
|
+
* @param timezone - IANA timezone ID
|
|
84
|
+
* @param options - Optional formatting options
|
|
85
|
+
* @returns Formatted datetime (e.g., "Dec 20, 2025 at 7:00 PM")
|
|
86
|
+
* @throws {DateTimeError} If timezone or ISO string is invalid
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* formatEventDateTime('2023-12-26T03:00:00Z', 'America/Los_Angeles')
|
|
90
|
+
* // "Dec 25, 2023 at 7:00 PM"
|
|
91
|
+
*/
|
|
92
|
+
export function formatEventDateTime(utcIso, timezone, options) {
|
|
93
|
+
const zonedDate = getZonedDate(utcIso, timezone);
|
|
94
|
+
// Respect includeDate/includeTime options
|
|
95
|
+
const includeDate = options?.includeDate !== false;
|
|
96
|
+
const includeTime = options?.includeTime !== false;
|
|
97
|
+
if (includeDate && includeTime) {
|
|
98
|
+
return format(zonedDate, DATE_FORMATS.DISPLAY_DATETIME);
|
|
99
|
+
}
|
|
100
|
+
else if (includeDate && !includeTime) {
|
|
101
|
+
return format(zonedDate, DATE_FORMATS.DISPLAY_DATE);
|
|
102
|
+
}
|
|
103
|
+
else if (!includeDate && includeTime) {
|
|
104
|
+
return format(zonedDate, DATE_FORMATS.DISPLAY_TIME);
|
|
105
|
+
}
|
|
106
|
+
// Fallback to full datetime
|
|
107
|
+
return format(zonedDate, DATE_FORMATS.DISPLAY_DATETIME);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Formats a time range in the specified timezone.
|
|
111
|
+
*
|
|
112
|
+
* @param startUtc - Start time as UTC ISO string
|
|
113
|
+
* @param endUtc - End time as UTC ISO string
|
|
114
|
+
* @param timezone - IANA timezone ID
|
|
115
|
+
* @returns Formatted time range (e.g., "7:00 PM - 10:00 PM")
|
|
116
|
+
* @throws {DateTimeError} If timezone or ISO strings are invalid
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* formatTimeRange(
|
|
120
|
+
* '2023-12-25T03:00:00Z',
|
|
121
|
+
* '2023-12-25T06:00:00Z',
|
|
122
|
+
* 'America/Los_Angeles'
|
|
123
|
+
* )
|
|
124
|
+
* // "7:00 PM - 10:00 PM"
|
|
125
|
+
*/
|
|
126
|
+
export function formatTimeRange(startUtc, endUtc, timezone) {
|
|
127
|
+
const startTime = formatEventTime(startUtc, timezone);
|
|
128
|
+
const endTime = formatEventTime(endUtc, timezone);
|
|
129
|
+
return `${startTime} - ${endTime}`;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Formats a date range in the specified timezone.
|
|
133
|
+
* Handles same-day, same-month, and cross-month/year ranges intelligently.
|
|
134
|
+
*
|
|
135
|
+
* @param startUtc - Start date as UTC ISO string
|
|
136
|
+
* @param endUtc - End date as UTC ISO string
|
|
137
|
+
* @param timezone - IANA timezone ID
|
|
138
|
+
* @returns Formatted date range (e.g., "Dec 20 - 22, 2025" or "Dec 20 - Jan 5, 2026")
|
|
139
|
+
* @throws {DateTimeError} If timezone or ISO strings are invalid
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* formatDateRange(
|
|
143
|
+
* '2023-12-20T08:00:00Z',
|
|
144
|
+
* '2023-12-22T08:00:00Z',
|
|
145
|
+
* 'America/Los_Angeles'
|
|
146
|
+
* )
|
|
147
|
+
* // "Dec 20 - 22, 2023"
|
|
148
|
+
*/
|
|
149
|
+
export function formatDateRange(startUtc, endUtc, timezone) {
|
|
150
|
+
const startZoned = getZonedDate(startUtc, timezone);
|
|
151
|
+
const endZoned = getZonedDate(endUtc, timezone);
|
|
152
|
+
const startYear = startZoned.getFullYear();
|
|
153
|
+
const endYear = endZoned.getFullYear();
|
|
154
|
+
const startMonth = startZoned.getMonth();
|
|
155
|
+
const endMonth = endZoned.getMonth();
|
|
156
|
+
const startDay = startZoned.getDate();
|
|
157
|
+
const endDay = endZoned.getDate();
|
|
158
|
+
// Same day
|
|
159
|
+
if (startYear === endYear && startMonth === endMonth && startDay === endDay) {
|
|
160
|
+
return format(startZoned, DATE_FORMATS.DISPLAY_DATE);
|
|
161
|
+
}
|
|
162
|
+
// Same month and year
|
|
163
|
+
if (startYear === endYear && startMonth === endMonth) {
|
|
164
|
+
return `${format(startZoned, 'MMM d')} - ${endDay}, ${startYear}`;
|
|
165
|
+
}
|
|
166
|
+
// Same year, different months
|
|
167
|
+
if (startYear === endYear) {
|
|
168
|
+
return `${format(startZoned, 'MMM d')} - ${format(endZoned, 'MMM d')}, ${startYear}`;
|
|
169
|
+
}
|
|
170
|
+
// Different years
|
|
171
|
+
return `${format(startZoned, DATE_FORMATS.DISPLAY_DATE)} - ${format(endZoned, DATE_FORMATS.DISPLAY_DATE)}`;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Formats a datetime as a relative time string (e.g., "2 hours ago", "in 3 days").
|
|
175
|
+
*
|
|
176
|
+
* @param utcIso - UTC ISO datetime string
|
|
177
|
+
* @param timezone - IANA timezone ID (used for consistency, though relative time is timezone-agnostic)
|
|
178
|
+
* @returns Relative time string
|
|
179
|
+
* @throws {DateTimeError} If timezone or ISO string is invalid
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* formatRelativeTime(new Date(Date.now() - 30 * 60 * 1000).toISOString(), 'America/Los_Angeles')
|
|
183
|
+
* // "30 minutes ago"
|
|
184
|
+
*/
|
|
185
|
+
export function formatRelativeTime(utcIso, timezone) {
|
|
186
|
+
// Validate inputs
|
|
187
|
+
if (!isValidTimezone(timezone)) {
|
|
188
|
+
throw new DateTimeError(`Invalid timezone: ${timezone}`, DateTimeErrorCode.INVALID_TIMEZONE, { timezone });
|
|
189
|
+
}
|
|
190
|
+
const date = parseAndValidateISO(utcIso);
|
|
191
|
+
const now = new Date();
|
|
192
|
+
const diffMs = date.getTime() - now.getTime();
|
|
193
|
+
const absDiffMs = Math.abs(diffMs);
|
|
194
|
+
const isPast = diffMs < 0;
|
|
195
|
+
const seconds = Math.floor(absDiffMs / DURATIONS.SECOND);
|
|
196
|
+
const minutes = Math.floor(absDiffMs / DURATIONS.MINUTE);
|
|
197
|
+
const hours = Math.floor(absDiffMs / DURATIONS.HOUR);
|
|
198
|
+
const days = Math.floor(absDiffMs / DURATIONS.DAY);
|
|
199
|
+
const weeks = Math.floor(absDiffMs / DURATIONS.WEEK);
|
|
200
|
+
const formatUnit = (value, unit) => {
|
|
201
|
+
const plural = value === 1 ? '' : 's';
|
|
202
|
+
if (isPast) {
|
|
203
|
+
return `${value} ${unit}${plural} ago`;
|
|
204
|
+
}
|
|
205
|
+
return `in ${value} ${unit}${plural}`;
|
|
206
|
+
};
|
|
207
|
+
if (seconds < RELATIVE_TIME_THRESHOLDS.JUST_NOW_SECONDS) {
|
|
208
|
+
return 'just now';
|
|
209
|
+
}
|
|
210
|
+
if (minutes < RELATIVE_TIME_THRESHOLDS.MINUTES_THRESHOLD) {
|
|
211
|
+
return formatUnit(minutes, 'minute');
|
|
212
|
+
}
|
|
213
|
+
if (hours < RELATIVE_TIME_THRESHOLDS.HOURS_THRESHOLD) {
|
|
214
|
+
return formatUnit(hours, 'hour');
|
|
215
|
+
}
|
|
216
|
+
if (days < RELATIVE_TIME_THRESHOLDS.DAYS_THRESHOLD) {
|
|
217
|
+
return formatUnit(days, 'day');
|
|
218
|
+
}
|
|
219
|
+
if (weeks < RELATIVE_TIME_THRESHOLDS.WEEKS_THRESHOLD) {
|
|
220
|
+
return formatUnit(weeks, 'week');
|
|
221
|
+
}
|
|
222
|
+
// For older dates, show the actual date
|
|
223
|
+
return formatEventDate(utcIso, timezone);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Extracts date parts from a UTC datetime in the specified timezone.
|
|
227
|
+
*
|
|
228
|
+
* @param utcIso - UTC ISO datetime string
|
|
229
|
+
* @param timezone - IANA timezone ID
|
|
230
|
+
* @returns Object with day, month, date, and year
|
|
231
|
+
* @throws {DateTimeError} If timezone or ISO string is invalid
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* getDateParts('2023-12-25T20:00:00Z', 'America/Los_Angeles')
|
|
235
|
+
* // { day: 'Mon', month: 'Dec', date: 25, year: 2023 }
|
|
236
|
+
*/
|
|
237
|
+
export function getDateParts(utcIso, timezone) {
|
|
238
|
+
const zonedDate = getZonedDate(utcIso, timezone);
|
|
239
|
+
return {
|
|
240
|
+
day: format(zonedDate, DATE_FORMATS.DAY_SHORT),
|
|
241
|
+
month: format(zonedDate, DATE_FORMATS.MONTH_SHORT),
|
|
242
|
+
date: zonedDate.getDate(),
|
|
243
|
+
year: zonedDate.getFullYear(),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Formats a datetime for display in notifications.
|
|
248
|
+
* Shows relative time for recent events, date for older ones.
|
|
249
|
+
*
|
|
250
|
+
* @param utcIso - UTC ISO datetime string
|
|
251
|
+
* @param timezone - IANA timezone ID
|
|
252
|
+
* @returns Formatted string suitable for notifications
|
|
253
|
+
*/
|
|
254
|
+
export function formatNotificationTime(utcIso, timezone) {
|
|
255
|
+
const date = parseAndValidateISO(utcIso);
|
|
256
|
+
const now = new Date();
|
|
257
|
+
const diffMs = now.getTime() - date.getTime();
|
|
258
|
+
// Less than 24 hours ago
|
|
259
|
+
if (diffMs < DURATIONS.DAY) {
|
|
260
|
+
return formatRelativeTime(utcIso, timezone);
|
|
261
|
+
}
|
|
262
|
+
// Less than 7 days ago
|
|
263
|
+
if (diffMs < DURATIONS.WEEK) {
|
|
264
|
+
const zonedDate = getZonedDate(utcIso, timezone);
|
|
265
|
+
return format(zonedDate, "EEEE 'at' h:mm a");
|
|
266
|
+
}
|
|
267
|
+
// Older - show full date
|
|
268
|
+
return formatEventDateTime(utcIso, timezone);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Formats the day of week from a UTC datetime.
|
|
272
|
+
*
|
|
273
|
+
* @param utcIso - UTC ISO datetime string
|
|
274
|
+
* @param timezone - IANA timezone ID
|
|
275
|
+
* @param short - If true, returns short form (e.g., "Mon"), otherwise full (e.g., "Monday")
|
|
276
|
+
* @returns Day of week string
|
|
277
|
+
*/
|
|
278
|
+
export function formatDayOfWeek(utcIso, timezone, short = true) {
|
|
279
|
+
const zonedDate = getZonedDate(utcIso, timezone);
|
|
280
|
+
return format(zonedDate, short ? DATE_FORMATS.DAY_SHORT : DATE_FORMATS.DAY_FULL);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Formats the month from a UTC datetime.
|
|
284
|
+
*
|
|
285
|
+
* @param utcIso - UTC ISO datetime string
|
|
286
|
+
* @param timezone - IANA timezone ID
|
|
287
|
+
* @param short - If true, returns short form (e.g., "Dec"), otherwise full (e.g., "December")
|
|
288
|
+
* @returns Month string
|
|
289
|
+
*/
|
|
290
|
+
export function formatMonth(utcIso, timezone, short = true) {
|
|
291
|
+
const zonedDate = getZonedDate(utcIso, timezone);
|
|
292
|
+
return format(zonedDate, short ? DATE_FORMATS.MONTH_SHORT : DATE_FORMATS.MONTH_FULL);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Gets the hour in the specified timezone (0-23).
|
|
296
|
+
*
|
|
297
|
+
* @param utcIso - UTC ISO datetime string
|
|
298
|
+
* @param timezone - IANA timezone ID
|
|
299
|
+
* @returns Hour (0-23)
|
|
300
|
+
*/
|
|
301
|
+
export function getHourInTimezone(utcIso, timezone) {
|
|
302
|
+
const zonedDate = getZonedDate(utcIso, timezone);
|
|
303
|
+
return zonedDate.getHours();
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Gets the date string (YYYY-MM-DD) in the specified timezone.
|
|
307
|
+
*
|
|
308
|
+
* @param utcIso - UTC ISO datetime string
|
|
309
|
+
* @param timezone - IANA timezone ID
|
|
310
|
+
* @returns Date string in YYYY-MM-DD format
|
|
311
|
+
*/
|
|
312
|
+
export function getDateInTimezone(utcIso, timezone) {
|
|
313
|
+
const zonedDate = getZonedDate(utcIso, timezone);
|
|
314
|
+
return format(zonedDate, DATE_FORMATS.API_DATE);
|
|
315
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DateTime Module
|
|
3
|
+
*
|
|
4
|
+
* Centralized date/time handling for the MicDrop platform.
|
|
5
|
+
* All datetime operations should use this module to ensure consistent
|
|
6
|
+
* timezone handling across the application.
|
|
7
|
+
*
|
|
8
|
+
* ## Golden Rules
|
|
9
|
+
*
|
|
10
|
+
* 1. **Backend is King** - All API requests send/receive UTC ISO strings
|
|
11
|
+
* 2. **Display is Local** - All UI components receive UTC + Timezone ID
|
|
12
|
+
* 3. **No `new Date()` in components** - Use these helpers instead
|
|
13
|
+
* 4. **Timezone is always required** - Every function requires explicit timezone
|
|
14
|
+
*
|
|
15
|
+
* ## Usage Examples
|
|
16
|
+
*
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import * as datetime from './';
|
|
19
|
+
*
|
|
20
|
+
* // Get venue timezone
|
|
21
|
+
* const tz = datetime.getVenueTimezone(venue);
|
|
22
|
+
*
|
|
23
|
+
* // Format for display
|
|
24
|
+
* const time = datetime.formatEventTime(event.startTime, tz);
|
|
25
|
+
* const date = datetime.formatEventDate(event.startTime, tz);
|
|
26
|
+
*
|
|
27
|
+
* // Parse form input to UTC for API
|
|
28
|
+
* const utc = datetime.combineDateAndTime('2023-12-25', '19:00', tz);
|
|
29
|
+
*
|
|
30
|
+
* // Parse API response for form
|
|
31
|
+
* const { date, time } = datetime.parseDateTimeFromAPI(event.startTime, tz);
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @module datetime
|
|
35
|
+
*/
|
|
36
|
+
export type { DateParts, FormatOptions, FormattedTimeRange, ISODateString, LocalDateString, LocalDateTimeString, LocalTimeString, TimeRange, TimezoneId, VenueWithTimezone, } from './types';
|
|
37
|
+
export { DateTimeError, DateTimeErrorCode } from './types';
|
|
38
|
+
export { COMMON_US_TIMEZONES, DATE_FORMATS, DEFAULT_TIMEZONE, DURATIONS, DURATIONS_MINUTES, EVENT_DEFAULTS, RELATIVE_TIME_THRESHOLDS, } from './constants';
|
|
39
|
+
export { getTimezoneDisplayName, getTimezoneOffset, getUserTimezone, getVenueTimezone, isDST, isValidTimezone, normalizeTimezone, } from './timezone';
|
|
40
|
+
export { formatDateRange, formatDayOfWeek, formatEventDate, formatEventDateTime, formatEventTime, formatMonth, formatNotificationTime, formatRelativeTime, formatTimeRange, getDateInTimezone, getDateParts, getHourInTimezone, } from './format';
|
|
41
|
+
export { combineDateAndTime, formatDateTimeForAPI, isNextDayTime, minutesToTimeString, parseDateTimeFromAPI, parseEndOfDay, parseLocalToUTC, parseStartOfDay, parseTimeToMinutes, parseUTCToLocal, stripNextDayPrefix, } from './parse';
|
|
42
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/datetime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,YAAY,EACV,SAAS,EACT,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,UAAU,EACV,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAG3D,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,KAAK,EACL,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,sBAAsB,EACtB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,kBAAkB,GACnB,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DateTime Module
|
|
3
|
+
*
|
|
4
|
+
* Centralized date/time handling for the MicDrop platform.
|
|
5
|
+
* All datetime operations should use this module to ensure consistent
|
|
6
|
+
* timezone handling across the application.
|
|
7
|
+
*
|
|
8
|
+
* ## Golden Rules
|
|
9
|
+
*
|
|
10
|
+
* 1. **Backend is King** - All API requests send/receive UTC ISO strings
|
|
11
|
+
* 2. **Display is Local** - All UI components receive UTC + Timezone ID
|
|
12
|
+
* 3. **No `new Date()` in components** - Use these helpers instead
|
|
13
|
+
* 4. **Timezone is always required** - Every function requires explicit timezone
|
|
14
|
+
*
|
|
15
|
+
* ## Usage Examples
|
|
16
|
+
*
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import * as datetime from './';
|
|
19
|
+
*
|
|
20
|
+
* // Get venue timezone
|
|
21
|
+
* const tz = datetime.getVenueTimezone(venue);
|
|
22
|
+
*
|
|
23
|
+
* // Format for display
|
|
24
|
+
* const time = datetime.formatEventTime(event.startTime, tz);
|
|
25
|
+
* const date = datetime.formatEventDate(event.startTime, tz);
|
|
26
|
+
*
|
|
27
|
+
* // Parse form input to UTC for API
|
|
28
|
+
* const utc = datetime.combineDateAndTime('2023-12-25', '19:00', tz);
|
|
29
|
+
*
|
|
30
|
+
* // Parse API response for form
|
|
31
|
+
* const { date, time } = datetime.parseDateTimeFromAPI(event.startTime, tz);
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @module datetime
|
|
35
|
+
*/
|
|
36
|
+
export { DateTimeError, DateTimeErrorCode } from './types';
|
|
37
|
+
// Constants
|
|
38
|
+
export { COMMON_US_TIMEZONES, DATE_FORMATS, DEFAULT_TIMEZONE, DURATIONS, DURATIONS_MINUTES, EVENT_DEFAULTS, RELATIVE_TIME_THRESHOLDS, } from './constants';
|
|
39
|
+
// Timezone utilities
|
|
40
|
+
export { getTimezoneDisplayName, getTimezoneOffset, getUserTimezone, getVenueTimezone, isDST, isValidTimezone, normalizeTimezone, } from './timezone';
|
|
41
|
+
// Format functions
|
|
42
|
+
export { formatDateRange, formatDayOfWeek, formatEventDate, formatEventDateTime, formatEventTime, formatMonth, formatNotificationTime, formatRelativeTime, formatTimeRange, getDateInTimezone, getDateParts, getHourInTimezone, } from './format';
|
|
43
|
+
// Parse functions
|
|
44
|
+
export { combineDateAndTime, formatDateTimeForAPI, isNextDayTime, minutesToTimeString, parseDateTimeFromAPI, parseEndOfDay, parseLocalToUTC, parseStartOfDay, parseTimeToMinutes, parseUTCToLocal, stripNextDayPrefix, } from './parse';
|