@blackcode_sa/metaestetics-api 1.13.4 → 1.13.5
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/admin/index.d.mts +15 -28
- package/dist/admin/index.d.ts +15 -28
- package/dist/index.d.mts +16 -29
- package/dist/index.d.ts +16 -29
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/package.json +121 -119
- package/src/__mocks__/firstore.ts +10 -10
- package/src/admin/aggregation/README.md +79 -79
- package/src/admin/aggregation/appointment/README.md +128 -128
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +1984 -1984
- package/src/admin/aggregation/appointment/index.ts +1 -1
- package/src/admin/aggregation/clinic/README.md +52 -52
- package/src/admin/aggregation/clinic/clinic.aggregation.service.ts +703 -703
- package/src/admin/aggregation/clinic/index.ts +1 -1
- package/src/admin/aggregation/forms/README.md +13 -13
- package/src/admin/aggregation/forms/filled-forms.aggregation.service.ts +322 -322
- package/src/admin/aggregation/forms/index.ts +1 -1
- package/src/admin/aggregation/index.ts +8 -8
- package/src/admin/aggregation/patient/README.md +27 -27
- package/src/admin/aggregation/patient/index.ts +1 -1
- package/src/admin/aggregation/patient/patient.aggregation.service.ts +141 -141
- package/src/admin/aggregation/practitioner/README.md +42 -42
- package/src/admin/aggregation/practitioner/index.ts +1 -1
- package/src/admin/aggregation/practitioner/practitioner.aggregation.service.ts +433 -433
- package/src/admin/aggregation/practitioner-invite/index.ts +1 -1
- package/src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts +961 -961
- package/src/admin/aggregation/procedure/README.md +43 -43
- package/src/admin/aggregation/procedure/index.ts +1 -1
- package/src/admin/aggregation/procedure/procedure.aggregation.service.ts +702 -702
- package/src/admin/aggregation/reviews/index.ts +1 -1
- package/src/admin/aggregation/reviews/reviews.aggregation.service.ts +689 -689
- package/src/admin/analytics/analytics.admin.service.ts +278 -278
- package/src/admin/analytics/index.ts +2 -2
- package/src/admin/booking/README.md +125 -125
- package/src/admin/booking/booking.admin.ts +1037 -1037
- package/src/admin/booking/booking.calculator.ts +712 -712
- package/src/admin/booking/booking.types.ts +59 -59
- package/src/admin/booking/index.ts +3 -3
- package/src/admin/booking/timezones-problem.md +185 -185
- package/src/admin/calendar/README.md +7 -7
- package/src/admin/calendar/calendar.admin.service.ts +345 -345
- package/src/admin/calendar/index.ts +1 -1
- package/src/admin/documentation-templates/document-manager.admin.ts +260 -260
- package/src/admin/documentation-templates/index.ts +1 -1
- package/src/admin/free-consultation/free-consultation-utils.admin.ts +148 -148
- package/src/admin/free-consultation/index.ts +1 -1
- package/src/admin/index.ts +81 -81
- package/src/admin/logger/index.ts +78 -78
- package/src/admin/mailing/README.md +95 -95
- package/src/admin/mailing/appointment/appointment.mailing.service.ts +732 -732
- package/src/admin/mailing/appointment/index.ts +1 -1
- package/src/admin/mailing/appointment/templates/patient/appointment-confirmed.html +40 -40
- package/src/admin/mailing/base.mailing.service.ts +208 -208
- package/src/admin/mailing/index.ts +3 -3
- package/src/admin/mailing/practitionerInvite/existing-practitioner-invite.mailing.ts +611 -611
- package/src/admin/mailing/practitionerInvite/index.ts +2 -2
- package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +395 -395
- package/src/admin/mailing/practitionerInvite/templates/existing-practitioner-invitation.template.ts +155 -155
- package/src/admin/mailing/practitionerInvite/templates/invitation.template.ts +101 -101
- package/src/admin/mailing/practitionerInvite/templates/invite-accepted-notification.template.ts +228 -228
- package/src/admin/mailing/practitionerInvite/templates/invite-rejected-notification.template.ts +242 -242
- package/src/admin/notifications/index.ts +1 -1
- package/src/admin/notifications/notifications.admin.ts +710 -710
- package/src/admin/requirements/README.md +128 -128
- package/src/admin/requirements/index.ts +1 -1
- package/src/admin/requirements/patient-requirements.admin.service.ts +475 -475
- package/src/admin/users/index.ts +1 -1
- package/src/admin/users/user-profile.admin.ts +405 -405
- package/src/backoffice/constants/certification.constants.ts +13 -13
- package/src/backoffice/constants/index.ts +1 -1
- package/src/backoffice/errors/backoffice.errors.ts +181 -181
- package/src/backoffice/errors/index.ts +1 -1
- package/src/backoffice/expo-safe/README.md +26 -26
- package/src/backoffice/expo-safe/index.ts +41 -41
- package/src/backoffice/index.ts +5 -5
- package/src/backoffice/services/FIXES_README.md +102 -102
- package/src/backoffice/services/README.md +57 -57
- package/src/backoffice/services/analytics.service.proposal.md +863 -863
- package/src/backoffice/services/analytics.service.summary.md +143 -143
- package/src/backoffice/services/brand.service.ts +256 -256
- package/src/backoffice/services/category.service.ts +384 -384
- package/src/backoffice/services/constants.service.ts +385 -385
- package/src/backoffice/services/documentation-template.service.ts +202 -202
- package/src/backoffice/services/index.ts +10 -10
- package/src/backoffice/services/migrate-products.ts +116 -116
- package/src/backoffice/services/product.service.ts +553 -553
- package/src/backoffice/services/requirement.service.ts +235 -235
- package/src/backoffice/services/subcategory.service.ts +461 -461
- package/src/backoffice/services/technology.service.ts +1151 -1151
- package/src/backoffice/types/README.md +12 -12
- package/src/backoffice/types/admin-constants.types.ts +69 -69
- package/src/backoffice/types/brand.types.ts +29 -29
- package/src/backoffice/types/category.types.ts +67 -67
- package/src/backoffice/types/documentation-templates.types.ts +28 -28
- package/src/backoffice/types/index.ts +10 -10
- package/src/backoffice/types/procedure-product.types.ts +38 -38
- package/src/backoffice/types/product.types.ts +240 -240
- package/src/backoffice/types/requirement.types.ts +63 -63
- package/src/backoffice/types/static/README.md +18 -18
- package/src/backoffice/types/static/blocking-condition.types.ts +21 -21
- package/src/backoffice/types/static/certification.types.ts +37 -37
- package/src/backoffice/types/static/contraindication.types.ts +19 -19
- package/src/backoffice/types/static/index.ts +6 -6
- package/src/backoffice/types/static/pricing.types.ts +16 -16
- package/src/backoffice/types/static/procedure-family.types.ts +14 -14
- package/src/backoffice/types/static/treatment-benefit.types.ts +22 -22
- package/src/backoffice/types/subcategory.types.ts +34 -34
- package/src/backoffice/types/technology.types.ts +168 -168
- package/src/backoffice/validations/index.ts +1 -1
- package/src/backoffice/validations/schemas.ts +164 -164
- package/src/config/__mocks__/firebase.ts +99 -99
- package/src/config/firebase.ts +78 -78
- package/src/config/index.ts +9 -9
- package/src/errors/auth.error.ts +6 -6
- package/src/errors/auth.errors.ts +200 -200
- package/src/errors/clinic.errors.ts +32 -32
- package/src/errors/firebase.errors.ts +47 -47
- package/src/errors/user.errors.ts +99 -99
- package/src/index.backup.ts +407 -407
- package/src/index.ts +6 -6
- package/src/locales/en.ts +31 -31
- package/src/recommender/admin/index.ts +1 -1
- package/src/recommender/admin/services/recommender.service.admin.ts +5 -5
- package/src/recommender/front/index.ts +1 -1
- package/src/recommender/front/services/onboarding.service.ts +5 -5
- package/src/recommender/front/services/recommender.service.ts +3 -3
- package/src/recommender/index.ts +1 -1
- package/src/services/PATIENTAUTH.MD +197 -197
- package/src/services/README.md +106 -106
- package/src/services/__tests__/auth/auth.mock.test.ts +17 -17
- package/src/services/__tests__/auth/auth.setup.ts +293 -293
- package/src/services/__tests__/auth.service.test.ts +346 -346
- package/src/services/__tests__/base.service.test.ts +77 -77
- package/src/services/__tests__/user.service.test.ts +528 -528
- package/src/services/analytics/ARCHITECTURE.md +199 -199
- package/src/services/analytics/CLOUD_FUNCTIONS.md +225 -225
- package/src/services/analytics/GROUPED_ANALYTICS.md +501 -501
- package/src/services/analytics/QUICK_START.md +393 -393
- package/src/services/analytics/README.md +304 -304
- package/src/services/analytics/SUMMARY.md +141 -141
- package/src/services/analytics/TRENDS.md +380 -380
- package/src/services/analytics/USAGE_GUIDE.md +518 -518
- package/src/services/analytics/analytics-cloud.service.ts +222 -222
- package/src/services/analytics/analytics.service.ts +2142 -2142
- package/src/services/analytics/index.ts +4 -4
- package/src/services/analytics/review-analytics.service.ts +941 -941
- package/src/services/analytics/utils/appointment-filtering.utils.ts +138 -138
- package/src/services/analytics/utils/cost-calculation.utils.ts +182 -182
- package/src/services/analytics/utils/grouping.utils.ts +434 -434
- package/src/services/analytics/utils/stored-analytics.utils.ts +347 -347
- package/src/services/analytics/utils/time-calculation.utils.ts +186 -186
- package/src/services/analytics/utils/trend-calculation.utils.ts +200 -200
- package/src/services/appointment/README.md +17 -17
- package/src/services/appointment/appointment.service.ts +2558 -2558
- package/src/services/appointment/index.ts +1 -1
- package/src/services/appointment/utils/appointment.utils.ts +552 -552
- package/src/services/appointment/utils/extended-procedure.utils.ts +314 -314
- package/src/services/appointment/utils/form-initialization.utils.ts +225 -225
- package/src/services/appointment/utils/recommended-procedure.utils.ts +195 -195
- package/src/services/appointment/utils/zone-management.utils.ts +353 -353
- package/src/services/appointment/utils/zone-photo.utils.ts +152 -152
- package/src/services/auth/auth.service.ts +989 -989
- package/src/services/auth/auth.v2.service.ts +961 -961
- package/src/services/auth/index.ts +7 -7
- package/src/services/auth/utils/error.utils.ts +90 -90
- package/src/services/auth/utils/firebase.utils.ts +49 -49
- package/src/services/auth/utils/index.ts +21 -21
- package/src/services/auth/utils/practitioner.utils.ts +125 -125
- package/src/services/base.service.ts +41 -41
- package/src/services/calendar/calendar.service.ts +1077 -1077
- package/src/services/calendar/calendar.v2.service.ts +1683 -1683
- package/src/services/calendar/calendar.v3.service.ts +313 -313
- package/src/services/calendar/externalCalendar.service.ts +178 -178
- package/src/services/calendar/index.ts +5 -5
- package/src/services/calendar/synced-calendars.service.ts +743 -743
- package/src/services/calendar/utils/appointment.utils.ts +265 -265
- package/src/services/calendar/utils/calendar-event.utils.ts +646 -646
- package/src/services/calendar/utils/clinic.utils.ts +237 -237
- package/src/services/calendar/utils/docs.utils.ts +157 -157
- package/src/services/calendar/utils/google-calendar.utils.ts +697 -697
- package/src/services/calendar/utils/index.ts +8 -8
- package/src/services/calendar/utils/patient.utils.ts +198 -198
- package/src/services/calendar/utils/practitioner.utils.ts +221 -221
- package/src/services/calendar/utils/synced-calendar.utils.ts +472 -472
- package/src/services/clinic/README.md +204 -204
- package/src/services/clinic/__tests__/clinic-admin.service.test.ts +287 -287
- package/src/services/clinic/__tests__/clinic-group.service.test.ts +352 -352
- package/src/services/clinic/__tests__/clinic.service.test.ts +354 -354
- package/src/services/clinic/billing-transactions.service.ts +217 -217
- package/src/services/clinic/clinic-admin.service.ts +202 -202
- package/src/services/clinic/clinic-group.service.ts +310 -310
- package/src/services/clinic/clinic.service.ts +708 -708
- package/src/services/clinic/index.ts +5 -5
- package/src/services/clinic/practitioner-invite.service.ts +519 -519
- package/src/services/clinic/utils/admin.utils.ts +551 -551
- package/src/services/clinic/utils/clinic-group.utils.ts +646 -646
- package/src/services/clinic/utils/clinic.utils.ts +949 -949
- package/src/services/clinic/utils/filter.utils.d.ts +23 -23
- package/src/services/clinic/utils/filter.utils.ts +446 -446
- package/src/services/clinic/utils/index.ts +11 -11
- package/src/services/clinic/utils/photos.utils.ts +188 -188
- package/src/services/clinic/utils/search.utils.ts +84 -84
- package/src/services/clinic/utils/tag.utils.ts +124 -124
- package/src/services/documentation-templates/documentation-template.service.ts +537 -537
- package/src/services/documentation-templates/filled-document.service.ts +587 -587
- package/src/services/documentation-templates/index.ts +2 -2
- package/src/services/index.ts +14 -14
- package/src/services/media/index.ts +1 -1
- package/src/services/media/media.service.ts +418 -418
- package/src/services/notifications/__tests__/notification.service.test.ts +242 -242
- package/src/services/notifications/index.ts +1 -1
- package/src/services/notifications/notification.service.ts +215 -215
- package/src/services/patient/README.md +48 -48
- package/src/services/patient/To-Do.md +43 -43
- package/src/services/patient/__tests__/patient.service.test.ts +294 -294
- package/src/services/patient/index.ts +2 -2
- package/src/services/patient/patient.service.ts +883 -883
- package/src/services/patient/patientRequirements.service.ts +285 -285
- package/src/services/patient/utils/aesthetic-analysis.utils.ts +176 -176
- package/src/services/patient/utils/clinic.utils.ts +80 -80
- package/src/services/patient/utils/docs.utils.ts +142 -142
- package/src/services/patient/utils/index.ts +9 -9
- package/src/services/patient/utils/location.utils.ts +126 -126
- package/src/services/patient/utils/medical-stuff.utils.ts +143 -143
- package/src/services/patient/utils/medical.utils.ts +458 -458
- package/src/services/patient/utils/practitioner.utils.ts +260 -260
- package/src/services/patient/utils/profile.utils.ts +510 -510
- package/src/services/patient/utils/sensitive.utils.ts +260 -260
- package/src/services/patient/utils/token.utils.ts +211 -211
- package/src/services/practitioner/README.md +145 -145
- package/src/services/practitioner/index.ts +1 -1
- package/src/services/practitioner/practitioner.service.ts +1742 -1742
- package/src/services/procedure/README.md +163 -163
- package/src/services/procedure/index.ts +1 -1
- package/src/services/procedure/procedure.service.ts +2200 -2200
- package/src/services/reviews/index.ts +1 -1
- package/src/services/reviews/reviews.service.ts +734 -734
- package/src/services/user/index.ts +1 -1
- package/src/services/user/user.service.ts +489 -489
- package/src/services/user/user.v2.service.ts +466 -466
- package/src/types/analytics/analytics.types.ts +597 -597
- package/src/types/analytics/grouped-analytics.types.ts +173 -173
- package/src/types/analytics/index.ts +4 -4
- package/src/types/analytics/stored-analytics.types.ts +137 -137
- package/src/types/appointment/index.ts +480 -480
- package/src/types/calendar/index.ts +258 -258
- package/src/types/calendar/synced-calendar.types.ts +66 -66
- package/src/types/clinic/index.ts +498 -489
- package/src/types/clinic/practitioner-invite.types.ts +91 -91
- package/src/types/clinic/preferences.types.ts +159 -159
- package/src/types/clinic/to-do +3 -3
- package/src/types/documentation-templates/index.ts +308 -308
- package/src/types/index.ts +47 -47
- package/src/types/notifications/README.md +77 -77
- package/src/types/notifications/index.ts +286 -286
- package/src/types/patient/aesthetic-analysis.types.ts +66 -66
- package/src/types/patient/allergies.ts +58 -58
- package/src/types/patient/index.ts +275 -275
- package/src/types/patient/medical-info.types.ts +152 -152
- package/src/types/patient/patient-requirements.ts +92 -92
- package/src/types/patient/token.types.ts +61 -61
- package/src/types/practitioner/index.ts +206 -206
- package/src/types/procedure/index.ts +181 -181
- package/src/types/profile/index.ts +39 -39
- package/src/types/reviews/index.ts +132 -132
- package/src/types/tz-lookup.d.ts +4 -4
- package/src/types/user/index.ts +38 -38
- package/src/utils/TIMESTAMPS.md +176 -176
- package/src/utils/TimestampUtils.ts +241 -241
- package/src/utils/index.ts +1 -1
- package/src/validations/appointment.schema.ts +574 -574
- package/src/validations/calendar.schema.ts +225 -225
- package/src/validations/clinic.schema.ts +494 -493
- package/src/validations/common.schema.ts +25 -25
- package/src/validations/documentation-templates/index.ts +1 -1
- package/src/validations/documentation-templates/template.schema.ts +220 -220
- package/src/validations/documentation-templates.schema.ts +10 -10
- package/src/validations/index.ts +20 -20
- package/src/validations/media.schema.ts +10 -10
- package/src/validations/notification.schema.ts +90 -90
- package/src/validations/patient/aesthetic-analysis.schema.ts +55 -55
- package/src/validations/patient/medical-info.schema.ts +125 -125
- package/src/validations/patient/patient-requirements.schema.ts +84 -84
- package/src/validations/patient/token.schema.ts +29 -29
- package/src/validations/patient.schema.ts +217 -217
- package/src/validations/practitioner.schema.ts +222 -222
- package/src/validations/procedure-product.schema.ts +41 -41
- package/src/validations/procedure.schema.ts +124 -124
- package/src/validations/profile-info.schema.ts +41 -41
- package/src/validations/reviews.schema.ts +195 -195
- package/src/validations/schemas.ts +104 -104
- package/src/validations/shared.schema.ts +78 -78
|
@@ -1,313 +1,313 @@
|
|
|
1
|
-
import { Auth } from "firebase/auth";
|
|
2
|
-
import { Firestore, Timestamp, serverTimestamp } from "firebase/firestore";
|
|
3
|
-
import { FirebaseApp } from "firebase/app";
|
|
4
|
-
import { BaseService } from "../base.service";
|
|
5
|
-
import {
|
|
6
|
-
CalendarEvent,
|
|
7
|
-
CalendarEventStatus,
|
|
8
|
-
CalendarEventTime,
|
|
9
|
-
CalendarEventType,
|
|
10
|
-
CalendarSyncStatus,
|
|
11
|
-
CreateCalendarEventData,
|
|
12
|
-
UpdateCalendarEventData,
|
|
13
|
-
CALENDAR_COLLECTION,
|
|
14
|
-
SearchCalendarEventsParams,
|
|
15
|
-
SearchLocationEnum,
|
|
16
|
-
DateRange,
|
|
17
|
-
CreateBlockingEventParams,
|
|
18
|
-
UpdateBlockingEventParams,
|
|
19
|
-
} from "../../types/calendar";
|
|
20
|
-
import { PRACTITIONERS_COLLECTION } from "../../types/practitioner";
|
|
21
|
-
import { CLINICS_COLLECTION } from "../../types/clinic";
|
|
22
|
-
import { doc, getDoc, setDoc, updateDoc, deleteDoc } from "firebase/firestore";
|
|
23
|
-
|
|
24
|
-
// Import utility functions
|
|
25
|
-
import { searchCalendarEventsUtil } from "./utils/calendar-event.utils";
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Calendar Service V3
|
|
29
|
-
* Focused on blocking event management and calendar event search
|
|
30
|
-
* Appointment logic is handled by AppointmentService and BookingAdmin
|
|
31
|
-
* External calendar sync is handled by dedicated cloud functions
|
|
32
|
-
*/
|
|
33
|
-
export class CalendarServiceV3 extends BaseService {
|
|
34
|
-
/**
|
|
35
|
-
* Creates a new CalendarServiceV3 instance
|
|
36
|
-
* @param db - Firestore instance
|
|
37
|
-
* @param auth - Firebase Auth instance
|
|
38
|
-
* @param app - Firebase App instance
|
|
39
|
-
*/
|
|
40
|
-
constructor(db: Firestore, auth: Auth, app: FirebaseApp) {
|
|
41
|
-
super(db, auth, app);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// #region Blocking Event CRUD Operations
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Creates a blocking event for a practitioner or clinic
|
|
48
|
-
* @param params - Blocking event creation parameters
|
|
49
|
-
* @returns Created calendar event
|
|
50
|
-
*/
|
|
51
|
-
async createBlockingEvent(
|
|
52
|
-
params: CreateBlockingEventParams
|
|
53
|
-
): Promise<CalendarEvent> {
|
|
54
|
-
// Validate input parameters
|
|
55
|
-
this.validateBlockingEventParams(params);
|
|
56
|
-
|
|
57
|
-
// Generate a unique ID for the event
|
|
58
|
-
const eventId = this.generateId();
|
|
59
|
-
|
|
60
|
-
// Determine the collection path based on entity type
|
|
61
|
-
const collectionPath = this.getEntityCalendarPath(
|
|
62
|
-
params.entityType,
|
|
63
|
-
params.entityId
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
// Create the event document reference
|
|
67
|
-
const eventRef = doc(this.db, collectionPath, eventId);
|
|
68
|
-
|
|
69
|
-
// Prepare the event data
|
|
70
|
-
const eventData: CreateCalendarEventData = {
|
|
71
|
-
id: eventId,
|
|
72
|
-
eventName: params.eventName,
|
|
73
|
-
eventTime: params.eventTime,
|
|
74
|
-
eventType: params.eventType,
|
|
75
|
-
description: params.description || "",
|
|
76
|
-
status: CalendarEventStatus.CONFIRMED, // Blocking events are always confirmed
|
|
77
|
-
syncStatus: CalendarSyncStatus.INTERNAL,
|
|
78
|
-
createdAt: serverTimestamp(),
|
|
79
|
-
updatedAt: serverTimestamp(),
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
// Set entity-specific fields
|
|
83
|
-
if (params.entityType === "practitioner") {
|
|
84
|
-
eventData.practitionerProfileId = params.entityId;
|
|
85
|
-
} else {
|
|
86
|
-
eventData.clinicBranchId = params.entityId;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Create the event
|
|
90
|
-
await setDoc(eventRef, eventData);
|
|
91
|
-
|
|
92
|
-
// Return the created event
|
|
93
|
-
return {
|
|
94
|
-
...eventData,
|
|
95
|
-
createdAt: Timestamp.now(),
|
|
96
|
-
updatedAt: Timestamp.now(),
|
|
97
|
-
} as CalendarEvent;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Updates a blocking event
|
|
102
|
-
* @param params - Blocking event update parameters
|
|
103
|
-
* @returns Updated calendar event
|
|
104
|
-
*/
|
|
105
|
-
async updateBlockingEvent(
|
|
106
|
-
params: UpdateBlockingEventParams
|
|
107
|
-
): Promise<CalendarEvent> {
|
|
108
|
-
// Determine the collection path
|
|
109
|
-
const collectionPath = this.getEntityCalendarPath(
|
|
110
|
-
params.entityType,
|
|
111
|
-
params.entityId
|
|
112
|
-
);
|
|
113
|
-
const eventRef = doc(this.db, collectionPath, params.eventId);
|
|
114
|
-
|
|
115
|
-
// Check if event exists
|
|
116
|
-
const eventDoc = await getDoc(eventRef);
|
|
117
|
-
if (!eventDoc.exists()) {
|
|
118
|
-
throw new Error(`Blocking event with ID ${params.eventId} not found`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Prepare update data
|
|
122
|
-
const updateData: Partial<UpdateCalendarEventData> = {
|
|
123
|
-
updatedAt: serverTimestamp(),
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
if (params.eventName !== undefined) {
|
|
127
|
-
updateData.eventName = params.eventName;
|
|
128
|
-
}
|
|
129
|
-
if (params.eventTime !== undefined) {
|
|
130
|
-
updateData.eventTime = params.eventTime;
|
|
131
|
-
}
|
|
132
|
-
if (params.description !== undefined) {
|
|
133
|
-
updateData.description = params.description;
|
|
134
|
-
}
|
|
135
|
-
if (params.status !== undefined) {
|
|
136
|
-
updateData.status = params.status;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Update the event
|
|
140
|
-
await updateDoc(eventRef, updateData);
|
|
141
|
-
|
|
142
|
-
// Get and return the updated event
|
|
143
|
-
const updatedEventDoc = await getDoc(eventRef);
|
|
144
|
-
return updatedEventDoc.data() as CalendarEvent;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Deletes a blocking event
|
|
149
|
-
* @param entityType - Type of entity (practitioner or clinic)
|
|
150
|
-
* @param entityId - ID of the entity
|
|
151
|
-
* @param eventId - ID of the event to delete
|
|
152
|
-
*/
|
|
153
|
-
async deleteBlockingEvent(
|
|
154
|
-
entityType: "practitioner" | "clinic",
|
|
155
|
-
entityId: string,
|
|
156
|
-
eventId: string
|
|
157
|
-
): Promise<void> {
|
|
158
|
-
// Determine the collection path
|
|
159
|
-
const collectionPath = this.getEntityCalendarPath(entityType, entityId);
|
|
160
|
-
const eventRef = doc(this.db, collectionPath, eventId);
|
|
161
|
-
|
|
162
|
-
// Check if event exists
|
|
163
|
-
const eventDoc = await getDoc(eventRef);
|
|
164
|
-
if (!eventDoc.exists()) {
|
|
165
|
-
throw new Error(`Blocking event with ID ${eventId} not found`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Delete the event
|
|
169
|
-
await deleteDoc(eventRef);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Gets a specific blocking event
|
|
174
|
-
* @param entityType - Type of entity (practitioner or clinic)
|
|
175
|
-
* @param entityId - ID of the entity
|
|
176
|
-
* @param eventId - ID of the event to retrieve
|
|
177
|
-
* @returns Calendar event or null if not found
|
|
178
|
-
*/
|
|
179
|
-
async getBlockingEvent(
|
|
180
|
-
entityType: "practitioner" | "clinic",
|
|
181
|
-
entityId: string,
|
|
182
|
-
eventId: string
|
|
183
|
-
): Promise<CalendarEvent | null> {
|
|
184
|
-
// Determine the collection path
|
|
185
|
-
const collectionPath = this.getEntityCalendarPath(entityType, entityId);
|
|
186
|
-
const eventRef = doc(this.db, collectionPath, eventId);
|
|
187
|
-
|
|
188
|
-
// Get the event
|
|
189
|
-
const eventDoc = await getDoc(eventRef);
|
|
190
|
-
if (!eventDoc.exists()) {
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return eventDoc.data() as CalendarEvent;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Gets blocking events for a specific entity
|
|
199
|
-
* @param entityType - Type of entity (practitioner or clinic)
|
|
200
|
-
* @param entityId - ID of the entity
|
|
201
|
-
* @param dateRange - Optional date range filter
|
|
202
|
-
* @param eventType - Optional event type filter
|
|
203
|
-
* @returns Array of calendar events
|
|
204
|
-
*/
|
|
205
|
-
async getEntityBlockingEvents(
|
|
206
|
-
entityType: "practitioner" | "clinic",
|
|
207
|
-
entityId: string,
|
|
208
|
-
dateRange?: DateRange,
|
|
209
|
-
eventType?: CalendarEventType
|
|
210
|
-
): Promise<CalendarEvent[]> {
|
|
211
|
-
// Use the existing search functionality
|
|
212
|
-
const searchParams: SearchCalendarEventsParams = {
|
|
213
|
-
searchLocation:
|
|
214
|
-
entityType === "practitioner"
|
|
215
|
-
? SearchLocationEnum.PRACTITIONER
|
|
216
|
-
: SearchLocationEnum.CLINIC,
|
|
217
|
-
entityId,
|
|
218
|
-
dateRange,
|
|
219
|
-
eventType,
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
// Filter to only blocking-type events if no specific eventType is provided
|
|
223
|
-
if (!eventType) {
|
|
224
|
-
// We'll need to filter the results to only include blocking-type events
|
|
225
|
-
const allEvents = await searchCalendarEventsUtil(this.db, searchParams);
|
|
226
|
-
return allEvents.filter(
|
|
227
|
-
(event) =>
|
|
228
|
-
event.eventType === CalendarEventType.BLOCKING ||
|
|
229
|
-
event.eventType === CalendarEventType.BREAK ||
|
|
230
|
-
event.eventType === CalendarEventType.FREE_DAY ||
|
|
231
|
-
event.eventType === CalendarEventType.OTHER
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return searchCalendarEventsUtil(this.db, searchParams);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// #endregion
|
|
239
|
-
|
|
240
|
-
// #region Calendar Event Search
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Searches for calendar events based on specified criteria.
|
|
244
|
-
* This method supports searching for ALL event types (appointments, blocking events, etc.)
|
|
245
|
-
*
|
|
246
|
-
* @param params - The search parameters
|
|
247
|
-
* @returns A promise that resolves to an array of matching calendar events
|
|
248
|
-
*/
|
|
249
|
-
async searchCalendarEvents(
|
|
250
|
-
params: SearchCalendarEventsParams
|
|
251
|
-
): Promise<CalendarEvent[]> {
|
|
252
|
-
// Use the utility function to perform the search
|
|
253
|
-
return searchCalendarEventsUtil(this.db, params);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// #endregion
|
|
257
|
-
|
|
258
|
-
// #region Private Helper Methods
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Gets the calendar collection path for a specific entity
|
|
262
|
-
* @param entityType - Type of entity (practitioner or clinic)
|
|
263
|
-
* @param entityId - ID of the entity
|
|
264
|
-
* @returns Collection path string
|
|
265
|
-
*/
|
|
266
|
-
private getEntityCalendarPath(
|
|
267
|
-
entityType: "practitioner" | "clinic",
|
|
268
|
-
entityId: string
|
|
269
|
-
): string {
|
|
270
|
-
if (entityType === "practitioner") {
|
|
271
|
-
return `${PRACTITIONERS_COLLECTION}/${entityId}/${CALENDAR_COLLECTION}`;
|
|
272
|
-
} else {
|
|
273
|
-
return `${CLINICS_COLLECTION}/${entityId}/${CALENDAR_COLLECTION}`;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Validates blocking event creation parameters
|
|
279
|
-
* @param params - Parameters to validate
|
|
280
|
-
* @throws Error if validation fails
|
|
281
|
-
*/
|
|
282
|
-
private validateBlockingEventParams(params: CreateBlockingEventParams): void {
|
|
283
|
-
if (!params.entityType || !params.entityId) {
|
|
284
|
-
throw new Error("Entity type and ID are required");
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (!params.eventName || params.eventName.trim() === "") {
|
|
288
|
-
throw new Error("Event name is required");
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (!params.eventTime || !params.eventTime.start || !params.eventTime.end) {
|
|
292
|
-
throw new Error("Event time with start and end is required");
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Validate that end time is after start time
|
|
296
|
-
if (params.eventTime.end.toMillis() <= params.eventTime.start.toMillis()) {
|
|
297
|
-
throw new Error("Event end time must be after start time");
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// Validate event type is one of the blocking types
|
|
301
|
-
const validTypes = [
|
|
302
|
-
CalendarEventType.BLOCKING,
|
|
303
|
-
CalendarEventType.BREAK,
|
|
304
|
-
CalendarEventType.FREE_DAY,
|
|
305
|
-
CalendarEventType.OTHER,
|
|
306
|
-
];
|
|
307
|
-
if (!validTypes.includes(params.eventType)) {
|
|
308
|
-
throw new Error("Invalid event type for blocking events");
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// #endregion
|
|
313
|
-
}
|
|
1
|
+
import { Auth } from "firebase/auth";
|
|
2
|
+
import { Firestore, Timestamp, serverTimestamp } from "firebase/firestore";
|
|
3
|
+
import { FirebaseApp } from "firebase/app";
|
|
4
|
+
import { BaseService } from "../base.service";
|
|
5
|
+
import {
|
|
6
|
+
CalendarEvent,
|
|
7
|
+
CalendarEventStatus,
|
|
8
|
+
CalendarEventTime,
|
|
9
|
+
CalendarEventType,
|
|
10
|
+
CalendarSyncStatus,
|
|
11
|
+
CreateCalendarEventData,
|
|
12
|
+
UpdateCalendarEventData,
|
|
13
|
+
CALENDAR_COLLECTION,
|
|
14
|
+
SearchCalendarEventsParams,
|
|
15
|
+
SearchLocationEnum,
|
|
16
|
+
DateRange,
|
|
17
|
+
CreateBlockingEventParams,
|
|
18
|
+
UpdateBlockingEventParams,
|
|
19
|
+
} from "../../types/calendar";
|
|
20
|
+
import { PRACTITIONERS_COLLECTION } from "../../types/practitioner";
|
|
21
|
+
import { CLINICS_COLLECTION } from "../../types/clinic";
|
|
22
|
+
import { doc, getDoc, setDoc, updateDoc, deleteDoc } from "firebase/firestore";
|
|
23
|
+
|
|
24
|
+
// Import utility functions
|
|
25
|
+
import { searchCalendarEventsUtil } from "./utils/calendar-event.utils";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Calendar Service V3
|
|
29
|
+
* Focused on blocking event management and calendar event search
|
|
30
|
+
* Appointment logic is handled by AppointmentService and BookingAdmin
|
|
31
|
+
* External calendar sync is handled by dedicated cloud functions
|
|
32
|
+
*/
|
|
33
|
+
export class CalendarServiceV3 extends BaseService {
|
|
34
|
+
/**
|
|
35
|
+
* Creates a new CalendarServiceV3 instance
|
|
36
|
+
* @param db - Firestore instance
|
|
37
|
+
* @param auth - Firebase Auth instance
|
|
38
|
+
* @param app - Firebase App instance
|
|
39
|
+
*/
|
|
40
|
+
constructor(db: Firestore, auth: Auth, app: FirebaseApp) {
|
|
41
|
+
super(db, auth, app);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// #region Blocking Event CRUD Operations
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Creates a blocking event for a practitioner or clinic
|
|
48
|
+
* @param params - Blocking event creation parameters
|
|
49
|
+
* @returns Created calendar event
|
|
50
|
+
*/
|
|
51
|
+
async createBlockingEvent(
|
|
52
|
+
params: CreateBlockingEventParams
|
|
53
|
+
): Promise<CalendarEvent> {
|
|
54
|
+
// Validate input parameters
|
|
55
|
+
this.validateBlockingEventParams(params);
|
|
56
|
+
|
|
57
|
+
// Generate a unique ID for the event
|
|
58
|
+
const eventId = this.generateId();
|
|
59
|
+
|
|
60
|
+
// Determine the collection path based on entity type
|
|
61
|
+
const collectionPath = this.getEntityCalendarPath(
|
|
62
|
+
params.entityType,
|
|
63
|
+
params.entityId
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// Create the event document reference
|
|
67
|
+
const eventRef = doc(this.db, collectionPath, eventId);
|
|
68
|
+
|
|
69
|
+
// Prepare the event data
|
|
70
|
+
const eventData: CreateCalendarEventData = {
|
|
71
|
+
id: eventId,
|
|
72
|
+
eventName: params.eventName,
|
|
73
|
+
eventTime: params.eventTime,
|
|
74
|
+
eventType: params.eventType,
|
|
75
|
+
description: params.description || "",
|
|
76
|
+
status: CalendarEventStatus.CONFIRMED, // Blocking events are always confirmed
|
|
77
|
+
syncStatus: CalendarSyncStatus.INTERNAL,
|
|
78
|
+
createdAt: serverTimestamp(),
|
|
79
|
+
updatedAt: serverTimestamp(),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Set entity-specific fields
|
|
83
|
+
if (params.entityType === "practitioner") {
|
|
84
|
+
eventData.practitionerProfileId = params.entityId;
|
|
85
|
+
} else {
|
|
86
|
+
eventData.clinicBranchId = params.entityId;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Create the event
|
|
90
|
+
await setDoc(eventRef, eventData);
|
|
91
|
+
|
|
92
|
+
// Return the created event
|
|
93
|
+
return {
|
|
94
|
+
...eventData,
|
|
95
|
+
createdAt: Timestamp.now(),
|
|
96
|
+
updatedAt: Timestamp.now(),
|
|
97
|
+
} as CalendarEvent;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Updates a blocking event
|
|
102
|
+
* @param params - Blocking event update parameters
|
|
103
|
+
* @returns Updated calendar event
|
|
104
|
+
*/
|
|
105
|
+
async updateBlockingEvent(
|
|
106
|
+
params: UpdateBlockingEventParams
|
|
107
|
+
): Promise<CalendarEvent> {
|
|
108
|
+
// Determine the collection path
|
|
109
|
+
const collectionPath = this.getEntityCalendarPath(
|
|
110
|
+
params.entityType,
|
|
111
|
+
params.entityId
|
|
112
|
+
);
|
|
113
|
+
const eventRef = doc(this.db, collectionPath, params.eventId);
|
|
114
|
+
|
|
115
|
+
// Check if event exists
|
|
116
|
+
const eventDoc = await getDoc(eventRef);
|
|
117
|
+
if (!eventDoc.exists()) {
|
|
118
|
+
throw new Error(`Blocking event with ID ${params.eventId} not found`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Prepare update data
|
|
122
|
+
const updateData: Partial<UpdateCalendarEventData> = {
|
|
123
|
+
updatedAt: serverTimestamp(),
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
if (params.eventName !== undefined) {
|
|
127
|
+
updateData.eventName = params.eventName;
|
|
128
|
+
}
|
|
129
|
+
if (params.eventTime !== undefined) {
|
|
130
|
+
updateData.eventTime = params.eventTime;
|
|
131
|
+
}
|
|
132
|
+
if (params.description !== undefined) {
|
|
133
|
+
updateData.description = params.description;
|
|
134
|
+
}
|
|
135
|
+
if (params.status !== undefined) {
|
|
136
|
+
updateData.status = params.status;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Update the event
|
|
140
|
+
await updateDoc(eventRef, updateData);
|
|
141
|
+
|
|
142
|
+
// Get and return the updated event
|
|
143
|
+
const updatedEventDoc = await getDoc(eventRef);
|
|
144
|
+
return updatedEventDoc.data() as CalendarEvent;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Deletes a blocking event
|
|
149
|
+
* @param entityType - Type of entity (practitioner or clinic)
|
|
150
|
+
* @param entityId - ID of the entity
|
|
151
|
+
* @param eventId - ID of the event to delete
|
|
152
|
+
*/
|
|
153
|
+
async deleteBlockingEvent(
|
|
154
|
+
entityType: "practitioner" | "clinic",
|
|
155
|
+
entityId: string,
|
|
156
|
+
eventId: string
|
|
157
|
+
): Promise<void> {
|
|
158
|
+
// Determine the collection path
|
|
159
|
+
const collectionPath = this.getEntityCalendarPath(entityType, entityId);
|
|
160
|
+
const eventRef = doc(this.db, collectionPath, eventId);
|
|
161
|
+
|
|
162
|
+
// Check if event exists
|
|
163
|
+
const eventDoc = await getDoc(eventRef);
|
|
164
|
+
if (!eventDoc.exists()) {
|
|
165
|
+
throw new Error(`Blocking event with ID ${eventId} not found`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Delete the event
|
|
169
|
+
await deleteDoc(eventRef);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Gets a specific blocking event
|
|
174
|
+
* @param entityType - Type of entity (practitioner or clinic)
|
|
175
|
+
* @param entityId - ID of the entity
|
|
176
|
+
* @param eventId - ID of the event to retrieve
|
|
177
|
+
* @returns Calendar event or null if not found
|
|
178
|
+
*/
|
|
179
|
+
async getBlockingEvent(
|
|
180
|
+
entityType: "practitioner" | "clinic",
|
|
181
|
+
entityId: string,
|
|
182
|
+
eventId: string
|
|
183
|
+
): Promise<CalendarEvent | null> {
|
|
184
|
+
// Determine the collection path
|
|
185
|
+
const collectionPath = this.getEntityCalendarPath(entityType, entityId);
|
|
186
|
+
const eventRef = doc(this.db, collectionPath, eventId);
|
|
187
|
+
|
|
188
|
+
// Get the event
|
|
189
|
+
const eventDoc = await getDoc(eventRef);
|
|
190
|
+
if (!eventDoc.exists()) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return eventDoc.data() as CalendarEvent;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Gets blocking events for a specific entity
|
|
199
|
+
* @param entityType - Type of entity (practitioner or clinic)
|
|
200
|
+
* @param entityId - ID of the entity
|
|
201
|
+
* @param dateRange - Optional date range filter
|
|
202
|
+
* @param eventType - Optional event type filter
|
|
203
|
+
* @returns Array of calendar events
|
|
204
|
+
*/
|
|
205
|
+
async getEntityBlockingEvents(
|
|
206
|
+
entityType: "practitioner" | "clinic",
|
|
207
|
+
entityId: string,
|
|
208
|
+
dateRange?: DateRange,
|
|
209
|
+
eventType?: CalendarEventType
|
|
210
|
+
): Promise<CalendarEvent[]> {
|
|
211
|
+
// Use the existing search functionality
|
|
212
|
+
const searchParams: SearchCalendarEventsParams = {
|
|
213
|
+
searchLocation:
|
|
214
|
+
entityType === "practitioner"
|
|
215
|
+
? SearchLocationEnum.PRACTITIONER
|
|
216
|
+
: SearchLocationEnum.CLINIC,
|
|
217
|
+
entityId,
|
|
218
|
+
dateRange,
|
|
219
|
+
eventType,
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Filter to only blocking-type events if no specific eventType is provided
|
|
223
|
+
if (!eventType) {
|
|
224
|
+
// We'll need to filter the results to only include blocking-type events
|
|
225
|
+
const allEvents = await searchCalendarEventsUtil(this.db, searchParams);
|
|
226
|
+
return allEvents.filter(
|
|
227
|
+
(event) =>
|
|
228
|
+
event.eventType === CalendarEventType.BLOCKING ||
|
|
229
|
+
event.eventType === CalendarEventType.BREAK ||
|
|
230
|
+
event.eventType === CalendarEventType.FREE_DAY ||
|
|
231
|
+
event.eventType === CalendarEventType.OTHER
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return searchCalendarEventsUtil(this.db, searchParams);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// #endregion
|
|
239
|
+
|
|
240
|
+
// #region Calendar Event Search
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Searches for calendar events based on specified criteria.
|
|
244
|
+
* This method supports searching for ALL event types (appointments, blocking events, etc.)
|
|
245
|
+
*
|
|
246
|
+
* @param params - The search parameters
|
|
247
|
+
* @returns A promise that resolves to an array of matching calendar events
|
|
248
|
+
*/
|
|
249
|
+
async searchCalendarEvents(
|
|
250
|
+
params: SearchCalendarEventsParams
|
|
251
|
+
): Promise<CalendarEvent[]> {
|
|
252
|
+
// Use the utility function to perform the search
|
|
253
|
+
return searchCalendarEventsUtil(this.db, params);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// #endregion
|
|
257
|
+
|
|
258
|
+
// #region Private Helper Methods
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Gets the calendar collection path for a specific entity
|
|
262
|
+
* @param entityType - Type of entity (practitioner or clinic)
|
|
263
|
+
* @param entityId - ID of the entity
|
|
264
|
+
* @returns Collection path string
|
|
265
|
+
*/
|
|
266
|
+
private getEntityCalendarPath(
|
|
267
|
+
entityType: "practitioner" | "clinic",
|
|
268
|
+
entityId: string
|
|
269
|
+
): string {
|
|
270
|
+
if (entityType === "practitioner") {
|
|
271
|
+
return `${PRACTITIONERS_COLLECTION}/${entityId}/${CALENDAR_COLLECTION}`;
|
|
272
|
+
} else {
|
|
273
|
+
return `${CLINICS_COLLECTION}/${entityId}/${CALENDAR_COLLECTION}`;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Validates blocking event creation parameters
|
|
279
|
+
* @param params - Parameters to validate
|
|
280
|
+
* @throws Error if validation fails
|
|
281
|
+
*/
|
|
282
|
+
private validateBlockingEventParams(params: CreateBlockingEventParams): void {
|
|
283
|
+
if (!params.entityType || !params.entityId) {
|
|
284
|
+
throw new Error("Entity type and ID are required");
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (!params.eventName || params.eventName.trim() === "") {
|
|
288
|
+
throw new Error("Event name is required");
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (!params.eventTime || !params.eventTime.start || !params.eventTime.end) {
|
|
292
|
+
throw new Error("Event time with start and end is required");
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Validate that end time is after start time
|
|
296
|
+
if (params.eventTime.end.toMillis() <= params.eventTime.start.toMillis()) {
|
|
297
|
+
throw new Error("Event end time must be after start time");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Validate event type is one of the blocking types
|
|
301
|
+
const validTypes = [
|
|
302
|
+
CalendarEventType.BLOCKING,
|
|
303
|
+
CalendarEventType.BREAK,
|
|
304
|
+
CalendarEventType.FREE_DAY,
|
|
305
|
+
CalendarEventType.OTHER,
|
|
306
|
+
];
|
|
307
|
+
if (!validTypes.includes(params.eventType)) {
|
|
308
|
+
throw new Error("Invalid event type for blocking events");
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// #endregion
|
|
313
|
+
}
|