@blackcode_sa/metaestetics-api 1.5.44 → 1.5.45
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.js +159 -23
- package/dist/admin/index.mjs +159 -23
- package/dist/index.d.mts +28 -2
- package/dist/index.d.ts +28 -2
- package/dist/index.js +1096 -942
- package/dist/index.mjs +969 -797
- package/package.json +1 -1
- package/src/admin/mailing/base.mailing.service.ts +108 -29
- package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +88 -2
- package/src/services/patient/patient.service.ts +180 -57
- package/src/services/patient/utils/clinic.utils.ts +80 -0
- package/src/services/patient/utils/practitioner.utils.ts +80 -0
package/dist/admin/index.js
CHANGED
|
@@ -1570,6 +1570,15 @@ var BaseMailingService = class {
|
|
|
1570
1570
|
constructor(firestore8, mailgunClient) {
|
|
1571
1571
|
this.db = firestore8;
|
|
1572
1572
|
this.mailgunClient = mailgunClient;
|
|
1573
|
+
if (!this.db) {
|
|
1574
|
+
console.error("[BaseMailingService] No Firestore instance provided");
|
|
1575
|
+
throw new Error("Firestore instance is required");
|
|
1576
|
+
}
|
|
1577
|
+
if (!this.mailgunClient) {
|
|
1578
|
+
console.error("[BaseMailingService] No Mailgun client provided");
|
|
1579
|
+
throw new Error("Mailgun client is required");
|
|
1580
|
+
}
|
|
1581
|
+
console.log("[BaseMailingService] Service initialized successfully");
|
|
1573
1582
|
}
|
|
1574
1583
|
/**
|
|
1575
1584
|
* Sends an email using Mailgun
|
|
@@ -1578,29 +1587,69 @@ var BaseMailingService = class {
|
|
|
1578
1587
|
*/
|
|
1579
1588
|
async sendEmail(data) {
|
|
1580
1589
|
try {
|
|
1590
|
+
if (!data) {
|
|
1591
|
+
throw new Error("Email data object is required");
|
|
1592
|
+
}
|
|
1593
|
+
if (!data.to) {
|
|
1594
|
+
throw new Error("Email 'to' address is required");
|
|
1595
|
+
}
|
|
1581
1596
|
if (!data.from) {
|
|
1582
1597
|
throw new Error(
|
|
1583
1598
|
"Email 'from' address must be provided in sendEmail data."
|
|
1584
1599
|
);
|
|
1585
1600
|
}
|
|
1601
|
+
if (!data.subject) {
|
|
1602
|
+
throw new Error("Email 'subject' is required");
|
|
1603
|
+
}
|
|
1604
|
+
if (!data.html && !data.text) {
|
|
1605
|
+
throw new Error("Email must have either 'html' or 'text' content");
|
|
1606
|
+
}
|
|
1607
|
+
console.log("[BaseMailingService] Sending email via Mailgun", {
|
|
1608
|
+
to: data.to,
|
|
1609
|
+
from: data.from,
|
|
1610
|
+
subject: data.subject,
|
|
1611
|
+
hasHtml: !!data.html,
|
|
1612
|
+
hasText: !!data.text
|
|
1613
|
+
});
|
|
1586
1614
|
return await new Promise(
|
|
1587
1615
|
(resolve, reject) => {
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
} else {
|
|
1593
|
-
console.log(
|
|
1594
|
-
"[BaseMailingService] Email sent successfully:",
|
|
1595
|
-
body
|
|
1596
|
-
);
|
|
1597
|
-
resolve(body);
|
|
1616
|
+
try {
|
|
1617
|
+
const messagesApi = this.mailgunClient.messages();
|
|
1618
|
+
if (!messagesApi) {
|
|
1619
|
+
throw new Error("Could not get Mailgun messages API");
|
|
1598
1620
|
}
|
|
1599
|
-
|
|
1621
|
+
messagesApi.send(data, (error, body) => {
|
|
1622
|
+
if (error) {
|
|
1623
|
+
console.error(
|
|
1624
|
+
"[BaseMailingService] Mailgun API error:",
|
|
1625
|
+
error instanceof Error ? error.message : error,
|
|
1626
|
+
error instanceof Error ? error.stack : ""
|
|
1627
|
+
);
|
|
1628
|
+
reject(error);
|
|
1629
|
+
} else {
|
|
1630
|
+
console.log(
|
|
1631
|
+
"[BaseMailingService] Email sent successfully:",
|
|
1632
|
+
body
|
|
1633
|
+
);
|
|
1634
|
+
resolve(body);
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1637
|
+
} catch (sendError) {
|
|
1638
|
+
console.error(
|
|
1639
|
+
"[BaseMailingService] Error in mailgun.messages().send():",
|
|
1640
|
+
sendError instanceof Error ? sendError.message : sendError,
|
|
1641
|
+
sendError instanceof Error ? sendError.stack : ""
|
|
1642
|
+
);
|
|
1643
|
+
reject(sendError);
|
|
1644
|
+
}
|
|
1600
1645
|
}
|
|
1601
1646
|
);
|
|
1602
1647
|
} catch (error) {
|
|
1603
|
-
console.error(
|
|
1648
|
+
console.error(
|
|
1649
|
+
"[BaseMailingService] Error in sendEmail:",
|
|
1650
|
+
error instanceof Error ? error.message : error,
|
|
1651
|
+
error instanceof Error ? error.stack : ""
|
|
1652
|
+
);
|
|
1604
1653
|
throw error;
|
|
1605
1654
|
}
|
|
1606
1655
|
}
|
|
@@ -1618,13 +1667,17 @@ var BaseMailingService = class {
|
|
|
1618
1667
|
subject: emailData.subject,
|
|
1619
1668
|
templateName: emailData.templateName,
|
|
1620
1669
|
success,
|
|
1621
|
-
error: error ? JSON.stringify(error) : null,
|
|
1670
|
+
error: error ? error instanceof Error ? { message: error.message, stack: error.stack } : JSON.stringify(error) : null,
|
|
1622
1671
|
sentAt: admin6.firestore.FieldValue.serverTimestamp()
|
|
1623
1672
|
});
|
|
1673
|
+
console.log(
|
|
1674
|
+
`[BaseMailingService] Email log recorded. Success: ${success}`
|
|
1675
|
+
);
|
|
1624
1676
|
} catch (logError) {
|
|
1625
1677
|
console.error(
|
|
1626
1678
|
"[BaseMailingService] Error logging email attempt:",
|
|
1627
|
-
logError
|
|
1679
|
+
logError instanceof Error ? logError.message : logError,
|
|
1680
|
+
logError instanceof Error ? logError.stack : ""
|
|
1628
1681
|
);
|
|
1629
1682
|
}
|
|
1630
1683
|
}
|
|
@@ -1635,12 +1688,25 @@ var BaseMailingService = class {
|
|
|
1635
1688
|
* @returns Rendered HTML string
|
|
1636
1689
|
*/
|
|
1637
1690
|
renderTemplate(template, variables) {
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1691
|
+
if (!template) {
|
|
1692
|
+
throw new Error("Email template is required");
|
|
1693
|
+
}
|
|
1694
|
+
try {
|
|
1695
|
+
let rendered = template;
|
|
1696
|
+
Object.entries(variables).forEach(([key, value]) => {
|
|
1697
|
+
const regex = new RegExp(`{{\\s*${key}\\s*}}`, "g");
|
|
1698
|
+
rendered = rendered.replace(regex, value || "");
|
|
1699
|
+
});
|
|
1700
|
+
return rendered;
|
|
1701
|
+
} catch (renderError) {
|
|
1702
|
+
console.error(
|
|
1703
|
+
"[BaseMailingService] Error rendering template:",
|
|
1704
|
+
renderError instanceof Error ? renderError.message : renderError
|
|
1705
|
+
);
|
|
1706
|
+
throw new Error(
|
|
1707
|
+
`Template rendering failed: ${renderError instanceof Error ? renderError.message : "Unknown error"}`
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1644
1710
|
}
|
|
1645
1711
|
};
|
|
1646
1712
|
|
|
@@ -1792,6 +1858,16 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1792
1858
|
contactEmail,
|
|
1793
1859
|
currentYear
|
|
1794
1860
|
};
|
|
1861
|
+
console.log("[PractitionerInviteMailingService] Template variables:", {
|
|
1862
|
+
clinicName: templateVariables.clinicName,
|
|
1863
|
+
practitionerName: templateVariables.practitionerName,
|
|
1864
|
+
expirationDate: templateVariables.expirationDate,
|
|
1865
|
+
registrationUrl: templateVariables.registrationUrl,
|
|
1866
|
+
contactName: templateVariables.contactName,
|
|
1867
|
+
contactEmail: templateVariables.contactEmail,
|
|
1868
|
+
// Don't log the invite token for security
|
|
1869
|
+
hasInviteToken: !!templateVariables.inviteToken
|
|
1870
|
+
});
|
|
1795
1871
|
const html = this.renderTemplate(
|
|
1796
1872
|
practitionerInvitationTemplate,
|
|
1797
1873
|
templateVariables
|
|
@@ -1802,6 +1878,15 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1802
1878
|
subject,
|
|
1803
1879
|
html
|
|
1804
1880
|
};
|
|
1881
|
+
console.log(
|
|
1882
|
+
"[PractitionerInviteMailingService] Sending email with data:",
|
|
1883
|
+
{
|
|
1884
|
+
to: emailData.to,
|
|
1885
|
+
from: emailData.from,
|
|
1886
|
+
subject: emailData.subject,
|
|
1887
|
+
hasHtml: !!emailData.html
|
|
1888
|
+
}
|
|
1889
|
+
);
|
|
1805
1890
|
const result = await this.sendEmail(emailData);
|
|
1806
1891
|
await this.logEmailAttempt(
|
|
1807
1892
|
{
|
|
@@ -1815,7 +1900,8 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1815
1900
|
} catch (error) {
|
|
1816
1901
|
console.error(
|
|
1817
1902
|
"[PractitionerInviteMailingService] Error sending invitation email:",
|
|
1818
|
-
error
|
|
1903
|
+
error instanceof Error ? error.message : error,
|
|
1904
|
+
error instanceof Error ? error.stack : ""
|
|
1819
1905
|
);
|
|
1820
1906
|
await this.logEmailAttempt(
|
|
1821
1907
|
{
|
|
@@ -1843,18 +1929,62 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1843
1929
|
"[PractitionerInviteMailingService] Handling token creation event for token:",
|
|
1844
1930
|
tokenData.id
|
|
1845
1931
|
);
|
|
1932
|
+
if (!tokenData || !tokenData.id || !tokenData.token || !tokenData.email) {
|
|
1933
|
+
throw new Error(
|
|
1934
|
+
`Invalid token data: Missing required properties. Token ID: ${tokenData == null ? void 0 : tokenData.id}`
|
|
1935
|
+
);
|
|
1936
|
+
}
|
|
1937
|
+
if (!tokenData.practitionerId) {
|
|
1938
|
+
throw new Error(
|
|
1939
|
+
`Token ${tokenData.id} is missing practitionerId reference`
|
|
1940
|
+
);
|
|
1941
|
+
}
|
|
1942
|
+
if (!tokenData.clinicId) {
|
|
1943
|
+
throw new Error(`Token ${tokenData.id} is missing clinicId reference`);
|
|
1944
|
+
}
|
|
1945
|
+
if (!tokenData.expiresAt) {
|
|
1946
|
+
throw new Error(`Token ${tokenData.id} is missing expiration date`);
|
|
1947
|
+
}
|
|
1948
|
+
console.log(
|
|
1949
|
+
`[PractitionerInviteMailingService] Fetching practitioner data: ${tokenData.practitionerId}`
|
|
1950
|
+
);
|
|
1846
1951
|
const practitionerRef = this.db.collection(PRACTITIONERS_COLLECTION).doc(tokenData.practitionerId);
|
|
1847
1952
|
const practitionerDoc = await practitionerRef.get();
|
|
1848
1953
|
if (!practitionerDoc.exists) {
|
|
1849
1954
|
throw new Error(`Practitioner ${tokenData.practitionerId} not found`);
|
|
1850
1955
|
}
|
|
1851
1956
|
const practitionerData = practitionerDoc.data();
|
|
1957
|
+
if (!practitionerData || !practitionerData.basicInfo) {
|
|
1958
|
+
throw new Error(
|
|
1959
|
+
`Practitioner ${tokenData.practitionerId} has invalid data structure`
|
|
1960
|
+
);
|
|
1961
|
+
}
|
|
1962
|
+
console.log(
|
|
1963
|
+
`[PractitionerInviteMailingService] Practitioner found: ${practitionerData.basicInfo.firstName} ${practitionerData.basicInfo.lastName}`
|
|
1964
|
+
);
|
|
1965
|
+
console.log(
|
|
1966
|
+
`[PractitionerInviteMailingService] Fetching clinic data: ${tokenData.clinicId}`
|
|
1967
|
+
);
|
|
1852
1968
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(tokenData.clinicId);
|
|
1853
1969
|
const clinicDoc = await clinicRef.get();
|
|
1854
1970
|
if (!clinicDoc.exists) {
|
|
1855
1971
|
throw new Error(`Clinic ${tokenData.clinicId} not found`);
|
|
1856
1972
|
}
|
|
1857
1973
|
const clinicData = clinicDoc.data();
|
|
1974
|
+
if (!clinicData || !clinicData.contactInfo) {
|
|
1975
|
+
throw new Error(
|
|
1976
|
+
`Clinic ${tokenData.clinicId} has invalid data structure`
|
|
1977
|
+
);
|
|
1978
|
+
}
|
|
1979
|
+
console.log(
|
|
1980
|
+
`[PractitionerInviteMailingService] Clinic found: ${clinicData.name}`
|
|
1981
|
+
);
|
|
1982
|
+
if (!fromAddress) {
|
|
1983
|
+
console.warn(
|
|
1984
|
+
"[PractitionerInviteMailingService] No fromAddress provided, using default"
|
|
1985
|
+
);
|
|
1986
|
+
fromAddress = this.DEFAULT_FROM_ADDRESS;
|
|
1987
|
+
}
|
|
1858
1988
|
const emailData = {
|
|
1859
1989
|
token: {
|
|
1860
1990
|
id: tokenData.id,
|
|
@@ -1870,12 +2000,17 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1870
2000
|
},
|
|
1871
2001
|
clinic: {
|
|
1872
2002
|
name: clinicData.name || "Medical Clinic",
|
|
1873
|
-
contactEmail: clinicData.contactInfo.email || "contact@medclinic.com"
|
|
2003
|
+
contactEmail: clinicData.contactInfo.email || "contact@medclinic.com",
|
|
2004
|
+
// Since there's no contactPerson in the Clinic model, we'll just use "Clinic Admin"
|
|
2005
|
+
contactName: "Clinic Admin"
|
|
1874
2006
|
},
|
|
1875
2007
|
options: {
|
|
1876
2008
|
fromAddress
|
|
1877
2009
|
}
|
|
1878
2010
|
};
|
|
2011
|
+
console.log(
|
|
2012
|
+
"[PractitionerInviteMailingService] Email data prepared, sending invitation"
|
|
2013
|
+
);
|
|
1879
2014
|
await this.sendInvitationEmail(emailData);
|
|
1880
2015
|
console.log(
|
|
1881
2016
|
"[PractitionerInviteMailingService] Invitation email sent successfully"
|
|
@@ -1883,7 +2018,8 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1883
2018
|
} catch (error) {
|
|
1884
2019
|
console.error(
|
|
1885
2020
|
"[PractitionerInviteMailingService] Error handling token creation event:",
|
|
1886
|
-
error
|
|
2021
|
+
error instanceof Error ? error.message : error,
|
|
2022
|
+
error instanceof Error ? error.stack : ""
|
|
1887
2023
|
);
|
|
1888
2024
|
throw error;
|
|
1889
2025
|
}
|
package/dist/admin/index.mjs
CHANGED
|
@@ -1523,6 +1523,15 @@ var BaseMailingService = class {
|
|
|
1523
1523
|
constructor(firestore8, mailgunClient) {
|
|
1524
1524
|
this.db = firestore8;
|
|
1525
1525
|
this.mailgunClient = mailgunClient;
|
|
1526
|
+
if (!this.db) {
|
|
1527
|
+
console.error("[BaseMailingService] No Firestore instance provided");
|
|
1528
|
+
throw new Error("Firestore instance is required");
|
|
1529
|
+
}
|
|
1530
|
+
if (!this.mailgunClient) {
|
|
1531
|
+
console.error("[BaseMailingService] No Mailgun client provided");
|
|
1532
|
+
throw new Error("Mailgun client is required");
|
|
1533
|
+
}
|
|
1534
|
+
console.log("[BaseMailingService] Service initialized successfully");
|
|
1526
1535
|
}
|
|
1527
1536
|
/**
|
|
1528
1537
|
* Sends an email using Mailgun
|
|
@@ -1531,29 +1540,69 @@ var BaseMailingService = class {
|
|
|
1531
1540
|
*/
|
|
1532
1541
|
async sendEmail(data) {
|
|
1533
1542
|
try {
|
|
1543
|
+
if (!data) {
|
|
1544
|
+
throw new Error("Email data object is required");
|
|
1545
|
+
}
|
|
1546
|
+
if (!data.to) {
|
|
1547
|
+
throw new Error("Email 'to' address is required");
|
|
1548
|
+
}
|
|
1534
1549
|
if (!data.from) {
|
|
1535
1550
|
throw new Error(
|
|
1536
1551
|
"Email 'from' address must be provided in sendEmail data."
|
|
1537
1552
|
);
|
|
1538
1553
|
}
|
|
1554
|
+
if (!data.subject) {
|
|
1555
|
+
throw new Error("Email 'subject' is required");
|
|
1556
|
+
}
|
|
1557
|
+
if (!data.html && !data.text) {
|
|
1558
|
+
throw new Error("Email must have either 'html' or 'text' content");
|
|
1559
|
+
}
|
|
1560
|
+
console.log("[BaseMailingService] Sending email via Mailgun", {
|
|
1561
|
+
to: data.to,
|
|
1562
|
+
from: data.from,
|
|
1563
|
+
subject: data.subject,
|
|
1564
|
+
hasHtml: !!data.html,
|
|
1565
|
+
hasText: !!data.text
|
|
1566
|
+
});
|
|
1539
1567
|
return await new Promise(
|
|
1540
1568
|
(resolve, reject) => {
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
} else {
|
|
1546
|
-
console.log(
|
|
1547
|
-
"[BaseMailingService] Email sent successfully:",
|
|
1548
|
-
body
|
|
1549
|
-
);
|
|
1550
|
-
resolve(body);
|
|
1569
|
+
try {
|
|
1570
|
+
const messagesApi = this.mailgunClient.messages();
|
|
1571
|
+
if (!messagesApi) {
|
|
1572
|
+
throw new Error("Could not get Mailgun messages API");
|
|
1551
1573
|
}
|
|
1552
|
-
|
|
1574
|
+
messagesApi.send(data, (error, body) => {
|
|
1575
|
+
if (error) {
|
|
1576
|
+
console.error(
|
|
1577
|
+
"[BaseMailingService] Mailgun API error:",
|
|
1578
|
+
error instanceof Error ? error.message : error,
|
|
1579
|
+
error instanceof Error ? error.stack : ""
|
|
1580
|
+
);
|
|
1581
|
+
reject(error);
|
|
1582
|
+
} else {
|
|
1583
|
+
console.log(
|
|
1584
|
+
"[BaseMailingService] Email sent successfully:",
|
|
1585
|
+
body
|
|
1586
|
+
);
|
|
1587
|
+
resolve(body);
|
|
1588
|
+
}
|
|
1589
|
+
});
|
|
1590
|
+
} catch (sendError) {
|
|
1591
|
+
console.error(
|
|
1592
|
+
"[BaseMailingService] Error in mailgun.messages().send():",
|
|
1593
|
+
sendError instanceof Error ? sendError.message : sendError,
|
|
1594
|
+
sendError instanceof Error ? sendError.stack : ""
|
|
1595
|
+
);
|
|
1596
|
+
reject(sendError);
|
|
1597
|
+
}
|
|
1553
1598
|
}
|
|
1554
1599
|
);
|
|
1555
1600
|
} catch (error) {
|
|
1556
|
-
console.error(
|
|
1601
|
+
console.error(
|
|
1602
|
+
"[BaseMailingService] Error in sendEmail:",
|
|
1603
|
+
error instanceof Error ? error.message : error,
|
|
1604
|
+
error instanceof Error ? error.stack : ""
|
|
1605
|
+
);
|
|
1557
1606
|
throw error;
|
|
1558
1607
|
}
|
|
1559
1608
|
}
|
|
@@ -1571,13 +1620,17 @@ var BaseMailingService = class {
|
|
|
1571
1620
|
subject: emailData.subject,
|
|
1572
1621
|
templateName: emailData.templateName,
|
|
1573
1622
|
success,
|
|
1574
|
-
error: error ? JSON.stringify(error) : null,
|
|
1623
|
+
error: error ? error instanceof Error ? { message: error.message, stack: error.stack } : JSON.stringify(error) : null,
|
|
1575
1624
|
sentAt: admin6.firestore.FieldValue.serverTimestamp()
|
|
1576
1625
|
});
|
|
1626
|
+
console.log(
|
|
1627
|
+
`[BaseMailingService] Email log recorded. Success: ${success}`
|
|
1628
|
+
);
|
|
1577
1629
|
} catch (logError) {
|
|
1578
1630
|
console.error(
|
|
1579
1631
|
"[BaseMailingService] Error logging email attempt:",
|
|
1580
|
-
logError
|
|
1632
|
+
logError instanceof Error ? logError.message : logError,
|
|
1633
|
+
logError instanceof Error ? logError.stack : ""
|
|
1581
1634
|
);
|
|
1582
1635
|
}
|
|
1583
1636
|
}
|
|
@@ -1588,12 +1641,25 @@ var BaseMailingService = class {
|
|
|
1588
1641
|
* @returns Rendered HTML string
|
|
1589
1642
|
*/
|
|
1590
1643
|
renderTemplate(template, variables) {
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1644
|
+
if (!template) {
|
|
1645
|
+
throw new Error("Email template is required");
|
|
1646
|
+
}
|
|
1647
|
+
try {
|
|
1648
|
+
let rendered = template;
|
|
1649
|
+
Object.entries(variables).forEach(([key, value]) => {
|
|
1650
|
+
const regex = new RegExp(`{{\\s*${key}\\s*}}`, "g");
|
|
1651
|
+
rendered = rendered.replace(regex, value || "");
|
|
1652
|
+
});
|
|
1653
|
+
return rendered;
|
|
1654
|
+
} catch (renderError) {
|
|
1655
|
+
console.error(
|
|
1656
|
+
"[BaseMailingService] Error rendering template:",
|
|
1657
|
+
renderError instanceof Error ? renderError.message : renderError
|
|
1658
|
+
);
|
|
1659
|
+
throw new Error(
|
|
1660
|
+
`Template rendering failed: ${renderError instanceof Error ? renderError.message : "Unknown error"}`
|
|
1661
|
+
);
|
|
1662
|
+
}
|
|
1597
1663
|
}
|
|
1598
1664
|
};
|
|
1599
1665
|
|
|
@@ -1745,6 +1811,16 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1745
1811
|
contactEmail,
|
|
1746
1812
|
currentYear
|
|
1747
1813
|
};
|
|
1814
|
+
console.log("[PractitionerInviteMailingService] Template variables:", {
|
|
1815
|
+
clinicName: templateVariables.clinicName,
|
|
1816
|
+
practitionerName: templateVariables.practitionerName,
|
|
1817
|
+
expirationDate: templateVariables.expirationDate,
|
|
1818
|
+
registrationUrl: templateVariables.registrationUrl,
|
|
1819
|
+
contactName: templateVariables.contactName,
|
|
1820
|
+
contactEmail: templateVariables.contactEmail,
|
|
1821
|
+
// Don't log the invite token for security
|
|
1822
|
+
hasInviteToken: !!templateVariables.inviteToken
|
|
1823
|
+
});
|
|
1748
1824
|
const html = this.renderTemplate(
|
|
1749
1825
|
practitionerInvitationTemplate,
|
|
1750
1826
|
templateVariables
|
|
@@ -1755,6 +1831,15 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1755
1831
|
subject,
|
|
1756
1832
|
html
|
|
1757
1833
|
};
|
|
1834
|
+
console.log(
|
|
1835
|
+
"[PractitionerInviteMailingService] Sending email with data:",
|
|
1836
|
+
{
|
|
1837
|
+
to: emailData.to,
|
|
1838
|
+
from: emailData.from,
|
|
1839
|
+
subject: emailData.subject,
|
|
1840
|
+
hasHtml: !!emailData.html
|
|
1841
|
+
}
|
|
1842
|
+
);
|
|
1758
1843
|
const result = await this.sendEmail(emailData);
|
|
1759
1844
|
await this.logEmailAttempt(
|
|
1760
1845
|
{
|
|
@@ -1768,7 +1853,8 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1768
1853
|
} catch (error) {
|
|
1769
1854
|
console.error(
|
|
1770
1855
|
"[PractitionerInviteMailingService] Error sending invitation email:",
|
|
1771
|
-
error
|
|
1856
|
+
error instanceof Error ? error.message : error,
|
|
1857
|
+
error instanceof Error ? error.stack : ""
|
|
1772
1858
|
);
|
|
1773
1859
|
await this.logEmailAttempt(
|
|
1774
1860
|
{
|
|
@@ -1796,18 +1882,62 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1796
1882
|
"[PractitionerInviteMailingService] Handling token creation event for token:",
|
|
1797
1883
|
tokenData.id
|
|
1798
1884
|
);
|
|
1885
|
+
if (!tokenData || !tokenData.id || !tokenData.token || !tokenData.email) {
|
|
1886
|
+
throw new Error(
|
|
1887
|
+
`Invalid token data: Missing required properties. Token ID: ${tokenData == null ? void 0 : tokenData.id}`
|
|
1888
|
+
);
|
|
1889
|
+
}
|
|
1890
|
+
if (!tokenData.practitionerId) {
|
|
1891
|
+
throw new Error(
|
|
1892
|
+
`Token ${tokenData.id} is missing practitionerId reference`
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1895
|
+
if (!tokenData.clinicId) {
|
|
1896
|
+
throw new Error(`Token ${tokenData.id} is missing clinicId reference`);
|
|
1897
|
+
}
|
|
1898
|
+
if (!tokenData.expiresAt) {
|
|
1899
|
+
throw new Error(`Token ${tokenData.id} is missing expiration date`);
|
|
1900
|
+
}
|
|
1901
|
+
console.log(
|
|
1902
|
+
`[PractitionerInviteMailingService] Fetching practitioner data: ${tokenData.practitionerId}`
|
|
1903
|
+
);
|
|
1799
1904
|
const practitionerRef = this.db.collection(PRACTITIONERS_COLLECTION).doc(tokenData.practitionerId);
|
|
1800
1905
|
const practitionerDoc = await practitionerRef.get();
|
|
1801
1906
|
if (!practitionerDoc.exists) {
|
|
1802
1907
|
throw new Error(`Practitioner ${tokenData.practitionerId} not found`);
|
|
1803
1908
|
}
|
|
1804
1909
|
const practitionerData = practitionerDoc.data();
|
|
1910
|
+
if (!practitionerData || !practitionerData.basicInfo) {
|
|
1911
|
+
throw new Error(
|
|
1912
|
+
`Practitioner ${tokenData.practitionerId} has invalid data structure`
|
|
1913
|
+
);
|
|
1914
|
+
}
|
|
1915
|
+
console.log(
|
|
1916
|
+
`[PractitionerInviteMailingService] Practitioner found: ${practitionerData.basicInfo.firstName} ${practitionerData.basicInfo.lastName}`
|
|
1917
|
+
);
|
|
1918
|
+
console.log(
|
|
1919
|
+
`[PractitionerInviteMailingService] Fetching clinic data: ${tokenData.clinicId}`
|
|
1920
|
+
);
|
|
1805
1921
|
const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(tokenData.clinicId);
|
|
1806
1922
|
const clinicDoc = await clinicRef.get();
|
|
1807
1923
|
if (!clinicDoc.exists) {
|
|
1808
1924
|
throw new Error(`Clinic ${tokenData.clinicId} not found`);
|
|
1809
1925
|
}
|
|
1810
1926
|
const clinicData = clinicDoc.data();
|
|
1927
|
+
if (!clinicData || !clinicData.contactInfo) {
|
|
1928
|
+
throw new Error(
|
|
1929
|
+
`Clinic ${tokenData.clinicId} has invalid data structure`
|
|
1930
|
+
);
|
|
1931
|
+
}
|
|
1932
|
+
console.log(
|
|
1933
|
+
`[PractitionerInviteMailingService] Clinic found: ${clinicData.name}`
|
|
1934
|
+
);
|
|
1935
|
+
if (!fromAddress) {
|
|
1936
|
+
console.warn(
|
|
1937
|
+
"[PractitionerInviteMailingService] No fromAddress provided, using default"
|
|
1938
|
+
);
|
|
1939
|
+
fromAddress = this.DEFAULT_FROM_ADDRESS;
|
|
1940
|
+
}
|
|
1811
1941
|
const emailData = {
|
|
1812
1942
|
token: {
|
|
1813
1943
|
id: tokenData.id,
|
|
@@ -1823,12 +1953,17 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1823
1953
|
},
|
|
1824
1954
|
clinic: {
|
|
1825
1955
|
name: clinicData.name || "Medical Clinic",
|
|
1826
|
-
contactEmail: clinicData.contactInfo.email || "contact@medclinic.com"
|
|
1956
|
+
contactEmail: clinicData.contactInfo.email || "contact@medclinic.com",
|
|
1957
|
+
// Since there's no contactPerson in the Clinic model, we'll just use "Clinic Admin"
|
|
1958
|
+
contactName: "Clinic Admin"
|
|
1827
1959
|
},
|
|
1828
1960
|
options: {
|
|
1829
1961
|
fromAddress
|
|
1830
1962
|
}
|
|
1831
1963
|
};
|
|
1964
|
+
console.log(
|
|
1965
|
+
"[PractitionerInviteMailingService] Email data prepared, sending invitation"
|
|
1966
|
+
);
|
|
1832
1967
|
await this.sendInvitationEmail(emailData);
|
|
1833
1968
|
console.log(
|
|
1834
1969
|
"[PractitionerInviteMailingService] Invitation email sent successfully"
|
|
@@ -1836,7 +1971,8 @@ var PractitionerInviteMailingService = class extends BaseMailingService {
|
|
|
1836
1971
|
} catch (error) {
|
|
1837
1972
|
console.error(
|
|
1838
1973
|
"[PractitionerInviteMailingService] Error handling token creation event:",
|
|
1839
|
-
error
|
|
1974
|
+
error instanceof Error ? error.message : error,
|
|
1975
|
+
error instanceof Error ? error.stack : ""
|
|
1840
1976
|
);
|
|
1841
1977
|
throw error;
|
|
1842
1978
|
}
|
package/dist/index.d.mts
CHANGED
|
@@ -4743,8 +4743,8 @@ declare class PatientService extends BaseService {
|
|
|
4743
4743
|
uploadProfilePhoto(patientId: string, file: File): Promise<string>;
|
|
4744
4744
|
updateProfilePhoto(patientId: string, file: File): Promise<string>;
|
|
4745
4745
|
deleteProfilePhoto(patientId: string): Promise<void>;
|
|
4746
|
-
updatePatientProfile(patientId: string, data: Partial<Omit<PatientProfile,
|
|
4747
|
-
updatePatientProfileByUserRef(userRef: string, data: Partial<Omit<PatientProfile,
|
|
4746
|
+
updatePatientProfile(patientId: string, data: Partial<Omit<PatientProfile, "id" | "createdAt" | "updatedAt">>): Promise<PatientProfile>;
|
|
4747
|
+
updatePatientProfileByUserRef(userRef: string, data: Partial<Omit<PatientProfile, "id" | "createdAt" | "updatedAt">>): Promise<PatientProfile>;
|
|
4748
4748
|
/**
|
|
4749
4749
|
* Searches for patient profiles based on clinic/practitioner association.
|
|
4750
4750
|
* Requires information about the requester for security checks.
|
|
@@ -4766,6 +4766,32 @@ declare class PatientService extends BaseService {
|
|
|
4766
4766
|
limit?: number;
|
|
4767
4767
|
startAfter?: string;
|
|
4768
4768
|
}): Promise<PatientProfile[]>;
|
|
4769
|
+
/**
|
|
4770
|
+
* Gets all patients associated with a specific practitioner.
|
|
4771
|
+
*
|
|
4772
|
+
* @param {string} practitionerId - ID of the practitioner whose patients to retrieve
|
|
4773
|
+
* @param {Object} options - Optional parameters for pagination
|
|
4774
|
+
* @param {number} options.limit - Maximum number of profiles to return
|
|
4775
|
+
* @param {string} options.startAfter - The ID of the document to start after (for pagination)
|
|
4776
|
+
* @returns {Promise<PatientProfile[]>} A promise resolving to an array of patient profiles
|
|
4777
|
+
*/
|
|
4778
|
+
getPatientsByPractitioner(practitionerId: string, options?: {
|
|
4779
|
+
limit?: number;
|
|
4780
|
+
startAfter?: string;
|
|
4781
|
+
}): Promise<PatientProfile[]>;
|
|
4782
|
+
/**
|
|
4783
|
+
* Gets all patients associated with a specific clinic.
|
|
4784
|
+
*
|
|
4785
|
+
* @param {string} clinicId - ID of the clinic whose patients to retrieve
|
|
4786
|
+
* @param {Object} options - Optional parameters for pagination
|
|
4787
|
+
* @param {number} options.limit - Maximum number of profiles to return
|
|
4788
|
+
* @param {string} options.startAfter - The ID of the document to start after (for pagination)
|
|
4789
|
+
* @returns {Promise<PatientProfile[]>} A promise resolving to an array of patient profiles
|
|
4790
|
+
*/
|
|
4791
|
+
getPatientsByClinic(clinicId: string, options?: {
|
|
4792
|
+
limit?: number;
|
|
4793
|
+
startAfter?: string;
|
|
4794
|
+
}): Promise<PatientProfile[]>;
|
|
4769
4795
|
}
|
|
4770
4796
|
|
|
4771
4797
|
declare class ClinicGroupService extends BaseService {
|
package/dist/index.d.ts
CHANGED
|
@@ -4743,8 +4743,8 @@ declare class PatientService extends BaseService {
|
|
|
4743
4743
|
uploadProfilePhoto(patientId: string, file: File): Promise<string>;
|
|
4744
4744
|
updateProfilePhoto(patientId: string, file: File): Promise<string>;
|
|
4745
4745
|
deleteProfilePhoto(patientId: string): Promise<void>;
|
|
4746
|
-
updatePatientProfile(patientId: string, data: Partial<Omit<PatientProfile,
|
|
4747
|
-
updatePatientProfileByUserRef(userRef: string, data: Partial<Omit<PatientProfile,
|
|
4746
|
+
updatePatientProfile(patientId: string, data: Partial<Omit<PatientProfile, "id" | "createdAt" | "updatedAt">>): Promise<PatientProfile>;
|
|
4747
|
+
updatePatientProfileByUserRef(userRef: string, data: Partial<Omit<PatientProfile, "id" | "createdAt" | "updatedAt">>): Promise<PatientProfile>;
|
|
4748
4748
|
/**
|
|
4749
4749
|
* Searches for patient profiles based on clinic/practitioner association.
|
|
4750
4750
|
* Requires information about the requester for security checks.
|
|
@@ -4766,6 +4766,32 @@ declare class PatientService extends BaseService {
|
|
|
4766
4766
|
limit?: number;
|
|
4767
4767
|
startAfter?: string;
|
|
4768
4768
|
}): Promise<PatientProfile[]>;
|
|
4769
|
+
/**
|
|
4770
|
+
* Gets all patients associated with a specific practitioner.
|
|
4771
|
+
*
|
|
4772
|
+
* @param {string} practitionerId - ID of the practitioner whose patients to retrieve
|
|
4773
|
+
* @param {Object} options - Optional parameters for pagination
|
|
4774
|
+
* @param {number} options.limit - Maximum number of profiles to return
|
|
4775
|
+
* @param {string} options.startAfter - The ID of the document to start after (for pagination)
|
|
4776
|
+
* @returns {Promise<PatientProfile[]>} A promise resolving to an array of patient profiles
|
|
4777
|
+
*/
|
|
4778
|
+
getPatientsByPractitioner(practitionerId: string, options?: {
|
|
4779
|
+
limit?: number;
|
|
4780
|
+
startAfter?: string;
|
|
4781
|
+
}): Promise<PatientProfile[]>;
|
|
4782
|
+
/**
|
|
4783
|
+
* Gets all patients associated with a specific clinic.
|
|
4784
|
+
*
|
|
4785
|
+
* @param {string} clinicId - ID of the clinic whose patients to retrieve
|
|
4786
|
+
* @param {Object} options - Optional parameters for pagination
|
|
4787
|
+
* @param {number} options.limit - Maximum number of profiles to return
|
|
4788
|
+
* @param {string} options.startAfter - The ID of the document to start after (for pagination)
|
|
4789
|
+
* @returns {Promise<PatientProfile[]>} A promise resolving to an array of patient profiles
|
|
4790
|
+
*/
|
|
4791
|
+
getPatientsByClinic(clinicId: string, options?: {
|
|
4792
|
+
limit?: number;
|
|
4793
|
+
startAfter?: string;
|
|
4794
|
+
}): Promise<PatientProfile[]>;
|
|
4769
4795
|
}
|
|
4770
4796
|
|
|
4771
4797
|
declare class ClinicGroupService extends BaseService {
|