@blackcode_sa/metaestetics-api 1.14.63 → 1.14.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.
@@ -1978,195 +1978,139 @@ var patientAppointmentConfirmedTemplate = `
1978
1978
  <meta charset="UTF-8">
1979
1979
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1980
1980
  <title>Appointment Confirmed</title>
1981
- <style>
1982
- body {
1983
- margin: 0;
1984
- padding: 0;
1985
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
1986
- background: linear-gradient(135deg, #a48a76 0%, #67574A 100%);
1987
- min-height: 100vh;
1988
- }
1989
- .email-container {
1990
- max-width: 600px;
1991
- margin: 0 auto;
1992
- background: #ffffff;
1993
- border-radius: 20px;
1994
- overflow: hidden;
1995
- box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
1996
- margin-top: 40px;
1997
- margin-bottom: 40px;
1998
- }
1999
- .header {
2000
- background: linear-gradient(135deg, #a48a76 0%, #67574A 100%);
2001
- padding: 40px 30px;
2002
- text-align: center;
2003
- color: white;
2004
- }
2005
- .header h1 {
2006
- margin: 0;
2007
- font-size: 28px;
2008
- font-weight: 300;
2009
- letter-spacing: 1px;
2010
- }
2011
- .header .subtitle {
2012
- margin: 10px 0 0 0;
2013
- font-size: 16px;
2014
- opacity: 0.9;
2015
- font-weight: 300;
2016
- }
2017
- .content {
2018
- padding: 40px 30px;
2019
- }
2020
- .greeting {
2021
- font-size: 18px;
2022
- color: #333;
2023
- margin-bottom: 25px;
2024
- font-weight: 400;
2025
- }
2026
- .appointment-card {
2027
- background: linear-gradient(135deg, #f8f6f5 0%, #f5f3f2 100%);
2028
- border-radius: 15px;
2029
- padding: 30px;
2030
- margin: 25px 0;
2031
- border-left: 5px solid #a48a76;
2032
- }
2033
- .appointment-title {
2034
- font-size: 20px;
2035
- color: #a48a76;
2036
- margin-bottom: 20px;
2037
- font-weight: 600;
2038
- }
2039
- .appointment-details {
2040
- display: grid;
2041
- gap: 15px;
2042
- }
2043
- .detail-row {
2044
- display: flex;
2045
- align-items: center;
2046
- padding: 8px 0;
2047
- }
2048
- .detail-label {
2049
- font-weight: 600;
2050
- color: #555;
2051
- min-width: 120px;
2052
- font-size: 14px;
2053
- }
2054
- .detail-value {
2055
- color: #333;
2056
- font-size: 16px;
2057
- font-weight: 500;
2058
- }
2059
- .procedure-name {
2060
- color: #67574A;
2061
- font-weight: 600;
2062
- }
2063
- .clinic-name {
2064
- color: #a48a76;
2065
- font-weight: 600;
2066
- }
2067
- .success-icon {
2068
- text-align: center;
2069
- margin: 20px 0;
2070
- font-size: 48px;
2071
- }
2072
- .footer {
2073
- background: #f8f9fa;
2074
- padding: 25px 30px;
2075
- text-align: center;
2076
- color: #666;
2077
- font-size: 14px;
2078
- border-top: 1px solid #eee;
2079
- }
2080
- .logo {
2081
- font-size: 24px;
2082
- font-weight: 700;
2083
- color: white;
2084
- margin-bottom: 5px;
2085
- }
2086
- .divider {
2087
- height: 2px;
2088
- background: linear-gradient(90deg, #a48a76, #67574A);
2089
- margin: 25px 0;
2090
- border-radius: 1px;
2091
- }
2092
- .thank-you {
2093
- background: linear-gradient(135deg, #f0ede8 0%, #ebe6e0 100%);
2094
- border-radius: 15px;
2095
- padding: 25px;
2096
- margin: 25px 0;
2097
- text-align: center;
2098
- border-left: 5px solid #4CAF50;
2099
- }
2100
- </style>
1981
+ <!--[if mso]>
1982
+ <noscript>
1983
+ <xml>
1984
+ <o:OfficeDocumentSettings>
1985
+ <o:PixelsPerInch>96</o:PixelsPerInch>
1986
+ </o:OfficeDocumentSettings>
1987
+ </xml>
1988
+ </noscript>
1989
+ <![endif]-->
2101
1990
  </head>
2102
- <body>
2103
- <div class="email-container">
2104
- <div class="header">
2105
- <div class="logo">MetaEstetics</div>
2106
- <h1>Appointment Confirmed</h1>
2107
- <div class="subtitle">Your Beauty Journey Awaits</div>
2108
- </div>
2109
-
2110
- <div class="content">
2111
- <div class="success-icon">\u2728</div>
2112
-
2113
- <div class="greeting">
2114
- Dear <strong>{{patientName}}</strong>,
2115
- </div>
2116
-
2117
- <p style="color: #555; font-size: 16px; line-height: 1.6; margin-bottom: 25px;">
2118
- We're delighted to confirm your appointment! Your journey to enhanced beauty and confidence is just around the corner.
2119
- </p>
2120
-
2121
- <div class="appointment-card">
2122
- <div class="appointment-title">\u{1F4C5} Your Appointment Details</div>
2123
- <div class="appointment-details">
2124
- <div class="detail-row">
2125
- <div class="detail-label">Procedure:</div>
2126
- <div class="detail-value procedure-name">{{procedureName}}</div>
2127
- </div>
2128
- <div class="detail-row">
2129
- <div class="detail-label">Date:</div>
2130
- <div class="detail-value">{{appointmentDate}}</div>
2131
- </div>
2132
- <div class="detail-row">
2133
- <div class="detail-label">Time:</div>
2134
- <div class="detail-value">{{appointmentTime}}</div>
2135
- </div>
2136
- <div class="detail-row">
2137
- <div class="detail-label">Practitioner:</div>
2138
- <div class="detail-value">{{practitionerName}}</div>
2139
- </div>
2140
- <div class="detail-row">
2141
- <div class="detail-label">Location:</div>
2142
- <div class="detail-value clinic-name">{{clinicName}}</div>
2143
- </div>
2144
- </div>
2145
- </div>
2146
-
2147
- <div class="divider"></div>
2148
-
2149
- <div class="thank-you">
2150
- <h3 style="margin: 0 0 10px 0; color: #4caf50; font-weight: 600;">Thank You for Choosing MetaEstetics!</h3>
2151
- <p style="margin: 0; color: #555; font-size: 14px;">
2152
- We look forward to providing you with exceptional care and outstanding results.
2153
- </p>
2154
- </div>
2155
-
2156
- <p style="color: #555; font-size: 14px; line-height: 1.6; margin-top: 25px;">
2157
- <strong>Important:</strong> Please arrive 15 minutes early for your appointment. If you need to reschedule or have any questions, please contact us as soon as possible.
2158
- </p>
2159
- </div>
2160
-
2161
- <div class="footer">
2162
- <p style="margin: 0 0 10px 0;">
2163
- <strong>MetaEstetics</strong> - Premium Aesthetic Services
2164
- </p>
2165
- <p style="margin: 0; font-size: 12px; color: #999;">
2166
- This is an automated message. Please do not reply to this email.
2167
- </p>
2168
- </div>
2169
- </div>
1991
+ <body style="margin: 0; padding: 0; background-color: #f8f6f5; font-family: Georgia, 'Times New Roman', serif;">
1992
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="background-color: #f8f6f5;">
1993
+ <tr>
1994
+ <td align="center" style="padding: 40px 20px;">
1995
+ <table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0" style="max-width: 600px; background-color: #ffffff; border-radius: 2px; box-shadow: 0 1px 3px rgba(103, 87, 74, 0.08);">
1996
+
1997
+ <!-- Header -->
1998
+ <tr>
1999
+ <td style="padding: 48px 48px 32px 48px; border-bottom: 1px solid #f0ebe6;">
2000
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
2001
+ <tr>
2002
+ <td>
2003
+ <h1 style="margin: 0; font-size: 24px; font-weight: 400; color: #67574A; letter-spacing: 2px; text-transform: uppercase; font-family: Georgia, 'Times New Roman', serif;">MetaEstetics</h1>
2004
+ </td>
2005
+ </tr>
2006
+ </table>
2007
+ </td>
2008
+ </tr>
2009
+
2010
+ <!-- Confirmed Banner -->
2011
+ <tr>
2012
+ <td style="padding: 0;">
2013
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="background-color: #00BB38;">
2014
+ <tr>
2015
+ <td style="padding: 20px 48px;">
2016
+ <p style="margin: 0; font-size: 13px; font-weight: 600; color: #ffffff; letter-spacing: 1.5px; text-transform: uppercase; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Appointment Confirmed</p>
2017
+ </td>
2018
+ </tr>
2019
+ </table>
2020
+ </td>
2021
+ </tr>
2022
+
2023
+ <!-- Main Content -->
2024
+ <tr>
2025
+ <td style="padding: 40px 48px;">
2026
+
2027
+ <!-- Greeting -->
2028
+ <p style="margin: 0 0 24px 0; font-size: 17px; color: #333333; line-height: 1.6; font-family: Georgia, 'Times New Roman', serif;">
2029
+ Dear {{patientName}},
2030
+ </p>
2031
+
2032
+ <p style="margin: 0 0 32px 0; font-size: 16px; color: #555555; line-height: 1.7; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
2033
+ Your appointment has been confirmed. We look forward to seeing you.
2034
+ </p>
2035
+
2036
+ <!-- Appointment Details Card -->
2037
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-bottom: 32px; background-color: #faf9f7; border-left: 3px solid #00BB38;">
2038
+ <tr>
2039
+ <td style="padding: 24px;">
2040
+ <p style="margin: 0 0 4px 0; font-size: 11px; font-weight: 600; color: #868686; letter-spacing: 1px; text-transform: uppercase; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Procedure</p>
2041
+ <p style="margin: 0 0 20px 0; font-size: 18px; color: #67574A; font-weight: 500; font-family: Georgia, 'Times New Roman', serif;">{{procedureName}}</p>
2042
+
2043
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
2044
+ <tr>
2045
+ <td style="padding-bottom: 16px;">
2046
+ <p style="margin: 0 0 2px 0; font-size: 11px; color: #868686; text-transform: uppercase; letter-spacing: 0.5px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Date & Time</p>
2047
+ <p style="margin: 0; font-size: 15px; color: #333333; font-weight: 500; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">{{appointmentDate}}</p>
2048
+ <p style="margin: 4px 0 0 0; font-size: 14px; color: #67574A; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">{{appointmentTime}}</p>
2049
+ </td>
2050
+ </tr>
2051
+ <tr>
2052
+ <td style="padding-bottom: 16px;">
2053
+ <p style="margin: 0 0 2px 0; font-size: 11px; color: #868686; text-transform: uppercase; letter-spacing: 0.5px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Practitioner</p>
2054
+ <p style="margin: 0; font-size: 15px; color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">{{practitionerName}}</p>
2055
+ </td>
2056
+ </tr>
2057
+ <tr>
2058
+ <td>
2059
+ <p style="margin: 0 0 2px 0; font-size: 11px; color: #868686; text-transform: uppercase; letter-spacing: 0.5px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Location</p>
2060
+ <p style="margin: 0; font-size: 15px; color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">{{clinicName}}</p>
2061
+ </td>
2062
+ </tr>
2063
+ </table>
2064
+ </td>
2065
+ </tr>
2066
+ </table>
2067
+
2068
+ <!-- Divider -->
2069
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-bottom: 32px;">
2070
+ <tr>
2071
+ <td style="height: 1px; background-color: #e8e4df;"></td>
2072
+ </tr>
2073
+ </table>
2074
+
2075
+ <!-- Important Notice -->
2076
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-bottom: 24px;">
2077
+ <tr>
2078
+ <td style="padding: 20px 24px; background-color: #faf9f7; border-left: 3px solid #a48a76;">
2079
+ <p style="margin: 0 0 8px 0; font-size: 13px; font-weight: 600; color: #67574A; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Before Your Visit</p>
2080
+ <p style="margin: 0; font-size: 14px; color: #555555; line-height: 1.6; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
2081
+ Please arrive 15 minutes early. If you need to reschedule or cancel, contact us through the MetaEstetics app.
2082
+ </p>
2083
+ </td>
2084
+ </tr>
2085
+ </table>
2086
+
2087
+ <!-- Thank You -->
2088
+ <p style="margin: 0; font-size: 14px; color: #868686; line-height: 1.7; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
2089
+ Thank you for choosing {{clinicName}}. We look forward to providing you with exceptional care.
2090
+ </p>
2091
+
2092
+ </td>
2093
+ </tr>
2094
+
2095
+ <!-- Footer -->
2096
+ <tr>
2097
+ <td style="padding: 32px 48px; background-color: #faf9f7; border-top: 1px solid #f0ebe6;">
2098
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
2099
+ <tr>
2100
+ <td>
2101
+ <p style="margin: 0 0 8px 0; font-size: 14px; font-weight: 500; color: #67574A; font-family: Georgia, 'Times New Roman', serif;">{{clinicName}}</p>
2102
+ <p style="margin: 0 0 16px 0; font-size: 13px; color: #868686; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Premium Aesthetic Services</p>
2103
+ <p style="margin: 0; font-size: 11px; color: #aaaaaa; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">This is an automated message from MetaEstetics. Please do not reply directly to this email.</p>
2104
+ </td>
2105
+ </tr>
2106
+ </table>
2107
+ </td>
2108
+ </tr>
2109
+
2110
+ </table>
2111
+ </td>
2112
+ </tr>
2113
+ </table>
2170
2114
  </body>
2171
2115
  </html>
2172
2116
  `;
@@ -2499,27 +2443,20 @@ var appointmentCancelledTemplate = `
2499
2443
  </table>
2500
2444
 
2501
2445
  <!-- Rebook Section -->
2502
- <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-bottom: 32px; background-color: #f0faf4; border-left: 3px solid #00BB38;">
2446
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-bottom: 24px; background-color: #f0faf4; border-left: 3px solid #00BB38;">
2503
2447
  <tr>
2504
- <td style="padding: 28px;">
2505
- <p style="margin: 0 0 12px 0; font-size: 15px; font-weight: 600; color: #00BB38; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Book a New Appointment</p>
2506
- <p style="margin: 0 0 20px 0; font-size: 14px; color: #555555; line-height: 1.7; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
2507
- We'd love to see you. Open the MetaEstetics app to browse available times and book a new appointment.
2448
+ <td style="padding: 24px;">
2449
+ <p style="margin: 0 0 8px 0; font-size: 14px; font-weight: 600; color: #00BB38; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Book a New Appointment</p>
2450
+ <p style="margin: 0; font-size: 14px; color: #555555; line-height: 1.6; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
2451
+ We'd love to see you again. Open the MetaEstetics app to browse available times and book a new appointment.
2508
2452
  </p>
2509
- <table role="presentation" cellspacing="0" cellpadding="0" border="0">
2510
- <tr>
2511
- <td style="background-color: #67574A; border-radius: 2px;">
2512
- <a href="#" style="display: inline-block; padding: 14px 32px; font-size: 13px; font-weight: 600; color: #ffffff; text-decoration: none; letter-spacing: 0.5px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Book New Appointment</a>
2513
- </td>
2514
- </tr>
2515
- </table>
2516
2453
  </td>
2517
2454
  </tr>
2518
2455
  </table>
2519
2456
 
2520
2457
  <!-- Support Info -->
2521
2458
  <p style="margin: 0; font-size: 13px; color: #868686; line-height: 1.7; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
2522
- If you have any questions about this cancellation, please contact {{clinicName}} directly through the app.
2459
+ If you have any questions about this cancellation, please contact {{clinicName}} through the MetaEstetics app.
2523
2460
  </p>
2524
2461
 
2525
2462
  </td>
@@ -2659,31 +2596,18 @@ var appointmentRescheduledProposalTemplate = `
2659
2596
  <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-bottom: 32px; background-color: #faf9f7;">
2660
2597
  <tr>
2661
2598
  <td style="padding: 28px;">
2662
- <p style="margin: 0 0 16px 0; font-size: 15px; font-weight: 600; color: #67574A; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">How to Respond</p>
2663
- <p style="margin: 0 0 16px 0; font-size: 14px; color: #555555; line-height: 1.7; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
2599
+ <p style="margin: 0 0 8px 0; font-size: 14px; font-weight: 600; color: #67574A; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">How to Respond</p>
2600
+ <p style="margin: 0; font-size: 14px; color: #555555; line-height: 1.6; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
2664
2601
  Open the MetaEstetics app to accept or decline this reschedule request. Your appointment will remain pending until you respond.
2665
2602
  </p>
2666
- <table role="presentation" cellspacing="0" cellpadding="0" border="0">
2667
- <tr>
2668
- <td style="background-color: #67574A; border-radius: 2px;">
2669
- <a href="#" style="display: inline-block; padding: 14px 32px; font-size: 13px; font-weight: 600; color: #ffffff; text-decoration: none; letter-spacing: 0.5px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">Open App</a>
2670
- </td>
2671
- </tr>
2672
- </table>
2673
2603
  </td>
2674
2604
  </tr>
2675
2605
  </table>
2676
2606
 
2677
- <!-- Pending Notice -->
2678
- <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
2679
- <tr>
2680
- <td style="padding: 16px 20px; background-color: #fff8f0; border: 1px solid #f0e6d9; border-radius: 2px;">
2681
- <p style="margin: 0; font-size: 13px; color: #a48a76; line-height: 1.6; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
2682
- <strong>Status:</strong> Pending your response. Please respond as soon as possible so we can confirm your appointment.
2683
- </p>
2684
- </td>
2685
- </tr>
2686
- </table>
2607
+ <!-- Response Notice -->
2608
+ <p style="margin: 0; font-size: 13px; color: #868686; line-height: 1.6; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
2609
+ Please respond at your earliest convenience so we can finalize your appointment. If you have questions, contact {{clinicName}} through the app.
2610
+ </p>
2687
2611
 
2688
2612
  </td>
2689
2613
  </tr>
@@ -3131,6 +3055,11 @@ var AppointmentMailingService = class extends BaseMailingService {
3131
3055
  };
3132
3056
 
3133
3057
  // src/admin/aggregation/appointment/appointment.aggregation.service.ts
3058
+ function sanitizeCancellationReason(reason) {
3059
+ if (!reason) return void 0;
3060
+ const isLikelyId = !reason.includes(" ") && /^[a-zA-Z0-9_-]+$/.test(reason) && reason.length > 15;
3061
+ return isLikelyId ? void 0 : reason;
3062
+ }
3134
3063
  var AppointmentAggregationService = class {
3135
3064
  /**
3136
3065
  * Constructor for AppointmentAggregationService.
@@ -3412,7 +3341,7 @@ var AppointmentAggregationService = class {
3412
3341
  appointment: after,
3413
3342
  recipientProfile: after.patientInfo,
3414
3343
  recipientRole: "patient",
3415
- cancellationReason: after.cancellationReason
3344
+ cancellationReason: sanitizeCancellationReason(after.cancellationReason)
3416
3345
  };
3417
3346
  await this.appointmentMailingService.sendAppointmentCancelledEmail(
3418
3347
  patientCancellationData
@@ -3426,7 +3355,7 @@ var AppointmentAggregationService = class {
3426
3355
  appointment: after,
3427
3356
  recipientProfile: after.practitionerInfo,
3428
3357
  recipientRole: "practitioner",
3429
- cancellationReason: after.cancellationReason
3358
+ cancellationReason: sanitizeCancellationReason(after.cancellationReason)
3430
3359
  };
3431
3360
  await this.appointmentMailingService.sendAppointmentCancelledEmail(
3432
3361
  practitionerCancellationData
@@ -14088,6 +14017,433 @@ var PatientInviteMailingService = class extends BaseMailingService {
14088
14017
  }
14089
14018
  };
14090
14019
 
14020
+ // src/admin/mailing/clinicWelcome/templates/welcome.template.ts
14021
+ var clinicWelcomeTemplate = `
14022
+ <!DOCTYPE html>
14023
+ <html>
14024
+ <head>
14025
+ <meta charset="UTF-8">
14026
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
14027
+ <title>Welcome to MetaEsthetics</title>
14028
+ <style>
14029
+ body {
14030
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
14031
+ line-height: 1.6;
14032
+ color: #333;
14033
+ margin: 0;
14034
+ padding: 0;
14035
+ background-color: #f5f5f5;
14036
+ }
14037
+ .container {
14038
+ max-width: 600px;
14039
+ margin: 0 auto;
14040
+ padding: 20px;
14041
+ }
14042
+ .header {
14043
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
14044
+ padding: 40px 20px;
14045
+ text-align: center;
14046
+ border-radius: 8px 8px 0 0;
14047
+ }
14048
+ .header h1 {
14049
+ color: white;
14050
+ margin: 0;
14051
+ font-size: 28px;
14052
+ font-weight: 600;
14053
+ }
14054
+ .header p {
14055
+ color: rgba(255, 255, 255, 0.9);
14056
+ margin: 10px 0 0 0;
14057
+ font-size: 16px;
14058
+ }
14059
+ .content {
14060
+ padding: 40px 30px;
14061
+ background-color: #ffffff;
14062
+ }
14063
+ .greeting {
14064
+ font-size: 18px;
14065
+ color: #333;
14066
+ margin-bottom: 20px;
14067
+ }
14068
+ .message {
14069
+ font-size: 16px;
14070
+ color: #555;
14071
+ margin-bottom: 25px;
14072
+ }
14073
+ .highlight-box {
14074
+ background: linear-gradient(135deg, #f6f9fc 0%, #eef2f7 100%);
14075
+ border-left: 4px solid #667eea;
14076
+ padding: 20px;
14077
+ margin: 25px 0;
14078
+ border-radius: 0 8px 8px 0;
14079
+ }
14080
+ .highlight-box h3 {
14081
+ margin: 0 0 10px 0;
14082
+ color: #333;
14083
+ font-size: 16px;
14084
+ }
14085
+ .highlight-box p {
14086
+ margin: 0;
14087
+ color: #555;
14088
+ }
14089
+ .next-steps {
14090
+ margin: 30px 0;
14091
+ }
14092
+ .next-steps h3 {
14093
+ color: #333;
14094
+ font-size: 18px;
14095
+ margin-bottom: 15px;
14096
+ }
14097
+ .step {
14098
+ display: flex;
14099
+ align-items: flex-start;
14100
+ margin-bottom: 15px;
14101
+ }
14102
+ .step-number {
14103
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
14104
+ color: white;
14105
+ width: 28px;
14106
+ height: 28px;
14107
+ border-radius: 50%;
14108
+ display: flex;
14109
+ align-items: center;
14110
+ justify-content: center;
14111
+ font-weight: 600;
14112
+ font-size: 14px;
14113
+ margin-right: 12px;
14114
+ flex-shrink: 0;
14115
+ }
14116
+ .step-content {
14117
+ flex: 1;
14118
+ padding-top: 3px;
14119
+ }
14120
+ .step-title {
14121
+ font-weight: 600;
14122
+ color: #333;
14123
+ margin-bottom: 3px;
14124
+ }
14125
+ .step-description {
14126
+ color: #666;
14127
+ font-size: 14px;
14128
+ }
14129
+ .button-container {
14130
+ text-align: center;
14131
+ margin: 35px 0;
14132
+ }
14133
+ .button {
14134
+ display: inline-block;
14135
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
14136
+ color: white;
14137
+ text-decoration: none;
14138
+ padding: 14px 32px;
14139
+ border-radius: 6px;
14140
+ font-weight: 600;
14141
+ font-size: 16px;
14142
+ transition: transform 0.2s;
14143
+ }
14144
+ .button:hover {
14145
+ transform: translateY(-2px);
14146
+ }
14147
+ .support-box {
14148
+ background-color: #f8f9fa;
14149
+ padding: 20px;
14150
+ border-radius: 8px;
14151
+ margin-top: 30px;
14152
+ text-align: center;
14153
+ }
14154
+ .support-box p {
14155
+ margin: 0 0 10px 0;
14156
+ color: #555;
14157
+ }
14158
+ .support-box a {
14159
+ color: #667eea;
14160
+ text-decoration: none;
14161
+ font-weight: 500;
14162
+ }
14163
+ .footer {
14164
+ padding: 30px;
14165
+ text-align: center;
14166
+ background-color: #f8f9fa;
14167
+ border-radius: 0 0 8px 8px;
14168
+ }
14169
+ .footer p {
14170
+ margin: 5px 0;
14171
+ font-size: 13px;
14172
+ color: #888;
14173
+ }
14174
+ .footer a {
14175
+ color: #667eea;
14176
+ text-decoration: none;
14177
+ }
14178
+ .social-links {
14179
+ margin: 15px 0;
14180
+ }
14181
+ .social-links a {
14182
+ display: inline-block;
14183
+ margin: 0 8px;
14184
+ color: #888;
14185
+ text-decoration: none;
14186
+ }
14187
+ </style>
14188
+ </head>
14189
+ <body>
14190
+ <div class="container">
14191
+ <div class="header">
14192
+ <h1>Welcome to MetaEsthetics!</h1>
14193
+ <p>Your clinic registration is complete</p>
14194
+ </div>
14195
+ <div class="content">
14196
+ <p class="greeting">Hello {{adminName}},</p>
14197
+
14198
+ <p class="message">
14199
+ Thank you for registering <strong>{{clinicGroupName}}</strong> with MetaEsthetics.
14200
+ Your account has been successfully created and you're now ready to start managing
14201
+ your aesthetic practice with our comprehensive platform.
14202
+ </p>
14203
+
14204
+ <div class="highlight-box">
14205
+ <h3>Account Details</h3>
14206
+ <p><strong>Clinic Group:</strong> {{clinicGroupName}}</p>
14207
+ <p><strong>Admin Email:</strong> {{adminEmail}}</p>
14208
+ <p><strong>Registration Date:</strong> {{registrationDate}}</p>
14209
+ </div>
14210
+
14211
+ <div class="next-steps">
14212
+ <h3>Get Started with MetaEsthetics</h3>
14213
+
14214
+ <div class="step">
14215
+ <div class="step-number">1</div>
14216
+ <div class="step-content">
14217
+ <div class="step-title">Complete Your Profile</div>
14218
+ <div class="step-description">Add your clinic details, working hours, and upload photos to attract patients.</div>
14219
+ </div>
14220
+ </div>
14221
+
14222
+ <div class="step">
14223
+ <div class="step-number">2</div>
14224
+ <div class="step-content">
14225
+ <div class="step-title">Add Your Team</div>
14226
+ <div class="step-description">Invite practitioners and staff members to join your clinic.</div>
14227
+ </div>
14228
+ </div>
14229
+
14230
+ <div class="step">
14231
+ <div class="step-number">3</div>
14232
+ <div class="step-content">
14233
+ <div class="step-title">Set Up Services</div>
14234
+ <div class="step-description">Configure your procedures, pricing, and availability for bookings.</div>
14235
+ </div>
14236
+ </div>
14237
+
14238
+ <div class="step">
14239
+ <div class="step-number">4</div>
14240
+ <div class="step-content">
14241
+ <div class="step-title">Start Accepting Patients</div>
14242
+ <div class="step-description">Begin managing appointments and growing your practice.</div>
14243
+ </div>
14244
+ </div>
14245
+ </div>
14246
+
14247
+ <div class="button-container">
14248
+ <a href="{{dashboardUrl}}" class="button">Go to Dashboard</a>
14249
+ </div>
14250
+
14251
+ <div class="support-box">
14252
+ <p>Need help getting started?</p>
14253
+ <p>Contact our support team at <a href="mailto:{{supportEmail}}">{{supportEmail}}</a></p>
14254
+ </div>
14255
+ </div>
14256
+ <div class="footer">
14257
+ <p>This is an automated message from MetaEsthetics.</p>
14258
+ <p>&copy; {{currentYear}} MetaEsthetics. All rights reserved.</p>
14259
+ <div class="social-links">
14260
+ <a href="https://metaesthetics.net">Website</a> |
14261
+ <a href="https://metaesthetics.net/privacy">Privacy Policy</a> |
14262
+ <a href="https://metaesthetics.net/terms">Terms of Service</a>
14263
+ </div>
14264
+ </div>
14265
+ </div>
14266
+ </body>
14267
+ </html>
14268
+ `;
14269
+
14270
+ // src/admin/mailing/clinicWelcome/clinicWelcome.mailing.ts
14271
+ var ClinicWelcomeMailingService = class extends BaseMailingService {
14272
+ /**
14273
+ * Constructor for ClinicWelcomeMailingService
14274
+ * @param firestore - Firestore instance provided by the caller
14275
+ * @param mailgunClient - Mailgun client instance (mailgun.js v10+) provided by the caller
14276
+ */
14277
+ constructor(firestore19, mailgunClient) {
14278
+ super(firestore19, mailgunClient);
14279
+ this.DEFAULT_DASHBOARD_URL = "https://clinic.metaesthetics.net/dashboard";
14280
+ this.DEFAULT_SUPPORT_EMAIL = "support@metaesthetics.net";
14281
+ this.DEFAULT_SUBJECT = "Welcome to MetaEsthetics - Your Clinic Registration is Complete";
14282
+ this.DEFAULT_MAILGUN_DOMAIN = "mg.metaesthetics.net";
14283
+ }
14284
+ /**
14285
+ * Sends a clinic welcome email
14286
+ * @param data - The clinic welcome email data
14287
+ * @returns Promise resolved when email is sent
14288
+ */
14289
+ async sendWelcomeEmail(data) {
14290
+ var _a, _b, _c, _d, _e, _f, _g;
14291
+ try {
14292
+ Logger.info(
14293
+ "[ClinicWelcomeMailingService] Sending welcome email to",
14294
+ data.admin.email
14295
+ );
14296
+ const registrationDate = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
14297
+ weekday: "long",
14298
+ year: "numeric",
14299
+ month: "long",
14300
+ day: "numeric"
14301
+ });
14302
+ const dashboardUrl = ((_a = data.options) == null ? void 0 : _a.dashboardUrl) || this.DEFAULT_DASHBOARD_URL;
14303
+ const supportEmail = ((_b = data.options) == null ? void 0 : _b.supportEmail) || this.DEFAULT_SUPPORT_EMAIL;
14304
+ const subject = ((_c = data.options) == null ? void 0 : _c.customSubject) || this.DEFAULT_SUBJECT;
14305
+ const fromAddress = ((_d = data.options) == null ? void 0 : _d.fromAddress) || `MetaEsthetics <no-reply@${((_e = data.options) == null ? void 0 : _e.mailgunDomain) || this.DEFAULT_MAILGUN_DOMAIN}>`;
14306
+ const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
14307
+ const templateVariables = {
14308
+ adminName: data.admin.name,
14309
+ adminEmail: data.admin.email,
14310
+ clinicGroupName: data.clinicGroup.name,
14311
+ registrationDate,
14312
+ dashboardUrl,
14313
+ supportEmail,
14314
+ currentYear
14315
+ };
14316
+ Logger.info("[ClinicWelcomeMailingService] Template variables:", {
14317
+ adminName: templateVariables.adminName,
14318
+ adminEmail: templateVariables.adminEmail,
14319
+ clinicGroupName: templateVariables.clinicGroupName,
14320
+ dashboardUrl: templateVariables.dashboardUrl
14321
+ });
14322
+ const html = this.renderTemplate(clinicWelcomeTemplate, templateVariables);
14323
+ const mailgunSendData = {
14324
+ to: data.admin.email,
14325
+ from: fromAddress,
14326
+ subject,
14327
+ html
14328
+ };
14329
+ const domainToSendFrom = ((_f = data.options) == null ? void 0 : _f.mailgunDomain) || this.DEFAULT_MAILGUN_DOMAIN;
14330
+ Logger.info("[ClinicWelcomeMailingService] Sending email with data:", {
14331
+ domain: domainToSendFrom,
14332
+ to: mailgunSendData.to,
14333
+ from: mailgunSendData.from,
14334
+ subject: mailgunSendData.subject,
14335
+ hasHtml: !!mailgunSendData.html
14336
+ });
14337
+ const result = await this.sendEmail(domainToSendFrom, mailgunSendData);
14338
+ await this.logEmailAttempt(
14339
+ {
14340
+ to: data.admin.email,
14341
+ subject,
14342
+ templateName: "clinic_welcome"
14343
+ },
14344
+ true
14345
+ );
14346
+ return result;
14347
+ } catch (error) {
14348
+ Logger.error(
14349
+ "[ClinicWelcomeMailingService] Error sending welcome email:",
14350
+ {
14351
+ errorMessage: error.message,
14352
+ errorDetails: error.details,
14353
+ errorStatus: error.status,
14354
+ stack: error.stack
14355
+ }
14356
+ );
14357
+ await this.logEmailAttempt(
14358
+ {
14359
+ to: data.admin.email,
14360
+ subject: ((_g = data.options) == null ? void 0 : _g.customSubject) || this.DEFAULT_SUBJECT,
14361
+ templateName: "clinic_welcome"
14362
+ },
14363
+ false,
14364
+ error
14365
+ );
14366
+ throw error;
14367
+ }
14368
+ }
14369
+ /**
14370
+ * Handles the clinic group creation event from Cloud Functions.
14371
+ * Fetches necessary data and sends the welcome email to the admin.
14372
+ * @param clinicGroupData - The clinic group data including id
14373
+ * @param mailgunConfig - Mailgun configuration (from, domain)
14374
+ * @returns Promise resolved when the email is sent
14375
+ */
14376
+ async handleClinicGroupCreationEvent(clinicGroupData, mailgunConfig) {
14377
+ try {
14378
+ Logger.info(
14379
+ "[ClinicWelcomeMailingService] Handling clinic group creation event for:",
14380
+ clinicGroupData.id
14381
+ );
14382
+ if (!clinicGroupData || !clinicGroupData.id) {
14383
+ throw new Error(
14384
+ `Invalid clinic group data: Missing required properties.`
14385
+ );
14386
+ }
14387
+ if (!clinicGroupData.contactPerson) {
14388
+ throw new Error(
14389
+ `Clinic group ${clinicGroupData.id} is missing contactPerson`
14390
+ );
14391
+ }
14392
+ if (!clinicGroupData.contactPerson.email) {
14393
+ throw new Error(
14394
+ `Clinic group ${clinicGroupData.id} is missing admin email`
14395
+ );
14396
+ }
14397
+ const adminName = `${clinicGroupData.contactPerson.firstName || ""} ${clinicGroupData.contactPerson.lastName || ""}`.trim() || "Clinic Admin";
14398
+ const adminEmail = clinicGroupData.contactPerson.email;
14399
+ Logger.info(
14400
+ `[ClinicWelcomeMailingService] Sending welcome email to admin: ${adminName} (${adminEmail})`
14401
+ );
14402
+ if (!mailgunConfig.fromAddress) {
14403
+ Logger.warn(
14404
+ "[ClinicWelcomeMailingService] No fromAddress provided, using default"
14405
+ );
14406
+ mailgunConfig.fromAddress = `MetaEsthetics <no-reply@${this.DEFAULT_MAILGUN_DOMAIN}>`;
14407
+ }
14408
+ const emailData = {
14409
+ admin: {
14410
+ name: adminName,
14411
+ email: adminEmail
14412
+ },
14413
+ clinicGroup: {
14414
+ id: clinicGroupData.id,
14415
+ name: clinicGroupData.name || "Your Clinic"
14416
+ },
14417
+ options: {
14418
+ fromAddress: mailgunConfig.fromAddress,
14419
+ mailgunDomain: mailgunConfig.domain,
14420
+ dashboardUrl: mailgunConfig.dashboardUrl,
14421
+ supportEmail: mailgunConfig.supportEmail
14422
+ }
14423
+ };
14424
+ Logger.info(
14425
+ "[ClinicWelcomeMailingService] Email data prepared, sending welcome email"
14426
+ );
14427
+ await this.sendWelcomeEmail(emailData);
14428
+ Logger.info(
14429
+ "[ClinicWelcomeMailingService] Welcome email sent successfully"
14430
+ );
14431
+ } catch (error) {
14432
+ Logger.error(
14433
+ "[ClinicWelcomeMailingService] Error handling clinic group creation event:",
14434
+ {
14435
+ errorMessage: error.message,
14436
+ errorDetails: error.details,
14437
+ errorStatus: error.status,
14438
+ stack: error.stack,
14439
+ clinicGroupId: clinicGroupData == null ? void 0 : clinicGroupData.id
14440
+ }
14441
+ );
14442
+ throw error;
14443
+ }
14444
+ }
14445
+ };
14446
+
14091
14447
  // src/admin/users/user-profile.admin.ts
14092
14448
  import * as admin18 from "firebase-admin";
14093
14449
  var UserProfileAdminService = class {
@@ -14389,6 +14745,7 @@ export {
14389
14745
  CLINIC_ANALYTICS_SUBCOLLECTION,
14390
14746
  CalendarAdminService,
14391
14747
  ClinicAggregationService,
14748
+ ClinicWelcomeMailingService,
14392
14749
  DASHBOARD_ANALYTICS_SUBCOLLECTION,
14393
14750
  DocumentManagerAdminService,
14394
14751
  ExistingPractitionerInviteMailingService,