@blackcode_sa/metaestetics-api 1.14.56 → 1.14.58
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 +9 -2
- package/dist/admin/index.d.ts +9 -2
- package/dist/admin/index.js +366 -2
- package/dist/admin/index.mjs +366 -2
- package/dist/index.d.mts +24 -3
- package/dist/index.d.ts +24 -3
- package/dist/index.js +195 -42
- package/dist/index.mjs +324 -168
- package/package.json +1 -1
- package/src/admin/mailing/appointment/appointment.mailing.service.ts +383 -2
- package/src/services/appointment/appointment.service.ts +41 -9
- package/src/services/appointment/utils/extended-procedure.utils.ts +1 -0
- package/src/services/appointment/utils/form-initialization.utils.ts +2 -0
- package/src/services/appointment/utils/zone-management.utils.ts +50 -3
- package/src/services/appointment/utils/zone-photo.utils.ts +39 -1
- package/src/services/procedure/procedure.service.ts +137 -40
- package/src/types/appointment/index.ts +4 -2
- package/src/validations/appointment.schema.ts +2 -1
package/dist/admin/index.d.mts
CHANGED
|
@@ -1659,6 +1659,7 @@ interface LinkedFormInfo {
|
|
|
1659
1659
|
path: string;
|
|
1660
1660
|
submittedAt?: Timestamp;
|
|
1661
1661
|
completedAt?: Timestamp;
|
|
1662
|
+
procedureId?: string;
|
|
1662
1663
|
}
|
|
1663
1664
|
/**
|
|
1664
1665
|
* Interface for summarized patient review information linked to an appointment.
|
|
@@ -1713,8 +1714,8 @@ interface ZoneItemData {
|
|
|
1713
1714
|
notes?: string;
|
|
1714
1715
|
notesVisibleToPatient?: boolean;
|
|
1715
1716
|
subtotal?: number;
|
|
1716
|
-
ionNumber?: string;
|
|
1717
|
-
expiryDate?: string;
|
|
1717
|
+
ionNumber?: string | null;
|
|
1718
|
+
expiryDate?: string | null;
|
|
1718
1719
|
createdAt?: string;
|
|
1719
1720
|
updatedAt?: string;
|
|
1720
1721
|
}
|
|
@@ -1767,6 +1768,7 @@ interface ExtendedProcedureInfo {
|
|
|
1767
1768
|
procedureId: string;
|
|
1768
1769
|
procedureName: string;
|
|
1769
1770
|
procedureDescription?: string;
|
|
1771
|
+
procedurePrice?: number;
|
|
1770
1772
|
procedureFamily?: ProcedureFamily;
|
|
1771
1773
|
procedureCategoryId: string;
|
|
1772
1774
|
procedureCategoryName: string;
|
|
@@ -4673,6 +4675,11 @@ declare class AppointmentMailingService extends BaseMailingService {
|
|
|
4673
4675
|
sendAppointmentConfirmedEmail(data: AppointmentConfirmationEmailData): Promise<any>;
|
|
4674
4676
|
sendAppointmentRequestedEmailToClinic(data: AppointmentRequestedEmailData): Promise<any>;
|
|
4675
4677
|
sendAppointmentCancelledEmail(data: AppointmentCancellationEmailData): Promise<any>;
|
|
4678
|
+
/**
|
|
4679
|
+
* Sends a reschedule proposal email to the patient
|
|
4680
|
+
* @param data - Appointment reschedule proposal email data
|
|
4681
|
+
* @returns Promise with the sending result
|
|
4682
|
+
*/
|
|
4676
4683
|
sendAppointmentRescheduledProposalEmail(data: AppointmentRescheduledProposalEmailData): Promise<any>;
|
|
4677
4684
|
sendReviewRequestEmail(data: ReviewRequestEmailData): Promise<any>;
|
|
4678
4685
|
sendReviewAddedEmail(data: ReviewAddedEmailData): Promise<any>;
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -1659,6 +1659,7 @@ interface LinkedFormInfo {
|
|
|
1659
1659
|
path: string;
|
|
1660
1660
|
submittedAt?: Timestamp;
|
|
1661
1661
|
completedAt?: Timestamp;
|
|
1662
|
+
procedureId?: string;
|
|
1662
1663
|
}
|
|
1663
1664
|
/**
|
|
1664
1665
|
* Interface for summarized patient review information linked to an appointment.
|
|
@@ -1713,8 +1714,8 @@ interface ZoneItemData {
|
|
|
1713
1714
|
notes?: string;
|
|
1714
1715
|
notesVisibleToPatient?: boolean;
|
|
1715
1716
|
subtotal?: number;
|
|
1716
|
-
ionNumber?: string;
|
|
1717
|
-
expiryDate?: string;
|
|
1717
|
+
ionNumber?: string | null;
|
|
1718
|
+
expiryDate?: string | null;
|
|
1718
1719
|
createdAt?: string;
|
|
1719
1720
|
updatedAt?: string;
|
|
1720
1721
|
}
|
|
@@ -1767,6 +1768,7 @@ interface ExtendedProcedureInfo {
|
|
|
1767
1768
|
procedureId: string;
|
|
1768
1769
|
procedureName: string;
|
|
1769
1770
|
procedureDescription?: string;
|
|
1771
|
+
procedurePrice?: number;
|
|
1770
1772
|
procedureFamily?: ProcedureFamily;
|
|
1771
1773
|
procedureCategoryId: string;
|
|
1772
1774
|
procedureCategoryName: string;
|
|
@@ -4673,6 +4675,11 @@ declare class AppointmentMailingService extends BaseMailingService {
|
|
|
4673
4675
|
sendAppointmentConfirmedEmail(data: AppointmentConfirmationEmailData): Promise<any>;
|
|
4674
4676
|
sendAppointmentRequestedEmailToClinic(data: AppointmentRequestedEmailData): Promise<any>;
|
|
4675
4677
|
sendAppointmentCancelledEmail(data: AppointmentCancellationEmailData): Promise<any>;
|
|
4678
|
+
/**
|
|
4679
|
+
* Sends a reschedule proposal email to the patient
|
|
4680
|
+
* @param data - Appointment reschedule proposal email data
|
|
4681
|
+
* @returns Promise with the sending result
|
|
4682
|
+
*/
|
|
4676
4683
|
sendAppointmentRescheduledProposalEmail(data: AppointmentRescheduledProposalEmailData): Promise<any>;
|
|
4677
4684
|
sendReviewRequestEmail(data: ReviewRequestEmailData): Promise<any>;
|
|
4678
4685
|
sendReviewAddedEmail(data: ReviewAddedEmailData): Promise<any>;
|
package/dist/admin/index.js
CHANGED
|
@@ -2363,6 +2363,284 @@ var clinicAppointmentRequestedTemplate = `
|
|
|
2363
2363
|
</body>
|
|
2364
2364
|
</html>
|
|
2365
2365
|
`;
|
|
2366
|
+
var appointmentRescheduledProposalTemplate = `
|
|
2367
|
+
<!DOCTYPE html>
|
|
2368
|
+
<html lang="en">
|
|
2369
|
+
<head>
|
|
2370
|
+
<meta charset="UTF-8">
|
|
2371
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2372
|
+
<title>Appointment Reschedule Proposal</title>
|
|
2373
|
+
<style>
|
|
2374
|
+
body {
|
|
2375
|
+
margin: 0;
|
|
2376
|
+
padding: 0;
|
|
2377
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
2378
|
+
background: linear-gradient(135deg, #a48a76 0%, #67574A 100%);
|
|
2379
|
+
min-height: 100vh;
|
|
2380
|
+
}
|
|
2381
|
+
.email-container {
|
|
2382
|
+
max-width: 600px;
|
|
2383
|
+
margin: 0 auto;
|
|
2384
|
+
background: #ffffff;
|
|
2385
|
+
border-radius: 20px;
|
|
2386
|
+
overflow: hidden;
|
|
2387
|
+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
|
2388
|
+
margin-top: 40px;
|
|
2389
|
+
margin-bottom: 40px;
|
|
2390
|
+
}
|
|
2391
|
+
.header {
|
|
2392
|
+
background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
|
|
2393
|
+
padding: 40px 30px;
|
|
2394
|
+
text-align: center;
|
|
2395
|
+
color: white;
|
|
2396
|
+
}
|
|
2397
|
+
.header h1 {
|
|
2398
|
+
margin: 0;
|
|
2399
|
+
font-size: 28px;
|
|
2400
|
+
font-weight: 300;
|
|
2401
|
+
letter-spacing: 1px;
|
|
2402
|
+
}
|
|
2403
|
+
.header .subtitle {
|
|
2404
|
+
margin: 10px 0 0 0;
|
|
2405
|
+
font-size: 16px;
|
|
2406
|
+
opacity: 0.9;
|
|
2407
|
+
font-weight: 300;
|
|
2408
|
+
}
|
|
2409
|
+
.content {
|
|
2410
|
+
padding: 40px 30px;
|
|
2411
|
+
}
|
|
2412
|
+
.greeting {
|
|
2413
|
+
font-size: 18px;
|
|
2414
|
+
color: #333;
|
|
2415
|
+
margin-bottom: 25px;
|
|
2416
|
+
font-weight: 400;
|
|
2417
|
+
}
|
|
2418
|
+
.info-box {
|
|
2419
|
+
background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%);
|
|
2420
|
+
border-radius: 15px;
|
|
2421
|
+
padding: 25px;
|
|
2422
|
+
margin: 25px 0;
|
|
2423
|
+
border-left: 5px solid #ff9800;
|
|
2424
|
+
}
|
|
2425
|
+
.info-box p {
|
|
2426
|
+
margin: 0;
|
|
2427
|
+
color: #e65100;
|
|
2428
|
+
font-size: 15px;
|
|
2429
|
+
font-weight: 500;
|
|
2430
|
+
line-height: 1.6;
|
|
2431
|
+
}
|
|
2432
|
+
.time-comparison {
|
|
2433
|
+
display: grid;
|
|
2434
|
+
gap: 20px;
|
|
2435
|
+
margin: 25px 0;
|
|
2436
|
+
}
|
|
2437
|
+
.time-card {
|
|
2438
|
+
background: linear-gradient(135deg, #f8f6f5 0%, #f5f3f2 100%);
|
|
2439
|
+
border-radius: 15px;
|
|
2440
|
+
padding: 25px;
|
|
2441
|
+
border-left: 5px solid #a48a76;
|
|
2442
|
+
}
|
|
2443
|
+
.time-card.old-time {
|
|
2444
|
+
border-left-color: #9e9e9e;
|
|
2445
|
+
opacity: 0.8;
|
|
2446
|
+
}
|
|
2447
|
+
.time-card.new-time {
|
|
2448
|
+
border-left-color: #ff9800;
|
|
2449
|
+
background: linear-gradient(135deg, #fff8e1 0%, #ffe0b2 100%);
|
|
2450
|
+
}
|
|
2451
|
+
.time-label {
|
|
2452
|
+
font-size: 14px;
|
|
2453
|
+
font-weight: 600;
|
|
2454
|
+
color: #666;
|
|
2455
|
+
text-transform: uppercase;
|
|
2456
|
+
letter-spacing: 0.5px;
|
|
2457
|
+
margin-bottom: 10px;
|
|
2458
|
+
}
|
|
2459
|
+
.time-label.old {
|
|
2460
|
+
color: #757575;
|
|
2461
|
+
}
|
|
2462
|
+
.time-label.new {
|
|
2463
|
+
color: #f57c00;
|
|
2464
|
+
}
|
|
2465
|
+
.appointment-card {
|
|
2466
|
+
background: linear-gradient(135deg, #f8f6f5 0%, #f5f3f2 100%);
|
|
2467
|
+
border-radius: 15px;
|
|
2468
|
+
padding: 30px;
|
|
2469
|
+
margin: 25px 0;
|
|
2470
|
+
border-left: 5px solid #a48a76;
|
|
2471
|
+
}
|
|
2472
|
+
.appointment-title {
|
|
2473
|
+
font-size: 20px;
|
|
2474
|
+
color: #a48a76;
|
|
2475
|
+
margin-bottom: 20px;
|
|
2476
|
+
font-weight: 600;
|
|
2477
|
+
}
|
|
2478
|
+
.appointment-details {
|
|
2479
|
+
display: grid;
|
|
2480
|
+
gap: 15px;
|
|
2481
|
+
}
|
|
2482
|
+
.detail-row {
|
|
2483
|
+
display: flex;
|
|
2484
|
+
align-items: center;
|
|
2485
|
+
padding: 8px 0;
|
|
2486
|
+
}
|
|
2487
|
+
.detail-label {
|
|
2488
|
+
font-weight: 600;
|
|
2489
|
+
color: #555;
|
|
2490
|
+
min-width: 120px;
|
|
2491
|
+
font-size: 14px;
|
|
2492
|
+
}
|
|
2493
|
+
.detail-value {
|
|
2494
|
+
color: #333;
|
|
2495
|
+
font-size: 16px;
|
|
2496
|
+
font-weight: 500;
|
|
2497
|
+
}
|
|
2498
|
+
.procedure-name {
|
|
2499
|
+
color: #67574A;
|
|
2500
|
+
font-weight: 600;
|
|
2501
|
+
}
|
|
2502
|
+
.clinic-name {
|
|
2503
|
+
color: #a48a76;
|
|
2504
|
+
font-weight: 600;
|
|
2505
|
+
}
|
|
2506
|
+
.action-section {
|
|
2507
|
+
background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%);
|
|
2508
|
+
border-radius: 15px;
|
|
2509
|
+
padding: 30px;
|
|
2510
|
+
margin: 30px 0;
|
|
2511
|
+
text-align: center;
|
|
2512
|
+
border-left: 5px solid #4caf50;
|
|
2513
|
+
}
|
|
2514
|
+
.action-section h3 {
|
|
2515
|
+
margin: 0 0 15px 0;
|
|
2516
|
+
color: #2e7d32;
|
|
2517
|
+
font-weight: 600;
|
|
2518
|
+
font-size: 18px;
|
|
2519
|
+
}
|
|
2520
|
+
.action-section p {
|
|
2521
|
+
margin: 0 0 20px 0;
|
|
2522
|
+
color: #555;
|
|
2523
|
+
font-size: 15px;
|
|
2524
|
+
line-height: 1.6;
|
|
2525
|
+
}
|
|
2526
|
+
.footer {
|
|
2527
|
+
background: #f8f9fa;
|
|
2528
|
+
padding: 25px 30px;
|
|
2529
|
+
text-align: center;
|
|
2530
|
+
color: #666;
|
|
2531
|
+
font-size: 14px;
|
|
2532
|
+
border-top: 1px solid #eee;
|
|
2533
|
+
}
|
|
2534
|
+
.logo {
|
|
2535
|
+
font-size: 24px;
|
|
2536
|
+
font-weight: 700;
|
|
2537
|
+
color: white;
|
|
2538
|
+
margin-bottom: 5px;
|
|
2539
|
+
}
|
|
2540
|
+
.divider {
|
|
2541
|
+
height: 2px;
|
|
2542
|
+
background: linear-gradient(90deg, #a48a76, #67574A);
|
|
2543
|
+
margin: 25px 0;
|
|
2544
|
+
border-radius: 1px;
|
|
2545
|
+
}
|
|
2546
|
+
.icon {
|
|
2547
|
+
text-align: center;
|
|
2548
|
+
margin: 20px 0;
|
|
2549
|
+
font-size: 48px;
|
|
2550
|
+
}
|
|
2551
|
+
.arrow {
|
|
2552
|
+
text-align: center;
|
|
2553
|
+
font-size: 32px;
|
|
2554
|
+
color: #ff9800;
|
|
2555
|
+
margin: 10px 0;
|
|
2556
|
+
}
|
|
2557
|
+
</style>
|
|
2558
|
+
</head>
|
|
2559
|
+
<body>
|
|
2560
|
+
<div class="email-container">
|
|
2561
|
+
<div class="header">
|
|
2562
|
+
<div class="logo">MetaEstetics</div>
|
|
2563
|
+
<h1>Appointment Reschedule Proposal</h1>
|
|
2564
|
+
<div class="subtitle">Action Required</div>
|
|
2565
|
+
</div>
|
|
2566
|
+
|
|
2567
|
+
<div class="content">
|
|
2568
|
+
<div class="icon">\u{1F4C5}</div>
|
|
2569
|
+
|
|
2570
|
+
<div class="greeting">
|
|
2571
|
+
Dear <strong>{{patientName}}</strong>,
|
|
2572
|
+
</div>
|
|
2573
|
+
|
|
2574
|
+
<p style="color: #555; font-size: 16px; line-height: 1.6; margin-bottom: 25px;">
|
|
2575
|
+
We hope this message finds you well. We need to propose a new time for your upcoming appointment. Please review the details below and confirm if the new time works for you.
|
|
2576
|
+
</p>
|
|
2577
|
+
|
|
2578
|
+
<div class="info-box">
|
|
2579
|
+
<p><strong>\u26A0\uFE0F Important:</strong> Please respond to this reschedule proposal as soon as possible. Your appointment will remain pending until you confirm or reject the new time.</p>
|
|
2580
|
+
</div>
|
|
2581
|
+
|
|
2582
|
+
<div class="appointment-card">
|
|
2583
|
+
<div class="appointment-title">\u{1F4CB} Appointment Details</div>
|
|
2584
|
+
<div class="appointment-details">
|
|
2585
|
+
<div class="detail-row">
|
|
2586
|
+
<div class="detail-label">Procedure:</div>
|
|
2587
|
+
<div class="detail-value procedure-name">{{procedureName}}</div>
|
|
2588
|
+
</div>
|
|
2589
|
+
<div class="detail-row">
|
|
2590
|
+
<div class="detail-label">Practitioner:</div>
|
|
2591
|
+
<div class="detail-value">{{practitionerName}}</div>
|
|
2592
|
+
</div>
|
|
2593
|
+
<div class="detail-row">
|
|
2594
|
+
<div class="detail-label">Location:</div>
|
|
2595
|
+
<div class="detail-value clinic-name">{{clinicName}}</div>
|
|
2596
|
+
</div>
|
|
2597
|
+
</div>
|
|
2598
|
+
</div>
|
|
2599
|
+
|
|
2600
|
+
<div class="time-comparison">
|
|
2601
|
+
<div class="time-card old-time">
|
|
2602
|
+
<div class="time-label old">Previous Time</div>
|
|
2603
|
+
<div style="font-size: 18px; font-weight: 600; color: #424242; margin-bottom: 8px;">{{previousDate}}</div>
|
|
2604
|
+
<div style="font-size: 16px; color: #616161;">{{previousTime}}</div>
|
|
2605
|
+
</div>
|
|
2606
|
+
|
|
2607
|
+
<div class="arrow">\u2193</div>
|
|
2608
|
+
|
|
2609
|
+
<div class="time-card new-time">
|
|
2610
|
+
<div class="time-label new">Proposed New Time</div>
|
|
2611
|
+
<div style="font-size: 18px; font-weight: 600; color: #e65100; margin-bottom: 8px;">{{newDate}}</div>
|
|
2612
|
+
<div style="font-size: 16px; color: #f57c00; font-weight: 500;">{{newTime}}</div>
|
|
2613
|
+
</div>
|
|
2614
|
+
</div>
|
|
2615
|
+
|
|
2616
|
+
<div class="divider"></div>
|
|
2617
|
+
|
|
2618
|
+
<div class="action-section">
|
|
2619
|
+
<h3>What's Next?</h3>
|
|
2620
|
+
<p>
|
|
2621
|
+
Please open the MetaEstetics app to accept or reject this reschedule proposal.
|
|
2622
|
+
If the new time works for you, simply tap "Accept Reschedule".
|
|
2623
|
+
If not, you can reject it and we'll work with you to find an alternative time.
|
|
2624
|
+
</p>
|
|
2625
|
+
</div>
|
|
2626
|
+
|
|
2627
|
+
<p style="color: #555; font-size: 14px; line-height: 1.6; margin-top: 25px;">
|
|
2628
|
+
<strong>Need Help?</strong> If you have any questions or concerns about this reschedule, please contact us directly through the app or reach out to {{clinicName}}.
|
|
2629
|
+
</p>
|
|
2630
|
+
</div>
|
|
2631
|
+
|
|
2632
|
+
<div class="footer">
|
|
2633
|
+
<p style="margin: 0 0 10px 0;">
|
|
2634
|
+
<strong>MetaEstetics</strong> - Premium Aesthetic Services
|
|
2635
|
+
</p>
|
|
2636
|
+
<p style="margin: 0; font-size: 12px; color: #999;">
|
|
2637
|
+
This is an automated message. Please do not reply to this email.
|
|
2638
|
+
</p>
|
|
2639
|
+
</div>
|
|
2640
|
+
</div>
|
|
2641
|
+
</body>
|
|
2642
|
+
</html>
|
|
2643
|
+
`;
|
|
2366
2644
|
var AppointmentMailingService = class extends BaseMailingService {
|
|
2367
2645
|
constructor(firestore19, mailgunClient) {
|
|
2368
2646
|
super(firestore19, mailgunClient);
|
|
@@ -2567,11 +2845,97 @@ var AppointmentMailingService = class extends BaseMailingService {
|
|
|
2567
2845
|
);
|
|
2568
2846
|
return Promise.resolve();
|
|
2569
2847
|
}
|
|
2848
|
+
/**
|
|
2849
|
+
* Sends a reschedule proposal email to the patient
|
|
2850
|
+
* @param data - Appointment reschedule proposal email data
|
|
2851
|
+
* @returns Promise with the sending result
|
|
2852
|
+
*/
|
|
2570
2853
|
async sendAppointmentRescheduledProposalEmail(data) {
|
|
2854
|
+
var _a, _b, _c, _d;
|
|
2571
2855
|
Logger.info(
|
|
2572
|
-
`[AppointmentMailingService]
|
|
2856
|
+
`[AppointmentMailingService] Preparing to send reschedule proposal email to patient: ${data.patientProfile.id}`
|
|
2573
2857
|
);
|
|
2574
|
-
|
|
2858
|
+
const recipientEmail = data.patientProfile.email;
|
|
2859
|
+
if (!recipientEmail) {
|
|
2860
|
+
Logger.error("[AppointmentMailingService] Patient email not found for reschedule proposal.", {
|
|
2861
|
+
patientId: data.patientProfile.id
|
|
2862
|
+
});
|
|
2863
|
+
throw new Error("Patient email address is missing.");
|
|
2864
|
+
}
|
|
2865
|
+
const clinicTimezone = data.appointment.clinic_tz || "UTC";
|
|
2866
|
+
Logger.debug("[AppointmentMailingService] Formatting appointment times for reschedule", {
|
|
2867
|
+
clinicTimezone,
|
|
2868
|
+
previousTime: data.previousStartTime.toDate().toISOString(),
|
|
2869
|
+
newTime: data.appointment.appointmentStartTime.toDate().toISOString()
|
|
2870
|
+
});
|
|
2871
|
+
const previousFormattedTime = this.formatTimestampInClinicTimezone(
|
|
2872
|
+
data.previousStartTime,
|
|
2873
|
+
clinicTimezone,
|
|
2874
|
+
"time"
|
|
2875
|
+
);
|
|
2876
|
+
const previousFormattedDate = this.formatTimestampInClinicTimezone(
|
|
2877
|
+
data.previousStartTime,
|
|
2878
|
+
clinicTimezone,
|
|
2879
|
+
"date"
|
|
2880
|
+
);
|
|
2881
|
+
const previousTimezoneName = this.getTimezoneDisplayName(clinicTimezone);
|
|
2882
|
+
const newFormattedTime = this.formatTimestampInClinicTimezone(
|
|
2883
|
+
data.appointment.appointmentStartTime,
|
|
2884
|
+
clinicTimezone,
|
|
2885
|
+
"time"
|
|
2886
|
+
);
|
|
2887
|
+
const newFormattedDate = this.formatTimestampInClinicTimezone(
|
|
2888
|
+
data.appointment.appointmentStartTime,
|
|
2889
|
+
clinicTimezone,
|
|
2890
|
+
"date"
|
|
2891
|
+
);
|
|
2892
|
+
const newTimezoneName = this.getTimezoneDisplayName(clinicTimezone);
|
|
2893
|
+
const templateVariables = {
|
|
2894
|
+
patientName: data.appointment.patientInfo.fullName,
|
|
2895
|
+
procedureName: data.appointment.procedureInfo.name,
|
|
2896
|
+
practitionerName: data.appointment.practitionerInfo.name,
|
|
2897
|
+
clinicName: data.appointment.clinicInfo.name,
|
|
2898
|
+
previousDate: previousFormattedDate,
|
|
2899
|
+
previousTime: `${previousFormattedTime} (${previousTimezoneName})`,
|
|
2900
|
+
newDate: newFormattedDate,
|
|
2901
|
+
newTime: `${newFormattedTime} (${newTimezoneName})`
|
|
2902
|
+
};
|
|
2903
|
+
const html = this.renderTemplate(appointmentRescheduledProposalTemplate, templateVariables);
|
|
2904
|
+
const subject = ((_a = data.options) == null ? void 0 : _a.customSubject) || `Action Required: Reschedule Proposal for Your ${data.appointment.procedureInfo.name} Appointment`;
|
|
2905
|
+
const fromAddress = ((_b = data.options) == null ? void 0 : _b.fromAddress) || `MetaEstetics <no-reply@${((_c = data.options) == null ? void 0 : _c.mailgunDomain) || this.DEFAULT_MAILGUN_DOMAIN}>`;
|
|
2906
|
+
const domainToSendFrom = ((_d = data.options) == null ? void 0 : _d.mailgunDomain) || this.DEFAULT_MAILGUN_DOMAIN;
|
|
2907
|
+
const mailgunSendData = {
|
|
2908
|
+
to: recipientEmail,
|
|
2909
|
+
from: fromAddress,
|
|
2910
|
+
subject,
|
|
2911
|
+
html
|
|
2912
|
+
};
|
|
2913
|
+
try {
|
|
2914
|
+
const result = await this.sendEmail(domainToSendFrom, mailgunSendData);
|
|
2915
|
+
await this.logEmailAttempt(
|
|
2916
|
+
{ to: recipientEmail, subject, templateName: "appointment_rescheduled_proposal" },
|
|
2917
|
+
true
|
|
2918
|
+
);
|
|
2919
|
+
Logger.info(
|
|
2920
|
+
`[AppointmentMailingService] Successfully sent reschedule proposal email to ${recipientEmail}`
|
|
2921
|
+
);
|
|
2922
|
+
return result;
|
|
2923
|
+
} catch (error) {
|
|
2924
|
+
await this.logEmailAttempt(
|
|
2925
|
+
{
|
|
2926
|
+
to: recipientEmail,
|
|
2927
|
+
subject,
|
|
2928
|
+
templateName: "appointment_rescheduled_proposal"
|
|
2929
|
+
},
|
|
2930
|
+
false,
|
|
2931
|
+
error
|
|
2932
|
+
);
|
|
2933
|
+
Logger.error(
|
|
2934
|
+
`[AppointmentMailingService] Error sending reschedule proposal email to ${recipientEmail}:`,
|
|
2935
|
+
error
|
|
2936
|
+
);
|
|
2937
|
+
throw error;
|
|
2938
|
+
}
|
|
2575
2939
|
}
|
|
2576
2940
|
async sendReviewRequestEmail(data) {
|
|
2577
2941
|
Logger.info(
|