@blackcode_sa/metaestetics-api 1.12.20 → 1.12.22

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.
@@ -2017,9 +2017,7 @@ var AppointmentAggregationService = class {
2017
2017
  );
2018
2018
  this.notificationsAdmin = new NotificationsAdmin(this.db);
2019
2019
  this.calendarAdminService = new CalendarAdminService(this.db);
2020
- this.patientRequirementsAdminService = new PatientRequirementsAdminService(
2021
- this.db
2022
- );
2020
+ this.patientRequirementsAdminService = new PatientRequirementsAdminService(this.db);
2023
2021
  Logger.info("[AppointmentAggregationService] Initialized.");
2024
2022
  }
2025
2023
  /**
@@ -2034,12 +2032,7 @@ var AppointmentAggregationService = class {
2034
2032
  `[AggService] Handling CREATE for appointment: ${appointment.id}, patient: ${appointment.patientId}, status: ${appointment.status}`
2035
2033
  );
2036
2034
  try {
2037
- const [
2038
- patientProfile,
2039
- patientSensitiveInfo,
2040
- practitionerProfile,
2041
- clinicInfo
2042
- ] = await Promise.all([
2035
+ const [patientProfile, patientSensitiveInfo, practitionerProfile, clinicInfo] = await Promise.all([
2043
2036
  this.fetchPatientProfile(appointment.patientId),
2044
2037
  this.fetchPatientSensitiveInfo(appointment.patientId),
2045
2038
  this.fetchPractitionerProfile(appointment.practitionerId),
@@ -2056,9 +2049,7 @@ var AppointmentAggregationService = class {
2056
2049
  );
2057
2050
  }
2058
2051
  if (appointment.status === "confirmed" /* CONFIRMED */) {
2059
- Logger.info(
2060
- `[AggService] Appt ${appointment.id} created as CONFIRMED.`
2061
- );
2052
+ Logger.info(`[AggService] Appt ${appointment.id} created as CONFIRMED.`);
2062
2053
  await this.createPreAppointmentRequirementInstances(appointment);
2063
2054
  if ((patientSensitiveInfo == null ? void 0 : patientSensitiveInfo.email) && patientProfile) {
2064
2055
  Logger.info(
@@ -2126,9 +2117,7 @@ var AppointmentAggregationService = class {
2126
2117
  );
2127
2118
  }
2128
2119
  }
2129
- Logger.info(
2130
- `[AggService] Successfully processed CREATE for appointment: ${appointment.id}`
2131
- );
2120
+ Logger.info(`[AggService] Successfully processed CREATE for appointment: ${appointment.id}`);
2132
2121
  } catch (error) {
2133
2122
  Logger.error(
2134
2123
  `[AggService] Critical error in handleAppointmentCreate for appointment ${appointment.id}:`,
@@ -2151,12 +2140,8 @@ var AppointmentAggregationService = class {
2151
2140
  try {
2152
2141
  const statusChanged = before.status !== after.status;
2153
2142
  const timeChanged = before.appointmentStartTime.toMillis() !== after.appointmentStartTime.toMillis() || before.appointmentEndTime.toMillis() !== after.appointmentEndTime.toMillis();
2154
- const [
2155
- patientProfile,
2156
- patientSensitiveInfo,
2157
- practitionerProfile,
2158
- clinicInfo
2159
- ] = await Promise.all([
2143
+ const zonePhotosChanged = this.hasZonePhotosChanged(before, after);
2144
+ const [patientProfile, patientSensitiveInfo, practitionerProfile, clinicInfo] = await Promise.all([
2160
2145
  this.fetchPatientProfile(after.patientId),
2161
2146
  this.fetchPatientSensitiveInfo(after.patientId),
2162
2147
  this.fetchPractitionerProfile(after.practitionerId),
@@ -2182,9 +2167,7 @@ var AppointmentAggregationService = class {
2182
2167
  recipientProfile: after.patientInfo,
2183
2168
  recipientRole: "patient"
2184
2169
  };
2185
- await this.appointmentMailingService.sendAppointmentConfirmedEmail(
2186
- emailData
2187
- );
2170
+ await this.appointmentMailingService.sendAppointmentConfirmedEmail(emailData);
2188
2171
  } else {
2189
2172
  Logger.warn(
2190
2173
  `[AggService] Cannot send confirmation email to patient ${after.patientId}: email missing.`
@@ -2215,9 +2198,7 @@ var AppointmentAggregationService = class {
2215
2198
  );
2216
2199
  }
2217
2200
  } else if (before.status === "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */ && after.status === "confirmed" /* CONFIRMED */) {
2218
- Logger.info(
2219
- `[AggService] Appt ${after.id} RESCHEDULED_BY_CLINIC -> CONFIRMED.`
2220
- );
2201
+ Logger.info(`[AggService] Appt ${after.id} RESCHEDULED_BY_CLINIC -> CONFIRMED.`);
2221
2202
  await this.updateRelatedPatientRequirementInstances(
2222
2203
  before,
2223
2204
  "supersededReschedule" /* SUPERSEDED_RESCHEDULE */
@@ -2236,9 +2217,7 @@ var AppointmentAggregationService = class {
2236
2217
  recipientProfile: after.patientInfo,
2237
2218
  recipientRole: "patient"
2238
2219
  };
2239
- await this.appointmentMailingService.sendAppointmentConfirmedEmail(
2240
- emailData
2241
- );
2220
+ await this.appointmentMailingService.sendAppointmentConfirmedEmail(emailData);
2242
2221
  }
2243
2222
  if ((patientProfile == null ? void 0 : patientProfile.expoTokens) && patientProfile.expoTokens.length > 0) {
2244
2223
  await this.notificationsAdmin.sendAppointmentConfirmedPush(
@@ -2349,21 +2328,16 @@ var AppointmentAggregationService = class {
2349
2328
  );
2350
2329
  }
2351
2330
  } else if (after.status === "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
2352
- Logger.info(
2353
- `[AggService] Appt ${after.id} status -> RESCHEDULED_BY_CLINIC.`
2354
- );
2331
+ Logger.info(`[AggService] Appt ${after.id} status -> RESCHEDULED_BY_CLINIC.`);
2355
2332
  await this.updateRelatedPatientRequirementInstances(
2356
2333
  before,
2357
2334
  // Pass the 'before' state for old requirements
2358
2335
  "supersededReschedule" /* SUPERSEDED_RESCHEDULE */
2359
2336
  );
2360
- await this.calendarAdminService.updateAppointmentCalendarEventsTime(
2361
- after,
2362
- {
2363
- start: after.appointmentStartTime,
2364
- end: after.appointmentEndTime
2365
- }
2366
- );
2337
+ await this.calendarAdminService.updateAppointmentCalendarEventsTime(after, {
2338
+ start: after.appointmentStartTime,
2339
+ end: after.appointmentEndTime
2340
+ });
2367
2341
  await this.calendarAdminService.updateAppointmentCalendarEventsStatus(
2368
2342
  after,
2369
2343
  "pending" /* PENDING */
@@ -2397,22 +2371,21 @@ var AppointmentAggregationService = class {
2397
2371
  "supersededReschedule" /* SUPERSEDED_RESCHEDULE */
2398
2372
  );
2399
2373
  await this.createPreAppointmentRequirementInstances(after);
2400
- await this.calendarAdminService.updateAppointmentCalendarEventsTime(
2401
- after,
2402
- {
2403
- start: after.appointmentStartTime,
2404
- end: after.appointmentEndTime
2405
- }
2406
- );
2374
+ await this.calendarAdminService.updateAppointmentCalendarEventsTime(after, {
2375
+ start: after.appointmentStartTime,
2376
+ end: after.appointmentEndTime
2377
+ });
2407
2378
  } else {
2408
2379
  Logger.warn(
2409
2380
  `[AggService] Independent time change detected for ${after.id} with status ${after.status}. Review implications for requirements and calendar.`
2410
2381
  );
2411
2382
  }
2412
2383
  }
2413
- Logger.info(
2414
- `[AggService] Successfully processed UPDATE for appointment: ${after.id}`
2415
- );
2384
+ if (zonePhotosChanged) {
2385
+ Logger.info(`[AggService] Zone photos changed for appointment ${after.id}`);
2386
+ await this.handleZonePhotosUpdate(before, after);
2387
+ }
2388
+ Logger.info(`[AggService] Successfully processed UPDATE for appointment: ${after.id}`);
2416
2389
  } catch (error) {
2417
2390
  Logger.error(
2418
2391
  `[AggService] Critical error in handleAppointmentUpdate for appointment ${after.id}:`,
@@ -2426,16 +2399,12 @@ var AppointmentAggregationService = class {
2426
2399
  * @returns {Promise<void>}
2427
2400
  */
2428
2401
  async handleAppointmentDelete(deletedAppointment) {
2429
- Logger.info(
2430
- `[AggService] Handling DELETE for appointment: ${deletedAppointment.id}`
2431
- );
2402
+ Logger.info(`[AggService] Handling DELETE for appointment: ${deletedAppointment.id}`);
2432
2403
  await this.updateRelatedPatientRequirementInstances(
2433
2404
  deletedAppointment,
2434
2405
  "cancelledAppointment" /* CANCELLED_APPOINTMENT */
2435
2406
  );
2436
- const patientProfile = await this.fetchPatientProfile(
2437
- deletedAppointment.patientId
2438
- );
2407
+ const patientProfile = await this.fetchPatientProfile(deletedAppointment.patientId);
2439
2408
  if (patientProfile) {
2440
2409
  await this.managePatientClinicPractitionerLinks(
2441
2410
  patientProfile,
@@ -2444,9 +2413,7 @@ var AppointmentAggregationService = class {
2444
2413
  "cancel"
2445
2414
  );
2446
2415
  }
2447
- await this.calendarAdminService.deleteAppointmentCalendarEvents(
2448
- deletedAppointment
2449
- );
2416
+ await this.calendarAdminService.deleteAppointmentCalendarEvents(deletedAppointment);
2450
2417
  }
2451
2418
  // --- Helper Methods for Aggregation Logic ---
2452
2419
  /**
@@ -2516,15 +2483,11 @@ var AppointmentAggregationService = class {
2516
2483
  `[AggService] Processing template ${template.id} (${template.name}) for appt ${appointment.id}`
2517
2484
  );
2518
2485
  const newInstanceRef = this.db.collection(PATIENTS_COLLECTION).doc(appointment.patientId).collection(PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME).doc();
2519
- Logger.debug(
2520
- `[AggService] Created doc reference: ${newInstanceRef.path}`
2521
- );
2486
+ Logger.debug(`[AggService] Created doc reference: ${newInstanceRef.path}`);
2522
2487
  const instructions = (((_a = template.timeframe) == null ? void 0 : _a.notifyAt) || []).map((notifyAtValue) => {
2523
2488
  let dueTime = appointment.appointmentStartTime;
2524
2489
  if (template.timeframe && typeof notifyAtValue === "number") {
2525
- const dueDateTime = new Date(
2526
- appointment.appointmentStartTime.toMillis()
2527
- );
2490
+ const dueDateTime = new Date(appointment.appointmentStartTime.toMillis());
2528
2491
  if (template.timeframe.unit === "days" /* DAYS */) {
2529
2492
  dueDateTime.setDate(dueDateTime.getDate() - notifyAtValue);
2530
2493
  } else if (template.timeframe.unit === "hours" /* HOURS */) {
@@ -2598,26 +2561,20 @@ var AppointmentAggregationService = class {
2598
2561
  Logger.warn(
2599
2562
  `[AggService] Batch commit reported success but documents not found! Attempting direct creation as fallback...`
2600
2563
  );
2601
- const fallbackPromises = createdInstances.map(
2602
- async ({ ref, data }) => {
2603
- try {
2604
- await ref.set(data);
2605
- Logger.info(
2606
- `[AggService] Fallback direct creation success for ${ref.id}`
2607
- );
2608
- return true;
2609
- } catch (fallbackError) {
2610
- Logger.error(
2611
- `[AggService] Fallback direct creation failed for ${ref.id}:`,
2612
- fallbackError
2613
- );
2614
- return false;
2615
- }
2564
+ const fallbackPromises = createdInstances.map(async ({ ref, data }) => {
2565
+ try {
2566
+ await ref.set(data);
2567
+ Logger.info(`[AggService] Fallback direct creation success for ${ref.id}`);
2568
+ return true;
2569
+ } catch (fallbackError) {
2570
+ Logger.error(
2571
+ `[AggService] Fallback direct creation failed for ${ref.id}:`,
2572
+ fallbackError
2573
+ );
2574
+ return false;
2616
2575
  }
2617
- );
2618
- const fallbackResults = await Promise.allSettled(
2619
- fallbackPromises
2620
- );
2576
+ });
2577
+ const fallbackResults = await Promise.allSettled(fallbackPromises);
2621
2578
  const successCount = fallbackResults.filter(
2622
2579
  (r) => r.status === "fulfilled" && r.value === true
2623
2580
  ).length;
@@ -2650,23 +2607,19 @@ var AppointmentAggregationService = class {
2650
2607
  commitError
2651
2608
  );
2652
2609
  Logger.info(`[AggService] Attempting direct creation as fallback...`);
2653
- const fallbackPromises = createdInstances.map(
2654
- async ({ ref, data }) => {
2655
- try {
2656
- await ref.set(data);
2657
- Logger.info(
2658
- `[AggService] Fallback direct creation success for ${ref.id}`
2659
- );
2660
- return true;
2661
- } catch (fallbackError) {
2662
- Logger.error(
2663
- `[AggService] Fallback direct creation failed for ${ref.id}:`,
2664
- fallbackError
2665
- );
2666
- return false;
2667
- }
2610
+ const fallbackPromises = createdInstances.map(async ({ ref, data }) => {
2611
+ try {
2612
+ await ref.set(data);
2613
+ Logger.info(`[AggService] Fallback direct creation success for ${ref.id}`);
2614
+ return true;
2615
+ } catch (fallbackError) {
2616
+ Logger.error(
2617
+ `[AggService] Fallback direct creation failed for ${ref.id}:`,
2618
+ fallbackError
2619
+ );
2620
+ return false;
2668
2621
  }
2669
- );
2622
+ });
2670
2623
  const fallbackResults = await Promise.allSettled(fallbackPromises);
2671
2624
  const successCount = fallbackResults.filter(
2672
2625
  (r) => r.status === "fulfilled" && r.value === true
@@ -2764,15 +2717,11 @@ var AppointmentAggregationService = class {
2764
2717
  `[AggService] Processing template ${template.id} (${template.name}) for appt ${appointment.id}`
2765
2718
  );
2766
2719
  const newInstanceRef = this.db.collection(PATIENTS_COLLECTION).doc(appointment.patientId).collection(PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME).doc();
2767
- Logger.debug(
2768
- `[AggService] Created doc reference: ${newInstanceRef.path}`
2769
- );
2720
+ Logger.debug(`[AggService] Created doc reference: ${newInstanceRef.path}`);
2770
2721
  const instructions = (((_a = template.timeframe) == null ? void 0 : _a.notifyAt) || []).map((notifyAtValue) => {
2771
2722
  let dueTime = appointment.appointmentEndTime;
2772
2723
  if (template.timeframe && typeof notifyAtValue === "number") {
2773
- const dueDateTime = new Date(
2774
- appointment.appointmentEndTime.toMillis()
2775
- );
2724
+ const dueDateTime = new Date(appointment.appointmentEndTime.toMillis());
2776
2725
  if (template.timeframe.unit === "days" /* DAYS */) {
2777
2726
  dueDateTime.setDate(dueDateTime.getDate() + notifyAtValue);
2778
2727
  } else if (template.timeframe.unit === "hours" /* HOURS */) {
@@ -2843,26 +2792,20 @@ var AppointmentAggregationService = class {
2843
2792
  Logger.warn(
2844
2793
  `[AggService] Batch commit reported success but documents not found! Attempting direct creation as fallback...`
2845
2794
  );
2846
- const fallbackPromises = createdInstances.map(
2847
- async ({ ref, data }) => {
2848
- try {
2849
- await ref.set(data);
2850
- Logger.info(
2851
- `[AggService] Fallback direct creation success for ${ref.id}`
2852
- );
2853
- return true;
2854
- } catch (fallbackError) {
2855
- Logger.error(
2856
- `[AggService] Fallback direct creation failed for ${ref.id}:`,
2857
- fallbackError
2858
- );
2859
- return false;
2860
- }
2795
+ const fallbackPromises = createdInstances.map(async ({ ref, data }) => {
2796
+ try {
2797
+ await ref.set(data);
2798
+ Logger.info(`[AggService] Fallback direct creation success for ${ref.id}`);
2799
+ return true;
2800
+ } catch (fallbackError) {
2801
+ Logger.error(
2802
+ `[AggService] Fallback direct creation failed for ${ref.id}:`,
2803
+ fallbackError
2804
+ );
2805
+ return false;
2861
2806
  }
2862
- );
2863
- const fallbackResults = await Promise.allSettled(
2864
- fallbackPromises
2865
- );
2807
+ });
2808
+ const fallbackResults = await Promise.allSettled(fallbackPromises);
2866
2809
  const successCount = fallbackResults.filter(
2867
2810
  (r) => r.status === "fulfilled" && r.value === true
2868
2811
  ).length;
@@ -2895,23 +2838,19 @@ var AppointmentAggregationService = class {
2895
2838
  commitError
2896
2839
  );
2897
2840
  Logger.info(`[AggService] Attempting direct creation as fallback...`);
2898
- const fallbackPromises = createdInstances.map(
2899
- async ({ ref, data }) => {
2900
- try {
2901
- await ref.set(data);
2902
- Logger.info(
2903
- `[AggService] Fallback direct creation success for ${ref.id}`
2904
- );
2905
- return true;
2906
- } catch (fallbackError) {
2907
- Logger.error(
2908
- `[AggService] Fallback direct creation failed for ${ref.id}:`,
2909
- fallbackError
2910
- );
2911
- return false;
2912
- }
2841
+ const fallbackPromises = createdInstances.map(async ({ ref, data }) => {
2842
+ try {
2843
+ await ref.set(data);
2844
+ Logger.info(`[AggService] Fallback direct creation success for ${ref.id}`);
2845
+ return true;
2846
+ } catch (fallbackError) {
2847
+ Logger.error(
2848
+ `[AggService] Fallback direct creation failed for ${ref.id}:`,
2849
+ fallbackError
2850
+ );
2851
+ return false;
2913
2852
  }
2914
- );
2853
+ });
2915
2854
  const fallbackResults = await Promise.allSettled(fallbackPromises);
2916
2855
  const successCount = fallbackResults.filter(
2917
2856
  (r) => r.status === "fulfilled" && r.value === true
@@ -3061,9 +3000,7 @@ var AppointmentAggregationService = class {
3061
3000
  updateData.doctorIds = admin6.firestore.FieldValue.arrayUnion(practitionerId);
3062
3001
  }
3063
3002
  if (!hasClinic) {
3064
- Logger.debug(
3065
- `[AggService] Adding clinic ${clinicId} to patient ${patientProfile.id}`
3066
- );
3003
+ Logger.debug(`[AggService] Adding clinic ${clinicId} to patient ${patientProfile.id}`);
3067
3004
  updateData.clinicIds = admin6.firestore.FieldValue.arrayUnion(clinicId);
3068
3005
  }
3069
3006
  await patientRef.update(updateData);
@@ -3118,28 +3055,19 @@ var AppointmentAggregationService = class {
3118
3055
  updateNeeded = true;
3119
3056
  }
3120
3057
  if (activeClinicAppointments === 0 && ((_b = patientProfile.clinicIds) == null ? void 0 : _b.includes(clinicId))) {
3121
- Logger.debug(
3122
- `[AggService] Removing clinic ${clinicId} from patient ${patientProfile.id}`
3123
- );
3058
+ Logger.debug(`[AggService] Removing clinic ${clinicId} from patient ${patientProfile.id}`);
3124
3059
  updateData.clinicIds = admin6.firestore.FieldValue.arrayRemove(clinicId);
3125
3060
  updateNeeded = true;
3126
3061
  }
3127
3062
  if (updateNeeded) {
3128
3063
  updateData.updatedAt = admin6.firestore.FieldValue.serverTimestamp();
3129
3064
  await patientRef.update(updateData);
3130
- Logger.info(
3131
- `[AggService] Successfully removed links from patient ${patientProfile.id}`
3132
- );
3065
+ Logger.info(`[AggService] Successfully removed links from patient ${patientProfile.id}`);
3133
3066
  } else {
3134
- Logger.info(
3135
- `[AggService] No links need to be removed from patient ${patientProfile.id}`
3136
- );
3067
+ Logger.info(`[AggService] No links need to be removed from patient ${patientProfile.id}`);
3137
3068
  }
3138
3069
  } catch (error) {
3139
- Logger.error(
3140
- `[AggService] Error removing links from patient profile:`,
3141
- error
3142
- );
3070
+ Logger.error(`[AggService] Error removing links from patient profile:`, error);
3143
3071
  throw error;
3144
3072
  }
3145
3073
  }
@@ -3172,10 +3100,7 @@ var AppointmentAggregationService = class {
3172
3100
  const doc = await this.db.collection(PATIENTS_COLLECTION).doc(patientId).get();
3173
3101
  return doc.exists ? doc.data() : null;
3174
3102
  } catch (error) {
3175
- Logger.error(
3176
- `[AggService] Error fetching patient profile ${patientId}:`,
3177
- error
3178
- );
3103
+ Logger.error(`[AggService] Error fetching patient profile ${patientId}:`, error);
3179
3104
  return null;
3180
3105
  }
3181
3106
  }
@@ -3188,17 +3113,12 @@ var AppointmentAggregationService = class {
3188
3113
  try {
3189
3114
  const doc = await this.db.collection(PATIENTS_COLLECTION).doc(patientId).collection(PATIENT_SENSITIVE_INFO_COLLECTION).doc(patientId).get();
3190
3115
  if (!doc.exists) {
3191
- Logger.warn(
3192
- `[AggService] No sensitive info found for patient ${patientId}`
3193
- );
3116
+ Logger.warn(`[AggService] No sensitive info found for patient ${patientId}`);
3194
3117
  return null;
3195
3118
  }
3196
3119
  return doc.data();
3197
3120
  } catch (error) {
3198
- Logger.error(
3199
- `[AggService] Error fetching patient sensitive info ${patientId}:`,
3200
- error
3201
- );
3121
+ Logger.error(`[AggService] Error fetching patient sensitive info ${patientId}:`, error);
3202
3122
  return null;
3203
3123
  }
3204
3124
  }
@@ -3209,25 +3129,18 @@ var AppointmentAggregationService = class {
3209
3129
  */
3210
3130
  async fetchPractitionerProfile(practitionerId) {
3211
3131
  if (!practitionerId) {
3212
- Logger.warn(
3213
- "[AggService] fetchPractitionerProfile called with no practitionerId."
3214
- );
3132
+ Logger.warn("[AggService] fetchPractitionerProfile called with no practitionerId.");
3215
3133
  return null;
3216
3134
  }
3217
3135
  try {
3218
3136
  const doc = await this.db.collection(PRACTITIONERS_COLLECTION).doc(practitionerId).get();
3219
3137
  if (!doc.exists) {
3220
- Logger.warn(
3221
- `[AggService] No practitioner profile found for ID ${practitionerId}`
3222
- );
3138
+ Logger.warn(`[AggService] No practitioner profile found for ID ${practitionerId}`);
3223
3139
  return null;
3224
3140
  }
3225
3141
  return doc.data();
3226
3142
  } catch (error) {
3227
- Logger.error(
3228
- `[AggService] Error fetching practitioner profile ${practitionerId}:`,
3229
- error
3230
- );
3143
+ Logger.error(`[AggService] Error fetching practitioner profile ${practitionerId}:`, error);
3231
3144
  return null;
3232
3145
  }
3233
3146
  }
@@ -3248,12 +3161,113 @@ var AppointmentAggregationService = class {
3248
3161
  return null;
3249
3162
  }
3250
3163
  return doc.data();
3164
+ } catch (error) {
3165
+ Logger.error(`[AggService] Error fetching clinic info ${clinicId}:`, error);
3166
+ return null;
3167
+ }
3168
+ }
3169
+ /**
3170
+ * Checks if zone photos have changed between two appointment states
3171
+ * @param before - The appointment state before update
3172
+ * @param after - The appointment state after update
3173
+ * @returns True if zone photos have changed, false otherwise
3174
+ */
3175
+ hasZonePhotosChanged(before, after) {
3176
+ var _a, _b;
3177
+ const beforePhotos = (_a = before.metadata) == null ? void 0 : _a.zonePhotos;
3178
+ const afterPhotos = (_b = after.metadata) == null ? void 0 : _b.zonePhotos;
3179
+ if (!beforePhotos && !afterPhotos) {
3180
+ return false;
3181
+ }
3182
+ if (!beforePhotos || !afterPhotos) {
3183
+ return true;
3184
+ }
3185
+ const beforeZones = Object.keys(beforePhotos);
3186
+ const afterZones = Object.keys(afterPhotos);
3187
+ if (beforeZones.length !== afterZones.length) {
3188
+ return true;
3189
+ }
3190
+ for (const zoneId of afterZones) {
3191
+ const beforeZonePhotos = beforePhotos[zoneId];
3192
+ const afterZonePhotos = afterPhotos[zoneId];
3193
+ if (!beforeZonePhotos && !afterZonePhotos) {
3194
+ continue;
3195
+ }
3196
+ if (!beforeZonePhotos || !afterZonePhotos) {
3197
+ return true;
3198
+ }
3199
+ if (beforeZonePhotos.before !== afterZonePhotos.before || beforeZonePhotos.after !== afterZonePhotos.after || beforeZonePhotos.beforeNote !== afterZonePhotos.beforeNote || beforeZonePhotos.afterNote !== afterZonePhotos.afterNote) {
3200
+ return true;
3201
+ }
3202
+ }
3203
+ return false;
3204
+ }
3205
+ /**
3206
+ * Handles zone photos update notifications and logging
3207
+ * @param before - The appointment state before update
3208
+ * @param after - The appointment state after update
3209
+ */
3210
+ async handleZonePhotosUpdate(before, after) {
3211
+ var _a, _b, _c;
3212
+ try {
3213
+ Logger.info(`[AggService] Processing zone photos update for appointment ${after.id}`);
3214
+ const beforePhotos = ((_a = before.metadata) == null ? void 0 : _a.zonePhotos) || {};
3215
+ const afterPhotos = ((_b = after.metadata) == null ? void 0 : _b.zonePhotos) || {};
3216
+ const updatedZones = [];
3217
+ const newPhotoTypes = [];
3218
+ for (const zoneId of Object.keys(afterPhotos)) {
3219
+ const beforeZonePhotos = beforePhotos[zoneId];
3220
+ const afterZonePhotos = afterPhotos[zoneId];
3221
+ if (!beforeZonePhotos) {
3222
+ updatedZones.push(zoneId);
3223
+ if (afterZonePhotos.before) {
3224
+ newPhotoTypes.push({ zoneId, photoType: "before" });
3225
+ }
3226
+ if (afterZonePhotos.after) {
3227
+ newPhotoTypes.push({ zoneId, photoType: "after" });
3228
+ }
3229
+ } else {
3230
+ if (beforeZonePhotos.before !== afterZonePhotos.before && afterZonePhotos.before) {
3231
+ updatedZones.push(zoneId);
3232
+ newPhotoTypes.push({ zoneId, photoType: "before" });
3233
+ }
3234
+ if (beforeZonePhotos.after !== afterZonePhotos.after && afterZonePhotos.after) {
3235
+ updatedZones.push(zoneId);
3236
+ newPhotoTypes.push({ zoneId, photoType: "after" });
3237
+ }
3238
+ }
3239
+ }
3240
+ if (updatedZones.length > 0) {
3241
+ Logger.info(
3242
+ `[AggService] Zone photos updated for appointment ${after.id}: ${updatedZones.join(
3243
+ ", "
3244
+ )}`
3245
+ );
3246
+ for (const { zoneId, photoType } of newPhotoTypes) {
3247
+ Logger.info(
3248
+ `[AggService] New ${photoType} photo added for zone ${zoneId} in appointment ${after.id}`
3249
+ );
3250
+ }
3251
+ }
3252
+ const selectedZones = ((_c = after.metadata) == null ? void 0 : _c.selectedZones) || [];
3253
+ if (selectedZones.length > 0) {
3254
+ const completedZones = selectedZones.filter((zoneId) => {
3255
+ const zonePhotos = afterPhotos[zoneId];
3256
+ return zonePhotos && (zonePhotos.before || zonePhotos.after);
3257
+ });
3258
+ const completionPercentage = completedZones.length / selectedZones.length * 100;
3259
+ Logger.info(
3260
+ `[AggService] Photo completion for appointment ${after.id}: ${completionPercentage.toFixed(1)}% (${completedZones.length}/${selectedZones.length} zones)`
3261
+ );
3262
+ if (completionPercentage === 100) {
3263
+ Logger.info(`[AggService] All zone photos completed for appointment ${after.id}`);
3264
+ }
3265
+ }
3251
3266
  } catch (error) {
3252
3267
  Logger.error(
3253
- `[AggService] Error fetching clinic info ${clinicId}:`,
3268
+ `[AggService] Error handling zone photos update for appointment ${after.id}:`,
3254
3269
  error
3255
3270
  );
3256
- return null;
3257
3271
  }
3258
3272
  }
3259
3273
  };