@blackcode_sa/metaestetics-api 1.5.29 → 1.5.30

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.
@@ -20,9 +20,9 @@ var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
20
20
  import * as admin from "firebase-admin";
21
21
  import { Expo } from "expo-server-sdk";
22
22
  var NotificationsAdmin = class {
23
- constructor(firestore6) {
23
+ constructor(firestore7) {
24
24
  this.expo = new Expo();
25
- this.db = firestore6 || admin.firestore();
25
+ this.db = firestore7 || admin.firestore();
26
26
  }
27
27
  /**
28
28
  * Dohvata notifikaciju po ID-u
@@ -209,8 +209,8 @@ var ClinicAggregationService = class {
209
209
  * Constructor for ClinicAggregationService.
210
210
  * @param firestore Optional Firestore instance. If not provided, it uses the default admin SDK instance.
211
211
  */
212
- constructor(firestore6) {
213
- this.db = firestore6 || admin2.firestore();
212
+ constructor(firestore7) {
213
+ this.db = firestore7 || admin2.firestore();
214
214
  }
215
215
  /**
216
216
  * Adds clinic information to a clinic group when a new clinic is created
@@ -684,8 +684,8 @@ var ClinicAggregationService = class {
684
684
  import * as admin3 from "firebase-admin";
685
685
  var CALENDAR_SUBCOLLECTION_ID2 = "calendar";
686
686
  var PractitionerAggregationService = class {
687
- constructor(firestore6) {
688
- this.db = firestore6 || admin3.firestore();
687
+ constructor(firestore7) {
688
+ this.db = firestore7 || admin3.firestore();
689
689
  }
690
690
  /**
691
691
  * Adds practitioner information to a clinic when a new practitioner is created
@@ -1020,8 +1020,8 @@ var PractitionerAggregationService = class {
1020
1020
  import * as admin4 from "firebase-admin";
1021
1021
  var CALENDAR_SUBCOLLECTION_ID3 = "calendar";
1022
1022
  var ProcedureAggregationService = class {
1023
- constructor(firestore6) {
1024
- this.db = firestore6 || admin4.firestore();
1023
+ constructor(firestore7) {
1024
+ this.db = firestore7 || admin4.firestore();
1025
1025
  }
1026
1026
  /**
1027
1027
  * Adds procedure information to a practitioner when a new procedure is created
@@ -1405,8 +1405,8 @@ var ProcedureAggregationService = class {
1405
1405
  import * as admin5 from "firebase-admin";
1406
1406
  var CALENDAR_SUBCOLLECTION_ID4 = "calendar";
1407
1407
  var PatientAggregationService = class {
1408
- constructor(firestore6) {
1409
- this.db = firestore6 || admin5.firestore();
1408
+ constructor(firestore7) {
1409
+ this.db = firestore7 || admin5.firestore();
1410
1410
  }
1411
1411
  // --- Methods for Patient Creation --- >
1412
1412
  // No specific aggregations defined for patient creation in the plan.
@@ -1510,6 +1510,339 @@ var PatientAggregationService = class {
1510
1510
  }
1511
1511
  };
1512
1512
 
1513
+ // src/admin/mailing/base.mailing.service.ts
1514
+ import * as admin6 from "firebase-admin";
1515
+ var BaseMailingService = class {
1516
+ // Removed config property as it's no longer managed here
1517
+ // protected config: MailgunConfig;
1518
+ /**
1519
+ * Constructor for BaseMailingService
1520
+ * @param firestore Firestore instance provided by the caller
1521
+ * @param mailgunClient Mailgun client instance provided by the caller
1522
+ */
1523
+ constructor(firestore7, mailgunClient) {
1524
+ this.db = firestore7;
1525
+ this.mailgunClient = mailgunClient;
1526
+ }
1527
+ /**
1528
+ * Sends an email using Mailgun
1529
+ * @param data Email data to send, including the 'from' address
1530
+ * @returns Promise with the sending result
1531
+ */
1532
+ async sendEmail(data) {
1533
+ try {
1534
+ if (!data.from) {
1535
+ throw new Error(
1536
+ "Email 'from' address must be provided in sendEmail data."
1537
+ );
1538
+ }
1539
+ return await new Promise(
1540
+ (resolve, reject) => {
1541
+ this.mailgunClient.messages().send(data, (error, body) => {
1542
+ if (error) {
1543
+ console.error("[BaseMailingService] Error sending email:", error);
1544
+ reject(error);
1545
+ } else {
1546
+ console.log(
1547
+ "[BaseMailingService] Email sent successfully:",
1548
+ body
1549
+ );
1550
+ resolve(body);
1551
+ }
1552
+ });
1553
+ }
1554
+ );
1555
+ } catch (error) {
1556
+ console.error("[BaseMailingService] Error in sendEmail:", error);
1557
+ throw error;
1558
+ }
1559
+ }
1560
+ /**
1561
+ * Logs email sending attempt to Firestore for tracking
1562
+ * @param emailData Email data that was sent
1563
+ * @param success Whether the email was sent successfully
1564
+ * @param error Error object if the email failed to send
1565
+ */
1566
+ async logEmailAttempt(emailData, success, error) {
1567
+ try {
1568
+ const emailLogRef = this.db.collection("email_logs").doc();
1569
+ await emailLogRef.set({
1570
+ to: emailData.to,
1571
+ subject: emailData.subject,
1572
+ templateName: emailData.templateName,
1573
+ success,
1574
+ error: error ? JSON.stringify(error) : null,
1575
+ sentAt: admin6.firestore.FieldValue.serverTimestamp()
1576
+ });
1577
+ } catch (logError) {
1578
+ console.error(
1579
+ "[BaseMailingService] Error logging email attempt:",
1580
+ logError
1581
+ );
1582
+ }
1583
+ }
1584
+ /**
1585
+ * Renders a simple HTML email template with variables
1586
+ * @param template HTML template string
1587
+ * @param variables Key-value pairs to replace in the template
1588
+ * @returns Rendered HTML string
1589
+ */
1590
+ renderTemplate(template, variables) {
1591
+ let rendered = template;
1592
+ Object.entries(variables).forEach(([key, value]) => {
1593
+ const regex = new RegExp(`{{\\s*${key}\\s*}}`, "g");
1594
+ rendered = rendered.replace(regex, value);
1595
+ });
1596
+ return rendered;
1597
+ }
1598
+ };
1599
+
1600
+ // src/admin/mailing/practitionerInvite/templates/invitation.template.ts
1601
+ var practitionerInvitationTemplate = `
1602
+ <!DOCTYPE html>
1603
+ <html>
1604
+ <head>
1605
+ <meta charset="UTF-8">
1606
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1607
+ <title>Join {{clinicName}} as a Practitioner</title>
1608
+ <style>
1609
+ body {
1610
+ font-family: Arial, sans-serif;
1611
+ line-height: 1.6;
1612
+ color: #333;
1613
+ margin: 0;
1614
+ padding: 0;
1615
+ }
1616
+ .container {
1617
+ max-width: 600px;
1618
+ margin: 0 auto;
1619
+ padding: 20px;
1620
+ }
1621
+ .header {
1622
+ background-color: #4A90E2;
1623
+ padding: 20px;
1624
+ text-align: center;
1625
+ color: white;
1626
+ }
1627
+ .content {
1628
+ padding: 20px;
1629
+ background-color: #f9f9f9;
1630
+ }
1631
+ .footer {
1632
+ padding: 20px;
1633
+ text-align: center;
1634
+ font-size: 12px;
1635
+ color: #888;
1636
+ }
1637
+ .button {
1638
+ display: inline-block;
1639
+ background-color: #4A90E2;
1640
+ color: white;
1641
+ text-decoration: none;
1642
+ padding: 12px 24px;
1643
+ border-radius: 4px;
1644
+ margin: 20px 0;
1645
+ font-weight: bold;
1646
+ }
1647
+ .token {
1648
+ font-size: 24px;
1649
+ font-weight: bold;
1650
+ color: #4A90E2;
1651
+ padding: 10px;
1652
+ background-color: #e9f0f9;
1653
+ border-radius: 4px;
1654
+ display: inline-block;
1655
+ letter-spacing: 2px;
1656
+ margin: 10px 0;
1657
+ }
1658
+ </style>
1659
+ </head>
1660
+ <body>
1661
+ <div class="container">
1662
+ <div class="header">
1663
+ <h1>You've Been Invited</h1>
1664
+ </div>
1665
+ <div class="content">
1666
+ <p>Hello {{practitionerName}},</p>
1667
+
1668
+ <p>You have been invited to join <strong>{{clinicName}}</strong> as a healthcare practitioner.</p>
1669
+
1670
+ <p>Your profile has been created and is ready for you to claim. Please use the following token to register:</p>
1671
+
1672
+ <div style="text-align: center;">
1673
+ <span class="token">{{inviteToken}}</span>
1674
+ </div>
1675
+
1676
+ <p>This token will expire on <strong>{{expirationDate}}</strong>.</p>
1677
+
1678
+ <p>To create your account:</p>
1679
+ <ol>
1680
+ <li>Visit {{registrationUrl}}</li>
1681
+ <li>Enter your email and create a password</li>
1682
+ <li>When prompted, enter the token above</li>
1683
+ </ol>
1684
+
1685
+ <div style="text-align: center;">
1686
+ <a href="{{registrationUrl}}" class="button">Create Your Account</a>
1687
+ </div>
1688
+
1689
+ <p>If you have any questions, please contact {{contactName}} at {{contactEmail}}.</p>
1690
+ </div>
1691
+ <div class="footer">
1692
+ <p>This is an automated message from {{clinicName}}. Please do not reply to this email.</p>
1693
+ <p>&copy; {{currentYear}} {{clinicName}}. All rights reserved.</p>
1694
+ </div>
1695
+ </div>
1696
+ </body>
1697
+ </html>
1698
+ `;
1699
+
1700
+ // src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts
1701
+ var PractitionerInviteMailingService = class extends BaseMailingService {
1702
+ /**
1703
+ * Constructor for PractitionerInviteMailingService
1704
+ * @param firestore Firestore instance provided by the caller
1705
+ * @param mailgunClient Mailgun client instance provided by the caller
1706
+ */
1707
+ constructor(firestore7, mailgunClient) {
1708
+ super(firestore7, mailgunClient);
1709
+ this.DEFAULT_REGISTRATION_URL = "https://app.medclinic.com/register";
1710
+ this.DEFAULT_SUBJECT = "You've Been Invited to Join as a Practitioner";
1711
+ this.DEFAULT_FROM_ADDRESS = "MedClinic <no-reply@your-domain.com>";
1712
+ }
1713
+ /**
1714
+ * Sends a practitioner invitation email
1715
+ * @param data The practitioner invitation data
1716
+ * @returns Promise resolved when email is sent
1717
+ */
1718
+ async sendInvitationEmail(data) {
1719
+ var _a, _b, _c, _d;
1720
+ try {
1721
+ console.log(
1722
+ "[PractitionerInviteMailingService] Sending invitation email to",
1723
+ data.token.email
1724
+ );
1725
+ const expirationDate = data.token.expiresAt.toDate().toLocaleDateString("en-US", {
1726
+ weekday: "long",
1727
+ year: "numeric",
1728
+ month: "long",
1729
+ day: "numeric"
1730
+ });
1731
+ const registrationUrl = ((_a = data.options) == null ? void 0 : _a.registrationUrl) || this.DEFAULT_REGISTRATION_URL;
1732
+ const contactName = data.clinic.contactName || "Clinic Administrator";
1733
+ const contactEmail = data.clinic.contactEmail;
1734
+ const subject = ((_b = data.options) == null ? void 0 : _b.customSubject) || this.DEFAULT_SUBJECT;
1735
+ const fromAddress = ((_c = data.options) == null ? void 0 : _c.fromAddress) || this.DEFAULT_FROM_ADDRESS;
1736
+ const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
1737
+ const practitionerName = `${data.practitioner.firstName} ${data.practitioner.lastName}`;
1738
+ const templateVariables = {
1739
+ clinicName: data.clinic.name,
1740
+ practitionerName,
1741
+ inviteToken: data.token.token,
1742
+ expirationDate,
1743
+ registrationUrl,
1744
+ contactName,
1745
+ contactEmail,
1746
+ currentYear
1747
+ };
1748
+ const html = this.renderTemplate(
1749
+ practitionerInvitationTemplate,
1750
+ templateVariables
1751
+ );
1752
+ const emailData = {
1753
+ to: data.token.email,
1754
+ from: fromAddress,
1755
+ subject,
1756
+ html
1757
+ };
1758
+ const result = await this.sendEmail(emailData);
1759
+ await this.logEmailAttempt(
1760
+ {
1761
+ to: data.token.email,
1762
+ subject,
1763
+ templateName: "practitioner_invitation"
1764
+ },
1765
+ true
1766
+ );
1767
+ return result;
1768
+ } catch (error) {
1769
+ console.error(
1770
+ "[PractitionerInviteMailingService] Error sending invitation email:",
1771
+ error
1772
+ );
1773
+ await this.logEmailAttempt(
1774
+ {
1775
+ to: data.token.email,
1776
+ subject: ((_d = data.options) == null ? void 0 : _d.customSubject) || this.DEFAULT_SUBJECT,
1777
+ templateName: "practitioner_invitation"
1778
+ },
1779
+ false,
1780
+ error
1781
+ );
1782
+ throw error;
1783
+ }
1784
+ }
1785
+ /**
1786
+ * Handles the practitioner token creation event from Cloud Functions
1787
+ * Fetches necessary data using defined types and collection constants,
1788
+ * and sends the invitation email.
1789
+ * @param tokenData The fully typed token object including its id
1790
+ * @param fromAddress The 'from' email address to use, obtained from config
1791
+ * @returns Promise resolved when the email is sent
1792
+ */
1793
+ async handleTokenCreationEvent(tokenData, fromAddress) {
1794
+ try {
1795
+ console.log(
1796
+ "[PractitionerInviteMailingService] Handling token creation event for token:",
1797
+ tokenData.id
1798
+ );
1799
+ const practitionerRef = this.db.collection(PRACTITIONERS_COLLECTION).doc(tokenData.practitionerId);
1800
+ const practitionerDoc = await practitionerRef.get();
1801
+ if (!practitionerDoc.exists) {
1802
+ throw new Error(`Practitioner ${tokenData.practitionerId} not found`);
1803
+ }
1804
+ const practitionerData = practitionerDoc.data();
1805
+ const clinicRef = this.db.collection(CLINICS_COLLECTION).doc(tokenData.clinicId);
1806
+ const clinicDoc = await clinicRef.get();
1807
+ if (!clinicDoc.exists) {
1808
+ throw new Error(`Clinic ${tokenData.clinicId} not found`);
1809
+ }
1810
+ const clinicData = clinicDoc.data();
1811
+ const emailData = {
1812
+ token: {
1813
+ id: tokenData.id,
1814
+ token: tokenData.token,
1815
+ practitionerId: tokenData.practitionerId,
1816
+ email: tokenData.email,
1817
+ clinicId: tokenData.clinicId,
1818
+ expiresAt: tokenData.expiresAt
1819
+ },
1820
+ practitioner: {
1821
+ firstName: practitionerData.basicInfo.firstName || "",
1822
+ lastName: practitionerData.basicInfo.lastName || ""
1823
+ },
1824
+ clinic: {
1825
+ name: clinicData.name || "Medical Clinic",
1826
+ contactEmail: clinicData.contactInfo.email || "contact@medclinic.com"
1827
+ },
1828
+ options: {
1829
+ fromAddress
1830
+ }
1831
+ };
1832
+ await this.sendInvitationEmail(emailData);
1833
+ console.log(
1834
+ "[PractitionerInviteMailingService] Invitation email sent successfully"
1835
+ );
1836
+ } catch (error) {
1837
+ console.error(
1838
+ "[PractitionerInviteMailingService] Error handling token creation event:",
1839
+ error
1840
+ );
1841
+ throw error;
1842
+ }
1843
+ }
1844
+ };
1845
+
1513
1846
  // src/types/index.ts
1514
1847
  var UserRole = /* @__PURE__ */ ((UserRole2) => {
1515
1848
  UserRole2["PATIENT"] = "patient";
@@ -1522,6 +1855,7 @@ var UserRole = /* @__PURE__ */ ((UserRole2) => {
1522
1855
  // src/admin/index.ts
1523
1856
  console.log("[Admin Module] Initialized and services exported.");
1524
1857
  export {
1858
+ BaseMailingService,
1525
1859
  ClinicAggregationService,
1526
1860
  NOTIFICATIONS_COLLECTION,
1527
1861
  NotificationStatus,
@@ -1529,6 +1863,7 @@ export {
1529
1863
  NotificationsAdmin,
1530
1864
  PatientAggregationService,
1531
1865
  PractitionerAggregationService,
1866
+ PractitionerInviteMailingService,
1532
1867
  ProcedureAggregationService,
1533
1868
  UserRole
1534
1869
  };
package/dist/index.d.mts CHANGED
@@ -4545,31 +4545,16 @@ declare class ClinicService extends BaseService {
4545
4545
  private clinicGroupService;
4546
4546
  private clinicAdminService;
4547
4547
  constructor(db: Firestore, auth: Auth, app: FirebaseApp, clinicGroupService: ClinicGroupService, clinicAdminService: ClinicAdminService);
4548
- /**
4549
- * Creates an aggregated ClinicInfo object from Clinic data.
4550
- * @param clinic The clinic object
4551
- * @returns ClinicInfo object
4552
- */
4553
- private _createClinicInfoForAggregation;
4554
- /**
4555
- * Updates the ClinicInfo within the clinicsInfo array for multiple practitioners.
4556
- * @param practitionerIds IDs of practitioners to update
4557
- * @param clinicInfo The updated ClinicInfo object
4558
- */
4559
- private _updateClinicInfoInPractitioners;
4560
4548
  /**
4561
4549
  * Creates a new clinic.
4562
- * Initializes empty doctorsInfo and proceduresInfo.
4563
- * Aggregation into Clinic happens via PractitionerService and ProcedureService.
4564
4550
  */
4565
4551
  createClinic(data: CreateClinicData, creatorAdminId: string): Promise<Clinic>;
4566
4552
  /**
4567
- * Updates a clinic and propagates changes (ClinicInfo) to associated practitioners.
4553
+ * Updates a clinic.
4568
4554
  */
4569
4555
  updateClinic(clinicId: string, data: Partial<Omit<Clinic, "id" | "createdAt" | "clinicGroupId">>, adminId: string): Promise<Clinic>;
4570
4556
  /**
4571
4557
  * Deactivates a clinic.
4572
- * Note: Does not currently remove ClinicInfo from practitioners (might be desired).
4573
4558
  */
4574
4559
  deactivateClinic(clinicId: string, adminId: string): Promise<void>;
4575
4560
  /**
@@ -4582,7 +4567,6 @@ declare class ClinicService extends BaseService {
4582
4567
  getClinicsByGroup(groupId: string): Promise<Clinic[]>;
4583
4568
  /**
4584
4569
  * Pretražuje klinike u određenom radijusu
4585
- * REVIEW: SearchUtils.findClinicsInRadius might need updating for filters.
4586
4570
  */
4587
4571
  findClinicsInRadius(center: {
4588
4572
  latitude: number;
@@ -4708,28 +4692,9 @@ declare class PractitionerService extends BaseService {
4708
4692
  private clinicService?;
4709
4693
  constructor(db: Firestore, auth: Auth, app: FirebaseApp, clinicService?: ClinicService);
4710
4694
  private getClinicService;
4711
- /**
4712
- * Postavlja referencu na ClinicService nakon inicijalizacije
4713
- */
4714
4695
  setClinicService(clinicService: ClinicService): void;
4715
4696
  /**
4716
- * Aggregates clinic information for a practitioner
4717
- * @param clinicIds Array of clinic IDs the practitioner works at
4718
- * @returns Array of ClinicInfo objects
4719
- */
4720
- private aggregateClinicInfo;
4721
- /**
4722
- * @deprecated Aggregation of procedure info is now handled by ProcedureService.
4723
- */
4724
- private aggregateProcedureInfo;
4725
- /**
4726
- * Updates aggregated data (clinics and procedures) for a practitioner
4727
- * @param practitionerId ID of the practitioner to update
4728
- * @returns Updated practitioner
4729
- */
4730
- updateAggregatedData(practitionerId: string): Promise<Practitioner | null>;
4731
- /**
4732
- * Kreira novog zdravstvenog radnika
4697
+ * Creates a new practitioner
4733
4698
  */
4734
4699
  createPractitioner(data: CreatePractitionerData): Promise<Practitioner>;
4735
4700
  /**
@@ -4791,15 +4756,15 @@ declare class PractitionerService extends BaseService {
4791
4756
  */
4792
4757
  getDraftPractitionersByClinic(clinicId: string): Promise<Practitioner[]>;
4793
4758
  /**
4794
- * Ažurira profil zdravstvenog radnika
4759
+ * Updates a practitioner
4795
4760
  */
4796
4761
  updatePractitioner(practitionerId: string, data: UpdatePractitionerData): Promise<Practitioner>;
4797
4762
  /**
4798
- * Dodaje kliniku zdravstvenom radniku
4763
+ * Adds a clinic to a practitioner
4799
4764
  */
4800
4765
  addClinic(practitionerId: string, clinicId: string): Promise<void>;
4801
4766
  /**
4802
- * Uklanja kliniku iz liste klinika zdravstvenog radnika
4767
+ * Removes a clinic from a practitioner
4803
4768
  */
4804
4769
  removeClinic(practitionerId: string, clinicId: string): Promise<void>;
4805
4770
  /**
@@ -4880,30 +4845,6 @@ declare class PractitionerService extends BaseService {
4880
4845
  practitioners: Practitioner[];
4881
4846
  lastDoc: any;
4882
4847
  }>;
4883
- /**
4884
- * Aggregates essential clinic information for embedding in Practitioner.
4885
- * @param clinicIds Array of clinic IDs the practitioner works at
4886
- * @returns Array of ClinicInfo objects
4887
- */
4888
- private _aggregateClinicInfoForPractitioner;
4889
- /**
4890
- * Creates an aggregated DoctorInfo object from Practitioner data.
4891
- * @param practitioner The practitioner object
4892
- * @returns DoctorInfo object
4893
- */
4894
- private _createDoctorInfoForClinic;
4895
- /**
4896
- * Updates the DoctorInfo within the doctorsInfo array for multiple clinics.
4897
- * @param clinicIds IDs of clinics to update
4898
- * @param doctorInfo The updated DoctorInfo object
4899
- */
4900
- private _updateDoctorInfoInClinics;
4901
- /**
4902
- * Removes DoctorInfo from the doctorsInfo array for multiple clinics.
4903
- * @param clinicIds IDs of clinics to update
4904
- * @param practitionerId ID of the practitioner whose info should be removed
4905
- */
4906
- private _removeDoctorInfoFromClinics;
4907
4848
  }
4908
4849
 
4909
4850
  declare class UserService extends BaseService {
@@ -5225,11 +5166,8 @@ declare class ProcedureService extends BaseService {
5225
5166
  private technologyService;
5226
5167
  private productService;
5227
5168
  constructor(db: Firestore, auth: Auth, app: FirebaseApp, categoryService: CategoryService, subcategoryService: SubcategoryService, technologyService: TechnologyService, productService: ProductService);
5228
- private _createProcedureSummaryInfo;
5229
- private _updatePractitionerProcedures;
5230
- private _updateClinicProcedures;
5231
5169
  /**
5232
- * Creates a new procedure and updates related practitioner/clinic aggregates
5170
+ * Creates a new procedure
5233
5171
  * @param data - The data for creating a new procedure
5234
5172
  * @returns The created procedure
5235
5173
  */
@@ -5253,19 +5191,19 @@ declare class ProcedureService extends BaseService {
5253
5191
  */
5254
5192
  getProceduresByPractitioner(practitionerId: string): Promise<Procedure[]>;
5255
5193
  /**
5256
- * Updates a procedure and its related aggregates in Practitioner and Clinic docs
5194
+ * Updates a procedure
5257
5195
  * @param id - The ID of the procedure to update
5258
5196
  * @param data - The data to update the procedure with
5259
5197
  * @returns The updated procedure
5260
5198
  */
5261
5199
  updateProcedure(id: string, data: UpdateProcedureData): Promise<Procedure>;
5262
5200
  /**
5263
- * Deactivates a procedure (soft delete) and updates aggregates
5201
+ * Deactivates a procedure (soft delete)
5264
5202
  * @param id - The ID of the procedure to deactivate
5265
5203
  */
5266
5204
  deactivateProcedure(id: string): Promise<void>;
5267
5205
  /**
5268
- * Deletes a procedure permanently and updates related aggregates
5206
+ * Deletes a procedure permanently
5269
5207
  * @param id - The ID of the procedure to delete
5270
5208
  * @returns A boolean indicating if the deletion was successful
5271
5209
  */
@@ -5292,6 +5230,61 @@ declare class ProcedureService extends BaseService {
5292
5230
  procedures: Procedure[];
5293
5231
  lastDoc: any;
5294
5232
  }>;
5233
+ /**
5234
+ * Searches and filters procedures based on multiple criteria
5235
+ *
5236
+ * @param filters - Various filters to apply
5237
+ * @param filters.nameSearch - Optional search text for procedure name
5238
+ * @param filters.treatmentBenefits - Optional array of treatment benefits to filter by
5239
+ * @param filters.procedureFamily - Optional procedure family to filter by
5240
+ * @param filters.procedureCategory - Optional procedure category to filter by
5241
+ * @param filters.procedureSubcategory - Optional procedure subcategory to filter by
5242
+ * @param filters.procedureTechnology - Optional procedure technology to filter by
5243
+ * @param filters.location - Optional location for distance-based search
5244
+ * @param filters.radiusInKm - Optional radius in kilometers (required if location is provided)
5245
+ * @param filters.minPrice - Optional minimum price
5246
+ * @param filters.maxPrice - Optional maximum price
5247
+ * @param filters.minRating - Optional minimum rating (0-5)
5248
+ * @param filters.maxRating - Optional maximum rating (0-5)
5249
+ * @param filters.pagination - Optional number of results per page
5250
+ * @param filters.lastDoc - Optional last document for pagination
5251
+ * @param filters.isActive - Optional filter for active procedures only
5252
+ * @returns Filtered procedures and the last document for pagination
5253
+ */
5254
+ getProceduresByFilters(filters: {
5255
+ nameSearch?: string;
5256
+ treatmentBenefits?: TreatmentBenefit[];
5257
+ procedureFamily?: ProcedureFamily;
5258
+ procedureCategory?: string;
5259
+ procedureSubcategory?: string;
5260
+ procedureTechnology?: string;
5261
+ location?: {
5262
+ latitude: number;
5263
+ longitude: number;
5264
+ };
5265
+ radiusInKm?: number;
5266
+ minPrice?: number;
5267
+ maxPrice?: number;
5268
+ minRating?: number;
5269
+ maxRating?: number;
5270
+ pagination?: number;
5271
+ lastDoc?: any;
5272
+ isActive?: boolean;
5273
+ }): Promise<{
5274
+ procedures: (Procedure & {
5275
+ distance?: number;
5276
+ })[];
5277
+ lastDoc: any;
5278
+ }>;
5279
+ /**
5280
+ * Helper method to apply in-memory filters to procedures
5281
+ * Used by getProceduresByFilters to apply filters that can't be done in Firestore queries
5282
+ *
5283
+ * @param procedures - The procedures to filter
5284
+ * @param filters - The filters to apply
5285
+ * @returns Filtered procedures
5286
+ */
5287
+ private applyInMemoryFilters;
5295
5288
  }
5296
5289
 
5297
5290
  /**