@blackcode_sa/metaestetics-api 1.14.47 → 1.14.50

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.
@@ -1711,6 +1711,7 @@ interface ZoneItemData {
1711
1711
  parentZone: string;
1712
1712
  subzones: string[];
1713
1713
  notes?: string;
1714
+ notesVisibleToPatient?: boolean;
1714
1715
  subtotal?: number;
1715
1716
  ionNumber?: string;
1716
1717
  createdAt?: string;
@@ -1711,6 +1711,7 @@ interface ZoneItemData {
1711
1711
  parentZone: string;
1712
1712
  subzones: string[];
1713
1713
  notes?: string;
1714
+ notesVisibleToPatient?: boolean;
1714
1715
  subtotal?: number;
1715
1716
  ionNumber?: string;
1716
1717
  createdAt?: string;
package/dist/index.d.mts CHANGED
@@ -5648,6 +5648,7 @@ interface ZoneItemData {
5648
5648
  parentZone: string;
5649
5649
  subzones: string[];
5650
5650
  notes?: string;
5651
+ notesVisibleToPatient?: boolean;
5651
5652
  subtotal?: number;
5652
5653
  ionNumber?: string;
5653
5654
  createdAt?: string;
@@ -7735,6 +7736,16 @@ declare class AppointmentService extends BaseService {
7735
7736
  * @returns The updated appointment
7736
7737
  */
7737
7738
  updateZonePhotoNoteVisibility(appointmentId: string, zoneId: string, photoIndex: number, noteType: 'before' | 'after', visibleToPatient: boolean, doctorId: string): Promise<Appointment>;
7739
+ /**
7740
+ * Updates visibility of notes for a zone item (product or standalone note)
7741
+ *
7742
+ * @param appointmentId ID of the appointment
7743
+ * @param zoneId Zone ID
7744
+ * @param itemIndex Index of the item in the zone
7745
+ * @param notesVisibleToPatient Whether the notes should be visible to patient
7746
+ * @returns The updated appointment
7747
+ */
7748
+ updateZoneItemNoteVisibility(appointmentId: string, zoneId: string, itemIndex: number, notesVisibleToPatient: boolean): Promise<Appointment>;
7738
7749
  /**
7739
7750
  * Gets a specific photo entry from a zone
7740
7751
  *
package/dist/index.d.ts CHANGED
@@ -5648,6 +5648,7 @@ interface ZoneItemData {
5648
5648
  parentZone: string;
5649
5649
  subzones: string[];
5650
5650
  notes?: string;
5651
+ notesVisibleToPatient?: boolean;
5651
5652
  subtotal?: number;
5652
5653
  ionNumber?: string;
5653
5654
  createdAt?: string;
@@ -7735,6 +7736,16 @@ declare class AppointmentService extends BaseService {
7735
7736
  * @returns The updated appointment
7736
7737
  */
7737
7738
  updateZonePhotoNoteVisibility(appointmentId: string, zoneId: string, photoIndex: number, noteType: 'before' | 'after', visibleToPatient: boolean, doctorId: string): Promise<Appointment>;
7739
+ /**
7740
+ * Updates visibility of notes for a zone item (product or standalone note)
7741
+ *
7742
+ * @param appointmentId ID of the appointment
7743
+ * @param zoneId Zone ID
7744
+ * @param itemIndex Index of the item in the zone
7745
+ * @param notesVisibleToPatient Whether the notes should be visible to patient
7746
+ * @returns The updated appointment
7747
+ */
7748
+ updateZoneItemNoteVisibility(appointmentId: string, zoneId: string, itemIndex: number, notesVisibleToPatient: boolean): Promise<Appointment>;
7738
7749
  /**
7739
7750
  * Gets a specific photo entry from a zone
7740
7751
  *
package/dist/index.js CHANGED
@@ -4996,21 +4996,15 @@ async function initializeFormsForExtendedProcedure(db, appointmentId, procedureI
4996
4996
  );
4997
4997
  continue;
4998
4998
  }
4999
- if (templateRef.isUserForm) {
5000
- console.log(
5001
- `[FormInit] Skipping user form ${templateRef.templateId} for extended procedure ${procedureId}.`
5002
- );
5003
- continue;
5004
- }
5005
4999
  const isRequired = templateRef.isRequired;
5006
- const formSubcollectionPath = DOCTOR_FORMS_SUBCOLLECTION;
5000
+ const isUserForm = templateRef.isUserForm || false;
5001
+ const formSubcollectionPath = isUserForm ? USER_FORMS_SUBCOLLECTION : DOCTOR_FORMS_SUBCOLLECTION;
5007
5002
  const appointmentRef = (0, import_firestore9.doc)(db, APPOINTMENTS_COLLECTION, appointmentId);
5008
5003
  const formsCollectionRef = (0, import_firestore9.collection)(appointmentRef, formSubcollectionPath);
5009
5004
  const filledDocumentData = {
5010
5005
  templateId: templateRef.templateId,
5011
5006
  templateVersion: template.version,
5012
- isUserForm: false,
5013
- // Always false for extended procedures
5007
+ isUserForm,
5014
5008
  isRequired,
5015
5009
  appointmentId,
5016
5010
  procedureId,
@@ -5025,14 +5019,16 @@ async function initializeFormsForExtendedProcedure(db, appointmentId, procedureI
5025
5019
  try {
5026
5020
  const docRef = await (0, import_firestore9.addDoc)(formsCollectionRef, filledDocumentData);
5027
5021
  const filledDocumentId = docRef.id;
5022
+ if (isUserForm && isRequired) {
5023
+ pendingUserFormsIds.push(filledDocumentId);
5024
+ }
5028
5025
  allLinkedFormIds.push(filledDocumentId);
5029
5026
  const linkedForm = {
5030
5027
  formId: filledDocumentId,
5031
5028
  templateId: template.id,
5032
5029
  templateVersion: template.version,
5033
5030
  title: template.title,
5034
- isUserForm: false,
5035
- // Always false for extended procedures
5031
+ isUserForm,
5036
5032
  isRequired,
5037
5033
  sortingOrder: templateRef.sortingOrder,
5038
5034
  status: "pending" /* PENDING */,
@@ -5040,7 +5036,7 @@ async function initializeFormsForExtendedProcedure(db, appointmentId, procedureI
5040
5036
  };
5041
5037
  initializedFormsInfo.push(linkedForm);
5042
5038
  console.log(
5043
- `[FormInit] Created FilledDocument ${filledDocumentId} (template: ${template.id}) for extended procedure ${procedureId} in appointment ${appointmentId}.`
5039
+ `[FormInit] Created FilledDocument ${filledDocumentId} (template: ${template.id}, isUserForm: ${isUserForm}) for extended procedure ${procedureId} in appointment ${appointmentId}.`
5044
5040
  );
5045
5041
  } catch (error) {
5046
5042
  console.error(
@@ -5074,6 +5070,26 @@ async function removeFormsForExtendedProcedure(db, appointmentId, procedureId) {
5074
5070
  );
5075
5071
  }
5076
5072
  }
5073
+ const userFormsRef = (0, import_firestore9.collection)(appointmentRef, USER_FORMS_SUBCOLLECTION);
5074
+ const userFormsQuery = (0, import_firestore9.query)(
5075
+ userFormsRef,
5076
+ (0, import_firestore9.where)("procedureId", "==", procedureId)
5077
+ );
5078
+ const userFormsSnap = await (0, import_firestore9.getDocs)(userFormsQuery);
5079
+ for (const formDoc of userFormsSnap.docs) {
5080
+ try {
5081
+ await (0, import_firestore9.deleteDoc)(formDoc.ref);
5082
+ removedFormIds.push(formDoc.id);
5083
+ console.log(
5084
+ `[FormInit] Removed user form ${formDoc.id} for extended procedure ${procedureId} from appointment ${appointmentId}.`
5085
+ );
5086
+ } catch (error) {
5087
+ console.error(
5088
+ `[FormInit] Error removing user form ${formDoc.id}:`,
5089
+ error
5090
+ );
5091
+ }
5092
+ }
5077
5093
  return removedFormIds;
5078
5094
  }
5079
5095
 
@@ -7005,6 +7021,28 @@ var AppointmentService = class extends BaseService {
7005
7021
  throw error;
7006
7022
  }
7007
7023
  }
7024
+ /**
7025
+ * Updates visibility of notes for a zone item (product or standalone note)
7026
+ *
7027
+ * @param appointmentId ID of the appointment
7028
+ * @param zoneId Zone ID
7029
+ * @param itemIndex Index of the item in the zone
7030
+ * @param notesVisibleToPatient Whether the notes should be visible to patient
7031
+ * @returns The updated appointment
7032
+ */
7033
+ async updateZoneItemNoteVisibility(appointmentId, zoneId, itemIndex, notesVisibleToPatient) {
7034
+ try {
7035
+ console.log(
7036
+ `[APPOINTMENT_SERVICE] Updating zone item note visibility at index ${itemIndex} for zone ${zoneId} to ${notesVisibleToPatient}`
7037
+ );
7038
+ return await updateZoneItemUtil(this.db, appointmentId, zoneId, itemIndex, {
7039
+ notesVisibleToPatient
7040
+ });
7041
+ } catch (error) {
7042
+ console.error(`[APPOINTMENT_SERVICE] Error updating zone item note visibility:`, error);
7043
+ throw error;
7044
+ }
7045
+ }
7008
7046
  /**
7009
7047
  * Gets a specific photo entry from a zone
7010
7048
  *
@@ -7033,7 +7071,13 @@ var AppointmentService = class extends BaseService {
7033
7071
  * @returns The updated appointment
7034
7072
  */
7035
7073
  async updateFinalizationNotes(appointmentId, sharedNotes, internalNotes) {
7074
+ var _a, _b, _c;
7036
7075
  try {
7076
+ console.log("\u{1F50D} [APPOINTMENT_SERVICE] updateFinalizationNotes called:", {
7077
+ appointmentId,
7078
+ sharedNotes,
7079
+ internalNotes
7080
+ });
7037
7081
  const appointment = await this.getAppointmentById(appointmentId);
7038
7082
  if (!appointment) {
7039
7083
  throw new Error(`Appointment ${appointmentId} not found`);
@@ -7050,23 +7094,40 @@ var AppointmentService = class extends BaseService {
7050
7094
  finalizationNotesInternal: null,
7051
7095
  finalizationNotes: null
7052
7096
  };
7097
+ console.log("\u{1F50D} [APPOINTMENT_SERVICE] Current metadata:", {
7098
+ finalizationNotesShared: currentMetadata.finalizationNotesShared,
7099
+ finalizationNotesInternal: currentMetadata.finalizationNotesInternal,
7100
+ finalizationNotes: currentMetadata.finalizationNotes
7101
+ });
7102
+ const metadataUpdate = {
7103
+ selectedZones: currentMetadata.selectedZones,
7104
+ zonePhotos: currentMetadata.zonePhotos,
7105
+ zonesData: currentMetadata.zonesData || null,
7106
+ appointmentProducts: currentMetadata.appointmentProducts || [],
7107
+ extendedProcedures: currentMetadata.extendedProcedures || [],
7108
+ recommendedProcedures: currentMetadata.recommendedProcedures || [],
7109
+ finalbilling: currentMetadata.finalbilling,
7110
+ finalizationNotesShared: sharedNotes !== void 0 ? sharedNotes : currentMetadata.finalizationNotesShared,
7111
+ finalizationNotesInternal: internalNotes !== void 0 ? internalNotes : currentMetadata.finalizationNotesInternal,
7112
+ // Keep deprecated field for backward compatibility during migration
7113
+ finalizationNotes: sharedNotes !== void 0 ? sharedNotes : currentMetadata.finalizationNotes || currentMetadata.finalizationNotesShared
7114
+ };
7115
+ console.log("\u{1F50D} [APPOINTMENT_SERVICE] Update data metadata:", {
7116
+ finalizationNotesShared: metadataUpdate.finalizationNotesShared,
7117
+ finalizationNotesInternal: metadataUpdate.finalizationNotesInternal,
7118
+ finalizationNotes: metadataUpdate.finalizationNotes
7119
+ });
7053
7120
  const updateData = {
7054
- metadata: {
7055
- selectedZones: currentMetadata.selectedZones,
7056
- zonePhotos: currentMetadata.zonePhotos,
7057
- zonesData: currentMetadata.zonesData || null,
7058
- appointmentProducts: currentMetadata.appointmentProducts || [],
7059
- extendedProcedures: currentMetadata.extendedProcedures || [],
7060
- recommendedProcedures: currentMetadata.recommendedProcedures || [],
7061
- finalbilling: currentMetadata.finalbilling,
7062
- finalizationNotesShared: sharedNotes !== void 0 ? sharedNotes : currentMetadata.finalizationNotesShared,
7063
- finalizationNotesInternal: internalNotes !== void 0 ? internalNotes : currentMetadata.finalizationNotesInternal,
7064
- // Keep deprecated field for backward compatibility during migration
7065
- finalizationNotes: sharedNotes !== void 0 ? sharedNotes : currentMetadata.finalizationNotes || currentMetadata.finalizationNotesShared
7066
- },
7121
+ metadata: metadataUpdate,
7067
7122
  updatedAt: (0, import_firestore14.serverTimestamp)()
7068
7123
  };
7069
- return await this.updateAppointment(appointmentId, updateData);
7124
+ const result = await this.updateAppointment(appointmentId, updateData);
7125
+ console.log("\u{1F50D} [APPOINTMENT_SERVICE] After update, result metadata:", {
7126
+ finalizationNotesShared: (_a = result.metadata) == null ? void 0 : _a.finalizationNotesShared,
7127
+ finalizationNotesInternal: (_b = result.metadata) == null ? void 0 : _b.finalizationNotesInternal,
7128
+ finalizationNotes: (_c = result.metadata) == null ? void 0 : _c.finalizationNotes
7129
+ });
7130
+ return result;
7070
7131
  } catch (error) {
7071
7132
  console.error(`[APPOINTMENT_SERVICE] Error updating finalization notes:`, error);
7072
7133
  throw error;
package/dist/index.mjs CHANGED
@@ -4882,21 +4882,15 @@ async function initializeFormsForExtendedProcedure(db, appointmentId, procedureI
4882
4882
  );
4883
4883
  continue;
4884
4884
  }
4885
- if (templateRef.isUserForm) {
4886
- console.log(
4887
- `[FormInit] Skipping user form ${templateRef.templateId} for extended procedure ${procedureId}.`
4888
- );
4889
- continue;
4890
- }
4891
4885
  const isRequired = templateRef.isRequired;
4892
- const formSubcollectionPath = DOCTOR_FORMS_SUBCOLLECTION;
4886
+ const isUserForm = templateRef.isUserForm || false;
4887
+ const formSubcollectionPath = isUserForm ? USER_FORMS_SUBCOLLECTION : DOCTOR_FORMS_SUBCOLLECTION;
4893
4888
  const appointmentRef = doc6(db, APPOINTMENTS_COLLECTION, appointmentId);
4894
4889
  const formsCollectionRef = collection5(appointmentRef, formSubcollectionPath);
4895
4890
  const filledDocumentData = {
4896
4891
  templateId: templateRef.templateId,
4897
4892
  templateVersion: template.version,
4898
- isUserForm: false,
4899
- // Always false for extended procedures
4893
+ isUserForm,
4900
4894
  isRequired,
4901
4895
  appointmentId,
4902
4896
  procedureId,
@@ -4911,14 +4905,16 @@ async function initializeFormsForExtendedProcedure(db, appointmentId, procedureI
4911
4905
  try {
4912
4906
  const docRef = await addDoc(formsCollectionRef, filledDocumentData);
4913
4907
  const filledDocumentId = docRef.id;
4908
+ if (isUserForm && isRequired) {
4909
+ pendingUserFormsIds.push(filledDocumentId);
4910
+ }
4914
4911
  allLinkedFormIds.push(filledDocumentId);
4915
4912
  const linkedForm = {
4916
4913
  formId: filledDocumentId,
4917
4914
  templateId: template.id,
4918
4915
  templateVersion: template.version,
4919
4916
  title: template.title,
4920
- isUserForm: false,
4921
- // Always false for extended procedures
4917
+ isUserForm,
4922
4918
  isRequired,
4923
4919
  sortingOrder: templateRef.sortingOrder,
4924
4920
  status: "pending" /* PENDING */,
@@ -4926,7 +4922,7 @@ async function initializeFormsForExtendedProcedure(db, appointmentId, procedureI
4926
4922
  };
4927
4923
  initializedFormsInfo.push(linkedForm);
4928
4924
  console.log(
4929
- `[FormInit] Created FilledDocument ${filledDocumentId} (template: ${template.id}) for extended procedure ${procedureId} in appointment ${appointmentId}.`
4925
+ `[FormInit] Created FilledDocument ${filledDocumentId} (template: ${template.id}, isUserForm: ${isUserForm}) for extended procedure ${procedureId} in appointment ${appointmentId}.`
4930
4926
  );
4931
4927
  } catch (error) {
4932
4928
  console.error(
@@ -4960,6 +4956,26 @@ async function removeFormsForExtendedProcedure(db, appointmentId, procedureId) {
4960
4956
  );
4961
4957
  }
4962
4958
  }
4959
+ const userFormsRef = collection5(appointmentRef, USER_FORMS_SUBCOLLECTION);
4960
+ const userFormsQuery = query5(
4961
+ userFormsRef,
4962
+ where5("procedureId", "==", procedureId)
4963
+ );
4964
+ const userFormsSnap = await getDocs5(userFormsQuery);
4965
+ for (const formDoc of userFormsSnap.docs) {
4966
+ try {
4967
+ await deleteDoc2(formDoc.ref);
4968
+ removedFormIds.push(formDoc.id);
4969
+ console.log(
4970
+ `[FormInit] Removed user form ${formDoc.id} for extended procedure ${procedureId} from appointment ${appointmentId}.`
4971
+ );
4972
+ } catch (error) {
4973
+ console.error(
4974
+ `[FormInit] Error removing user form ${formDoc.id}:`,
4975
+ error
4976
+ );
4977
+ }
4978
+ }
4963
4979
  return removedFormIds;
4964
4980
  }
4965
4981
 
@@ -6891,6 +6907,28 @@ var AppointmentService = class extends BaseService {
6891
6907
  throw error;
6892
6908
  }
6893
6909
  }
6910
+ /**
6911
+ * Updates visibility of notes for a zone item (product or standalone note)
6912
+ *
6913
+ * @param appointmentId ID of the appointment
6914
+ * @param zoneId Zone ID
6915
+ * @param itemIndex Index of the item in the zone
6916
+ * @param notesVisibleToPatient Whether the notes should be visible to patient
6917
+ * @returns The updated appointment
6918
+ */
6919
+ async updateZoneItemNoteVisibility(appointmentId, zoneId, itemIndex, notesVisibleToPatient) {
6920
+ try {
6921
+ console.log(
6922
+ `[APPOINTMENT_SERVICE] Updating zone item note visibility at index ${itemIndex} for zone ${zoneId} to ${notesVisibleToPatient}`
6923
+ );
6924
+ return await updateZoneItemUtil(this.db, appointmentId, zoneId, itemIndex, {
6925
+ notesVisibleToPatient
6926
+ });
6927
+ } catch (error) {
6928
+ console.error(`[APPOINTMENT_SERVICE] Error updating zone item note visibility:`, error);
6929
+ throw error;
6930
+ }
6931
+ }
6894
6932
  /**
6895
6933
  * Gets a specific photo entry from a zone
6896
6934
  *
@@ -6919,7 +6957,13 @@ var AppointmentService = class extends BaseService {
6919
6957
  * @returns The updated appointment
6920
6958
  */
6921
6959
  async updateFinalizationNotes(appointmentId, sharedNotes, internalNotes) {
6960
+ var _a, _b, _c;
6922
6961
  try {
6962
+ console.log("\u{1F50D} [APPOINTMENT_SERVICE] updateFinalizationNotes called:", {
6963
+ appointmentId,
6964
+ sharedNotes,
6965
+ internalNotes
6966
+ });
6923
6967
  const appointment = await this.getAppointmentById(appointmentId);
6924
6968
  if (!appointment) {
6925
6969
  throw new Error(`Appointment ${appointmentId} not found`);
@@ -6936,23 +6980,40 @@ var AppointmentService = class extends BaseService {
6936
6980
  finalizationNotesInternal: null,
6937
6981
  finalizationNotes: null
6938
6982
  };
6983
+ console.log("\u{1F50D} [APPOINTMENT_SERVICE] Current metadata:", {
6984
+ finalizationNotesShared: currentMetadata.finalizationNotesShared,
6985
+ finalizationNotesInternal: currentMetadata.finalizationNotesInternal,
6986
+ finalizationNotes: currentMetadata.finalizationNotes
6987
+ });
6988
+ const metadataUpdate = {
6989
+ selectedZones: currentMetadata.selectedZones,
6990
+ zonePhotos: currentMetadata.zonePhotos,
6991
+ zonesData: currentMetadata.zonesData || null,
6992
+ appointmentProducts: currentMetadata.appointmentProducts || [],
6993
+ extendedProcedures: currentMetadata.extendedProcedures || [],
6994
+ recommendedProcedures: currentMetadata.recommendedProcedures || [],
6995
+ finalbilling: currentMetadata.finalbilling,
6996
+ finalizationNotesShared: sharedNotes !== void 0 ? sharedNotes : currentMetadata.finalizationNotesShared,
6997
+ finalizationNotesInternal: internalNotes !== void 0 ? internalNotes : currentMetadata.finalizationNotesInternal,
6998
+ // Keep deprecated field for backward compatibility during migration
6999
+ finalizationNotes: sharedNotes !== void 0 ? sharedNotes : currentMetadata.finalizationNotes || currentMetadata.finalizationNotesShared
7000
+ };
7001
+ console.log("\u{1F50D} [APPOINTMENT_SERVICE] Update data metadata:", {
7002
+ finalizationNotesShared: metadataUpdate.finalizationNotesShared,
7003
+ finalizationNotesInternal: metadataUpdate.finalizationNotesInternal,
7004
+ finalizationNotes: metadataUpdate.finalizationNotes
7005
+ });
6939
7006
  const updateData = {
6940
- metadata: {
6941
- selectedZones: currentMetadata.selectedZones,
6942
- zonePhotos: currentMetadata.zonePhotos,
6943
- zonesData: currentMetadata.zonesData || null,
6944
- appointmentProducts: currentMetadata.appointmentProducts || [],
6945
- extendedProcedures: currentMetadata.extendedProcedures || [],
6946
- recommendedProcedures: currentMetadata.recommendedProcedures || [],
6947
- finalbilling: currentMetadata.finalbilling,
6948
- finalizationNotesShared: sharedNotes !== void 0 ? sharedNotes : currentMetadata.finalizationNotesShared,
6949
- finalizationNotesInternal: internalNotes !== void 0 ? internalNotes : currentMetadata.finalizationNotesInternal,
6950
- // Keep deprecated field for backward compatibility during migration
6951
- finalizationNotes: sharedNotes !== void 0 ? sharedNotes : currentMetadata.finalizationNotes || currentMetadata.finalizationNotesShared
6952
- },
7007
+ metadata: metadataUpdate,
6953
7008
  updatedAt: serverTimestamp7()
6954
7009
  };
6955
- return await this.updateAppointment(appointmentId, updateData);
7010
+ const result = await this.updateAppointment(appointmentId, updateData);
7011
+ console.log("\u{1F50D} [APPOINTMENT_SERVICE] After update, result metadata:", {
7012
+ finalizationNotesShared: (_a = result.metadata) == null ? void 0 : _a.finalizationNotesShared,
7013
+ finalizationNotesInternal: (_b = result.metadata) == null ? void 0 : _b.finalizationNotesInternal,
7014
+ finalizationNotes: (_c = result.metadata) == null ? void 0 : _c.finalizationNotes
7015
+ });
7016
+ return result;
6956
7017
  } catch (error) {
6957
7018
  console.error(`[APPOINTMENT_SERVICE] Error updating finalization notes:`, error);
6958
7019
  throw error;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.14.47",
4
+ "version": "1.14.50",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -2200,6 +2200,34 @@ export class AppointmentService extends BaseService {
2200
2200
  }
2201
2201
  }
2202
2202
 
2203
+ /**
2204
+ * Updates visibility of notes for a zone item (product or standalone note)
2205
+ *
2206
+ * @param appointmentId ID of the appointment
2207
+ * @param zoneId Zone ID
2208
+ * @param itemIndex Index of the item in the zone
2209
+ * @param notesVisibleToPatient Whether the notes should be visible to patient
2210
+ * @returns The updated appointment
2211
+ */
2212
+ async updateZoneItemNoteVisibility(
2213
+ appointmentId: string,
2214
+ zoneId: string,
2215
+ itemIndex: number,
2216
+ notesVisibleToPatient: boolean,
2217
+ ): Promise<Appointment> {
2218
+ try {
2219
+ console.log(
2220
+ `[APPOINTMENT_SERVICE] Updating zone item note visibility at index ${itemIndex} for zone ${zoneId} to ${notesVisibleToPatient}`,
2221
+ );
2222
+ return await updateZoneItemUtil(this.db, appointmentId, zoneId, itemIndex, {
2223
+ notesVisibleToPatient,
2224
+ });
2225
+ } catch (error) {
2226
+ console.error(`[APPOINTMENT_SERVICE] Error updating zone item note visibility:`, error);
2227
+ throw error;
2228
+ }
2229
+ }
2230
+
2203
2231
  /**
2204
2232
  * Gets a specific photo entry from a zone
2205
2233
  *
@@ -2238,6 +2266,12 @@ export class AppointmentService extends BaseService {
2238
2266
  internalNotes?: string | null,
2239
2267
  ): Promise<Appointment> {
2240
2268
  try {
2269
+ console.log('🔍 [APPOINTMENT_SERVICE] updateFinalizationNotes called:', {
2270
+ appointmentId,
2271
+ sharedNotes,
2272
+ internalNotes,
2273
+ });
2274
+
2241
2275
  const appointment = await this.getAppointmentById(appointmentId);
2242
2276
  if (!appointment) {
2243
2277
  throw new Error(`Appointment ${appointmentId} not found`);
@@ -2256,29 +2290,51 @@ export class AppointmentService extends BaseService {
2256
2290
  finalizationNotes: null,
2257
2291
  };
2258
2292
 
2293
+ console.log('🔍 [APPOINTMENT_SERVICE] Current metadata:', {
2294
+ finalizationNotesShared: currentMetadata.finalizationNotesShared,
2295
+ finalizationNotesInternal: currentMetadata.finalizationNotesInternal,
2296
+ finalizationNotes: currentMetadata.finalizationNotes,
2297
+ });
2298
+
2299
+ const metadataUpdate = {
2300
+ selectedZones: currentMetadata.selectedZones,
2301
+ zonePhotos: currentMetadata.zonePhotos,
2302
+ zonesData: currentMetadata.zonesData || null,
2303
+ appointmentProducts: currentMetadata.appointmentProducts || [],
2304
+ extendedProcedures: currentMetadata.extendedProcedures || [],
2305
+ recommendedProcedures: currentMetadata.recommendedProcedures || [],
2306
+ finalbilling: currentMetadata.finalbilling,
2307
+ finalizationNotesShared:
2308
+ sharedNotes !== undefined ? sharedNotes : currentMetadata.finalizationNotesShared,
2309
+ finalizationNotesInternal:
2310
+ internalNotes !== undefined ? internalNotes : currentMetadata.finalizationNotesInternal,
2311
+ // Keep deprecated field for backward compatibility during migration
2312
+ finalizationNotes:
2313
+ sharedNotes !== undefined
2314
+ ? sharedNotes
2315
+ : currentMetadata.finalizationNotes || currentMetadata.finalizationNotesShared,
2316
+ };
2317
+
2318
+ console.log('🔍 [APPOINTMENT_SERVICE] Update data metadata:', {
2319
+ finalizationNotesShared: metadataUpdate.finalizationNotesShared,
2320
+ finalizationNotesInternal: metadataUpdate.finalizationNotesInternal,
2321
+ finalizationNotes: metadataUpdate.finalizationNotes,
2322
+ });
2323
+
2259
2324
  const updateData: UpdateAppointmentData = {
2260
- metadata: {
2261
- selectedZones: currentMetadata.selectedZones,
2262
- zonePhotos: currentMetadata.zonePhotos,
2263
- zonesData: currentMetadata.zonesData || null,
2264
- appointmentProducts: currentMetadata.appointmentProducts || [],
2265
- extendedProcedures: currentMetadata.extendedProcedures || [],
2266
- recommendedProcedures: currentMetadata.recommendedProcedures || [],
2267
- finalbilling: currentMetadata.finalbilling,
2268
- finalizationNotesShared:
2269
- sharedNotes !== undefined ? sharedNotes : currentMetadata.finalizationNotesShared,
2270
- finalizationNotesInternal:
2271
- internalNotes !== undefined ? internalNotes : currentMetadata.finalizationNotesInternal,
2272
- // Keep deprecated field for backward compatibility during migration
2273
- finalizationNotes:
2274
- sharedNotes !== undefined
2275
- ? sharedNotes
2276
- : currentMetadata.finalizationNotes || currentMetadata.finalizationNotesShared,
2277
- },
2325
+ metadata: metadataUpdate,
2278
2326
  updatedAt: serverTimestamp(),
2279
2327
  };
2280
2328
 
2281
- return await this.updateAppointment(appointmentId, updateData);
2329
+ const result = await this.updateAppointment(appointmentId, updateData);
2330
+
2331
+ console.log('🔍 [APPOINTMENT_SERVICE] After update, result metadata:', {
2332
+ finalizationNotesShared: result.metadata?.finalizationNotesShared,
2333
+ finalizationNotesInternal: result.metadata?.finalizationNotesInternal,
2334
+ finalizationNotes: result.metadata?.finalizationNotes,
2335
+ });
2336
+
2337
+ return result;
2282
2338
  } catch (error) {
2283
2339
  console.error(`[APPOINTMENT_SERVICE] Error updating finalization notes:`, error);
2284
2340
  throw error;
@@ -3,6 +3,7 @@ import {
3
3
  DocumentTemplate,
4
4
  FilledDocumentStatus,
5
5
  DOCTOR_FORMS_SUBCOLLECTION,
6
+ USER_FORMS_SUBCOLLECTION,
6
7
  DOCUMENTATION_TEMPLATES_COLLECTION,
7
8
  } from '../../../types/documentation-templates';
8
9
  import {
@@ -77,7 +78,7 @@ export async function initializeFormsForExtendedProcedure(
77
78
  }
78
79
  }
79
80
 
80
- // Initialize forms for each template (only doctor forms for extended procedures)
81
+ // Initialize forms for each template (both user forms and doctor forms for extended procedures)
81
82
  for (const templateRef of technologyTemplates) {
82
83
  const template = templatesMap.get(templateRef.templateId);
83
84
  if (!template) {
@@ -87,16 +88,11 @@ export async function initializeFormsForExtendedProcedure(
87
88
  continue;
88
89
  }
89
90
 
90
- // Skip user forms - only create doctor forms for extended procedures
91
- if (templateRef.isUserForm) {
92
- console.log(
93
- `[FormInit] Skipping user form ${templateRef.templateId} for extended procedure ${procedureId}.`
94
- );
95
- continue;
96
- }
97
-
98
91
  const isRequired = templateRef.isRequired;
99
- const formSubcollectionPath = DOCTOR_FORMS_SUBCOLLECTION;
92
+ const isUserForm = templateRef.isUserForm || false;
93
+ const formSubcollectionPath = isUserForm
94
+ ? USER_FORMS_SUBCOLLECTION
95
+ : DOCTOR_FORMS_SUBCOLLECTION;
100
96
 
101
97
  // Create form document in subcollection
102
98
  const appointmentRef = doc(db, APPOINTMENTS_COLLECTION, appointmentId);
@@ -105,7 +101,7 @@ export async function initializeFormsForExtendedProcedure(
105
101
  const filledDocumentData = {
106
102
  templateId: templateRef.templateId,
107
103
  templateVersion: template.version,
108
- isUserForm: false, // Always false for extended procedures
104
+ isUserForm: isUserForm,
109
105
  isRequired: isRequired,
110
106
  appointmentId: appointmentId,
111
107
  procedureId: procedureId,
@@ -122,7 +118,10 @@ export async function initializeFormsForExtendedProcedure(
122
118
  const docRef = await addDoc(formsCollectionRef, filledDocumentData);
123
119
  const filledDocumentId = docRef.id;
124
120
 
125
- // No user forms for extended procedures, so no pending user forms
121
+ // Add to pendingUserFormsIds if it's a required user form
122
+ if (isUserForm && isRequired) {
123
+ pendingUserFormsIds.push(filledDocumentId);
124
+ }
126
125
 
127
126
  allLinkedFormIds.push(filledDocumentId);
128
127
 
@@ -131,7 +130,7 @@ export async function initializeFormsForExtendedProcedure(
131
130
  templateId: template.id,
132
131
  templateVersion: template.version,
133
132
  title: template.title,
134
- isUserForm: false, // Always false for extended procedures
133
+ isUserForm: isUserForm,
135
134
  isRequired: isRequired,
136
135
  sortingOrder: templateRef.sortingOrder,
137
136
  status: FilledDocumentStatus.PENDING,
@@ -140,7 +139,7 @@ export async function initializeFormsForExtendedProcedure(
140
139
  initializedFormsInfo.push(linkedForm);
141
140
 
142
141
  console.log(
143
- `[FormInit] Created FilledDocument ${filledDocumentId} (template: ${template.id}) for extended procedure ${procedureId} in appointment ${appointmentId}.`
142
+ `[FormInit] Created FilledDocument ${filledDocumentId} (template: ${template.id}, isUserForm: ${isUserForm}) for extended procedure ${procedureId} in appointment ${appointmentId}.`
144
143
  );
145
144
  } catch (error) {
146
145
  console.error(
@@ -155,6 +154,7 @@ export async function initializeFormsForExtendedProcedure(
155
154
 
156
155
  /**
157
156
  * Removes all forms associated with a specific procedure from an appointment
157
+ * Removes both user forms and doctor forms
158
158
  * @param db Firestore instance
159
159
  * @param appointmentId Appointment ID
160
160
  * @param procedureId Procedure ID to remove forms for
@@ -167,11 +167,10 @@ export async function removeFormsForExtendedProcedure(
167
167
  ): Promise<string[]> {
168
168
  const removedFormIds: string[] = [];
169
169
 
170
- // Only remove from doctor forms subcollection (no user forms for extended procedures)
171
170
  const appointmentRef = doc(db, APPOINTMENTS_COLLECTION, appointmentId);
172
- const doctorFormsRef = collection(appointmentRef, DOCTOR_FORMS_SUBCOLLECTION);
173
171
 
174
- // Query doctor forms for this procedure
172
+ // Remove from doctor forms subcollection
173
+ const doctorFormsRef = collection(appointmentRef, DOCTOR_FORMS_SUBCOLLECTION);
175
174
  const doctorFormsQuery = query(
176
175
  doctorFormsRef,
177
176
  where('procedureId', '==', procedureId)
@@ -193,6 +192,29 @@ export async function removeFormsForExtendedProcedure(
193
192
  }
194
193
  }
195
194
 
195
+ // Remove from user forms subcollection
196
+ const userFormsRef = collection(appointmentRef, USER_FORMS_SUBCOLLECTION);
197
+ const userFormsQuery = query(
198
+ userFormsRef,
199
+ where('procedureId', '==', procedureId)
200
+ );
201
+ const userFormsSnap = await getDocs(userFormsQuery);
202
+
203
+ for (const formDoc of userFormsSnap.docs) {
204
+ try {
205
+ await deleteDoc(formDoc.ref);
206
+ removedFormIds.push(formDoc.id);
207
+ console.log(
208
+ `[FormInit] Removed user form ${formDoc.id} for extended procedure ${procedureId} from appointment ${appointmentId}.`
209
+ );
210
+ } catch (error) {
211
+ console.error(
212
+ `[FormInit] Error removing user form ${formDoc.id}:`,
213
+ error
214
+ );
215
+ }
216
+ }
217
+
196
218
  return removedFormIds;
197
219
  }
198
220
 
@@ -211,9 +233,9 @@ export async function getFormsForExtendedProcedure(
211
233
  const formIds: string[] = [];
212
234
 
213
235
  const appointmentRef = doc(db, APPOINTMENTS_COLLECTION, appointmentId);
214
- const doctorFormsRef = collection(appointmentRef, DOCTOR_FORMS_SUBCOLLECTION);
215
236
 
216
237
  // Query doctor forms for this procedure
238
+ const doctorFormsRef = collection(appointmentRef, DOCTOR_FORMS_SUBCOLLECTION);
217
239
  const doctorFormsQuery = query(
218
240
  doctorFormsRef,
219
241
  where('procedureId', '==', procedureId)
@@ -221,5 +243,14 @@ export async function getFormsForExtendedProcedure(
221
243
  const doctorFormsSnap = await getDocs(doctorFormsQuery);
222
244
  doctorFormsSnap.docs.forEach(doc => formIds.push(doc.id));
223
245
 
246
+ // Query user forms for this procedure
247
+ const userFormsRef = collection(appointmentRef, USER_FORMS_SUBCOLLECTION);
248
+ const userFormsQuery = query(
249
+ userFormsRef,
250
+ where('procedureId', '==', procedureId)
251
+ );
252
+ const userFormsSnap = await getDocs(userFormsQuery);
253
+ userFormsSnap.docs.forEach(doc => formIds.push(doc.id));
254
+
224
255
  return formIds;
225
256
  }
@@ -166,6 +166,7 @@ export interface ZoneItemData {
166
166
  parentZone: string; // Zone key in format "category.zone" (e.g., "face.forehead")
167
167
  subzones: string[];
168
168
  notes?: string;
169
+ notesVisibleToPatient?: boolean; // Whether notes are visible to patient (privacy-first, default false)
169
170
  subtotal?: number;
170
171
  ionNumber?: string;
171
172
  createdAt?: string; // ISO timestamp