@blackcode_sa/metaestetics-api 1.7.34 → 1.7.36
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
CHANGED
|
@@ -2282,6 +2282,12 @@ declare class PractitionerInviteAggregationService {
|
|
|
2282
2282
|
* @returns {Promise<void>}
|
|
2283
2283
|
*/
|
|
2284
2284
|
private updatePractitionerWorkingHours;
|
|
2285
|
+
/**
|
|
2286
|
+
* Fetches a clinic admin by ID
|
|
2287
|
+
* @param adminId The clinic admin ID
|
|
2288
|
+
* @returns The clinic admin or null if not found
|
|
2289
|
+
*/
|
|
2290
|
+
private fetchClinicAdminById;
|
|
2285
2291
|
/**
|
|
2286
2292
|
* Fetches a practitioner by ID.
|
|
2287
2293
|
* @param practitionerId The practitioner ID.
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -2282,6 +2282,12 @@ declare class PractitionerInviteAggregationService {
|
|
|
2282
2282
|
* @returns {Promise<void>}
|
|
2283
2283
|
*/
|
|
2284
2284
|
private updatePractitionerWorkingHours;
|
|
2285
|
+
/**
|
|
2286
|
+
* Fetches a clinic admin by ID
|
|
2287
|
+
* @param adminId The clinic admin ID
|
|
2288
|
+
* @returns The clinic admin or null if not found
|
|
2289
|
+
*/
|
|
2290
|
+
private fetchClinicAdminById;
|
|
2285
2291
|
/**
|
|
2286
2292
|
* Fetches a practitioner by ID.
|
|
2287
2293
|
* @param practitionerId The practitioner ID.
|
package/dist/admin/index.js
CHANGED
|
@@ -926,6 +926,7 @@ var PractitionerInviteStatus = /* @__PURE__ */ ((PractitionerInviteStatus2) => {
|
|
|
926
926
|
|
|
927
927
|
// src/types/clinic/index.ts
|
|
928
928
|
var CLINIC_GROUPS_COLLECTION = "clinic_groups";
|
|
929
|
+
var CLINIC_ADMINS_COLLECTION = "clinic_admins";
|
|
929
930
|
var CLINICS_COLLECTION = "clinics";
|
|
930
931
|
|
|
931
932
|
// src/types/patient/index.ts
|
|
@@ -2236,6 +2237,23 @@ var PractitionerInviteAggregationService = class {
|
|
|
2236
2237
|
}
|
|
2237
2238
|
}
|
|
2238
2239
|
// --- Data Fetching Helpers ---
|
|
2240
|
+
/**
|
|
2241
|
+
* Fetches a clinic admin by ID
|
|
2242
|
+
* @param adminId The clinic admin ID
|
|
2243
|
+
* @returns The clinic admin or null if not found
|
|
2244
|
+
*/
|
|
2245
|
+
async fetchClinicAdminById(adminId) {
|
|
2246
|
+
try {
|
|
2247
|
+
const doc = await this.db.collection(CLINIC_ADMINS_COLLECTION).doc(adminId).get();
|
|
2248
|
+
return doc.exists ? doc.data() : null;
|
|
2249
|
+
} catch (error) {
|
|
2250
|
+
Logger.error(
|
|
2251
|
+
`[PractitionerInviteAggService] Error fetching clinic admin ${adminId}:`,
|
|
2252
|
+
error
|
|
2253
|
+
);
|
|
2254
|
+
return null;
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2239
2257
|
/**
|
|
2240
2258
|
* Fetches a practitioner by ID.
|
|
2241
2259
|
* @param practitionerId The practitioner ID.
|
|
@@ -2279,40 +2297,88 @@ var PractitionerInviteAggregationService = class {
|
|
|
2279
2297
|
* @param emailConfig Email configuration
|
|
2280
2298
|
*/
|
|
2281
2299
|
async sendAcceptanceNotificationEmail(invite, practitioner, clinic, emailConfig) {
|
|
2282
|
-
var _a, _b, _c;
|
|
2300
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2283
2301
|
if (!this.mailingService) return;
|
|
2284
|
-
|
|
2285
|
-
invite
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2302
|
+
try {
|
|
2303
|
+
const admin17 = await this.fetchClinicAdminById(invite.invitedBy);
|
|
2304
|
+
if (!admin17) {
|
|
2305
|
+
Logger.warn(
|
|
2306
|
+
`[PractitionerInviteAggService] Admin ${invite.invitedBy} not found, using clinic contact email as fallback`
|
|
2307
|
+
);
|
|
2308
|
+
const notificationData2 = {
|
|
2309
|
+
invite,
|
|
2310
|
+
practitioner: {
|
|
2311
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
2312
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
2313
|
+
specialties: ((_b = (_a = practitioner.certification) == null ? void 0 : _a.specialties) == null ? void 0 : _b.map(
|
|
2314
|
+
(s) => s.name || s
|
|
2315
|
+
)) || [],
|
|
2316
|
+
profileImageUrl: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : null,
|
|
2317
|
+
experienceYears: void 0
|
|
2318
|
+
},
|
|
2319
|
+
clinic: {
|
|
2320
|
+
name: clinic.name,
|
|
2321
|
+
adminName: "Admin",
|
|
2322
|
+
adminEmail: clinic.contactInfo.email
|
|
2323
|
+
},
|
|
2324
|
+
context: {
|
|
2325
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
2326
|
+
responseDate: ((_c = invite.acceptedAt) == null ? void 0 : _c.toDate().toLocaleDateString()) || (/* @__PURE__ */ new Date()).toLocaleDateString()
|
|
2327
|
+
},
|
|
2328
|
+
urls: {
|
|
2329
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
2330
|
+
practitionerProfileUrl: emailConfig.practitionerProfileUrl
|
|
2331
|
+
},
|
|
2332
|
+
options: {
|
|
2333
|
+
fromAddress: emailConfig.fromAddress,
|
|
2334
|
+
mailgunDomain: emailConfig.domain
|
|
2335
|
+
}
|
|
2336
|
+
};
|
|
2337
|
+
await this.mailingService.sendAcceptedNotificationEmail(
|
|
2338
|
+
notificationData2
|
|
2339
|
+
);
|
|
2340
|
+
return;
|
|
2313
2341
|
}
|
|
2314
|
-
|
|
2315
|
-
|
|
2342
|
+
const adminName = `${admin17.contactInfo.firstName} ${admin17.contactInfo.lastName}`;
|
|
2343
|
+
const notificationData = {
|
|
2344
|
+
invite,
|
|
2345
|
+
practitioner: {
|
|
2346
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
2347
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
2348
|
+
specialties: ((_e = (_d = practitioner.certification) == null ? void 0 : _d.specialties) == null ? void 0 : _e.map(
|
|
2349
|
+
(s) => s.name || s
|
|
2350
|
+
)) || [],
|
|
2351
|
+
profileImageUrl: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : null,
|
|
2352
|
+
experienceYears: void 0
|
|
2353
|
+
// This would need to be calculated or stored in practitioner data
|
|
2354
|
+
},
|
|
2355
|
+
clinic: {
|
|
2356
|
+
name: clinic.name,
|
|
2357
|
+
adminName,
|
|
2358
|
+
adminEmail: admin17.contactInfo.email
|
|
2359
|
+
// Use the specific admin's email
|
|
2360
|
+
},
|
|
2361
|
+
context: {
|
|
2362
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
2363
|
+
responseDate: ((_f = invite.acceptedAt) == null ? void 0 : _f.toDate().toLocaleDateString()) || (/* @__PURE__ */ new Date()).toLocaleDateString()
|
|
2364
|
+
},
|
|
2365
|
+
urls: {
|
|
2366
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
2367
|
+
practitionerProfileUrl: emailConfig.practitionerProfileUrl
|
|
2368
|
+
},
|
|
2369
|
+
options: {
|
|
2370
|
+
fromAddress: emailConfig.fromAddress,
|
|
2371
|
+
mailgunDomain: emailConfig.domain
|
|
2372
|
+
}
|
|
2373
|
+
};
|
|
2374
|
+
await this.mailingService.sendAcceptedNotificationEmail(notificationData);
|
|
2375
|
+
} catch (error) {
|
|
2376
|
+
Logger.error(
|
|
2377
|
+
`[PractitionerInviteAggService] Error sending acceptance notification email:`,
|
|
2378
|
+
error
|
|
2379
|
+
);
|
|
2380
|
+
throw error;
|
|
2381
|
+
}
|
|
2316
2382
|
}
|
|
2317
2383
|
/**
|
|
2318
2384
|
* Sends rejection notification email to clinic admin
|
|
@@ -2322,39 +2388,87 @@ var PractitionerInviteAggregationService = class {
|
|
|
2322
2388
|
* @param emailConfig Email configuration
|
|
2323
2389
|
*/
|
|
2324
2390
|
async sendRejectionNotificationEmail(invite, practitioner, clinic, emailConfig) {
|
|
2325
|
-
var _a, _b, _c;
|
|
2391
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2326
2392
|
if (!this.mailingService) return;
|
|
2327
|
-
|
|
2328
|
-
invite
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2393
|
+
try {
|
|
2394
|
+
const admin17 = await this.fetchClinicAdminById(invite.invitedBy);
|
|
2395
|
+
if (!admin17) {
|
|
2396
|
+
Logger.warn(
|
|
2397
|
+
`[PractitionerInviteAggService] Admin ${invite.invitedBy} not found, using clinic contact email as fallback`
|
|
2398
|
+
);
|
|
2399
|
+
const notificationData2 = {
|
|
2400
|
+
invite,
|
|
2401
|
+
practitioner: {
|
|
2402
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
2403
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
2404
|
+
specialties: ((_b = (_a = practitioner.certification) == null ? void 0 : _a.specialties) == null ? void 0 : _b.map(
|
|
2405
|
+
(s) => s.name || s
|
|
2406
|
+
)) || [],
|
|
2407
|
+
profileImageUrl: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : null
|
|
2408
|
+
},
|
|
2409
|
+
clinic: {
|
|
2410
|
+
name: clinic.name,
|
|
2411
|
+
adminName: "Admin",
|
|
2412
|
+
adminEmail: clinic.contactInfo.email
|
|
2413
|
+
},
|
|
2414
|
+
context: {
|
|
2415
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
2416
|
+
responseDate: ((_c = invite.rejectedAt) == null ? void 0 : _c.toDate().toLocaleDateString()) || (/* @__PURE__ */ new Date()).toLocaleDateString(),
|
|
2417
|
+
rejectionReason: invite.rejectionReason || void 0
|
|
2418
|
+
},
|
|
2419
|
+
urls: {
|
|
2420
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
2421
|
+
findPractitionersUrl: emailConfig.findPractitionersUrl
|
|
2422
|
+
},
|
|
2423
|
+
options: {
|
|
2424
|
+
fromAddress: emailConfig.fromAddress,
|
|
2425
|
+
mailgunDomain: emailConfig.domain
|
|
2426
|
+
}
|
|
2427
|
+
};
|
|
2428
|
+
await this.mailingService.sendRejectedNotificationEmail(
|
|
2429
|
+
notificationData2
|
|
2430
|
+
);
|
|
2431
|
+
return;
|
|
2355
2432
|
}
|
|
2356
|
-
|
|
2357
|
-
|
|
2433
|
+
const adminName = `${admin17.contactInfo.firstName} ${admin17.contactInfo.lastName}`;
|
|
2434
|
+
const notificationData = {
|
|
2435
|
+
invite,
|
|
2436
|
+
practitioner: {
|
|
2437
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
2438
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
2439
|
+
specialties: ((_e = (_d = practitioner.certification) == null ? void 0 : _d.specialties) == null ? void 0 : _e.map(
|
|
2440
|
+
(s) => s.name || s
|
|
2441
|
+
)) || [],
|
|
2442
|
+
profileImageUrl: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : null
|
|
2443
|
+
},
|
|
2444
|
+
clinic: {
|
|
2445
|
+
name: clinic.name,
|
|
2446
|
+
adminName,
|
|
2447
|
+
adminEmail: admin17.contactInfo.email
|
|
2448
|
+
// Use the specific admin's email
|
|
2449
|
+
},
|
|
2450
|
+
context: {
|
|
2451
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
2452
|
+
responseDate: ((_f = invite.rejectedAt) == null ? void 0 : _f.toDate().toLocaleDateString()) || (/* @__PURE__ */ new Date()).toLocaleDateString(),
|
|
2453
|
+
rejectionReason: invite.rejectionReason || void 0
|
|
2454
|
+
},
|
|
2455
|
+
urls: {
|
|
2456
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
2457
|
+
findPractitionersUrl: emailConfig.findPractitionersUrl
|
|
2458
|
+
},
|
|
2459
|
+
options: {
|
|
2460
|
+
fromAddress: emailConfig.fromAddress,
|
|
2461
|
+
mailgunDomain: emailConfig.domain
|
|
2462
|
+
}
|
|
2463
|
+
};
|
|
2464
|
+
await this.mailingService.sendRejectedNotificationEmail(notificationData);
|
|
2465
|
+
} catch (error) {
|
|
2466
|
+
Logger.error(
|
|
2467
|
+
`[PractitionerInviteAggService] Error sending rejection notification email:`,
|
|
2468
|
+
error
|
|
2469
|
+
);
|
|
2470
|
+
throw error;
|
|
2471
|
+
}
|
|
2358
2472
|
}
|
|
2359
2473
|
};
|
|
2360
2474
|
|
package/dist/admin/index.mjs
CHANGED
|
@@ -865,6 +865,7 @@ var PractitionerInviteStatus = /* @__PURE__ */ ((PractitionerInviteStatus2) => {
|
|
|
865
865
|
|
|
866
866
|
// src/types/clinic/index.ts
|
|
867
867
|
var CLINIC_GROUPS_COLLECTION = "clinic_groups";
|
|
868
|
+
var CLINIC_ADMINS_COLLECTION = "clinic_admins";
|
|
868
869
|
var CLINICS_COLLECTION = "clinics";
|
|
869
870
|
|
|
870
871
|
// src/types/patient/index.ts
|
|
@@ -2175,6 +2176,23 @@ var PractitionerInviteAggregationService = class {
|
|
|
2175
2176
|
}
|
|
2176
2177
|
}
|
|
2177
2178
|
// --- Data Fetching Helpers ---
|
|
2179
|
+
/**
|
|
2180
|
+
* Fetches a clinic admin by ID
|
|
2181
|
+
* @param adminId The clinic admin ID
|
|
2182
|
+
* @returns The clinic admin or null if not found
|
|
2183
|
+
*/
|
|
2184
|
+
async fetchClinicAdminById(adminId) {
|
|
2185
|
+
try {
|
|
2186
|
+
const doc = await this.db.collection(CLINIC_ADMINS_COLLECTION).doc(adminId).get();
|
|
2187
|
+
return doc.exists ? doc.data() : null;
|
|
2188
|
+
} catch (error) {
|
|
2189
|
+
Logger.error(
|
|
2190
|
+
`[PractitionerInviteAggService] Error fetching clinic admin ${adminId}:`,
|
|
2191
|
+
error
|
|
2192
|
+
);
|
|
2193
|
+
return null;
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2178
2196
|
/**
|
|
2179
2197
|
* Fetches a practitioner by ID.
|
|
2180
2198
|
* @param practitionerId The practitioner ID.
|
|
@@ -2218,40 +2236,88 @@ var PractitionerInviteAggregationService = class {
|
|
|
2218
2236
|
* @param emailConfig Email configuration
|
|
2219
2237
|
*/
|
|
2220
2238
|
async sendAcceptanceNotificationEmail(invite, practitioner, clinic, emailConfig) {
|
|
2221
|
-
var _a, _b, _c;
|
|
2239
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2222
2240
|
if (!this.mailingService) return;
|
|
2223
|
-
|
|
2224
|
-
invite
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2241
|
+
try {
|
|
2242
|
+
const admin17 = await this.fetchClinicAdminById(invite.invitedBy);
|
|
2243
|
+
if (!admin17) {
|
|
2244
|
+
Logger.warn(
|
|
2245
|
+
`[PractitionerInviteAggService] Admin ${invite.invitedBy} not found, using clinic contact email as fallback`
|
|
2246
|
+
);
|
|
2247
|
+
const notificationData2 = {
|
|
2248
|
+
invite,
|
|
2249
|
+
practitioner: {
|
|
2250
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
2251
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
2252
|
+
specialties: ((_b = (_a = practitioner.certification) == null ? void 0 : _a.specialties) == null ? void 0 : _b.map(
|
|
2253
|
+
(s) => s.name || s
|
|
2254
|
+
)) || [],
|
|
2255
|
+
profileImageUrl: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : null,
|
|
2256
|
+
experienceYears: void 0
|
|
2257
|
+
},
|
|
2258
|
+
clinic: {
|
|
2259
|
+
name: clinic.name,
|
|
2260
|
+
adminName: "Admin",
|
|
2261
|
+
adminEmail: clinic.contactInfo.email
|
|
2262
|
+
},
|
|
2263
|
+
context: {
|
|
2264
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
2265
|
+
responseDate: ((_c = invite.acceptedAt) == null ? void 0 : _c.toDate().toLocaleDateString()) || (/* @__PURE__ */ new Date()).toLocaleDateString()
|
|
2266
|
+
},
|
|
2267
|
+
urls: {
|
|
2268
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
2269
|
+
practitionerProfileUrl: emailConfig.practitionerProfileUrl
|
|
2270
|
+
},
|
|
2271
|
+
options: {
|
|
2272
|
+
fromAddress: emailConfig.fromAddress,
|
|
2273
|
+
mailgunDomain: emailConfig.domain
|
|
2274
|
+
}
|
|
2275
|
+
};
|
|
2276
|
+
await this.mailingService.sendAcceptedNotificationEmail(
|
|
2277
|
+
notificationData2
|
|
2278
|
+
);
|
|
2279
|
+
return;
|
|
2252
2280
|
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2281
|
+
const adminName = `${admin17.contactInfo.firstName} ${admin17.contactInfo.lastName}`;
|
|
2282
|
+
const notificationData = {
|
|
2283
|
+
invite,
|
|
2284
|
+
practitioner: {
|
|
2285
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
2286
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
2287
|
+
specialties: ((_e = (_d = practitioner.certification) == null ? void 0 : _d.specialties) == null ? void 0 : _e.map(
|
|
2288
|
+
(s) => s.name || s
|
|
2289
|
+
)) || [],
|
|
2290
|
+
profileImageUrl: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : null,
|
|
2291
|
+
experienceYears: void 0
|
|
2292
|
+
// This would need to be calculated or stored in practitioner data
|
|
2293
|
+
},
|
|
2294
|
+
clinic: {
|
|
2295
|
+
name: clinic.name,
|
|
2296
|
+
adminName,
|
|
2297
|
+
adminEmail: admin17.contactInfo.email
|
|
2298
|
+
// Use the specific admin's email
|
|
2299
|
+
},
|
|
2300
|
+
context: {
|
|
2301
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
2302
|
+
responseDate: ((_f = invite.acceptedAt) == null ? void 0 : _f.toDate().toLocaleDateString()) || (/* @__PURE__ */ new Date()).toLocaleDateString()
|
|
2303
|
+
},
|
|
2304
|
+
urls: {
|
|
2305
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
2306
|
+
practitionerProfileUrl: emailConfig.practitionerProfileUrl
|
|
2307
|
+
},
|
|
2308
|
+
options: {
|
|
2309
|
+
fromAddress: emailConfig.fromAddress,
|
|
2310
|
+
mailgunDomain: emailConfig.domain
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
await this.mailingService.sendAcceptedNotificationEmail(notificationData);
|
|
2314
|
+
} catch (error) {
|
|
2315
|
+
Logger.error(
|
|
2316
|
+
`[PractitionerInviteAggService] Error sending acceptance notification email:`,
|
|
2317
|
+
error
|
|
2318
|
+
);
|
|
2319
|
+
throw error;
|
|
2320
|
+
}
|
|
2255
2321
|
}
|
|
2256
2322
|
/**
|
|
2257
2323
|
* Sends rejection notification email to clinic admin
|
|
@@ -2261,39 +2327,87 @@ var PractitionerInviteAggregationService = class {
|
|
|
2261
2327
|
* @param emailConfig Email configuration
|
|
2262
2328
|
*/
|
|
2263
2329
|
async sendRejectionNotificationEmail(invite, practitioner, clinic, emailConfig) {
|
|
2264
|
-
var _a, _b, _c;
|
|
2330
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2265
2331
|
if (!this.mailingService) return;
|
|
2266
|
-
|
|
2267
|
-
invite
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2332
|
+
try {
|
|
2333
|
+
const admin17 = await this.fetchClinicAdminById(invite.invitedBy);
|
|
2334
|
+
if (!admin17) {
|
|
2335
|
+
Logger.warn(
|
|
2336
|
+
`[PractitionerInviteAggService] Admin ${invite.invitedBy} not found, using clinic contact email as fallback`
|
|
2337
|
+
);
|
|
2338
|
+
const notificationData2 = {
|
|
2339
|
+
invite,
|
|
2340
|
+
practitioner: {
|
|
2341
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
2342
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
2343
|
+
specialties: ((_b = (_a = practitioner.certification) == null ? void 0 : _a.specialties) == null ? void 0 : _b.map(
|
|
2344
|
+
(s) => s.name || s
|
|
2345
|
+
)) || [],
|
|
2346
|
+
profileImageUrl: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : null
|
|
2347
|
+
},
|
|
2348
|
+
clinic: {
|
|
2349
|
+
name: clinic.name,
|
|
2350
|
+
adminName: "Admin",
|
|
2351
|
+
adminEmail: clinic.contactInfo.email
|
|
2352
|
+
},
|
|
2353
|
+
context: {
|
|
2354
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
2355
|
+
responseDate: ((_c = invite.rejectedAt) == null ? void 0 : _c.toDate().toLocaleDateString()) || (/* @__PURE__ */ new Date()).toLocaleDateString(),
|
|
2356
|
+
rejectionReason: invite.rejectionReason || void 0
|
|
2357
|
+
},
|
|
2358
|
+
urls: {
|
|
2359
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
2360
|
+
findPractitionersUrl: emailConfig.findPractitionersUrl
|
|
2361
|
+
},
|
|
2362
|
+
options: {
|
|
2363
|
+
fromAddress: emailConfig.fromAddress,
|
|
2364
|
+
mailgunDomain: emailConfig.domain
|
|
2365
|
+
}
|
|
2366
|
+
};
|
|
2367
|
+
await this.mailingService.sendRejectedNotificationEmail(
|
|
2368
|
+
notificationData2
|
|
2369
|
+
);
|
|
2370
|
+
return;
|
|
2294
2371
|
}
|
|
2295
|
-
|
|
2296
|
-
|
|
2372
|
+
const adminName = `${admin17.contactInfo.firstName} ${admin17.contactInfo.lastName}`;
|
|
2373
|
+
const notificationData = {
|
|
2374
|
+
invite,
|
|
2375
|
+
practitioner: {
|
|
2376
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
2377
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
2378
|
+
specialties: ((_e = (_d = practitioner.certification) == null ? void 0 : _d.specialties) == null ? void 0 : _e.map(
|
|
2379
|
+
(s) => s.name || s
|
|
2380
|
+
)) || [],
|
|
2381
|
+
profileImageUrl: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : null
|
|
2382
|
+
},
|
|
2383
|
+
clinic: {
|
|
2384
|
+
name: clinic.name,
|
|
2385
|
+
adminName,
|
|
2386
|
+
adminEmail: admin17.contactInfo.email
|
|
2387
|
+
// Use the specific admin's email
|
|
2388
|
+
},
|
|
2389
|
+
context: {
|
|
2390
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
2391
|
+
responseDate: ((_f = invite.rejectedAt) == null ? void 0 : _f.toDate().toLocaleDateString()) || (/* @__PURE__ */ new Date()).toLocaleDateString(),
|
|
2392
|
+
rejectionReason: invite.rejectionReason || void 0
|
|
2393
|
+
},
|
|
2394
|
+
urls: {
|
|
2395
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
2396
|
+
findPractitionersUrl: emailConfig.findPractitionersUrl
|
|
2397
|
+
},
|
|
2398
|
+
options: {
|
|
2399
|
+
fromAddress: emailConfig.fromAddress,
|
|
2400
|
+
mailgunDomain: emailConfig.domain
|
|
2401
|
+
}
|
|
2402
|
+
};
|
|
2403
|
+
await this.mailingService.sendRejectedNotificationEmail(notificationData);
|
|
2404
|
+
} catch (error) {
|
|
2405
|
+
Logger.error(
|
|
2406
|
+
`[PractitionerInviteAggService] Error sending rejection notification email:`,
|
|
2407
|
+
error
|
|
2408
|
+
);
|
|
2409
|
+
throw error;
|
|
2410
|
+
}
|
|
2297
2411
|
}
|
|
2298
2412
|
};
|
|
2299
2413
|
|
package/package.json
CHANGED
package/src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts
CHANGED
|
@@ -10,7 +10,12 @@ import {
|
|
|
10
10
|
PRACTITIONERS_COLLECTION,
|
|
11
11
|
PractitionerClinicWorkingHours,
|
|
12
12
|
} from "../../../types/practitioner";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
CLINICS_COLLECTION,
|
|
15
|
+
Clinic,
|
|
16
|
+
ClinicAdmin,
|
|
17
|
+
CLINIC_ADMINS_COLLECTION,
|
|
18
|
+
} from "../../../types/clinic";
|
|
14
19
|
import { ClinicInfo } from "../../../types/profile";
|
|
15
20
|
import { Logger } from "../../logger";
|
|
16
21
|
import { ExistingPractitionerInviteMailingService } from "../../mailing/practitionerInvite/existing-practitioner-invite.mailing";
|
|
@@ -645,6 +650,29 @@ export class PractitionerInviteAggregationService {
|
|
|
645
650
|
|
|
646
651
|
// --- Data Fetching Helpers ---
|
|
647
652
|
|
|
653
|
+
/**
|
|
654
|
+
* Fetches a clinic admin by ID
|
|
655
|
+
* @param adminId The clinic admin ID
|
|
656
|
+
* @returns The clinic admin or null if not found
|
|
657
|
+
*/
|
|
658
|
+
private async fetchClinicAdminById(
|
|
659
|
+
adminId: string
|
|
660
|
+
): Promise<ClinicAdmin | null> {
|
|
661
|
+
try {
|
|
662
|
+
const doc = await this.db
|
|
663
|
+
.collection(CLINIC_ADMINS_COLLECTION)
|
|
664
|
+
.doc(adminId)
|
|
665
|
+
.get();
|
|
666
|
+
return doc.exists ? (doc.data() as ClinicAdmin) : null;
|
|
667
|
+
} catch (error) {
|
|
668
|
+
Logger.error(
|
|
669
|
+
`[PractitionerInviteAggService] Error fetching clinic admin ${adminId}:`,
|
|
670
|
+
error
|
|
671
|
+
);
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
648
676
|
/**
|
|
649
677
|
* Fetches a practitioner by ID.
|
|
650
678
|
* @param practitionerId The practitioner ID.
|
|
@@ -711,43 +739,104 @@ export class PractitionerInviteAggregationService {
|
|
|
711
739
|
): Promise<void> {
|
|
712
740
|
if (!this.mailingService) return;
|
|
713
741
|
|
|
714
|
-
|
|
715
|
-
invite
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
:
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
742
|
+
try {
|
|
743
|
+
// Fetch the admin who created the invite
|
|
744
|
+
const admin = await this.fetchClinicAdminById(invite.invitedBy);
|
|
745
|
+
if (!admin) {
|
|
746
|
+
Logger.warn(
|
|
747
|
+
`[PractitionerInviteAggService] Admin ${invite.invitedBy} not found, using clinic contact email as fallback`
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
// Fallback to clinic contact email
|
|
751
|
+
const notificationData = {
|
|
752
|
+
invite,
|
|
753
|
+
practitioner: {
|
|
754
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
755
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
756
|
+
specialties:
|
|
757
|
+
practitioner.certification?.specialties?.map(
|
|
758
|
+
(s: any) => s.name || s
|
|
759
|
+
) || [],
|
|
760
|
+
profileImageUrl:
|
|
761
|
+
typeof practitioner.basicInfo.profileImageUrl === "string"
|
|
762
|
+
? practitioner.basicInfo.profileImageUrl
|
|
763
|
+
: null,
|
|
764
|
+
experienceYears: undefined,
|
|
765
|
+
},
|
|
766
|
+
clinic: {
|
|
767
|
+
name: clinic.name,
|
|
768
|
+
adminName: "Admin",
|
|
769
|
+
adminEmail: clinic.contactInfo.email,
|
|
770
|
+
},
|
|
771
|
+
context: {
|
|
772
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
773
|
+
responseDate:
|
|
774
|
+
invite.acceptedAt?.toDate().toLocaleDateString() ||
|
|
775
|
+
new Date().toLocaleDateString(),
|
|
776
|
+
},
|
|
777
|
+
urls: {
|
|
778
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
779
|
+
practitionerProfileUrl: emailConfig.practitionerProfileUrl,
|
|
780
|
+
},
|
|
781
|
+
options: {
|
|
782
|
+
fromAddress: emailConfig.fromAddress,
|
|
783
|
+
mailgunDomain: emailConfig.domain,
|
|
784
|
+
},
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
await this.mailingService.sendAcceptedNotificationEmail(
|
|
788
|
+
notificationData
|
|
789
|
+
);
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Use specific admin details
|
|
794
|
+
const adminName = `${admin.contactInfo.firstName} ${admin.contactInfo.lastName}`;
|
|
795
|
+
|
|
796
|
+
const notificationData = {
|
|
797
|
+
invite,
|
|
798
|
+
practitioner: {
|
|
799
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
800
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
801
|
+
specialties:
|
|
802
|
+
practitioner.certification?.specialties?.map(
|
|
803
|
+
(s: any) => s.name || s
|
|
804
|
+
) || [],
|
|
805
|
+
profileImageUrl:
|
|
806
|
+
typeof practitioner.basicInfo.profileImageUrl === "string"
|
|
807
|
+
? practitioner.basicInfo.profileImageUrl
|
|
808
|
+
: null,
|
|
809
|
+
experienceYears: undefined, // This would need to be calculated or stored in practitioner data
|
|
810
|
+
},
|
|
811
|
+
clinic: {
|
|
812
|
+
name: clinic.name,
|
|
813
|
+
adminName: adminName,
|
|
814
|
+
adminEmail: admin.contactInfo.email, // Use the specific admin's email
|
|
815
|
+
},
|
|
816
|
+
context: {
|
|
817
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
818
|
+
responseDate:
|
|
819
|
+
invite.acceptedAt?.toDate().toLocaleDateString() ||
|
|
820
|
+
new Date().toLocaleDateString(),
|
|
821
|
+
},
|
|
822
|
+
urls: {
|
|
823
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
824
|
+
practitionerProfileUrl: emailConfig.practitionerProfileUrl,
|
|
825
|
+
},
|
|
826
|
+
options: {
|
|
827
|
+
fromAddress: emailConfig.fromAddress,
|
|
828
|
+
mailgunDomain: emailConfig.domain,
|
|
829
|
+
},
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
await this.mailingService.sendAcceptedNotificationEmail(notificationData);
|
|
833
|
+
} catch (error) {
|
|
834
|
+
Logger.error(
|
|
835
|
+
`[PractitionerInviteAggService] Error sending acceptance notification email:`,
|
|
836
|
+
error
|
|
837
|
+
);
|
|
838
|
+
throw error;
|
|
839
|
+
}
|
|
751
840
|
}
|
|
752
841
|
|
|
753
842
|
/**
|
|
@@ -770,42 +859,103 @@ export class PractitionerInviteAggregationService {
|
|
|
770
859
|
): Promise<void> {
|
|
771
860
|
if (!this.mailingService) return;
|
|
772
861
|
|
|
773
|
-
|
|
774
|
-
invite
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
:
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
862
|
+
try {
|
|
863
|
+
// Fetch the admin who created the invite
|
|
864
|
+
const admin = await this.fetchClinicAdminById(invite.invitedBy);
|
|
865
|
+
if (!admin) {
|
|
866
|
+
Logger.warn(
|
|
867
|
+
`[PractitionerInviteAggService] Admin ${invite.invitedBy} not found, using clinic contact email as fallback`
|
|
868
|
+
);
|
|
869
|
+
|
|
870
|
+
// Fallback to clinic contact email
|
|
871
|
+
const notificationData = {
|
|
872
|
+
invite,
|
|
873
|
+
practitioner: {
|
|
874
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
875
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
876
|
+
specialties:
|
|
877
|
+
practitioner.certification?.specialties?.map(
|
|
878
|
+
(s: any) => s.name || s
|
|
879
|
+
) || [],
|
|
880
|
+
profileImageUrl:
|
|
881
|
+
typeof practitioner.basicInfo.profileImageUrl === "string"
|
|
882
|
+
? practitioner.basicInfo.profileImageUrl
|
|
883
|
+
: null,
|
|
884
|
+
},
|
|
885
|
+
clinic: {
|
|
886
|
+
name: clinic.name,
|
|
887
|
+
adminName: "Admin",
|
|
888
|
+
adminEmail: clinic.contactInfo.email,
|
|
889
|
+
},
|
|
890
|
+
context: {
|
|
891
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
892
|
+
responseDate:
|
|
893
|
+
invite.rejectedAt?.toDate().toLocaleDateString() ||
|
|
894
|
+
new Date().toLocaleDateString(),
|
|
895
|
+
rejectionReason: invite.rejectionReason || undefined,
|
|
896
|
+
},
|
|
897
|
+
urls: {
|
|
898
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
899
|
+
findPractitionersUrl: emailConfig.findPractitionersUrl,
|
|
900
|
+
},
|
|
901
|
+
options: {
|
|
902
|
+
fromAddress: emailConfig.fromAddress,
|
|
903
|
+
mailgunDomain: emailConfig.domain,
|
|
904
|
+
},
|
|
905
|
+
};
|
|
906
|
+
|
|
907
|
+
await this.mailingService.sendRejectedNotificationEmail(
|
|
908
|
+
notificationData
|
|
909
|
+
);
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// Use specific admin details
|
|
914
|
+
const adminName = `${admin.contactInfo.firstName} ${admin.contactInfo.lastName}`;
|
|
915
|
+
|
|
916
|
+
const notificationData = {
|
|
917
|
+
invite,
|
|
918
|
+
practitioner: {
|
|
919
|
+
firstName: practitioner.basicInfo.firstName || "",
|
|
920
|
+
lastName: practitioner.basicInfo.lastName || "",
|
|
921
|
+
specialties:
|
|
922
|
+
practitioner.certification?.specialties?.map(
|
|
923
|
+
(s: any) => s.name || s
|
|
924
|
+
) || [],
|
|
925
|
+
profileImageUrl:
|
|
926
|
+
typeof practitioner.basicInfo.profileImageUrl === "string"
|
|
927
|
+
? practitioner.basicInfo.profileImageUrl
|
|
928
|
+
: null,
|
|
929
|
+
},
|
|
930
|
+
clinic: {
|
|
931
|
+
name: clinic.name,
|
|
932
|
+
adminName: adminName,
|
|
933
|
+
adminEmail: admin.contactInfo.email, // Use the specific admin's email
|
|
934
|
+
},
|
|
935
|
+
context: {
|
|
936
|
+
invitationDate: invite.createdAt.toDate().toLocaleDateString(),
|
|
937
|
+
responseDate:
|
|
938
|
+
invite.rejectedAt?.toDate().toLocaleDateString() ||
|
|
939
|
+
new Date().toLocaleDateString(),
|
|
940
|
+
rejectionReason: invite.rejectionReason || undefined,
|
|
941
|
+
},
|
|
942
|
+
urls: {
|
|
943
|
+
clinicDashboardUrl: emailConfig.clinicDashboardUrl,
|
|
944
|
+
findPractitionersUrl: emailConfig.findPractitionersUrl,
|
|
945
|
+
},
|
|
946
|
+
options: {
|
|
947
|
+
fromAddress: emailConfig.fromAddress,
|
|
948
|
+
mailgunDomain: emailConfig.domain,
|
|
949
|
+
},
|
|
950
|
+
};
|
|
951
|
+
|
|
952
|
+
await this.mailingService.sendRejectedNotificationEmail(notificationData);
|
|
953
|
+
} catch (error) {
|
|
954
|
+
Logger.error(
|
|
955
|
+
`[PractitionerInviteAggService] Error sending rejection notification email:`,
|
|
956
|
+
error
|
|
957
|
+
);
|
|
958
|
+
throw error;
|
|
959
|
+
}
|
|
810
960
|
}
|
|
811
961
|
}
|