@blackcode_sa/metaestetics-api 1.14.58 → 1.14.59

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.
@@ -707,4 +707,61 @@ export class NotificationsAdmin {
707
707
  return null;
708
708
  }
709
709
  }
710
+
711
+ /**
712
+ * Sends a reminder push notification for a pending reschedule request.
713
+ * Used when a clinic has proposed a reschedule and the patient hasn't responded.
714
+ * @param appointment The appointment with pending reschedule.
715
+ * @param patientUserId The ID of the patient.
716
+ * @param patientExpoTokens Array of Expo push tokens for the patient.
717
+ * @param reminderCount Optional count of reminders already sent (for tracking).
718
+ */
719
+ async sendRescheduleReminderPush(
720
+ appointment: Appointment,
721
+ patientUserId: string,
722
+ patientExpoTokens: string[],
723
+ reminderCount?: number
724
+ ): Promise<string | null> {
725
+ if (!patientExpoTokens || patientExpoTokens.length === 0) {
726
+ console.log(
727
+ `[NotificationsAdmin] No expo tokens for patient ${patientUserId} for appointment ${appointment.id} reschedule reminder. Skipping push.`
728
+ );
729
+ return null;
730
+ }
731
+
732
+ const title = "Reminder: Reschedule Request Pending";
733
+ const body = `You have a pending reschedule request for your ${appointment.procedureInfo.name} appointment. Please respond in the app.`;
734
+
735
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
736
+
737
+ const notificationData: Omit<
738
+ Notification,
739
+ "id" | "createdAt" | "updatedAt" | "status" | "isRead"
740
+ > = {
741
+ userId: patientUserId,
742
+ userRole: UserRole.PATIENT,
743
+ notificationType: NotificationType.APPOINTMENT_RESCHEDULED_REMINDER,
744
+ notificationTime: notificationTimestampForDb as any,
745
+ notificationTokens: patientExpoTokens,
746
+ title,
747
+ body,
748
+ appointmentId: appointment.id,
749
+ };
750
+
751
+ try {
752
+ const notificationId = await this.createNotification(
753
+ notificationData as Notification
754
+ );
755
+ console.log(
756
+ `[NotificationsAdmin] Created APPOINTMENT_RESCHEDULED_REMINDER notification ${notificationId} for patient ${patientUserId}. Reminder count: ${reminderCount ?? 1}.`
757
+ );
758
+ return notificationId;
759
+ } catch (error) {
760
+ console.error(
761
+ `[NotificationsAdmin] Error creating APPOINTMENT_RESCHEDULED_REMINDER notification for patient ${patientUserId}:`,
762
+ error
763
+ );
764
+ return null;
765
+ }
766
+ }
710
767
  }
@@ -319,6 +319,9 @@ export interface Appointment {
319
319
  confirmationTime?: Timestamp | null;
320
320
  cancellationTime?: Timestamp | null;
321
321
  rescheduleTime?: Timestamp | null;
322
+ /** Reschedule reminder tracking */
323
+ rescheduleReminderSentAt?: Timestamp | null;
324
+ rescheduleReminderCount?: number;
322
325
  appointmentStartTime: Timestamp;
323
326
  appointmentEndTime: Timestamp;
324
327
  procedureActualStartTime?: Timestamp | null; // NEW: Actual start time of the procedure
@@ -418,6 +421,9 @@ export interface UpdateAppointmentData {
418
421
  confirmationTime?: Timestamp | FieldValue | null;
419
422
  cancellationTime?: Timestamp | FieldValue | null;
420
423
  rescheduleTime?: Timestamp | FieldValue | null;
424
+ /** Reschedule reminder tracking */
425
+ rescheduleReminderSentAt?: Timestamp | FieldValue | null;
426
+ rescheduleReminderCount?: number | FieldValue;
421
427
  procedureActualStartTime?: Timestamp | FieldValue | null; // NEW
422
428
  actualDurationMinutes?: number;
423
429
  cancellationReason?: string | null;
@@ -8,6 +8,7 @@ export enum NotificationType {
8
8
  APPOINTMENT_REMINDER = "appointmentReminder", // For upcoming appointments
9
9
  APPOINTMENT_STATUS_CHANGE = "appointmentStatusChange", // Generic for status changes like confirmed, checked-in etc.
10
10
  APPOINTMENT_RESCHEDULED_PROPOSAL = "appointmentRescheduledProposal", // When clinic proposes a new time
11
+ APPOINTMENT_RESCHEDULED_REMINDER = "appointmentRescheduledReminder", // Reminder for pending reschedule request
11
12
  APPOINTMENT_CANCELLED = "appointmentCancelled", // When an appointment is cancelled
12
13
 
13
14
  // --- Requirement-Driven Instructions ---
@@ -185,6 +186,18 @@ export interface AppointmentRescheduledProposalNotification
185
186
  // May include a deep link to confirm/reject reschedule.
186
187
  }
187
188
 
189
+ /**
190
+ * Notification reminding the patient about a pending reschedule request they haven't responded to.
191
+ * Example: "Reminder: You have a pending reschedule request for your [Procedure Name] appointment."
192
+ */
193
+ export interface AppointmentRescheduledReminderNotification
194
+ extends BaseNotification {
195
+ notificationType: NotificationType.APPOINTMENT_RESCHEDULED_REMINDER;
196
+ appointmentId: string; // Mandatory
197
+ procedureName?: string;
198
+ reminderCount?: number; // Number of reminders sent so far
199
+ }
200
+
188
201
  /**
189
202
  * Notification informing about a cancelled appointment.
190
203
  * Example: "Your appointment for [Procedure Name] on [Date] has been cancelled."
@@ -277,6 +290,7 @@ export type Notification =
277
290
  | AppointmentReminderNotification
278
291
  | AppointmentStatusChangeNotification
279
292
  | AppointmentRescheduledProposalNotification
293
+ | AppointmentRescheduledReminderNotification
280
294
  | AppointmentCancelledNotification
281
295
  | FormReminderNotification
282
296
  | FormSubmissionConfirmationNotification