@blackcode_sa/metaestetics-api 1.13.3 → 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 +18 -30
- package/dist/index.d.ts +18 -30
- package/dist/index.js +11 -3
- package/dist/index.mjs +11 -3
- 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 -2191
- 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,743 +1,743 @@
|
|
|
1
|
-
import { Auth } from "firebase/auth";
|
|
2
|
-
import { Firestore, Timestamp } from "firebase/firestore";
|
|
3
|
-
import { FirebaseApp } from "firebase/app";
|
|
4
|
-
import { BaseService } from "../base.service";
|
|
5
|
-
import {
|
|
6
|
-
SyncedCalendar,
|
|
7
|
-
SyncedCalendarProvider,
|
|
8
|
-
CreateSyncedCalendarData,
|
|
9
|
-
UpdateSyncedCalendarData,
|
|
10
|
-
SYNCED_CALENDARS_COLLECTION,
|
|
11
|
-
} from "../../types/calendar/synced-calendar.types";
|
|
12
|
-
import {
|
|
13
|
-
CalendarEvent,
|
|
14
|
-
CalendarEventStatus,
|
|
15
|
-
CalendarSyncStatus,
|
|
16
|
-
} from "../../types/calendar";
|
|
17
|
-
|
|
18
|
-
// Import utility functions
|
|
19
|
-
import {
|
|
20
|
-
createPractitionerSyncedCalendarUtil,
|
|
21
|
-
createPatientSyncedCalendarUtil,
|
|
22
|
-
createClinicSyncedCalendarUtil,
|
|
23
|
-
getPractitionerSyncedCalendarUtil,
|
|
24
|
-
getPractitionerSyncedCalendarsUtil,
|
|
25
|
-
getPatientSyncedCalendarUtil,
|
|
26
|
-
getPatientSyncedCalendarsUtil,
|
|
27
|
-
getClinicSyncedCalendarUtil,
|
|
28
|
-
getClinicSyncedCalendarsUtil,
|
|
29
|
-
updatePractitionerSyncedCalendarUtil,
|
|
30
|
-
updatePatientSyncedCalendarUtil,
|
|
31
|
-
updateClinicSyncedCalendarUtil,
|
|
32
|
-
deletePractitionerSyncedCalendarUtil,
|
|
33
|
-
deletePatientSyncedCalendarUtil,
|
|
34
|
-
deleteClinicSyncedCalendarUtil,
|
|
35
|
-
updateLastSyncedTimestampUtil,
|
|
36
|
-
} from "./utils/synced-calendar.utils";
|
|
37
|
-
|
|
38
|
-
// Import Google Calendar utilities
|
|
39
|
-
import {
|
|
40
|
-
authenticateWithGoogleCalendarUtil,
|
|
41
|
-
refreshGoogleCalendarTokenUtil,
|
|
42
|
-
listGoogleCalendarsUtil,
|
|
43
|
-
syncEventsToGoogleCalendarUtil,
|
|
44
|
-
fetchEventsFromGoogleCalendarUtil,
|
|
45
|
-
convertGoogleEventToCalendarEventUtil,
|
|
46
|
-
deleteGoogleCalendarEventUtil,
|
|
47
|
-
getGoogleCalendarOAuthUrlUtil,
|
|
48
|
-
GOOGLE_CALENDAR_API_URL,
|
|
49
|
-
makeRequest,
|
|
50
|
-
} from "./utils/google-calendar.utils";
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Service for managing synced calendars and calendar synchronization
|
|
54
|
-
*/
|
|
55
|
-
export class SyncedCalendarsService extends BaseService {
|
|
56
|
-
/**
|
|
57
|
-
* Creates a new SyncedCalendarsService instance
|
|
58
|
-
* @param db - Firestore instance
|
|
59
|
-
* @param auth - Firebase Auth instance
|
|
60
|
-
* @param app - Firebase App instance
|
|
61
|
-
*/
|
|
62
|
-
constructor(db: Firestore, auth: Auth, app: FirebaseApp) {
|
|
63
|
-
super(db, auth, app);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// ===== Practitioner Synced Calendars =====
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Creates a synced calendar for a practitioner
|
|
70
|
-
* @param practitionerId - ID of the practitioner
|
|
71
|
-
* @param calendarData - Synced calendar data
|
|
72
|
-
* @returns Created synced calendar
|
|
73
|
-
*/
|
|
74
|
-
async createPractitionerSyncedCalendar(
|
|
75
|
-
practitionerId: string,
|
|
76
|
-
calendarData: Omit<
|
|
77
|
-
CreateSyncedCalendarData,
|
|
78
|
-
"id" | "createdAt" | "updatedAt"
|
|
79
|
-
>
|
|
80
|
-
): Promise<SyncedCalendar> {
|
|
81
|
-
return createPractitionerSyncedCalendarUtil(
|
|
82
|
-
this.db,
|
|
83
|
-
practitionerId,
|
|
84
|
-
calendarData,
|
|
85
|
-
this.generateId.bind(this)
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Gets a synced calendar for a practitioner
|
|
91
|
-
* @param practitionerId - ID of the practitioner
|
|
92
|
-
* @param calendarId - ID of the synced calendar
|
|
93
|
-
* @returns Synced calendar or null if not found
|
|
94
|
-
*/
|
|
95
|
-
async getPractitionerSyncedCalendar(
|
|
96
|
-
practitionerId: string,
|
|
97
|
-
calendarId: string
|
|
98
|
-
): Promise<SyncedCalendar | null> {
|
|
99
|
-
return getPractitionerSyncedCalendarUtil(
|
|
100
|
-
this.db,
|
|
101
|
-
practitionerId,
|
|
102
|
-
calendarId
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Gets all synced calendars for a practitioner
|
|
108
|
-
* @param practitionerId - ID of the practitioner
|
|
109
|
-
* @returns Array of synced calendars
|
|
110
|
-
*/
|
|
111
|
-
async getPractitionerSyncedCalendars(
|
|
112
|
-
practitionerId: string
|
|
113
|
-
): Promise<SyncedCalendar[]> {
|
|
114
|
-
return getPractitionerSyncedCalendarsUtil(this.db, practitionerId);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Updates a synced calendar for a practitioner
|
|
119
|
-
* @param practitionerId - ID of the practitioner
|
|
120
|
-
* @param calendarId - ID of the synced calendar
|
|
121
|
-
* @param updateData - Data to update
|
|
122
|
-
* @returns Updated synced calendar
|
|
123
|
-
*/
|
|
124
|
-
async updatePractitionerSyncedCalendar(
|
|
125
|
-
practitionerId: string,
|
|
126
|
-
calendarId: string,
|
|
127
|
-
updateData: Omit<UpdateSyncedCalendarData, "updatedAt">
|
|
128
|
-
): Promise<SyncedCalendar> {
|
|
129
|
-
return updatePractitionerSyncedCalendarUtil(
|
|
130
|
-
this.db,
|
|
131
|
-
practitionerId,
|
|
132
|
-
calendarId,
|
|
133
|
-
updateData
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Deletes a synced calendar for a practitioner
|
|
139
|
-
* @param practitionerId - ID of the practitioner
|
|
140
|
-
* @param calendarId - ID of the synced calendar
|
|
141
|
-
*/
|
|
142
|
-
async deletePractitionerSyncedCalendar(
|
|
143
|
-
practitionerId: string,
|
|
144
|
-
calendarId: string
|
|
145
|
-
): Promise<void> {
|
|
146
|
-
return deletePractitionerSyncedCalendarUtil(
|
|
147
|
-
this.db,
|
|
148
|
-
practitionerId,
|
|
149
|
-
calendarId
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// ===== Patient Synced Calendars =====
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Creates a synced calendar for a patient
|
|
157
|
-
* @param patientId - ID of the patient
|
|
158
|
-
* @param calendarData - Synced calendar data
|
|
159
|
-
* @returns Created synced calendar
|
|
160
|
-
*/
|
|
161
|
-
async createPatientSyncedCalendar(
|
|
162
|
-
patientId: string,
|
|
163
|
-
calendarData: Omit<
|
|
164
|
-
CreateSyncedCalendarData,
|
|
165
|
-
"id" | "createdAt" | "updatedAt"
|
|
166
|
-
>
|
|
167
|
-
): Promise<SyncedCalendar> {
|
|
168
|
-
return createPatientSyncedCalendarUtil(
|
|
169
|
-
this.db,
|
|
170
|
-
patientId,
|
|
171
|
-
calendarData,
|
|
172
|
-
this.generateId.bind(this)
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Gets a synced calendar for a patient
|
|
178
|
-
* @param patientId - ID of the patient
|
|
179
|
-
* @param calendarId - ID of the synced calendar
|
|
180
|
-
* @returns Synced calendar or null if not found
|
|
181
|
-
*/
|
|
182
|
-
async getPatientSyncedCalendar(
|
|
183
|
-
patientId: string,
|
|
184
|
-
calendarId: string
|
|
185
|
-
): Promise<SyncedCalendar | null> {
|
|
186
|
-
return getPatientSyncedCalendarUtil(this.db, patientId, calendarId);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Gets all synced calendars for a patient
|
|
191
|
-
* @param patientId - ID of the patient
|
|
192
|
-
* @returns Array of synced calendars
|
|
193
|
-
*/
|
|
194
|
-
async getPatientSyncedCalendars(
|
|
195
|
-
patientId: string
|
|
196
|
-
): Promise<SyncedCalendar[]> {
|
|
197
|
-
return getPatientSyncedCalendarsUtil(this.db, patientId);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Updates a synced calendar for a patient
|
|
202
|
-
* @param patientId - ID of the patient
|
|
203
|
-
* @param calendarId - ID of the synced calendar
|
|
204
|
-
* @param updateData - Data to update
|
|
205
|
-
* @returns Updated synced calendar
|
|
206
|
-
*/
|
|
207
|
-
async updatePatientSyncedCalendar(
|
|
208
|
-
patientId: string,
|
|
209
|
-
calendarId: string,
|
|
210
|
-
updateData: Omit<UpdateSyncedCalendarData, "updatedAt">
|
|
211
|
-
): Promise<SyncedCalendar> {
|
|
212
|
-
return updatePatientSyncedCalendarUtil(
|
|
213
|
-
this.db,
|
|
214
|
-
patientId,
|
|
215
|
-
calendarId,
|
|
216
|
-
updateData
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Deletes a synced calendar for a patient
|
|
222
|
-
* @param patientId - ID of the patient
|
|
223
|
-
* @param calendarId - ID of the synced calendar
|
|
224
|
-
*/
|
|
225
|
-
async deletePatientSyncedCalendar(
|
|
226
|
-
patientId: string,
|
|
227
|
-
calendarId: string
|
|
228
|
-
): Promise<void> {
|
|
229
|
-
return deletePatientSyncedCalendarUtil(this.db, patientId, calendarId);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// ===== Clinic Synced Calendars =====
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Creates a synced calendar for a clinic
|
|
236
|
-
* @param clinicId - ID of the clinic
|
|
237
|
-
* @param calendarData - Synced calendar data
|
|
238
|
-
* @returns Created synced calendar
|
|
239
|
-
*/
|
|
240
|
-
async createClinicSyncedCalendar(
|
|
241
|
-
clinicId: string,
|
|
242
|
-
calendarData: Omit<
|
|
243
|
-
CreateSyncedCalendarData,
|
|
244
|
-
"id" | "createdAt" | "updatedAt"
|
|
245
|
-
>
|
|
246
|
-
): Promise<SyncedCalendar> {
|
|
247
|
-
return createClinicSyncedCalendarUtil(
|
|
248
|
-
this.db,
|
|
249
|
-
clinicId,
|
|
250
|
-
calendarData,
|
|
251
|
-
this.generateId.bind(this)
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Gets a synced calendar for a clinic
|
|
257
|
-
* @param clinicId - ID of the clinic
|
|
258
|
-
* @param calendarId - ID of the synced calendar
|
|
259
|
-
* @returns Synced calendar or null if not found
|
|
260
|
-
*/
|
|
261
|
-
async getClinicSyncedCalendar(
|
|
262
|
-
clinicId: string,
|
|
263
|
-
calendarId: string
|
|
264
|
-
): Promise<SyncedCalendar | null> {
|
|
265
|
-
return getClinicSyncedCalendarUtil(this.db, clinicId, calendarId);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Gets all synced calendars for a clinic
|
|
270
|
-
* @param clinicId - ID of the clinic
|
|
271
|
-
* @returns Array of synced calendars
|
|
272
|
-
*/
|
|
273
|
-
async getClinicSyncedCalendars(clinicId: string): Promise<SyncedCalendar[]> {
|
|
274
|
-
return getClinicSyncedCalendarsUtil(this.db, clinicId);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Updates a synced calendar for a clinic
|
|
279
|
-
* @param clinicId - ID of the clinic
|
|
280
|
-
* @param calendarId - ID of the synced calendar
|
|
281
|
-
* @param updateData - Data to update
|
|
282
|
-
* @returns Updated synced calendar
|
|
283
|
-
*/
|
|
284
|
-
async updateClinicSyncedCalendar(
|
|
285
|
-
clinicId: string,
|
|
286
|
-
calendarId: string,
|
|
287
|
-
updateData: Omit<UpdateSyncedCalendarData, "updatedAt">
|
|
288
|
-
): Promise<SyncedCalendar> {
|
|
289
|
-
return updateClinicSyncedCalendarUtil(
|
|
290
|
-
this.db,
|
|
291
|
-
clinicId,
|
|
292
|
-
calendarId,
|
|
293
|
-
updateData
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Deletes a synced calendar for a clinic
|
|
299
|
-
* @param clinicId - ID of the clinic
|
|
300
|
-
* @param calendarId - ID of the synced calendar
|
|
301
|
-
*/
|
|
302
|
-
async deleteClinicSyncedCalendar(
|
|
303
|
-
clinicId: string,
|
|
304
|
-
calendarId: string
|
|
305
|
-
): Promise<void> {
|
|
306
|
-
return deleteClinicSyncedCalendarUtil(this.db, clinicId, calendarId);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// ===== Google Calendar Integration =====
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Gets the OAuth URL for Google Calendar
|
|
313
|
-
* @param scopes - OAuth scopes to request
|
|
314
|
-
* @returns OAuth URL
|
|
315
|
-
*/
|
|
316
|
-
getGoogleCalendarOAuthUrl(
|
|
317
|
-
scopes: string[] = ["https://www.googleapis.com/auth/calendar"]
|
|
318
|
-
): string {
|
|
319
|
-
return getGoogleCalendarOAuthUrlUtil(scopes);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Authenticates with Google Calendar using an authorization code
|
|
324
|
-
* @param authCode - Authorization code from Google OAuth
|
|
325
|
-
* @returns Access token, refresh token, and expiration time
|
|
326
|
-
*/
|
|
327
|
-
async authenticateWithGoogleCalendar(
|
|
328
|
-
authCode: string
|
|
329
|
-
): Promise<{ accessToken: string; refreshToken: string; expiresIn: number }> {
|
|
330
|
-
return authenticateWithGoogleCalendarUtil(authCode);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Lists available Google Calendars for a user
|
|
335
|
-
* @param accessToken - Google API access token
|
|
336
|
-
* @returns List of available calendars
|
|
337
|
-
*/
|
|
338
|
-
async listGoogleCalendars(
|
|
339
|
-
accessToken: string
|
|
340
|
-
): Promise<Array<{ id: string; name: string }>> {
|
|
341
|
-
return listGoogleCalendarsUtil(accessToken);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Syncs events from our system to Google Calendar for a practitioner
|
|
346
|
-
* @param practitionerId - ID of the practitioner
|
|
347
|
-
* @param calendarId - ID of the synced calendar
|
|
348
|
-
* @param events - Events to sync
|
|
349
|
-
* @param existingSyncId - Optional existing sync ID for updating an event
|
|
350
|
-
* @returns Result of the sync operation
|
|
351
|
-
*/
|
|
352
|
-
async syncPractitionerEventsToGoogleCalendar(
|
|
353
|
-
practitionerId: string,
|
|
354
|
-
calendarId: string,
|
|
355
|
-
events: CalendarEvent[],
|
|
356
|
-
existingSyncId?: string
|
|
357
|
-
): Promise<{
|
|
358
|
-
success: boolean;
|
|
359
|
-
syncedEvents: number;
|
|
360
|
-
errors: any[];
|
|
361
|
-
eventIds: string[];
|
|
362
|
-
}> {
|
|
363
|
-
const syncedCalendar = await this.getPractitionerSyncedCalendar(
|
|
364
|
-
practitionerId,
|
|
365
|
-
calendarId
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
if (!syncedCalendar) {
|
|
369
|
-
throw new Error("Synced calendar not found");
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
return syncEventsToGoogleCalendarUtil(
|
|
373
|
-
this.db,
|
|
374
|
-
"practitioner",
|
|
375
|
-
practitionerId,
|
|
376
|
-
syncedCalendar,
|
|
377
|
-
events,
|
|
378
|
-
existingSyncId
|
|
379
|
-
);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Syncs events from our system to Google Calendar for a patient
|
|
384
|
-
* @param patientId - ID of the patient
|
|
385
|
-
* @param calendarId - ID of the synced calendar
|
|
386
|
-
* @param events - Events to sync
|
|
387
|
-
* @param existingSyncId - Optional existing sync ID for updating an event
|
|
388
|
-
* @returns Result of the sync operation
|
|
389
|
-
*/
|
|
390
|
-
async syncPatientEventsToGoogleCalendar(
|
|
391
|
-
patientId: string,
|
|
392
|
-
calendarId: string,
|
|
393
|
-
events: CalendarEvent[],
|
|
394
|
-
existingSyncId?: string
|
|
395
|
-
): Promise<{
|
|
396
|
-
success: boolean;
|
|
397
|
-
syncedEvents: number;
|
|
398
|
-
errors: any[];
|
|
399
|
-
eventIds: string[];
|
|
400
|
-
}> {
|
|
401
|
-
const syncedCalendar = await this.getPatientSyncedCalendar(
|
|
402
|
-
patientId,
|
|
403
|
-
calendarId
|
|
404
|
-
);
|
|
405
|
-
|
|
406
|
-
if (!syncedCalendar) {
|
|
407
|
-
throw new Error("Synced calendar not found");
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
return syncEventsToGoogleCalendarUtil(
|
|
411
|
-
this.db,
|
|
412
|
-
"patient",
|
|
413
|
-
patientId,
|
|
414
|
-
syncedCalendar,
|
|
415
|
-
events,
|
|
416
|
-
existingSyncId
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Syncs events from our system to Google Calendar for a clinic
|
|
422
|
-
* @param clinicId - ID of the clinic
|
|
423
|
-
* @param calendarId - ID of the synced calendar
|
|
424
|
-
* @param events - Events to sync
|
|
425
|
-
* @returns Result of the sync operation
|
|
426
|
-
*/
|
|
427
|
-
async syncClinicEventsToGoogleCalendar(
|
|
428
|
-
clinicId: string,
|
|
429
|
-
calendarId: string,
|
|
430
|
-
events: CalendarEvent[]
|
|
431
|
-
): Promise<{ success: boolean; syncedEvents: number; errors: any[] }> {
|
|
432
|
-
const syncedCalendar = await this.getClinicSyncedCalendar(
|
|
433
|
-
clinicId,
|
|
434
|
-
calendarId
|
|
435
|
-
);
|
|
436
|
-
|
|
437
|
-
if (!syncedCalendar) {
|
|
438
|
-
throw new Error("Synced calendar not found");
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
return syncEventsToGoogleCalendarUtil(
|
|
442
|
-
this.db,
|
|
443
|
-
"clinic",
|
|
444
|
-
clinicId,
|
|
445
|
-
syncedCalendar,
|
|
446
|
-
events
|
|
447
|
-
);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Fetches events from Google Calendar for a practitioner
|
|
452
|
-
* @param practitionerId - ID of the practitioner
|
|
453
|
-
* @param calendarId - ID of the synced calendar
|
|
454
|
-
* @param startDate - Start date for fetching events
|
|
455
|
-
* @param endDate - End date for fetching events
|
|
456
|
-
* @returns Events fetched from Google Calendar
|
|
457
|
-
*/
|
|
458
|
-
async fetchEventsFromPractitionerGoogleCalendar(
|
|
459
|
-
practitionerId: string,
|
|
460
|
-
calendarId: string,
|
|
461
|
-
startDate: Date,
|
|
462
|
-
endDate: Date
|
|
463
|
-
): Promise<any[]> {
|
|
464
|
-
const syncedCalendar = await this.getPractitionerSyncedCalendar(
|
|
465
|
-
practitionerId,
|
|
466
|
-
calendarId
|
|
467
|
-
);
|
|
468
|
-
|
|
469
|
-
if (!syncedCalendar) {
|
|
470
|
-
throw new Error("Synced calendar not found");
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
return fetchEventsFromGoogleCalendarUtil(
|
|
474
|
-
this.db,
|
|
475
|
-
"practitioner",
|
|
476
|
-
practitionerId,
|
|
477
|
-
syncedCalendar,
|
|
478
|
-
startDate,
|
|
479
|
-
endDate
|
|
480
|
-
);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Fetches events from Google Calendar for a patient
|
|
485
|
-
* @param patientId - ID of the patient
|
|
486
|
-
* @param calendarId - ID of the synced calendar
|
|
487
|
-
* @param startDate - Start date for fetching events
|
|
488
|
-
* @param endDate - End date for fetching events
|
|
489
|
-
* @returns Events fetched from Google Calendar
|
|
490
|
-
*/
|
|
491
|
-
async fetchEventsFromPatientGoogleCalendar(
|
|
492
|
-
patientId: string,
|
|
493
|
-
calendarId: string,
|
|
494
|
-
startDate: Date,
|
|
495
|
-
endDate: Date
|
|
496
|
-
): Promise<any[]> {
|
|
497
|
-
const syncedCalendar = await this.getPatientSyncedCalendar(
|
|
498
|
-
patientId,
|
|
499
|
-
calendarId
|
|
500
|
-
);
|
|
501
|
-
|
|
502
|
-
if (!syncedCalendar) {
|
|
503
|
-
throw new Error("Synced calendar not found");
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
return fetchEventsFromGoogleCalendarUtil(
|
|
507
|
-
this.db,
|
|
508
|
-
"patient",
|
|
509
|
-
patientId,
|
|
510
|
-
syncedCalendar,
|
|
511
|
-
startDate,
|
|
512
|
-
endDate
|
|
513
|
-
);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* Fetches events from Google Calendar for a clinic
|
|
518
|
-
* @param clinicId - ID of the clinic
|
|
519
|
-
* @param calendarId - ID of the synced calendar
|
|
520
|
-
* @param startDate - Start date for fetching events
|
|
521
|
-
* @param endDate - End date for fetching events
|
|
522
|
-
* @returns Events fetched from Google Calendar
|
|
523
|
-
*/
|
|
524
|
-
async fetchEventsFromClinicGoogleCalendar(
|
|
525
|
-
clinicId: string,
|
|
526
|
-
calendarId: string,
|
|
527
|
-
startDate: Date,
|
|
528
|
-
endDate: Date
|
|
529
|
-
): Promise<any[]> {
|
|
530
|
-
const syncedCalendar = await this.getClinicSyncedCalendar(
|
|
531
|
-
clinicId,
|
|
532
|
-
calendarId
|
|
533
|
-
);
|
|
534
|
-
|
|
535
|
-
if (!syncedCalendar) {
|
|
536
|
-
throw new Error("Synced calendar not found");
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
return fetchEventsFromGoogleCalendarUtil(
|
|
540
|
-
this.db,
|
|
541
|
-
"clinic",
|
|
542
|
-
clinicId,
|
|
543
|
-
syncedCalendar,
|
|
544
|
-
startDate,
|
|
545
|
-
endDate
|
|
546
|
-
);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* Deletes an event from Google Calendar for a practitioner
|
|
551
|
-
* @param practitionerId - ID of the practitioner
|
|
552
|
-
* @param calendarId - ID of the synced calendar
|
|
553
|
-
* @param eventId - ID of the event in Google Calendar
|
|
554
|
-
* @returns Success status
|
|
555
|
-
*/
|
|
556
|
-
async deletePractitionerGoogleCalendarEvent(
|
|
557
|
-
practitionerId: string,
|
|
558
|
-
calendarId: string,
|
|
559
|
-
eventId: string
|
|
560
|
-
): Promise<boolean> {
|
|
561
|
-
const syncedCalendar = await this.getPractitionerSyncedCalendar(
|
|
562
|
-
practitionerId,
|
|
563
|
-
calendarId
|
|
564
|
-
);
|
|
565
|
-
|
|
566
|
-
if (!syncedCalendar) {
|
|
567
|
-
throw new Error("Synced calendar not found");
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
return deleteGoogleCalendarEventUtil(
|
|
571
|
-
this.db,
|
|
572
|
-
"practitioner",
|
|
573
|
-
practitionerId,
|
|
574
|
-
syncedCalendar,
|
|
575
|
-
eventId
|
|
576
|
-
);
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
/**
|
|
580
|
-
* Deletes an event from Google Calendar for a patient
|
|
581
|
-
* @param patientId - ID of the patient
|
|
582
|
-
* @param calendarId - ID of the synced calendar
|
|
583
|
-
* @param eventId - ID of the event in Google Calendar
|
|
584
|
-
* @returns Success status
|
|
585
|
-
*/
|
|
586
|
-
async deletePatientGoogleCalendarEvent(
|
|
587
|
-
patientId: string,
|
|
588
|
-
calendarId: string,
|
|
589
|
-
eventId: string
|
|
590
|
-
): Promise<boolean> {
|
|
591
|
-
const syncedCalendar = await this.getPatientSyncedCalendar(
|
|
592
|
-
patientId,
|
|
593
|
-
calendarId
|
|
594
|
-
);
|
|
595
|
-
|
|
596
|
-
if (!syncedCalendar) {
|
|
597
|
-
throw new Error("Synced calendar not found");
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
return deleteGoogleCalendarEventUtil(
|
|
601
|
-
this.db,
|
|
602
|
-
"patient",
|
|
603
|
-
patientId,
|
|
604
|
-
syncedCalendar,
|
|
605
|
-
eventId
|
|
606
|
-
);
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* Deletes an event from Google Calendar for a clinic
|
|
611
|
-
* @param clinicId - ID of the clinic
|
|
612
|
-
* @param calendarId - ID of the synced calendar
|
|
613
|
-
* @param eventId - ID of the event in Google Calendar
|
|
614
|
-
* @returns Success status
|
|
615
|
-
*/
|
|
616
|
-
async deleteClinicGoogleCalendarEvent(
|
|
617
|
-
clinicId: string,
|
|
618
|
-
calendarId: string,
|
|
619
|
-
eventId: string
|
|
620
|
-
): Promise<boolean> {
|
|
621
|
-
const syncedCalendar = await this.getClinicSyncedCalendar(
|
|
622
|
-
clinicId,
|
|
623
|
-
calendarId
|
|
624
|
-
);
|
|
625
|
-
|
|
626
|
-
if (!syncedCalendar) {
|
|
627
|
-
throw new Error("Synced calendar not found");
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
return deleteGoogleCalendarEventUtil(
|
|
631
|
-
this.db,
|
|
632
|
-
"clinic",
|
|
633
|
-
clinicId,
|
|
634
|
-
syncedCalendar,
|
|
635
|
-
eventId
|
|
636
|
-
);
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
/**
|
|
640
|
-
* Converts Google Calendar events to our system's format for a practitioner
|
|
641
|
-
* @param practitionerId - ID of the practitioner
|
|
642
|
-
* @param googleEvents - Google Calendar events
|
|
643
|
-
* @returns Converted calendar events
|
|
644
|
-
*/
|
|
645
|
-
convertGoogleEventsToPractitionerEvents(
|
|
646
|
-
practitionerId: string,
|
|
647
|
-
googleEvents: any[]
|
|
648
|
-
): Partial<CalendarEvent>[] {
|
|
649
|
-
return googleEvents.map((event) =>
|
|
650
|
-
convertGoogleEventToCalendarEventUtil(
|
|
651
|
-
event,
|
|
652
|
-
practitionerId,
|
|
653
|
-
"practitioner"
|
|
654
|
-
)
|
|
655
|
-
);
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
/**
|
|
659
|
-
* Converts Google Calendar events to our system's format for a patient
|
|
660
|
-
* @param patientId - ID of the patient
|
|
661
|
-
* @param googleEvents - Google Calendar events
|
|
662
|
-
* @returns Converted calendar events
|
|
663
|
-
*/
|
|
664
|
-
convertGoogleEventsToPatientEvents(
|
|
665
|
-
patientId: string,
|
|
666
|
-
googleEvents: any[]
|
|
667
|
-
): Partial<CalendarEvent>[] {
|
|
668
|
-
return googleEvents.map((event) =>
|
|
669
|
-
convertGoogleEventToCalendarEventUtil(event, patientId, "patient")
|
|
670
|
-
);
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
/**
|
|
674
|
-
* Converts Google Calendar events to our system's format for a clinic
|
|
675
|
-
* @param clinicId - ID of the clinic
|
|
676
|
-
* @param googleEvents - Google Calendar events
|
|
677
|
-
* @returns Converted calendar events
|
|
678
|
-
*/
|
|
679
|
-
convertGoogleEventsToClinicEvents(
|
|
680
|
-
clinicId: string,
|
|
681
|
-
googleEvents: any[]
|
|
682
|
-
): Partial<CalendarEvent>[] {
|
|
683
|
-
return googleEvents.map((event) =>
|
|
684
|
-
convertGoogleEventToCalendarEventUtil(event, clinicId, "clinic")
|
|
685
|
-
);
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
/**
|
|
689
|
-
* Fetches a single event from Google Calendar for a practitioner
|
|
690
|
-
* @param practitionerId - ID of the practitioner
|
|
691
|
-
* @param calendarId - ID of the synced calendar
|
|
692
|
-
* @param eventId - ID of the event in Google Calendar
|
|
693
|
-
* @returns The event data or null if not found
|
|
694
|
-
*/
|
|
695
|
-
async fetchEventFromPractitionerGoogleCalendar(
|
|
696
|
-
practitionerId: string,
|
|
697
|
-
calendarId: string,
|
|
698
|
-
eventId: string
|
|
699
|
-
): Promise<any | null> {
|
|
700
|
-
const syncedCalendar = await this.getPractitionerSyncedCalendar(
|
|
701
|
-
practitionerId,
|
|
702
|
-
calendarId
|
|
703
|
-
);
|
|
704
|
-
|
|
705
|
-
if (!syncedCalendar) {
|
|
706
|
-
throw new Error("Synced calendar not found");
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
try {
|
|
710
|
-
// Refresh token if needed
|
|
711
|
-
const { accessToken } = await refreshGoogleCalendarTokenUtil(
|
|
712
|
-
syncedCalendar.refreshToken
|
|
713
|
-
);
|
|
714
|
-
|
|
715
|
-
// Call Google Calendar API to fetch the single event
|
|
716
|
-
const response = await makeRequest(
|
|
717
|
-
"get",
|
|
718
|
-
`${GOOGLE_CALENDAR_API_URL}/calendars/${syncedCalendar.calendarId}/events/${eventId}`,
|
|
719
|
-
{ Authorization: `Bearer ${accessToken}` }
|
|
720
|
-
);
|
|
721
|
-
|
|
722
|
-
// Update the last synced timestamp
|
|
723
|
-
await updateLastSyncedTimestampUtil(
|
|
724
|
-
this.db,
|
|
725
|
-
"practitioner",
|
|
726
|
-
practitionerId,
|
|
727
|
-
syncedCalendar.id
|
|
728
|
-
);
|
|
729
|
-
|
|
730
|
-
return response;
|
|
731
|
-
} catch (error) {
|
|
732
|
-
// If the event was not found (404), return null
|
|
733
|
-
if ((error as any).response?.status === 404) {
|
|
734
|
-
return null;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
console.error(
|
|
738
|
-
`Error fetching event from Google Calendar: ${(error as Error).message}`
|
|
739
|
-
);
|
|
740
|
-
throw error;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
}
|
|
1
|
+
import { Auth } from "firebase/auth";
|
|
2
|
+
import { Firestore, Timestamp } from "firebase/firestore";
|
|
3
|
+
import { FirebaseApp } from "firebase/app";
|
|
4
|
+
import { BaseService } from "../base.service";
|
|
5
|
+
import {
|
|
6
|
+
SyncedCalendar,
|
|
7
|
+
SyncedCalendarProvider,
|
|
8
|
+
CreateSyncedCalendarData,
|
|
9
|
+
UpdateSyncedCalendarData,
|
|
10
|
+
SYNCED_CALENDARS_COLLECTION,
|
|
11
|
+
} from "../../types/calendar/synced-calendar.types";
|
|
12
|
+
import {
|
|
13
|
+
CalendarEvent,
|
|
14
|
+
CalendarEventStatus,
|
|
15
|
+
CalendarSyncStatus,
|
|
16
|
+
} from "../../types/calendar";
|
|
17
|
+
|
|
18
|
+
// Import utility functions
|
|
19
|
+
import {
|
|
20
|
+
createPractitionerSyncedCalendarUtil,
|
|
21
|
+
createPatientSyncedCalendarUtil,
|
|
22
|
+
createClinicSyncedCalendarUtil,
|
|
23
|
+
getPractitionerSyncedCalendarUtil,
|
|
24
|
+
getPractitionerSyncedCalendarsUtil,
|
|
25
|
+
getPatientSyncedCalendarUtil,
|
|
26
|
+
getPatientSyncedCalendarsUtil,
|
|
27
|
+
getClinicSyncedCalendarUtil,
|
|
28
|
+
getClinicSyncedCalendarsUtil,
|
|
29
|
+
updatePractitionerSyncedCalendarUtil,
|
|
30
|
+
updatePatientSyncedCalendarUtil,
|
|
31
|
+
updateClinicSyncedCalendarUtil,
|
|
32
|
+
deletePractitionerSyncedCalendarUtil,
|
|
33
|
+
deletePatientSyncedCalendarUtil,
|
|
34
|
+
deleteClinicSyncedCalendarUtil,
|
|
35
|
+
updateLastSyncedTimestampUtil,
|
|
36
|
+
} from "./utils/synced-calendar.utils";
|
|
37
|
+
|
|
38
|
+
// Import Google Calendar utilities
|
|
39
|
+
import {
|
|
40
|
+
authenticateWithGoogleCalendarUtil,
|
|
41
|
+
refreshGoogleCalendarTokenUtil,
|
|
42
|
+
listGoogleCalendarsUtil,
|
|
43
|
+
syncEventsToGoogleCalendarUtil,
|
|
44
|
+
fetchEventsFromGoogleCalendarUtil,
|
|
45
|
+
convertGoogleEventToCalendarEventUtil,
|
|
46
|
+
deleteGoogleCalendarEventUtil,
|
|
47
|
+
getGoogleCalendarOAuthUrlUtil,
|
|
48
|
+
GOOGLE_CALENDAR_API_URL,
|
|
49
|
+
makeRequest,
|
|
50
|
+
} from "./utils/google-calendar.utils";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Service for managing synced calendars and calendar synchronization
|
|
54
|
+
*/
|
|
55
|
+
export class SyncedCalendarsService extends BaseService {
|
|
56
|
+
/**
|
|
57
|
+
* Creates a new SyncedCalendarsService instance
|
|
58
|
+
* @param db - Firestore instance
|
|
59
|
+
* @param auth - Firebase Auth instance
|
|
60
|
+
* @param app - Firebase App instance
|
|
61
|
+
*/
|
|
62
|
+
constructor(db: Firestore, auth: Auth, app: FirebaseApp) {
|
|
63
|
+
super(db, auth, app);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ===== Practitioner Synced Calendars =====
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Creates a synced calendar for a practitioner
|
|
70
|
+
* @param practitionerId - ID of the practitioner
|
|
71
|
+
* @param calendarData - Synced calendar data
|
|
72
|
+
* @returns Created synced calendar
|
|
73
|
+
*/
|
|
74
|
+
async createPractitionerSyncedCalendar(
|
|
75
|
+
practitionerId: string,
|
|
76
|
+
calendarData: Omit<
|
|
77
|
+
CreateSyncedCalendarData,
|
|
78
|
+
"id" | "createdAt" | "updatedAt"
|
|
79
|
+
>
|
|
80
|
+
): Promise<SyncedCalendar> {
|
|
81
|
+
return createPractitionerSyncedCalendarUtil(
|
|
82
|
+
this.db,
|
|
83
|
+
practitionerId,
|
|
84
|
+
calendarData,
|
|
85
|
+
this.generateId.bind(this)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Gets a synced calendar for a practitioner
|
|
91
|
+
* @param practitionerId - ID of the practitioner
|
|
92
|
+
* @param calendarId - ID of the synced calendar
|
|
93
|
+
* @returns Synced calendar or null if not found
|
|
94
|
+
*/
|
|
95
|
+
async getPractitionerSyncedCalendar(
|
|
96
|
+
practitionerId: string,
|
|
97
|
+
calendarId: string
|
|
98
|
+
): Promise<SyncedCalendar | null> {
|
|
99
|
+
return getPractitionerSyncedCalendarUtil(
|
|
100
|
+
this.db,
|
|
101
|
+
practitionerId,
|
|
102
|
+
calendarId
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Gets all synced calendars for a practitioner
|
|
108
|
+
* @param practitionerId - ID of the practitioner
|
|
109
|
+
* @returns Array of synced calendars
|
|
110
|
+
*/
|
|
111
|
+
async getPractitionerSyncedCalendars(
|
|
112
|
+
practitionerId: string
|
|
113
|
+
): Promise<SyncedCalendar[]> {
|
|
114
|
+
return getPractitionerSyncedCalendarsUtil(this.db, practitionerId);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Updates a synced calendar for a practitioner
|
|
119
|
+
* @param practitionerId - ID of the practitioner
|
|
120
|
+
* @param calendarId - ID of the synced calendar
|
|
121
|
+
* @param updateData - Data to update
|
|
122
|
+
* @returns Updated synced calendar
|
|
123
|
+
*/
|
|
124
|
+
async updatePractitionerSyncedCalendar(
|
|
125
|
+
practitionerId: string,
|
|
126
|
+
calendarId: string,
|
|
127
|
+
updateData: Omit<UpdateSyncedCalendarData, "updatedAt">
|
|
128
|
+
): Promise<SyncedCalendar> {
|
|
129
|
+
return updatePractitionerSyncedCalendarUtil(
|
|
130
|
+
this.db,
|
|
131
|
+
practitionerId,
|
|
132
|
+
calendarId,
|
|
133
|
+
updateData
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Deletes a synced calendar for a practitioner
|
|
139
|
+
* @param practitionerId - ID of the practitioner
|
|
140
|
+
* @param calendarId - ID of the synced calendar
|
|
141
|
+
*/
|
|
142
|
+
async deletePractitionerSyncedCalendar(
|
|
143
|
+
practitionerId: string,
|
|
144
|
+
calendarId: string
|
|
145
|
+
): Promise<void> {
|
|
146
|
+
return deletePractitionerSyncedCalendarUtil(
|
|
147
|
+
this.db,
|
|
148
|
+
practitionerId,
|
|
149
|
+
calendarId
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ===== Patient Synced Calendars =====
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Creates a synced calendar for a patient
|
|
157
|
+
* @param patientId - ID of the patient
|
|
158
|
+
* @param calendarData - Synced calendar data
|
|
159
|
+
* @returns Created synced calendar
|
|
160
|
+
*/
|
|
161
|
+
async createPatientSyncedCalendar(
|
|
162
|
+
patientId: string,
|
|
163
|
+
calendarData: Omit<
|
|
164
|
+
CreateSyncedCalendarData,
|
|
165
|
+
"id" | "createdAt" | "updatedAt"
|
|
166
|
+
>
|
|
167
|
+
): Promise<SyncedCalendar> {
|
|
168
|
+
return createPatientSyncedCalendarUtil(
|
|
169
|
+
this.db,
|
|
170
|
+
patientId,
|
|
171
|
+
calendarData,
|
|
172
|
+
this.generateId.bind(this)
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Gets a synced calendar for a patient
|
|
178
|
+
* @param patientId - ID of the patient
|
|
179
|
+
* @param calendarId - ID of the synced calendar
|
|
180
|
+
* @returns Synced calendar or null if not found
|
|
181
|
+
*/
|
|
182
|
+
async getPatientSyncedCalendar(
|
|
183
|
+
patientId: string,
|
|
184
|
+
calendarId: string
|
|
185
|
+
): Promise<SyncedCalendar | null> {
|
|
186
|
+
return getPatientSyncedCalendarUtil(this.db, patientId, calendarId);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Gets all synced calendars for a patient
|
|
191
|
+
* @param patientId - ID of the patient
|
|
192
|
+
* @returns Array of synced calendars
|
|
193
|
+
*/
|
|
194
|
+
async getPatientSyncedCalendars(
|
|
195
|
+
patientId: string
|
|
196
|
+
): Promise<SyncedCalendar[]> {
|
|
197
|
+
return getPatientSyncedCalendarsUtil(this.db, patientId);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Updates a synced calendar for a patient
|
|
202
|
+
* @param patientId - ID of the patient
|
|
203
|
+
* @param calendarId - ID of the synced calendar
|
|
204
|
+
* @param updateData - Data to update
|
|
205
|
+
* @returns Updated synced calendar
|
|
206
|
+
*/
|
|
207
|
+
async updatePatientSyncedCalendar(
|
|
208
|
+
patientId: string,
|
|
209
|
+
calendarId: string,
|
|
210
|
+
updateData: Omit<UpdateSyncedCalendarData, "updatedAt">
|
|
211
|
+
): Promise<SyncedCalendar> {
|
|
212
|
+
return updatePatientSyncedCalendarUtil(
|
|
213
|
+
this.db,
|
|
214
|
+
patientId,
|
|
215
|
+
calendarId,
|
|
216
|
+
updateData
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Deletes a synced calendar for a patient
|
|
222
|
+
* @param patientId - ID of the patient
|
|
223
|
+
* @param calendarId - ID of the synced calendar
|
|
224
|
+
*/
|
|
225
|
+
async deletePatientSyncedCalendar(
|
|
226
|
+
patientId: string,
|
|
227
|
+
calendarId: string
|
|
228
|
+
): Promise<void> {
|
|
229
|
+
return deletePatientSyncedCalendarUtil(this.db, patientId, calendarId);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ===== Clinic Synced Calendars =====
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Creates a synced calendar for a clinic
|
|
236
|
+
* @param clinicId - ID of the clinic
|
|
237
|
+
* @param calendarData - Synced calendar data
|
|
238
|
+
* @returns Created synced calendar
|
|
239
|
+
*/
|
|
240
|
+
async createClinicSyncedCalendar(
|
|
241
|
+
clinicId: string,
|
|
242
|
+
calendarData: Omit<
|
|
243
|
+
CreateSyncedCalendarData,
|
|
244
|
+
"id" | "createdAt" | "updatedAt"
|
|
245
|
+
>
|
|
246
|
+
): Promise<SyncedCalendar> {
|
|
247
|
+
return createClinicSyncedCalendarUtil(
|
|
248
|
+
this.db,
|
|
249
|
+
clinicId,
|
|
250
|
+
calendarData,
|
|
251
|
+
this.generateId.bind(this)
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Gets a synced calendar for a clinic
|
|
257
|
+
* @param clinicId - ID of the clinic
|
|
258
|
+
* @param calendarId - ID of the synced calendar
|
|
259
|
+
* @returns Synced calendar or null if not found
|
|
260
|
+
*/
|
|
261
|
+
async getClinicSyncedCalendar(
|
|
262
|
+
clinicId: string,
|
|
263
|
+
calendarId: string
|
|
264
|
+
): Promise<SyncedCalendar | null> {
|
|
265
|
+
return getClinicSyncedCalendarUtil(this.db, clinicId, calendarId);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Gets all synced calendars for a clinic
|
|
270
|
+
* @param clinicId - ID of the clinic
|
|
271
|
+
* @returns Array of synced calendars
|
|
272
|
+
*/
|
|
273
|
+
async getClinicSyncedCalendars(clinicId: string): Promise<SyncedCalendar[]> {
|
|
274
|
+
return getClinicSyncedCalendarsUtil(this.db, clinicId);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Updates a synced calendar for a clinic
|
|
279
|
+
* @param clinicId - ID of the clinic
|
|
280
|
+
* @param calendarId - ID of the synced calendar
|
|
281
|
+
* @param updateData - Data to update
|
|
282
|
+
* @returns Updated synced calendar
|
|
283
|
+
*/
|
|
284
|
+
async updateClinicSyncedCalendar(
|
|
285
|
+
clinicId: string,
|
|
286
|
+
calendarId: string,
|
|
287
|
+
updateData: Omit<UpdateSyncedCalendarData, "updatedAt">
|
|
288
|
+
): Promise<SyncedCalendar> {
|
|
289
|
+
return updateClinicSyncedCalendarUtil(
|
|
290
|
+
this.db,
|
|
291
|
+
clinicId,
|
|
292
|
+
calendarId,
|
|
293
|
+
updateData
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Deletes a synced calendar for a clinic
|
|
299
|
+
* @param clinicId - ID of the clinic
|
|
300
|
+
* @param calendarId - ID of the synced calendar
|
|
301
|
+
*/
|
|
302
|
+
async deleteClinicSyncedCalendar(
|
|
303
|
+
clinicId: string,
|
|
304
|
+
calendarId: string
|
|
305
|
+
): Promise<void> {
|
|
306
|
+
return deleteClinicSyncedCalendarUtil(this.db, clinicId, calendarId);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ===== Google Calendar Integration =====
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Gets the OAuth URL for Google Calendar
|
|
313
|
+
* @param scopes - OAuth scopes to request
|
|
314
|
+
* @returns OAuth URL
|
|
315
|
+
*/
|
|
316
|
+
getGoogleCalendarOAuthUrl(
|
|
317
|
+
scopes: string[] = ["https://www.googleapis.com/auth/calendar"]
|
|
318
|
+
): string {
|
|
319
|
+
return getGoogleCalendarOAuthUrlUtil(scopes);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Authenticates with Google Calendar using an authorization code
|
|
324
|
+
* @param authCode - Authorization code from Google OAuth
|
|
325
|
+
* @returns Access token, refresh token, and expiration time
|
|
326
|
+
*/
|
|
327
|
+
async authenticateWithGoogleCalendar(
|
|
328
|
+
authCode: string
|
|
329
|
+
): Promise<{ accessToken: string; refreshToken: string; expiresIn: number }> {
|
|
330
|
+
return authenticateWithGoogleCalendarUtil(authCode);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Lists available Google Calendars for a user
|
|
335
|
+
* @param accessToken - Google API access token
|
|
336
|
+
* @returns List of available calendars
|
|
337
|
+
*/
|
|
338
|
+
async listGoogleCalendars(
|
|
339
|
+
accessToken: string
|
|
340
|
+
): Promise<Array<{ id: string; name: string }>> {
|
|
341
|
+
return listGoogleCalendarsUtil(accessToken);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Syncs events from our system to Google Calendar for a practitioner
|
|
346
|
+
* @param practitionerId - ID of the practitioner
|
|
347
|
+
* @param calendarId - ID of the synced calendar
|
|
348
|
+
* @param events - Events to sync
|
|
349
|
+
* @param existingSyncId - Optional existing sync ID for updating an event
|
|
350
|
+
* @returns Result of the sync operation
|
|
351
|
+
*/
|
|
352
|
+
async syncPractitionerEventsToGoogleCalendar(
|
|
353
|
+
practitionerId: string,
|
|
354
|
+
calendarId: string,
|
|
355
|
+
events: CalendarEvent[],
|
|
356
|
+
existingSyncId?: string
|
|
357
|
+
): Promise<{
|
|
358
|
+
success: boolean;
|
|
359
|
+
syncedEvents: number;
|
|
360
|
+
errors: any[];
|
|
361
|
+
eventIds: string[];
|
|
362
|
+
}> {
|
|
363
|
+
const syncedCalendar = await this.getPractitionerSyncedCalendar(
|
|
364
|
+
practitionerId,
|
|
365
|
+
calendarId
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
if (!syncedCalendar) {
|
|
369
|
+
throw new Error("Synced calendar not found");
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return syncEventsToGoogleCalendarUtil(
|
|
373
|
+
this.db,
|
|
374
|
+
"practitioner",
|
|
375
|
+
practitionerId,
|
|
376
|
+
syncedCalendar,
|
|
377
|
+
events,
|
|
378
|
+
existingSyncId
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Syncs events from our system to Google Calendar for a patient
|
|
384
|
+
* @param patientId - ID of the patient
|
|
385
|
+
* @param calendarId - ID of the synced calendar
|
|
386
|
+
* @param events - Events to sync
|
|
387
|
+
* @param existingSyncId - Optional existing sync ID for updating an event
|
|
388
|
+
* @returns Result of the sync operation
|
|
389
|
+
*/
|
|
390
|
+
async syncPatientEventsToGoogleCalendar(
|
|
391
|
+
patientId: string,
|
|
392
|
+
calendarId: string,
|
|
393
|
+
events: CalendarEvent[],
|
|
394
|
+
existingSyncId?: string
|
|
395
|
+
): Promise<{
|
|
396
|
+
success: boolean;
|
|
397
|
+
syncedEvents: number;
|
|
398
|
+
errors: any[];
|
|
399
|
+
eventIds: string[];
|
|
400
|
+
}> {
|
|
401
|
+
const syncedCalendar = await this.getPatientSyncedCalendar(
|
|
402
|
+
patientId,
|
|
403
|
+
calendarId
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
if (!syncedCalendar) {
|
|
407
|
+
throw new Error("Synced calendar not found");
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return syncEventsToGoogleCalendarUtil(
|
|
411
|
+
this.db,
|
|
412
|
+
"patient",
|
|
413
|
+
patientId,
|
|
414
|
+
syncedCalendar,
|
|
415
|
+
events,
|
|
416
|
+
existingSyncId
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Syncs events from our system to Google Calendar for a clinic
|
|
422
|
+
* @param clinicId - ID of the clinic
|
|
423
|
+
* @param calendarId - ID of the synced calendar
|
|
424
|
+
* @param events - Events to sync
|
|
425
|
+
* @returns Result of the sync operation
|
|
426
|
+
*/
|
|
427
|
+
async syncClinicEventsToGoogleCalendar(
|
|
428
|
+
clinicId: string,
|
|
429
|
+
calendarId: string,
|
|
430
|
+
events: CalendarEvent[]
|
|
431
|
+
): Promise<{ success: boolean; syncedEvents: number; errors: any[] }> {
|
|
432
|
+
const syncedCalendar = await this.getClinicSyncedCalendar(
|
|
433
|
+
clinicId,
|
|
434
|
+
calendarId
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
if (!syncedCalendar) {
|
|
438
|
+
throw new Error("Synced calendar not found");
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return syncEventsToGoogleCalendarUtil(
|
|
442
|
+
this.db,
|
|
443
|
+
"clinic",
|
|
444
|
+
clinicId,
|
|
445
|
+
syncedCalendar,
|
|
446
|
+
events
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Fetches events from Google Calendar for a practitioner
|
|
452
|
+
* @param practitionerId - ID of the practitioner
|
|
453
|
+
* @param calendarId - ID of the synced calendar
|
|
454
|
+
* @param startDate - Start date for fetching events
|
|
455
|
+
* @param endDate - End date for fetching events
|
|
456
|
+
* @returns Events fetched from Google Calendar
|
|
457
|
+
*/
|
|
458
|
+
async fetchEventsFromPractitionerGoogleCalendar(
|
|
459
|
+
practitionerId: string,
|
|
460
|
+
calendarId: string,
|
|
461
|
+
startDate: Date,
|
|
462
|
+
endDate: Date
|
|
463
|
+
): Promise<any[]> {
|
|
464
|
+
const syncedCalendar = await this.getPractitionerSyncedCalendar(
|
|
465
|
+
practitionerId,
|
|
466
|
+
calendarId
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
if (!syncedCalendar) {
|
|
470
|
+
throw new Error("Synced calendar not found");
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return fetchEventsFromGoogleCalendarUtil(
|
|
474
|
+
this.db,
|
|
475
|
+
"practitioner",
|
|
476
|
+
practitionerId,
|
|
477
|
+
syncedCalendar,
|
|
478
|
+
startDate,
|
|
479
|
+
endDate
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Fetches events from Google Calendar for a patient
|
|
485
|
+
* @param patientId - ID of the patient
|
|
486
|
+
* @param calendarId - ID of the synced calendar
|
|
487
|
+
* @param startDate - Start date for fetching events
|
|
488
|
+
* @param endDate - End date for fetching events
|
|
489
|
+
* @returns Events fetched from Google Calendar
|
|
490
|
+
*/
|
|
491
|
+
async fetchEventsFromPatientGoogleCalendar(
|
|
492
|
+
patientId: string,
|
|
493
|
+
calendarId: string,
|
|
494
|
+
startDate: Date,
|
|
495
|
+
endDate: Date
|
|
496
|
+
): Promise<any[]> {
|
|
497
|
+
const syncedCalendar = await this.getPatientSyncedCalendar(
|
|
498
|
+
patientId,
|
|
499
|
+
calendarId
|
|
500
|
+
);
|
|
501
|
+
|
|
502
|
+
if (!syncedCalendar) {
|
|
503
|
+
throw new Error("Synced calendar not found");
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return fetchEventsFromGoogleCalendarUtil(
|
|
507
|
+
this.db,
|
|
508
|
+
"patient",
|
|
509
|
+
patientId,
|
|
510
|
+
syncedCalendar,
|
|
511
|
+
startDate,
|
|
512
|
+
endDate
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Fetches events from Google Calendar for a clinic
|
|
518
|
+
* @param clinicId - ID of the clinic
|
|
519
|
+
* @param calendarId - ID of the synced calendar
|
|
520
|
+
* @param startDate - Start date for fetching events
|
|
521
|
+
* @param endDate - End date for fetching events
|
|
522
|
+
* @returns Events fetched from Google Calendar
|
|
523
|
+
*/
|
|
524
|
+
async fetchEventsFromClinicGoogleCalendar(
|
|
525
|
+
clinicId: string,
|
|
526
|
+
calendarId: string,
|
|
527
|
+
startDate: Date,
|
|
528
|
+
endDate: Date
|
|
529
|
+
): Promise<any[]> {
|
|
530
|
+
const syncedCalendar = await this.getClinicSyncedCalendar(
|
|
531
|
+
clinicId,
|
|
532
|
+
calendarId
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
if (!syncedCalendar) {
|
|
536
|
+
throw new Error("Synced calendar not found");
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return fetchEventsFromGoogleCalendarUtil(
|
|
540
|
+
this.db,
|
|
541
|
+
"clinic",
|
|
542
|
+
clinicId,
|
|
543
|
+
syncedCalendar,
|
|
544
|
+
startDate,
|
|
545
|
+
endDate
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Deletes an event from Google Calendar for a practitioner
|
|
551
|
+
* @param practitionerId - ID of the practitioner
|
|
552
|
+
* @param calendarId - ID of the synced calendar
|
|
553
|
+
* @param eventId - ID of the event in Google Calendar
|
|
554
|
+
* @returns Success status
|
|
555
|
+
*/
|
|
556
|
+
async deletePractitionerGoogleCalendarEvent(
|
|
557
|
+
practitionerId: string,
|
|
558
|
+
calendarId: string,
|
|
559
|
+
eventId: string
|
|
560
|
+
): Promise<boolean> {
|
|
561
|
+
const syncedCalendar = await this.getPractitionerSyncedCalendar(
|
|
562
|
+
practitionerId,
|
|
563
|
+
calendarId
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
if (!syncedCalendar) {
|
|
567
|
+
throw new Error("Synced calendar not found");
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return deleteGoogleCalendarEventUtil(
|
|
571
|
+
this.db,
|
|
572
|
+
"practitioner",
|
|
573
|
+
practitionerId,
|
|
574
|
+
syncedCalendar,
|
|
575
|
+
eventId
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Deletes an event from Google Calendar for a patient
|
|
581
|
+
* @param patientId - ID of the patient
|
|
582
|
+
* @param calendarId - ID of the synced calendar
|
|
583
|
+
* @param eventId - ID of the event in Google Calendar
|
|
584
|
+
* @returns Success status
|
|
585
|
+
*/
|
|
586
|
+
async deletePatientGoogleCalendarEvent(
|
|
587
|
+
patientId: string,
|
|
588
|
+
calendarId: string,
|
|
589
|
+
eventId: string
|
|
590
|
+
): Promise<boolean> {
|
|
591
|
+
const syncedCalendar = await this.getPatientSyncedCalendar(
|
|
592
|
+
patientId,
|
|
593
|
+
calendarId
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
if (!syncedCalendar) {
|
|
597
|
+
throw new Error("Synced calendar not found");
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return deleteGoogleCalendarEventUtil(
|
|
601
|
+
this.db,
|
|
602
|
+
"patient",
|
|
603
|
+
patientId,
|
|
604
|
+
syncedCalendar,
|
|
605
|
+
eventId
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Deletes an event from Google Calendar for a clinic
|
|
611
|
+
* @param clinicId - ID of the clinic
|
|
612
|
+
* @param calendarId - ID of the synced calendar
|
|
613
|
+
* @param eventId - ID of the event in Google Calendar
|
|
614
|
+
* @returns Success status
|
|
615
|
+
*/
|
|
616
|
+
async deleteClinicGoogleCalendarEvent(
|
|
617
|
+
clinicId: string,
|
|
618
|
+
calendarId: string,
|
|
619
|
+
eventId: string
|
|
620
|
+
): Promise<boolean> {
|
|
621
|
+
const syncedCalendar = await this.getClinicSyncedCalendar(
|
|
622
|
+
clinicId,
|
|
623
|
+
calendarId
|
|
624
|
+
);
|
|
625
|
+
|
|
626
|
+
if (!syncedCalendar) {
|
|
627
|
+
throw new Error("Synced calendar not found");
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
return deleteGoogleCalendarEventUtil(
|
|
631
|
+
this.db,
|
|
632
|
+
"clinic",
|
|
633
|
+
clinicId,
|
|
634
|
+
syncedCalendar,
|
|
635
|
+
eventId
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Converts Google Calendar events to our system's format for a practitioner
|
|
641
|
+
* @param practitionerId - ID of the practitioner
|
|
642
|
+
* @param googleEvents - Google Calendar events
|
|
643
|
+
* @returns Converted calendar events
|
|
644
|
+
*/
|
|
645
|
+
convertGoogleEventsToPractitionerEvents(
|
|
646
|
+
practitionerId: string,
|
|
647
|
+
googleEvents: any[]
|
|
648
|
+
): Partial<CalendarEvent>[] {
|
|
649
|
+
return googleEvents.map((event) =>
|
|
650
|
+
convertGoogleEventToCalendarEventUtil(
|
|
651
|
+
event,
|
|
652
|
+
practitionerId,
|
|
653
|
+
"practitioner"
|
|
654
|
+
)
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Converts Google Calendar events to our system's format for a patient
|
|
660
|
+
* @param patientId - ID of the patient
|
|
661
|
+
* @param googleEvents - Google Calendar events
|
|
662
|
+
* @returns Converted calendar events
|
|
663
|
+
*/
|
|
664
|
+
convertGoogleEventsToPatientEvents(
|
|
665
|
+
patientId: string,
|
|
666
|
+
googleEvents: any[]
|
|
667
|
+
): Partial<CalendarEvent>[] {
|
|
668
|
+
return googleEvents.map((event) =>
|
|
669
|
+
convertGoogleEventToCalendarEventUtil(event, patientId, "patient")
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Converts Google Calendar events to our system's format for a clinic
|
|
675
|
+
* @param clinicId - ID of the clinic
|
|
676
|
+
* @param googleEvents - Google Calendar events
|
|
677
|
+
* @returns Converted calendar events
|
|
678
|
+
*/
|
|
679
|
+
convertGoogleEventsToClinicEvents(
|
|
680
|
+
clinicId: string,
|
|
681
|
+
googleEvents: any[]
|
|
682
|
+
): Partial<CalendarEvent>[] {
|
|
683
|
+
return googleEvents.map((event) =>
|
|
684
|
+
convertGoogleEventToCalendarEventUtil(event, clinicId, "clinic")
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Fetches a single event from Google Calendar for a practitioner
|
|
690
|
+
* @param practitionerId - ID of the practitioner
|
|
691
|
+
* @param calendarId - ID of the synced calendar
|
|
692
|
+
* @param eventId - ID of the event in Google Calendar
|
|
693
|
+
* @returns The event data or null if not found
|
|
694
|
+
*/
|
|
695
|
+
async fetchEventFromPractitionerGoogleCalendar(
|
|
696
|
+
practitionerId: string,
|
|
697
|
+
calendarId: string,
|
|
698
|
+
eventId: string
|
|
699
|
+
): Promise<any | null> {
|
|
700
|
+
const syncedCalendar = await this.getPractitionerSyncedCalendar(
|
|
701
|
+
practitionerId,
|
|
702
|
+
calendarId
|
|
703
|
+
);
|
|
704
|
+
|
|
705
|
+
if (!syncedCalendar) {
|
|
706
|
+
throw new Error("Synced calendar not found");
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
try {
|
|
710
|
+
// Refresh token if needed
|
|
711
|
+
const { accessToken } = await refreshGoogleCalendarTokenUtil(
|
|
712
|
+
syncedCalendar.refreshToken
|
|
713
|
+
);
|
|
714
|
+
|
|
715
|
+
// Call Google Calendar API to fetch the single event
|
|
716
|
+
const response = await makeRequest(
|
|
717
|
+
"get",
|
|
718
|
+
`${GOOGLE_CALENDAR_API_URL}/calendars/${syncedCalendar.calendarId}/events/${eventId}`,
|
|
719
|
+
{ Authorization: `Bearer ${accessToken}` }
|
|
720
|
+
);
|
|
721
|
+
|
|
722
|
+
// Update the last synced timestamp
|
|
723
|
+
await updateLastSyncedTimestampUtil(
|
|
724
|
+
this.db,
|
|
725
|
+
"practitioner",
|
|
726
|
+
practitionerId,
|
|
727
|
+
syncedCalendar.id
|
|
728
|
+
);
|
|
729
|
+
|
|
730
|
+
return response;
|
|
731
|
+
} catch (error) {
|
|
732
|
+
// If the event was not found (404), return null
|
|
733
|
+
if ((error as any).response?.status === 404) {
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
console.error(
|
|
738
|
+
`Error fetching event from Google Calendar: ${(error as Error).message}`
|
|
739
|
+
);
|
|
740
|
+
throw error;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|