@blackcode_sa/metaestetics-api 1.6.14 → 1.6.15
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 +343 -2
- package/dist/admin/index.d.ts +343 -2
- package/dist/admin/index.js +246 -157
- package/dist/admin/index.mjs +238 -157
- package/package.json +1 -1
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +2 -2
- package/src/admin/booking/booking.admin.ts +8 -4
- package/src/admin/calendar/calendar.admin.service.ts +8 -11
- package/src/admin/index.ts +21 -0
- package/src/admin/notifications/notifications.admin.ts +12 -30
- package/src/admin/requirements/patient-requirements.admin.service.ts +1 -1
- package/src/utils/TimestampUtils.ts +122 -17
package/dist/admin/index.js
CHANGED
|
@@ -30,11 +30,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/admin/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
APPOINTMENTS_COLLECTION: () => APPOINTMENTS_COLLECTION,
|
|
33
34
|
AppointmentAggregationService: () => AppointmentAggregationService,
|
|
35
|
+
AppointmentMailingService: () => AppointmentMailingService,
|
|
34
36
|
AppointmentStatus: () => AppointmentStatus,
|
|
35
37
|
BaseMailingService: () => BaseMailingService,
|
|
36
38
|
BookingAdmin: () => BookingAdmin,
|
|
39
|
+
BookingAvailabilityCalculator: () => BookingAvailabilityCalculator,
|
|
40
|
+
CalendarAdminService: () => CalendarAdminService,
|
|
37
41
|
ClinicAggregationService: () => ClinicAggregationService,
|
|
42
|
+
DocumentManagerAdminService: () => DocumentManagerAdminService,
|
|
43
|
+
Logger: () => Logger,
|
|
44
|
+
MediaType: () => MediaType,
|
|
38
45
|
NOTIFICATIONS_COLLECTION: () => NOTIFICATIONS_COLLECTION,
|
|
39
46
|
NotificationStatus: () => NotificationStatus,
|
|
40
47
|
NotificationType: () => NotificationType,
|
|
@@ -44,6 +51,7 @@ __export(index_exports, {
|
|
|
44
51
|
PatientInstructionStatus: () => PatientInstructionStatus,
|
|
45
52
|
PatientRequirementOverallStatus: () => PatientRequirementOverallStatus,
|
|
46
53
|
PatientRequirementsAdminService: () => PatientRequirementsAdminService,
|
|
54
|
+
PaymentStatus: () => PaymentStatus,
|
|
47
55
|
PractitionerAggregationService: () => PractitionerAggregationService,
|
|
48
56
|
PractitionerInviteMailingService: () => PractitionerInviteMailingService,
|
|
49
57
|
PractitionerTokenStatus: () => PractitionerTokenStatus,
|
|
@@ -84,7 +92,7 @@ var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
|
|
|
84
92
|
})(NotificationStatus || {});
|
|
85
93
|
|
|
86
94
|
// src/admin/notifications/notifications.admin.ts
|
|
87
|
-
var
|
|
95
|
+
var admin = __toESM(require("firebase-admin"));
|
|
88
96
|
var import_expo_server_sdk = require("expo-server-sdk");
|
|
89
97
|
|
|
90
98
|
// src/types/appointment/index.ts
|
|
@@ -101,6 +109,21 @@ var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
|
|
|
101
109
|
AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
|
|
102
110
|
return AppointmentStatus2;
|
|
103
111
|
})(AppointmentStatus || {});
|
|
112
|
+
var PaymentStatus = /* @__PURE__ */ ((PaymentStatus2) => {
|
|
113
|
+
PaymentStatus2["UNPAID"] = "unpaid";
|
|
114
|
+
PaymentStatus2["PAID"] = "paid";
|
|
115
|
+
PaymentStatus2["PARTIALLY_PAID"] = "partially_paid";
|
|
116
|
+
PaymentStatus2["REFUNDED"] = "refunded";
|
|
117
|
+
PaymentStatus2["NOT_APPLICABLE"] = "not_applicable";
|
|
118
|
+
return PaymentStatus2;
|
|
119
|
+
})(PaymentStatus || {});
|
|
120
|
+
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
121
|
+
MediaType2["BEFORE_PHOTO"] = "before_photo";
|
|
122
|
+
MediaType2["AFTER_PHOTO"] = "after_photo";
|
|
123
|
+
MediaType2["CONSENT_SCAN"] = "consent_scan";
|
|
124
|
+
MediaType2["OTHER_DOCUMENT"] = "other_document";
|
|
125
|
+
return MediaType2;
|
|
126
|
+
})(MediaType || {});
|
|
104
127
|
var APPOINTMENTS_COLLECTION = "appointments";
|
|
105
128
|
|
|
106
129
|
// src/types/documentation-templates/index.ts
|
|
@@ -119,117 +142,11 @@ var UserRole = /* @__PURE__ */ ((UserRole2) => {
|
|
|
119
142
|
return UserRole2;
|
|
120
143
|
})(UserRole || {});
|
|
121
144
|
|
|
122
|
-
// src/utils/TimestampUtils.ts
|
|
123
|
-
var admin = __toESM(require("firebase-admin"));
|
|
124
|
-
var import_firestore = require("firebase/firestore");
|
|
125
|
-
var TimestampUtils = class {
|
|
126
|
-
/**
|
|
127
|
-
* Converts an admin Firestore Timestamp to a client Firestore Timestamp
|
|
128
|
-
* @param adminTimestamp - Admin SDK Timestamp (from firebase-admin)
|
|
129
|
-
* @returns A client SDK Timestamp (from firebase/firestore) with same seconds/nanoseconds or null if input is null
|
|
130
|
-
*/
|
|
131
|
-
static adminToClient(adminTimestamp) {
|
|
132
|
-
if (!adminTimestamp) return null;
|
|
133
|
-
return new import_firestore.Timestamp(
|
|
134
|
-
adminTimestamp.seconds,
|
|
135
|
-
adminTimestamp.nanoseconds
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Converts a client Firestore Timestamp to an admin Firestore Timestamp
|
|
140
|
-
* @param clientTimestamp - Client SDK Timestamp (from firebase/firestore)
|
|
141
|
-
* @returns An admin SDK Timestamp (from firebase-admin) with same seconds/nanoseconds or null if input is null
|
|
142
|
-
*/
|
|
143
|
-
static clientToAdmin(clientTimestamp) {
|
|
144
|
-
if (!clientTimestamp) return null;
|
|
145
|
-
return new admin.firestore.Timestamp(
|
|
146
|
-
clientTimestamp.seconds,
|
|
147
|
-
clientTimestamp.nanoseconds
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Creates a client-compatible timestamp for the current time
|
|
152
|
-
* @returns A client SDK Timestamp (from firebase/firestore) for the current time
|
|
153
|
-
*/
|
|
154
|
-
static nowAsClient() {
|
|
155
|
-
const now = admin.firestore.Timestamp.now();
|
|
156
|
-
return this.adminToClient(now);
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Converts a Date object to a client Firestore Timestamp
|
|
160
|
-
* @param date - JavaScript Date object
|
|
161
|
-
* @returns A client SDK Timestamp (from firebase/firestore) or null if input is null
|
|
162
|
-
*/
|
|
163
|
-
static dateToClientTimestamp(date) {
|
|
164
|
-
if (!date) return null;
|
|
165
|
-
return import_firestore.Timestamp.fromDate(date);
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Converts a Date object to an admin Firestore Timestamp
|
|
169
|
-
* @param date - JavaScript Date object
|
|
170
|
-
* @returns An admin SDK Timestamp (from firebase-admin) or null if input is null
|
|
171
|
-
*/
|
|
172
|
-
static dateToAdminTimestamp(date) {
|
|
173
|
-
if (!date) return null;
|
|
174
|
-
return admin.firestore.Timestamp.fromDate(date);
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Deeply converts all admin Firestore Timestamps in an object to client Firestore Timestamps
|
|
178
|
-
* @param obj - Object that may contain admin Firestore Timestamps
|
|
179
|
-
* @returns The same object with all admin Timestamps converted to client Timestamps
|
|
180
|
-
*/
|
|
181
|
-
static convertObjectTimestampsAdminToClient(obj) {
|
|
182
|
-
if (!obj || typeof obj !== "object") {
|
|
183
|
-
return obj;
|
|
184
|
-
}
|
|
185
|
-
if (obj instanceof admin.firestore.Timestamp) {
|
|
186
|
-
return this.adminToClient(obj);
|
|
187
|
-
}
|
|
188
|
-
if (Array.isArray(obj)) {
|
|
189
|
-
return obj.map(
|
|
190
|
-
(item) => this.convertObjectTimestampsAdminToClient(item)
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
const result = { ...obj };
|
|
194
|
-
for (const key in result) {
|
|
195
|
-
if (Object.prototype.hasOwnProperty.call(result, key)) {
|
|
196
|
-
result[key] = this.convertObjectTimestampsAdminToClient(result[key]);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return result;
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Deeply converts all client Firestore Timestamps in an object to admin Firestore Timestamps
|
|
203
|
-
* @param obj - Object that may contain client Firestore Timestamps
|
|
204
|
-
* @returns The same object with all client Timestamps converted to admin Timestamps
|
|
205
|
-
*/
|
|
206
|
-
static convertObjectTimestampsClientToAdmin(obj) {
|
|
207
|
-
if (!obj || typeof obj !== "object") {
|
|
208
|
-
return obj;
|
|
209
|
-
}
|
|
210
|
-
if (obj instanceof import_firestore.Timestamp) {
|
|
211
|
-
return this.clientToAdmin(obj);
|
|
212
|
-
}
|
|
213
|
-
if (Array.isArray(obj)) {
|
|
214
|
-
return obj.map(
|
|
215
|
-
(item) => this.convertObjectTimestampsClientToAdmin(item)
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
const result = { ...obj };
|
|
219
|
-
for (const key in result) {
|
|
220
|
-
if (Object.prototype.hasOwnProperty.call(result, key)) {
|
|
221
|
-
result[key] = this.convertObjectTimestampsClientToAdmin(result[key]);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
return result;
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
|
|
228
145
|
// src/admin/notifications/notifications.admin.ts
|
|
229
146
|
var NotificationsAdmin = class {
|
|
230
147
|
constructor(firestore12) {
|
|
231
148
|
this.expo = new import_expo_server_sdk.Expo();
|
|
232
|
-
this.db = firestore12 ||
|
|
149
|
+
this.db = firestore12 || admin.firestore();
|
|
233
150
|
}
|
|
234
151
|
/**
|
|
235
152
|
* Dohvata notifikaciju po ID-u
|
|
@@ -245,8 +162,8 @@ var NotificationsAdmin = class {
|
|
|
245
162
|
const docRef = await this.db.collection("notifications").add({
|
|
246
163
|
...notification,
|
|
247
164
|
status: "pending" /* PENDING */,
|
|
248
|
-
createdAt:
|
|
249
|
-
updatedAt:
|
|
165
|
+
createdAt: admin.firestore.FieldValue.serverTimestamp(),
|
|
166
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp()
|
|
250
167
|
});
|
|
251
168
|
return docRef.id;
|
|
252
169
|
}
|
|
@@ -272,10 +189,10 @@ var NotificationsAdmin = class {
|
|
|
272
189
|
async updateNotificationStatus(notificationId, status, error) {
|
|
273
190
|
const update = {
|
|
274
191
|
status,
|
|
275
|
-
updatedAt:
|
|
192
|
+
updatedAt: admin.firestore.FieldValue.serverTimestamp()
|
|
276
193
|
};
|
|
277
194
|
if (status === "sent" /* SENT */) {
|
|
278
|
-
update.sentAt =
|
|
195
|
+
update.sentAt = admin.firestore.FieldValue.serverTimestamp();
|
|
279
196
|
}
|
|
280
197
|
if (error) {
|
|
281
198
|
update.error = error;
|
|
@@ -345,7 +262,7 @@ var NotificationsAdmin = class {
|
|
|
345
262
|
* Procesira notifikacije koje čekaju na slanje sa batch limitom
|
|
346
263
|
*/
|
|
347
264
|
async processPendingNotifications(batchSize = 100) {
|
|
348
|
-
const now =
|
|
265
|
+
const now = admin.firestore.Timestamp.now();
|
|
349
266
|
const pendingNotifications = await this.db.collection("notifications").where("status", "==", "pending" /* PENDING */).where("notificationTime", "<=", now).limit(batchSize).get();
|
|
350
267
|
const results = await Promise.allSettled(
|
|
351
268
|
pendingNotifications.docs.map(async (doc) => {
|
|
@@ -376,7 +293,7 @@ var NotificationsAdmin = class {
|
|
|
376
293
|
const oldNotifications = await this.db.collection("notifications").where(
|
|
377
294
|
"createdAt",
|
|
378
295
|
"<=",
|
|
379
|
-
|
|
296
|
+
admin.firestore.Timestamp.fromDate(cutoffDate)
|
|
380
297
|
).limit(batchSize).get();
|
|
381
298
|
if (oldNotifications.empty) {
|
|
382
299
|
break;
|
|
@@ -418,15 +335,12 @@ var NotificationsAdmin = class {
|
|
|
418
335
|
title = "New Appointment Confirmed";
|
|
419
336
|
body = `Appointment for ${appointment.procedureInfo.name} with ${appointment.patientInfo.fullName} on ${appointment.appointmentStartTime.toDate().toLocaleDateString()} is confirmed.`;
|
|
420
337
|
}
|
|
421
|
-
const
|
|
422
|
-
const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
|
|
423
|
-
adminTsNow
|
|
424
|
-
);
|
|
338
|
+
const notificationTimestampForDb = admin.firestore.Timestamp.now();
|
|
425
339
|
const notificationData = {
|
|
426
340
|
userId: recipientUserId,
|
|
427
341
|
userRole: recipientRole,
|
|
428
342
|
notificationType: "appointmentStatusChange" /* APPOINTMENT_STATUS_CHANGE */,
|
|
429
|
-
notificationTime:
|
|
343
|
+
notificationTime: notificationTimestampForDb,
|
|
430
344
|
notificationTokens: recipientExpoTokens,
|
|
431
345
|
title,
|
|
432
346
|
body,
|
|
@@ -472,15 +386,12 @@ var NotificationsAdmin = class {
|
|
|
472
386
|
body += ` Reason: ${appointment.cancellationReason}`;
|
|
473
387
|
}
|
|
474
388
|
}
|
|
475
|
-
const
|
|
476
|
-
const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
|
|
477
|
-
adminTsNow
|
|
478
|
-
);
|
|
389
|
+
const notificationTimestampForDb = admin.firestore.Timestamp.now();
|
|
479
390
|
const notificationData = {
|
|
480
391
|
userId: recipientUserId,
|
|
481
392
|
userRole: recipientRole,
|
|
482
393
|
notificationType: "appointmentCancelled" /* APPOINTMENT_CANCELLED */,
|
|
483
|
-
notificationTime:
|
|
394
|
+
notificationTime: notificationTimestampForDb,
|
|
484
395
|
notificationTokens: recipientExpoTokens,
|
|
485
396
|
title,
|
|
486
397
|
body,
|
|
@@ -511,15 +422,12 @@ var NotificationsAdmin = class {
|
|
|
511
422
|
}
|
|
512
423
|
const title = "Appointment Reschedule Proposed";
|
|
513
424
|
const body = `Action Required: A new time has been proposed for your appointment for ${appointment.procedureInfo.name}. Please review in the app.`;
|
|
514
|
-
const
|
|
515
|
-
const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
|
|
516
|
-
adminTsNow
|
|
517
|
-
);
|
|
425
|
+
const notificationTimestampForDb = admin.firestore.Timestamp.now();
|
|
518
426
|
const notificationData = {
|
|
519
427
|
userId: patientUserId,
|
|
520
428
|
userRole: "patient" /* PATIENT */,
|
|
521
429
|
notificationType: "appointmentRescheduledProposal" /* APPOINTMENT_RESCHEDULED_PROPOSAL */,
|
|
522
|
-
notificationTime:
|
|
430
|
+
notificationTime: notificationTimestampForDb,
|
|
523
431
|
notificationTokens: patientExpoTokens,
|
|
524
432
|
title,
|
|
525
433
|
body,
|
|
@@ -550,16 +458,13 @@ var NotificationsAdmin = class {
|
|
|
550
458
|
}
|
|
551
459
|
const title = "Payment Updated";
|
|
552
460
|
const body = `Your payment status for the appointment (${appointment.procedureInfo.name}) on ${appointment.appointmentStartTime.toDate().toLocaleDateString()} is now ${appointment.paymentStatus}.`;
|
|
553
|
-
const
|
|
554
|
-
const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
|
|
555
|
-
adminTsNow
|
|
556
|
-
);
|
|
461
|
+
const notificationTimestampForDb = admin.firestore.Timestamp.now();
|
|
557
462
|
const notificationType = appointment.paymentStatus === "paid" /* PAID */ ? "paymentConfirmation" /* PAYMENT_CONFIRMATION */ : "generalMessage" /* GENERAL_MESSAGE */;
|
|
558
463
|
const notificationData = {
|
|
559
464
|
userId: patientUserId,
|
|
560
465
|
userRole: "patient" /* PATIENT */,
|
|
561
466
|
notificationType,
|
|
562
|
-
notificationTime:
|
|
467
|
+
notificationTime: notificationTimestampForDb,
|
|
563
468
|
notificationTokens: patientExpoTokens,
|
|
564
469
|
title,
|
|
565
470
|
body,
|
|
@@ -590,15 +495,12 @@ var NotificationsAdmin = class {
|
|
|
590
495
|
}
|
|
591
496
|
const title = "Leave a Review";
|
|
592
497
|
const body = `How was your recent appointment for ${appointment.procedureInfo.name}? We'd love to hear your feedback!`;
|
|
593
|
-
const
|
|
594
|
-
const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
|
|
595
|
-
adminTsNow
|
|
596
|
-
);
|
|
498
|
+
const notificationTimestampForDb = admin.firestore.Timestamp.now();
|
|
597
499
|
const notificationData = {
|
|
598
500
|
userId: patientUserId,
|
|
599
501
|
userRole: "patient" /* PATIENT */,
|
|
600
502
|
notificationType: "reviewRequest" /* REVIEW_REQUEST */,
|
|
601
|
-
notificationTime:
|
|
503
|
+
notificationTime: notificationTimestampForDb,
|
|
602
504
|
notificationTokens: patientExpoTokens,
|
|
603
505
|
title,
|
|
604
506
|
body,
|
|
@@ -635,16 +537,13 @@ var NotificationsAdmin = class {
|
|
|
635
537
|
}
|
|
636
538
|
const title = "New Review Received";
|
|
637
539
|
const body = `A new review has been added by ${appointment.patientInfo.fullName} for your appointment on ${appointment.appointmentStartTime.toDate().toLocaleDateString()}.`;
|
|
638
|
-
const
|
|
639
|
-
const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
|
|
640
|
-
adminTsNow
|
|
641
|
-
);
|
|
540
|
+
const notificationTimestampForDb = admin.firestore.Timestamp.now();
|
|
642
541
|
const tempNotificationType = "generalMessage" /* GENERAL_MESSAGE */;
|
|
643
542
|
const notificationData = {
|
|
644
543
|
userId: recipientUserId,
|
|
645
544
|
userRole: "practitioner" /* PRACTITIONER */,
|
|
646
545
|
notificationType: tempNotificationType,
|
|
647
|
-
notificationTime:
|
|
546
|
+
notificationTime: notificationTimestampForDb,
|
|
648
547
|
notificationTokens: recipientExpoTokens,
|
|
649
548
|
title,
|
|
650
549
|
body,
|
|
@@ -668,6 +567,187 @@ var NotificationsAdmin = class {
|
|
|
668
567
|
}
|
|
669
568
|
};
|
|
670
569
|
|
|
570
|
+
// src/utils/TimestampUtils.ts
|
|
571
|
+
var admin2 = __toESM(require("firebase-admin"));
|
|
572
|
+
var import_firestore = require("firebase/firestore");
|
|
573
|
+
var IS_SERVER_ENV = process.env.NODE_ENV === "production" || process.env.FUNCTIONS_EMULATOR === "true" || process.env.FIREBASE_CONFIG !== void 0;
|
|
574
|
+
var TimestampUtils = class {
|
|
575
|
+
/**
|
|
576
|
+
* Enables server mode where admin timestamps are preserved when saving
|
|
577
|
+
* to Firestore via the admin SDK
|
|
578
|
+
*/
|
|
579
|
+
static enableServerMode() {
|
|
580
|
+
this.serverMode = true;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Disables server mode - use this only for client-side or mixed environments
|
|
584
|
+
*/
|
|
585
|
+
static disableServerMode() {
|
|
586
|
+
this.serverMode = false;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Converts an admin Firestore Timestamp to a client Firestore Timestamp
|
|
590
|
+
* In server mode, returns the original admin timestamp for storage consistency
|
|
591
|
+
*
|
|
592
|
+
* @param adminTimestamp - Admin SDK Timestamp (from firebase-admin)
|
|
593
|
+
* @returns A client SDK Timestamp (from firebase/firestore) with same seconds/nanoseconds,
|
|
594
|
+
* or the original admin timestamp in server mode,
|
|
595
|
+
* or null if input is null
|
|
596
|
+
*/
|
|
597
|
+
static adminToClient(adminTimestamp) {
|
|
598
|
+
if (!adminTimestamp) return null;
|
|
599
|
+
if (this.serverMode) {
|
|
600
|
+
return adminTimestamp;
|
|
601
|
+
}
|
|
602
|
+
return new import_firestore.Timestamp(
|
|
603
|
+
adminTimestamp.seconds,
|
|
604
|
+
adminTimestamp.nanoseconds
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Converts a client Firestore Timestamp to an admin Firestore Timestamp
|
|
609
|
+
* @param clientTimestamp - Client SDK Timestamp (from firebase/firestore)
|
|
610
|
+
* @returns An admin SDK Timestamp (from firebase-admin) with same seconds/nanoseconds or null if input is null
|
|
611
|
+
*/
|
|
612
|
+
static clientToAdmin(clientTimestamp) {
|
|
613
|
+
if (!clientTimestamp) return null;
|
|
614
|
+
return new admin2.firestore.Timestamp(
|
|
615
|
+
clientTimestamp.seconds,
|
|
616
|
+
clientTimestamp.nanoseconds
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Creates a timestamp for the current time in the appropriate format based on environment
|
|
621
|
+
* @returns A timestamp for the current time (admin timestamp in server mode, client in client mode)
|
|
622
|
+
*/
|
|
623
|
+
static nowAsTimestamp() {
|
|
624
|
+
const now = admin2.firestore.Timestamp.now();
|
|
625
|
+
if (this.serverMode) {
|
|
626
|
+
return now;
|
|
627
|
+
}
|
|
628
|
+
return this.adminToClient(now);
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* @deprecated Use nowAsTimestamp() instead for better cross-environment compatibility
|
|
632
|
+
*/
|
|
633
|
+
static nowAsClient() {
|
|
634
|
+
const now = admin2.firestore.Timestamp.now();
|
|
635
|
+
return this.adminToClient(now);
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Converts a Date object to a timestamp in the appropriate format based on environment
|
|
639
|
+
* @param date - JavaScript Date object
|
|
640
|
+
* @returns A timestamp (admin timestamp in server mode, client in client mode) or null if input is null
|
|
641
|
+
*/
|
|
642
|
+
static dateToTimestamp(date) {
|
|
643
|
+
if (!date) return null;
|
|
644
|
+
if (this.serverMode) {
|
|
645
|
+
return admin2.firestore.Timestamp.fromDate(date);
|
|
646
|
+
}
|
|
647
|
+
return import_firestore.Timestamp.fromDate(date);
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* @deprecated Use dateToTimestamp() instead for better cross-environment compatibility
|
|
651
|
+
*/
|
|
652
|
+
static dateToClientTimestamp(date) {
|
|
653
|
+
if (!date) return null;
|
|
654
|
+
return import_firestore.Timestamp.fromDate(date);
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* @deprecated Use dateToTimestamp() instead for better cross-environment compatibility
|
|
658
|
+
*/
|
|
659
|
+
static dateToAdminTimestamp(date) {
|
|
660
|
+
if (!date) return null;
|
|
661
|
+
return admin2.firestore.Timestamp.fromDate(date);
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Gets a server timestamp field value for use in create/update operations
|
|
665
|
+
* Works in both admin and client environments
|
|
666
|
+
*/
|
|
667
|
+
static serverTimestamp() {
|
|
668
|
+
if (this.serverMode) {
|
|
669
|
+
return admin2.firestore.FieldValue.serverTimestamp();
|
|
670
|
+
}
|
|
671
|
+
throw new Error("Server timestamp in client mode not implemented");
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* For objects with mixed timestamp types, ensures all timestamps are
|
|
675
|
+
* in the correct format for the current environment
|
|
676
|
+
*/
|
|
677
|
+
static normalizeTimestamps(obj) {
|
|
678
|
+
if (!obj || typeof obj !== "object") {
|
|
679
|
+
return obj;
|
|
680
|
+
}
|
|
681
|
+
if (obj instanceof admin2.firestore.Timestamp) {
|
|
682
|
+
return this.serverMode ? obj : this.adminToClient(obj);
|
|
683
|
+
}
|
|
684
|
+
if (obj instanceof import_firestore.Timestamp && this.serverMode) {
|
|
685
|
+
return this.clientToAdmin(obj);
|
|
686
|
+
}
|
|
687
|
+
if (Array.isArray(obj)) {
|
|
688
|
+
return obj.map((item) => this.normalizeTimestamps(item));
|
|
689
|
+
}
|
|
690
|
+
const result = { ...obj };
|
|
691
|
+
for (const key in result) {
|
|
692
|
+
if (Object.prototype.hasOwnProperty.call(result, key)) {
|
|
693
|
+
result[key] = this.normalizeTimestamps(result[key]);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return result;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* @deprecated Use normalizeTimestamps() instead for better cross-environment compatibility
|
|
700
|
+
*/
|
|
701
|
+
static convertObjectTimestampsAdminToClient(obj) {
|
|
702
|
+
if (!obj || typeof obj !== "object") {
|
|
703
|
+
return obj;
|
|
704
|
+
}
|
|
705
|
+
if (obj instanceof admin2.firestore.Timestamp) {
|
|
706
|
+
return this.adminToClient(obj);
|
|
707
|
+
}
|
|
708
|
+
if (Array.isArray(obj)) {
|
|
709
|
+
return obj.map(
|
|
710
|
+
(item) => this.convertObjectTimestampsAdminToClient(item)
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
const result = { ...obj };
|
|
714
|
+
for (const key in result) {
|
|
715
|
+
if (Object.prototype.hasOwnProperty.call(result, key)) {
|
|
716
|
+
result[key] = this.convertObjectTimestampsAdminToClient(result[key]);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return result;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* @deprecated Use normalizeTimestamps() instead for better cross-environment compatibility
|
|
723
|
+
*/
|
|
724
|
+
static convertObjectTimestampsClientToAdmin(obj) {
|
|
725
|
+
if (!obj || typeof obj !== "object") {
|
|
726
|
+
return obj;
|
|
727
|
+
}
|
|
728
|
+
if (obj instanceof import_firestore.Timestamp) {
|
|
729
|
+
return this.clientToAdmin(obj);
|
|
730
|
+
}
|
|
731
|
+
if (Array.isArray(obj)) {
|
|
732
|
+
return obj.map(
|
|
733
|
+
(item) => this.convertObjectTimestampsClientToAdmin(item)
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
const result = { ...obj };
|
|
737
|
+
for (const key in result) {
|
|
738
|
+
if (Object.prototype.hasOwnProperty.call(result, key)) {
|
|
739
|
+
result[key] = this.convertObjectTimestampsClientToAdmin(result[key]);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
return result;
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
/**
|
|
746
|
+
* Flag to force server mode where admin timestamps are preserved
|
|
747
|
+
* This should be true in Cloud Functions environments
|
|
748
|
+
*/
|
|
749
|
+
TimestampUtils.serverMode = IS_SERVER_ENV;
|
|
750
|
+
|
|
671
751
|
// src/admin/aggregation/clinic/clinic.aggregation.service.ts
|
|
672
752
|
var admin3 = __toESM(require("firebase-admin"));
|
|
673
753
|
|
|
@@ -2128,7 +2208,7 @@ var PatientRequirementsAdminService = class {
|
|
|
2128
2208
|
userRole: "patient" /* PATIENT */,
|
|
2129
2209
|
notificationType: "requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */,
|
|
2130
2210
|
notificationTime: currentInstruction.dueTime,
|
|
2131
|
-
//
|
|
2211
|
+
// dueTime should be an admin.firestore.Timestamp already
|
|
2132
2212
|
notificationTokens: patientExpoTokens,
|
|
2133
2213
|
title: `Reminder: ${instance.requirementName}`,
|
|
2134
2214
|
body: currentInstruction.instructionText,
|
|
@@ -2470,14 +2550,8 @@ var CalendarAdminService = class {
|
|
|
2470
2550
|
const batch = this.db.batch();
|
|
2471
2551
|
const serverTimestamp = admin8.firestore.FieldValue.serverTimestamp();
|
|
2472
2552
|
const firestoreCompatibleEventTime = {
|
|
2473
|
-
start:
|
|
2474
|
-
|
|
2475
|
-
nanoseconds: newEventTime.start.nanoseconds
|
|
2476
|
-
},
|
|
2477
|
-
end: {
|
|
2478
|
-
seconds: newEventTime.end.seconds,
|
|
2479
|
-
nanoseconds: newEventTime.end.nanoseconds
|
|
2480
|
-
}
|
|
2553
|
+
start: TimestampUtils.clientToAdmin(newEventTime.start) || admin8.firestore.Timestamp.now(),
|
|
2554
|
+
end: TimestampUtils.clientToAdmin(newEventTime.end) || admin8.firestore.Timestamp.now()
|
|
2481
2555
|
};
|
|
2482
2556
|
if (appointment.calendarEventId) {
|
|
2483
2557
|
const practitionerEventRef = this.db.doc(
|
|
@@ -3225,7 +3299,8 @@ var AppointmentAggregationService = class {
|
|
|
3225
3299
|
status: "pendingNotification" /* PENDING_NOTIFICATION */,
|
|
3226
3300
|
originalNotifyAtValue: notifyAtValue,
|
|
3227
3301
|
originalTimeframeUnit: template.timeframe.unit,
|
|
3228
|
-
updatedAt: admin10.firestore.
|
|
3302
|
+
updatedAt: admin10.firestore.Timestamp.now(),
|
|
3303
|
+
// Use current server timestamp
|
|
3229
3304
|
notificationId: void 0,
|
|
3230
3305
|
actionTakenAt: void 0
|
|
3231
3306
|
};
|
|
@@ -3335,7 +3410,8 @@ var AppointmentAggregationService = class {
|
|
|
3335
3410
|
status: "pendingNotification" /* PENDING_NOTIFICATION */,
|
|
3336
3411
|
originalNotifyAtValue: notifyAtValue,
|
|
3337
3412
|
originalTimeframeUnit: template.timeframe.unit,
|
|
3338
|
-
updatedAt: admin10.firestore.
|
|
3413
|
+
updatedAt: admin10.firestore.Timestamp.now(),
|
|
3414
|
+
// Use current server timestamp
|
|
3339
3415
|
notificationId: void 0,
|
|
3340
3416
|
actionTakenAt: void 0
|
|
3341
3417
|
};
|
|
@@ -4546,8 +4622,12 @@ var BookingAdmin = class {
|
|
|
4546
4622
|
return events.map((event) => ({
|
|
4547
4623
|
...event,
|
|
4548
4624
|
eventTime: {
|
|
4549
|
-
start: TimestampUtils.adminToClient(
|
|
4550
|
-
|
|
4625
|
+
start: TimestampUtils.adminToClient(
|
|
4626
|
+
event.eventTime.start
|
|
4627
|
+
),
|
|
4628
|
+
end: TimestampUtils.adminToClient(
|
|
4629
|
+
event.eventTime.end
|
|
4630
|
+
)
|
|
4551
4631
|
}
|
|
4552
4632
|
// Convert any other timestamps in the event if needed
|
|
4553
4633
|
}));
|
|
@@ -5012,13 +5092,21 @@ var BookingAdmin = class {
|
|
|
5012
5092
|
|
|
5013
5093
|
// src/admin/index.ts
|
|
5014
5094
|
console.log("[Admin Module] Initialized and services exported.");
|
|
5095
|
+
TimestampUtils.enableServerMode();
|
|
5015
5096
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5016
5097
|
0 && (module.exports = {
|
|
5098
|
+
APPOINTMENTS_COLLECTION,
|
|
5017
5099
|
AppointmentAggregationService,
|
|
5100
|
+
AppointmentMailingService,
|
|
5018
5101
|
AppointmentStatus,
|
|
5019
5102
|
BaseMailingService,
|
|
5020
5103
|
BookingAdmin,
|
|
5104
|
+
BookingAvailabilityCalculator,
|
|
5105
|
+
CalendarAdminService,
|
|
5021
5106
|
ClinicAggregationService,
|
|
5107
|
+
DocumentManagerAdminService,
|
|
5108
|
+
Logger,
|
|
5109
|
+
MediaType,
|
|
5022
5110
|
NOTIFICATIONS_COLLECTION,
|
|
5023
5111
|
NotificationStatus,
|
|
5024
5112
|
NotificationType,
|
|
@@ -5028,6 +5116,7 @@ console.log("[Admin Module] Initialized and services exported.");
|
|
|
5028
5116
|
PatientInstructionStatus,
|
|
5029
5117
|
PatientRequirementOverallStatus,
|
|
5030
5118
|
PatientRequirementsAdminService,
|
|
5119
|
+
PaymentStatus,
|
|
5031
5120
|
PractitionerAggregationService,
|
|
5032
5121
|
PractitionerInviteMailingService,
|
|
5033
5122
|
PractitionerTokenStatus,
|