@blackcode_sa/metaestetics-api 1.12.67 → 1.12.69
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 +34 -1
- package/dist/admin/index.d.ts +34 -1
- package/dist/admin/index.js +104 -0
- package/dist/admin/index.mjs +104 -0
- package/dist/backoffice/index.d.mts +40 -0
- package/dist/backoffice/index.d.ts +40 -0
- package/dist/backoffice/index.js +118 -18
- package/dist/backoffice/index.mjs +118 -20
- package/dist/index.d.mts +61 -2
- package/dist/index.d.ts +61 -2
- package/dist/index.js +249 -37
- package/dist/index.mjs +249 -39
- package/package.json +1 -1
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +140 -0
- package/src/backoffice/services/README.md +17 -0
- package/src/backoffice/services/analytics.service.proposal.md +859 -0
- package/src/backoffice/services/analytics.service.summary.md +143 -0
- package/src/backoffice/services/category.service.ts +49 -6
- package/src/backoffice/services/subcategory.service.ts +50 -6
- package/src/backoffice/services/technology.service.ts +53 -6
- package/src/services/appointment/appointment.service.ts +59 -6
- package/src/services/procedure/procedure.service.ts +120 -7
- package/src/types/notifications/index.ts +21 -0
package/dist/admin/index.d.mts
CHANGED
|
@@ -2053,6 +2053,7 @@ declare enum NotificationType {
|
|
|
2053
2053
|
FORM_REMINDER = "formReminder",// Reminds user to fill a specific form
|
|
2054
2054
|
FORM_SUBMISSION_CONFIRMATION = "formSubmissionConfirmation",// Confirms form was submitted
|
|
2055
2055
|
REVIEW_REQUEST = "reviewRequest",// Request for patient review post-appointment
|
|
2056
|
+
PROCEDURE_RECOMMENDATION = "procedureRecommendation",// Doctor recommended a procedure for follow-up
|
|
2056
2057
|
PAYMENT_DUE = "paymentDue",
|
|
2057
2058
|
PAYMENT_CONFIRMATION = "paymentConfirmation",
|
|
2058
2059
|
PAYMENT_FAILED = "paymentFailed",
|
|
@@ -2222,6 +2223,24 @@ interface ReviewRequestNotification extends BaseNotification {
|
|
|
2222
2223
|
practitionerName?: string;
|
|
2223
2224
|
procedureName?: string;
|
|
2224
2225
|
}
|
|
2226
|
+
/**
|
|
2227
|
+
* Notification for when a doctor recommends a procedure for follow-up.
|
|
2228
|
+
* Example: "Dr. Smith recommended [Procedure Name] for you. Suggested timeframe: in 2 weeks"
|
|
2229
|
+
*/
|
|
2230
|
+
interface ProcedureRecommendationNotification extends BaseNotification {
|
|
2231
|
+
notificationType: NotificationType.PROCEDURE_RECOMMENDATION;
|
|
2232
|
+
appointmentId: string;
|
|
2233
|
+
recommendationId: string;
|
|
2234
|
+
procedureId: string;
|
|
2235
|
+
procedureName: string;
|
|
2236
|
+
practitionerName: string;
|
|
2237
|
+
clinicName: string;
|
|
2238
|
+
note?: string;
|
|
2239
|
+
timeframe: {
|
|
2240
|
+
value: number;
|
|
2241
|
+
unit: 'day' | 'week' | 'month' | 'year';
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2225
2244
|
/**
|
|
2226
2245
|
* Generic notification for direct messages or announcements.
|
|
2227
2246
|
*/
|
|
@@ -2237,7 +2256,7 @@ interface PaymentConfirmationNotification extends BaseNotification {
|
|
|
2237
2256
|
/**
|
|
2238
2257
|
* Unija svih tipova notifikacija
|
|
2239
2258
|
*/
|
|
2240
|
-
type Notification = PreRequirementNotification | PostRequirementNotification | RequirementInstructionDueNotification | AppointmentReminderNotification | AppointmentStatusChangeNotification | AppointmentRescheduledProposalNotification | AppointmentCancelledNotification | FormReminderNotification | FormSubmissionConfirmationNotification | ReviewRequestNotification | GeneralMessageNotification | PaymentConfirmationNotification;
|
|
2259
|
+
type Notification = PreRequirementNotification | PostRequirementNotification | RequirementInstructionDueNotification | AppointmentReminderNotification | AppointmentStatusChangeNotification | AppointmentRescheduledProposalNotification | AppointmentCancelledNotification | FormReminderNotification | FormSubmissionConfirmationNotification | ReviewRequestNotification | ProcedureRecommendationNotification | GeneralMessageNotification | PaymentConfirmationNotification;
|
|
2241
2260
|
|
|
2242
2261
|
/**
|
|
2243
2262
|
* Minimal interface for the new mailgun.js client's messages API
|
|
@@ -2676,6 +2695,20 @@ declare class AppointmentAggregationService {
|
|
|
2676
2695
|
* @param after - The appointment state after update
|
|
2677
2696
|
*/
|
|
2678
2697
|
private handleZonePhotosUpdate;
|
|
2698
|
+
/**
|
|
2699
|
+
* Checks if recommended procedures have changed between two appointment states
|
|
2700
|
+
* @param before - The appointment state before update
|
|
2701
|
+
* @param after - The appointment state after update
|
|
2702
|
+
* @returns True if recommendations have changed, false otherwise
|
|
2703
|
+
*/
|
|
2704
|
+
private hasRecommendationsChanged;
|
|
2705
|
+
/**
|
|
2706
|
+
* Handles recommended procedures update - creates notifications for newly added recommendations
|
|
2707
|
+
* @param before - The appointment state before update
|
|
2708
|
+
* @param after - The appointment state after update
|
|
2709
|
+
* @param patientProfile - The patient profile (for expo tokens)
|
|
2710
|
+
*/
|
|
2711
|
+
private handleRecommendedProceduresUpdate;
|
|
2679
2712
|
}
|
|
2680
2713
|
|
|
2681
2714
|
/**
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -2053,6 +2053,7 @@ declare enum NotificationType {
|
|
|
2053
2053
|
FORM_REMINDER = "formReminder",// Reminds user to fill a specific form
|
|
2054
2054
|
FORM_SUBMISSION_CONFIRMATION = "formSubmissionConfirmation",// Confirms form was submitted
|
|
2055
2055
|
REVIEW_REQUEST = "reviewRequest",// Request for patient review post-appointment
|
|
2056
|
+
PROCEDURE_RECOMMENDATION = "procedureRecommendation",// Doctor recommended a procedure for follow-up
|
|
2056
2057
|
PAYMENT_DUE = "paymentDue",
|
|
2057
2058
|
PAYMENT_CONFIRMATION = "paymentConfirmation",
|
|
2058
2059
|
PAYMENT_FAILED = "paymentFailed",
|
|
@@ -2222,6 +2223,24 @@ interface ReviewRequestNotification extends BaseNotification {
|
|
|
2222
2223
|
practitionerName?: string;
|
|
2223
2224
|
procedureName?: string;
|
|
2224
2225
|
}
|
|
2226
|
+
/**
|
|
2227
|
+
* Notification for when a doctor recommends a procedure for follow-up.
|
|
2228
|
+
* Example: "Dr. Smith recommended [Procedure Name] for you. Suggested timeframe: in 2 weeks"
|
|
2229
|
+
*/
|
|
2230
|
+
interface ProcedureRecommendationNotification extends BaseNotification {
|
|
2231
|
+
notificationType: NotificationType.PROCEDURE_RECOMMENDATION;
|
|
2232
|
+
appointmentId: string;
|
|
2233
|
+
recommendationId: string;
|
|
2234
|
+
procedureId: string;
|
|
2235
|
+
procedureName: string;
|
|
2236
|
+
practitionerName: string;
|
|
2237
|
+
clinicName: string;
|
|
2238
|
+
note?: string;
|
|
2239
|
+
timeframe: {
|
|
2240
|
+
value: number;
|
|
2241
|
+
unit: 'day' | 'week' | 'month' | 'year';
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2225
2244
|
/**
|
|
2226
2245
|
* Generic notification for direct messages or announcements.
|
|
2227
2246
|
*/
|
|
@@ -2237,7 +2256,7 @@ interface PaymentConfirmationNotification extends BaseNotification {
|
|
|
2237
2256
|
/**
|
|
2238
2257
|
* Unija svih tipova notifikacija
|
|
2239
2258
|
*/
|
|
2240
|
-
type Notification = PreRequirementNotification | PostRequirementNotification | RequirementInstructionDueNotification | AppointmentReminderNotification | AppointmentStatusChangeNotification | AppointmentRescheduledProposalNotification | AppointmentCancelledNotification | FormReminderNotification | FormSubmissionConfirmationNotification | ReviewRequestNotification | GeneralMessageNotification | PaymentConfirmationNotification;
|
|
2259
|
+
type Notification = PreRequirementNotification | PostRequirementNotification | RequirementInstructionDueNotification | AppointmentReminderNotification | AppointmentStatusChangeNotification | AppointmentRescheduledProposalNotification | AppointmentCancelledNotification | FormReminderNotification | FormSubmissionConfirmationNotification | ReviewRequestNotification | ProcedureRecommendationNotification | GeneralMessageNotification | PaymentConfirmationNotification;
|
|
2241
2260
|
|
|
2242
2261
|
/**
|
|
2243
2262
|
* Minimal interface for the new mailgun.js client's messages API
|
|
@@ -2676,6 +2695,20 @@ declare class AppointmentAggregationService {
|
|
|
2676
2695
|
* @param after - The appointment state after update
|
|
2677
2696
|
*/
|
|
2678
2697
|
private handleZonePhotosUpdate;
|
|
2698
|
+
/**
|
|
2699
|
+
* Checks if recommended procedures have changed between two appointment states
|
|
2700
|
+
* @param before - The appointment state before update
|
|
2701
|
+
* @param after - The appointment state after update
|
|
2702
|
+
* @returns True if recommendations have changed, false otherwise
|
|
2703
|
+
*/
|
|
2704
|
+
private hasRecommendationsChanged;
|
|
2705
|
+
/**
|
|
2706
|
+
* Handles recommended procedures update - creates notifications for newly added recommendations
|
|
2707
|
+
* @param before - The appointment state before update
|
|
2708
|
+
* @param after - The appointment state after update
|
|
2709
|
+
* @param patientProfile - The patient profile (for expo tokens)
|
|
2710
|
+
*/
|
|
2711
|
+
private handleRecommendedProceduresUpdate;
|
|
2679
2712
|
}
|
|
2680
2713
|
|
|
2681
2714
|
/**
|
package/dist/admin/index.js
CHANGED
|
@@ -489,6 +489,7 @@ var NotificationType = /* @__PURE__ */ ((NotificationType2) => {
|
|
|
489
489
|
NotificationType2["FORM_REMINDER"] = "formReminder";
|
|
490
490
|
NotificationType2["FORM_SUBMISSION_CONFIRMATION"] = "formSubmissionConfirmation";
|
|
491
491
|
NotificationType2["REVIEW_REQUEST"] = "reviewRequest";
|
|
492
|
+
NotificationType2["PROCEDURE_RECOMMENDATION"] = "procedureRecommendation";
|
|
492
493
|
NotificationType2["PAYMENT_DUE"] = "paymentDue";
|
|
493
494
|
NotificationType2["PAYMENT_CONFIRMATION"] = "paymentConfirmation";
|
|
494
495
|
NotificationType2["PAYMENT_FAILED"] = "paymentFailed";
|
|
@@ -2928,6 +2929,11 @@ var AppointmentAggregationService = class {
|
|
|
2928
2929
|
Logger.info(`[AggService] Zone photos changed for appointment ${after.id}`);
|
|
2929
2930
|
await this.handleZonePhotosUpdate(before, after);
|
|
2930
2931
|
}
|
|
2932
|
+
const recommendationsChanged = this.hasRecommendationsChanged(before, after);
|
|
2933
|
+
if (recommendationsChanged) {
|
|
2934
|
+
Logger.info(`[AggService] Recommended procedures changed for appointment ${after.id}`);
|
|
2935
|
+
await this.handleRecommendedProceduresUpdate(before, after, patientProfile);
|
|
2936
|
+
}
|
|
2931
2937
|
Logger.info(`[AggService] Successfully processed UPDATE for appointment: ${after.id}`);
|
|
2932
2938
|
} catch (error) {
|
|
2933
2939
|
Logger.error(
|
|
@@ -3960,6 +3966,104 @@ var AppointmentAggregationService = class {
|
|
|
3960
3966
|
);
|
|
3961
3967
|
}
|
|
3962
3968
|
}
|
|
3969
|
+
/**
|
|
3970
|
+
* Checks if recommended procedures have changed between two appointment states
|
|
3971
|
+
* @param before - The appointment state before update
|
|
3972
|
+
* @param after - The appointment state after update
|
|
3973
|
+
* @returns True if recommendations have changed, false otherwise
|
|
3974
|
+
*/
|
|
3975
|
+
hasRecommendationsChanged(before, after) {
|
|
3976
|
+
var _a, _b;
|
|
3977
|
+
const beforeRecommendations = ((_a = before.metadata) == null ? void 0 : _a.recommendedProcedures) || [];
|
|
3978
|
+
const afterRecommendations = ((_b = after.metadata) == null ? void 0 : _b.recommendedProcedures) || [];
|
|
3979
|
+
if (beforeRecommendations.length !== afterRecommendations.length) {
|
|
3980
|
+
return true;
|
|
3981
|
+
}
|
|
3982
|
+
for (let i = 0; i < afterRecommendations.length; i++) {
|
|
3983
|
+
const beforeRec = beforeRecommendations[i];
|
|
3984
|
+
const afterRec = afterRecommendations[i];
|
|
3985
|
+
if (!beforeRec || !afterRec) {
|
|
3986
|
+
return true;
|
|
3987
|
+
}
|
|
3988
|
+
if (beforeRec.procedure.procedureId !== afterRec.procedure.procedureId || beforeRec.note !== afterRec.note || beforeRec.timeframe.value !== afterRec.timeframe.value || beforeRec.timeframe.unit !== afterRec.timeframe.unit) {
|
|
3989
|
+
return true;
|
|
3990
|
+
}
|
|
3991
|
+
}
|
|
3992
|
+
return false;
|
|
3993
|
+
}
|
|
3994
|
+
/**
|
|
3995
|
+
* Handles recommended procedures update - creates notifications for newly added recommendations
|
|
3996
|
+
* @param before - The appointment state before update
|
|
3997
|
+
* @param after - The appointment state after update
|
|
3998
|
+
* @param patientProfile - The patient profile (for expo tokens)
|
|
3999
|
+
*/
|
|
4000
|
+
async handleRecommendedProceduresUpdate(before, after, patientProfile) {
|
|
4001
|
+
var _a, _b, _c, _d, _e;
|
|
4002
|
+
try {
|
|
4003
|
+
const beforeRecommendations = ((_a = before.metadata) == null ? void 0 : _a.recommendedProcedures) || [];
|
|
4004
|
+
const afterRecommendations = ((_b = after.metadata) == null ? void 0 : _b.recommendedProcedures) || [];
|
|
4005
|
+
const newRecommendations = afterRecommendations.slice(beforeRecommendations.length);
|
|
4006
|
+
if (newRecommendations.length === 0) {
|
|
4007
|
+
Logger.info(
|
|
4008
|
+
`[AggService] No new recommendations detected for appointment ${after.id}`
|
|
4009
|
+
);
|
|
4010
|
+
return;
|
|
4011
|
+
}
|
|
4012
|
+
Logger.info(
|
|
4013
|
+
`[AggService] Found ${newRecommendations.length} new recommendation(s) for appointment ${after.id}`
|
|
4014
|
+
);
|
|
4015
|
+
for (let i = 0; i < newRecommendations.length; i++) {
|
|
4016
|
+
const recommendation = newRecommendations[i];
|
|
4017
|
+
const recommendationIndex = beforeRecommendations.length + i;
|
|
4018
|
+
const recommendationId = `${after.id}:${recommendationIndex}`;
|
|
4019
|
+
const timeframeText = `${recommendation.timeframe.value} ${recommendation.timeframe.unit}${recommendation.timeframe.value > 1 ? "s" : ""}`;
|
|
4020
|
+
const notificationPayload = {
|
|
4021
|
+
userId: after.patientId,
|
|
4022
|
+
userRole: "patient" /* PATIENT */,
|
|
4023
|
+
notificationType: "procedureRecommendation" /* PROCEDURE_RECOMMENDATION */,
|
|
4024
|
+
notificationTime: admin6.firestore.Timestamp.now(),
|
|
4025
|
+
notificationTokens: (patientProfile == null ? void 0 : patientProfile.expoTokens) || [],
|
|
4026
|
+
title: "New Procedure Recommendation",
|
|
4027
|
+
body: `${((_c = after.practitionerInfo) == null ? void 0 : _c.name) || "Your doctor"} recommended "${recommendation.procedure.procedureName}" for you. Suggested timeframe: in ${timeframeText}`,
|
|
4028
|
+
appointmentId: after.id,
|
|
4029
|
+
recommendationId,
|
|
4030
|
+
procedureId: recommendation.procedure.procedureId,
|
|
4031
|
+
procedureName: recommendation.procedure.procedureName,
|
|
4032
|
+
practitionerName: ((_d = after.practitionerInfo) == null ? void 0 : _d.name) || "Unknown Practitioner",
|
|
4033
|
+
clinicName: ((_e = after.clinicInfo) == null ? void 0 : _e.name) || "Unknown Clinic",
|
|
4034
|
+
note: recommendation.note,
|
|
4035
|
+
timeframe: recommendation.timeframe
|
|
4036
|
+
};
|
|
4037
|
+
try {
|
|
4038
|
+
const notificationId = await this.notificationsAdmin.createNotification(
|
|
4039
|
+
notificationPayload
|
|
4040
|
+
);
|
|
4041
|
+
Logger.info(
|
|
4042
|
+
`[AggService] Created notification ${notificationId} for recommendation ${recommendationId}`
|
|
4043
|
+
);
|
|
4044
|
+
if ((patientProfile == null ? void 0 : patientProfile.expoTokens) && patientProfile.expoTokens.length > 0) {
|
|
4045
|
+
const notification = await this.notificationsAdmin.getNotification(notificationId);
|
|
4046
|
+
if (notification) {
|
|
4047
|
+
await this.notificationsAdmin.sendPushNotification(notification);
|
|
4048
|
+
Logger.info(
|
|
4049
|
+
`[AggService] Sent push notification for recommendation ${recommendationId}`
|
|
4050
|
+
);
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4053
|
+
} catch (error) {
|
|
4054
|
+
Logger.error(
|
|
4055
|
+
`[AggService] Error creating notification for recommendation ${recommendationId}:`,
|
|
4056
|
+
error
|
|
4057
|
+
);
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
} catch (error) {
|
|
4061
|
+
Logger.error(
|
|
4062
|
+
`[AggService] Error handling recommended procedures update for appointment ${after.id}:`,
|
|
4063
|
+
error
|
|
4064
|
+
);
|
|
4065
|
+
}
|
|
4066
|
+
}
|
|
3963
4067
|
};
|
|
3964
4068
|
|
|
3965
4069
|
// src/admin/aggregation/clinic/clinic.aggregation.service.ts
|
package/dist/admin/index.mjs
CHANGED
|
@@ -427,6 +427,7 @@ var NotificationType = /* @__PURE__ */ ((NotificationType2) => {
|
|
|
427
427
|
NotificationType2["FORM_REMINDER"] = "formReminder";
|
|
428
428
|
NotificationType2["FORM_SUBMISSION_CONFIRMATION"] = "formSubmissionConfirmation";
|
|
429
429
|
NotificationType2["REVIEW_REQUEST"] = "reviewRequest";
|
|
430
|
+
NotificationType2["PROCEDURE_RECOMMENDATION"] = "procedureRecommendation";
|
|
430
431
|
NotificationType2["PAYMENT_DUE"] = "paymentDue";
|
|
431
432
|
NotificationType2["PAYMENT_CONFIRMATION"] = "paymentConfirmation";
|
|
432
433
|
NotificationType2["PAYMENT_FAILED"] = "paymentFailed";
|
|
@@ -2866,6 +2867,11 @@ var AppointmentAggregationService = class {
|
|
|
2866
2867
|
Logger.info(`[AggService] Zone photos changed for appointment ${after.id}`);
|
|
2867
2868
|
await this.handleZonePhotosUpdate(before, after);
|
|
2868
2869
|
}
|
|
2870
|
+
const recommendationsChanged = this.hasRecommendationsChanged(before, after);
|
|
2871
|
+
if (recommendationsChanged) {
|
|
2872
|
+
Logger.info(`[AggService] Recommended procedures changed for appointment ${after.id}`);
|
|
2873
|
+
await this.handleRecommendedProceduresUpdate(before, after, patientProfile);
|
|
2874
|
+
}
|
|
2869
2875
|
Logger.info(`[AggService] Successfully processed UPDATE for appointment: ${after.id}`);
|
|
2870
2876
|
} catch (error) {
|
|
2871
2877
|
Logger.error(
|
|
@@ -3898,6 +3904,104 @@ var AppointmentAggregationService = class {
|
|
|
3898
3904
|
);
|
|
3899
3905
|
}
|
|
3900
3906
|
}
|
|
3907
|
+
/**
|
|
3908
|
+
* Checks if recommended procedures have changed between two appointment states
|
|
3909
|
+
* @param before - The appointment state before update
|
|
3910
|
+
* @param after - The appointment state after update
|
|
3911
|
+
* @returns True if recommendations have changed, false otherwise
|
|
3912
|
+
*/
|
|
3913
|
+
hasRecommendationsChanged(before, after) {
|
|
3914
|
+
var _a, _b;
|
|
3915
|
+
const beforeRecommendations = ((_a = before.metadata) == null ? void 0 : _a.recommendedProcedures) || [];
|
|
3916
|
+
const afterRecommendations = ((_b = after.metadata) == null ? void 0 : _b.recommendedProcedures) || [];
|
|
3917
|
+
if (beforeRecommendations.length !== afterRecommendations.length) {
|
|
3918
|
+
return true;
|
|
3919
|
+
}
|
|
3920
|
+
for (let i = 0; i < afterRecommendations.length; i++) {
|
|
3921
|
+
const beforeRec = beforeRecommendations[i];
|
|
3922
|
+
const afterRec = afterRecommendations[i];
|
|
3923
|
+
if (!beforeRec || !afterRec) {
|
|
3924
|
+
return true;
|
|
3925
|
+
}
|
|
3926
|
+
if (beforeRec.procedure.procedureId !== afterRec.procedure.procedureId || beforeRec.note !== afterRec.note || beforeRec.timeframe.value !== afterRec.timeframe.value || beforeRec.timeframe.unit !== afterRec.timeframe.unit) {
|
|
3927
|
+
return true;
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
return false;
|
|
3931
|
+
}
|
|
3932
|
+
/**
|
|
3933
|
+
* Handles recommended procedures update - creates notifications for newly added recommendations
|
|
3934
|
+
* @param before - The appointment state before update
|
|
3935
|
+
* @param after - The appointment state after update
|
|
3936
|
+
* @param patientProfile - The patient profile (for expo tokens)
|
|
3937
|
+
*/
|
|
3938
|
+
async handleRecommendedProceduresUpdate(before, after, patientProfile) {
|
|
3939
|
+
var _a, _b, _c, _d, _e;
|
|
3940
|
+
try {
|
|
3941
|
+
const beforeRecommendations = ((_a = before.metadata) == null ? void 0 : _a.recommendedProcedures) || [];
|
|
3942
|
+
const afterRecommendations = ((_b = after.metadata) == null ? void 0 : _b.recommendedProcedures) || [];
|
|
3943
|
+
const newRecommendations = afterRecommendations.slice(beforeRecommendations.length);
|
|
3944
|
+
if (newRecommendations.length === 0) {
|
|
3945
|
+
Logger.info(
|
|
3946
|
+
`[AggService] No new recommendations detected for appointment ${after.id}`
|
|
3947
|
+
);
|
|
3948
|
+
return;
|
|
3949
|
+
}
|
|
3950
|
+
Logger.info(
|
|
3951
|
+
`[AggService] Found ${newRecommendations.length} new recommendation(s) for appointment ${after.id}`
|
|
3952
|
+
);
|
|
3953
|
+
for (let i = 0; i < newRecommendations.length; i++) {
|
|
3954
|
+
const recommendation = newRecommendations[i];
|
|
3955
|
+
const recommendationIndex = beforeRecommendations.length + i;
|
|
3956
|
+
const recommendationId = `${after.id}:${recommendationIndex}`;
|
|
3957
|
+
const timeframeText = `${recommendation.timeframe.value} ${recommendation.timeframe.unit}${recommendation.timeframe.value > 1 ? "s" : ""}`;
|
|
3958
|
+
const notificationPayload = {
|
|
3959
|
+
userId: after.patientId,
|
|
3960
|
+
userRole: "patient" /* PATIENT */,
|
|
3961
|
+
notificationType: "procedureRecommendation" /* PROCEDURE_RECOMMENDATION */,
|
|
3962
|
+
notificationTime: admin6.firestore.Timestamp.now(),
|
|
3963
|
+
notificationTokens: (patientProfile == null ? void 0 : patientProfile.expoTokens) || [],
|
|
3964
|
+
title: "New Procedure Recommendation",
|
|
3965
|
+
body: `${((_c = after.practitionerInfo) == null ? void 0 : _c.name) || "Your doctor"} recommended "${recommendation.procedure.procedureName}" for you. Suggested timeframe: in ${timeframeText}`,
|
|
3966
|
+
appointmentId: after.id,
|
|
3967
|
+
recommendationId,
|
|
3968
|
+
procedureId: recommendation.procedure.procedureId,
|
|
3969
|
+
procedureName: recommendation.procedure.procedureName,
|
|
3970
|
+
practitionerName: ((_d = after.practitionerInfo) == null ? void 0 : _d.name) || "Unknown Practitioner",
|
|
3971
|
+
clinicName: ((_e = after.clinicInfo) == null ? void 0 : _e.name) || "Unknown Clinic",
|
|
3972
|
+
note: recommendation.note,
|
|
3973
|
+
timeframe: recommendation.timeframe
|
|
3974
|
+
};
|
|
3975
|
+
try {
|
|
3976
|
+
const notificationId = await this.notificationsAdmin.createNotification(
|
|
3977
|
+
notificationPayload
|
|
3978
|
+
);
|
|
3979
|
+
Logger.info(
|
|
3980
|
+
`[AggService] Created notification ${notificationId} for recommendation ${recommendationId}`
|
|
3981
|
+
);
|
|
3982
|
+
if ((patientProfile == null ? void 0 : patientProfile.expoTokens) && patientProfile.expoTokens.length > 0) {
|
|
3983
|
+
const notification = await this.notificationsAdmin.getNotification(notificationId);
|
|
3984
|
+
if (notification) {
|
|
3985
|
+
await this.notificationsAdmin.sendPushNotification(notification);
|
|
3986
|
+
Logger.info(
|
|
3987
|
+
`[AggService] Sent push notification for recommendation ${recommendationId}`
|
|
3988
|
+
);
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
} catch (error) {
|
|
3992
|
+
Logger.error(
|
|
3993
|
+
`[AggService] Error creating notification for recommendation ${recommendationId}:`,
|
|
3994
|
+
error
|
|
3995
|
+
);
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
} catch (error) {
|
|
3999
|
+
Logger.error(
|
|
4000
|
+
`[AggService] Error handling recommended procedures update for appointment ${after.id}:`,
|
|
4001
|
+
error
|
|
4002
|
+
);
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
3901
4005
|
};
|
|
3902
4006
|
|
|
3903
4007
|
// src/admin/aggregation/clinic/clinic.aggregation.service.ts
|
|
@@ -209,6 +209,12 @@ interface ICategoryService {
|
|
|
209
209
|
* });
|
|
210
210
|
*/
|
|
211
211
|
declare class CategoryService extends BaseService implements ICategoryService {
|
|
212
|
+
/**
|
|
213
|
+
* Filters out excluded categories from a list.
|
|
214
|
+
* @param categories - List of categories to filter
|
|
215
|
+
* @returns Filtered list without excluded categories
|
|
216
|
+
*/
|
|
217
|
+
private filterExcludedCategories;
|
|
212
218
|
/**
|
|
213
219
|
* Referenca na Firestore kolekciju kategorija
|
|
214
220
|
*/
|
|
@@ -294,6 +300,13 @@ declare class CategoryService extends BaseService implements ICategoryService {
|
|
|
294
300
|
* @returns Kategorija ili null ako ne postoji
|
|
295
301
|
*/
|
|
296
302
|
getById(id: string): Promise<Category | null>;
|
|
303
|
+
/**
|
|
304
|
+
* Internal method to get category by ID without filtering.
|
|
305
|
+
* Used internally for consultation procedures.
|
|
306
|
+
* @param id - ID of the category to get
|
|
307
|
+
* @returns Category or null if not found
|
|
308
|
+
*/
|
|
309
|
+
getByIdInternal(id: string): Promise<Category | null>;
|
|
297
310
|
/**
|
|
298
311
|
* Finds a category by exact name match within a specific family.
|
|
299
312
|
* Used for CSV import matching.
|
|
@@ -1900,6 +1913,12 @@ declare class RequirementService extends BaseService {
|
|
|
1900
1913
|
* });
|
|
1901
1914
|
*/
|
|
1902
1915
|
declare class SubcategoryService extends BaseService {
|
|
1916
|
+
/**
|
|
1917
|
+
* Filters out excluded subcategories from a list.
|
|
1918
|
+
* @param subcategories - List of subcategories to filter
|
|
1919
|
+
* @returns Filtered list without excluded subcategories
|
|
1920
|
+
*/
|
|
1921
|
+
private filterExcludedSubcategories;
|
|
1903
1922
|
/**
|
|
1904
1923
|
* Vraća referencu na Firestore kolekciju podkategorija za određenu kategoriju
|
|
1905
1924
|
* @param categoryId - ID roditeljske kategorije
|
|
@@ -1994,6 +2013,14 @@ declare class SubcategoryService extends BaseService {
|
|
|
1994
2013
|
* @returns Podkategorija ili null ako ne postoji
|
|
1995
2014
|
*/
|
|
1996
2015
|
getById(categoryId: string, subcategoryId: string): Promise<Subcategory | null>;
|
|
2016
|
+
/**
|
|
2017
|
+
* Internal method to get subcategory by ID without filtering.
|
|
2018
|
+
* Used internally for consultation procedures.
|
|
2019
|
+
* @param categoryId - ID of the category
|
|
2020
|
+
* @param subcategoryId - ID of the subcategory to get
|
|
2021
|
+
* @returns Subcategory or null if not found
|
|
2022
|
+
*/
|
|
2023
|
+
getByIdInternal(categoryId: string, subcategoryId: string): Promise<Subcategory | null>;
|
|
1997
2024
|
/**
|
|
1998
2025
|
* Finds a subcategory by exact name match within a specific category.
|
|
1999
2026
|
* Used for CSV import matching.
|
|
@@ -2020,6 +2047,12 @@ declare class SubcategoryService extends BaseService {
|
|
|
2020
2047
|
* Service for managing technologies.
|
|
2021
2048
|
*/
|
|
2022
2049
|
declare class TechnologyService extends BaseService implements ITechnologyService {
|
|
2050
|
+
/**
|
|
2051
|
+
* Filters out excluded technologies from a list.
|
|
2052
|
+
* @param technologies - List of technologies to filter
|
|
2053
|
+
* @returns Filtered list without excluded technologies
|
|
2054
|
+
*/
|
|
2055
|
+
private filterExcludedTechnologies;
|
|
2023
2056
|
/**
|
|
2024
2057
|
* Reference to the Firestore collection of technologies.
|
|
2025
2058
|
*/
|
|
@@ -2127,6 +2160,13 @@ declare class TechnologyService extends BaseService implements ITechnologyServic
|
|
|
2127
2160
|
* @returns The technology or null if it doesn't exist.
|
|
2128
2161
|
*/
|
|
2129
2162
|
getById(id: string): Promise<Technology | null>;
|
|
2163
|
+
/**
|
|
2164
|
+
* Internal method to get technology by ID without filtering.
|
|
2165
|
+
* Used internally for consultation procedures.
|
|
2166
|
+
* @param id - The ID of the requested technology
|
|
2167
|
+
* @returns The technology or null if it doesn't exist
|
|
2168
|
+
*/
|
|
2169
|
+
getByIdInternal(id: string): Promise<Technology | null>;
|
|
2130
2170
|
/**
|
|
2131
2171
|
* Finds a technology by exact name match.
|
|
2132
2172
|
* Used for CSV import duplicate detection.
|
|
@@ -209,6 +209,12 @@ interface ICategoryService {
|
|
|
209
209
|
* });
|
|
210
210
|
*/
|
|
211
211
|
declare class CategoryService extends BaseService implements ICategoryService {
|
|
212
|
+
/**
|
|
213
|
+
* Filters out excluded categories from a list.
|
|
214
|
+
* @param categories - List of categories to filter
|
|
215
|
+
* @returns Filtered list without excluded categories
|
|
216
|
+
*/
|
|
217
|
+
private filterExcludedCategories;
|
|
212
218
|
/**
|
|
213
219
|
* Referenca na Firestore kolekciju kategorija
|
|
214
220
|
*/
|
|
@@ -294,6 +300,13 @@ declare class CategoryService extends BaseService implements ICategoryService {
|
|
|
294
300
|
* @returns Kategorija ili null ako ne postoji
|
|
295
301
|
*/
|
|
296
302
|
getById(id: string): Promise<Category | null>;
|
|
303
|
+
/**
|
|
304
|
+
* Internal method to get category by ID without filtering.
|
|
305
|
+
* Used internally for consultation procedures.
|
|
306
|
+
* @param id - ID of the category to get
|
|
307
|
+
* @returns Category or null if not found
|
|
308
|
+
*/
|
|
309
|
+
getByIdInternal(id: string): Promise<Category | null>;
|
|
297
310
|
/**
|
|
298
311
|
* Finds a category by exact name match within a specific family.
|
|
299
312
|
* Used for CSV import matching.
|
|
@@ -1900,6 +1913,12 @@ declare class RequirementService extends BaseService {
|
|
|
1900
1913
|
* });
|
|
1901
1914
|
*/
|
|
1902
1915
|
declare class SubcategoryService extends BaseService {
|
|
1916
|
+
/**
|
|
1917
|
+
* Filters out excluded subcategories from a list.
|
|
1918
|
+
* @param subcategories - List of subcategories to filter
|
|
1919
|
+
* @returns Filtered list without excluded subcategories
|
|
1920
|
+
*/
|
|
1921
|
+
private filterExcludedSubcategories;
|
|
1903
1922
|
/**
|
|
1904
1923
|
* Vraća referencu na Firestore kolekciju podkategorija za određenu kategoriju
|
|
1905
1924
|
* @param categoryId - ID roditeljske kategorije
|
|
@@ -1994,6 +2013,14 @@ declare class SubcategoryService extends BaseService {
|
|
|
1994
2013
|
* @returns Podkategorija ili null ako ne postoji
|
|
1995
2014
|
*/
|
|
1996
2015
|
getById(categoryId: string, subcategoryId: string): Promise<Subcategory | null>;
|
|
2016
|
+
/**
|
|
2017
|
+
* Internal method to get subcategory by ID without filtering.
|
|
2018
|
+
* Used internally for consultation procedures.
|
|
2019
|
+
* @param categoryId - ID of the category
|
|
2020
|
+
* @param subcategoryId - ID of the subcategory to get
|
|
2021
|
+
* @returns Subcategory or null if not found
|
|
2022
|
+
*/
|
|
2023
|
+
getByIdInternal(categoryId: string, subcategoryId: string): Promise<Subcategory | null>;
|
|
1997
2024
|
/**
|
|
1998
2025
|
* Finds a subcategory by exact name match within a specific category.
|
|
1999
2026
|
* Used for CSV import matching.
|
|
@@ -2020,6 +2047,12 @@ declare class SubcategoryService extends BaseService {
|
|
|
2020
2047
|
* Service for managing technologies.
|
|
2021
2048
|
*/
|
|
2022
2049
|
declare class TechnologyService extends BaseService implements ITechnologyService {
|
|
2050
|
+
/**
|
|
2051
|
+
* Filters out excluded technologies from a list.
|
|
2052
|
+
* @param technologies - List of technologies to filter
|
|
2053
|
+
* @returns Filtered list without excluded technologies
|
|
2054
|
+
*/
|
|
2055
|
+
private filterExcludedTechnologies;
|
|
2023
2056
|
/**
|
|
2024
2057
|
* Reference to the Firestore collection of technologies.
|
|
2025
2058
|
*/
|
|
@@ -2127,6 +2160,13 @@ declare class TechnologyService extends BaseService implements ITechnologyServic
|
|
|
2127
2160
|
* @returns The technology or null if it doesn't exist.
|
|
2128
2161
|
*/
|
|
2129
2162
|
getById(id: string): Promise<Technology | null>;
|
|
2163
|
+
/**
|
|
2164
|
+
* Internal method to get technology by ID without filtering.
|
|
2165
|
+
* Used internally for consultation procedures.
|
|
2166
|
+
* @param id - The ID of the requested technology
|
|
2167
|
+
* @returns The technology or null if it doesn't exist
|
|
2168
|
+
*/
|
|
2169
|
+
getByIdInternal(id: string): Promise<Technology | null>;
|
|
2130
2170
|
/**
|
|
2131
2171
|
* Finds a technology by exact name match.
|
|
2132
2172
|
* Used for CSV import duplicate detection.
|