@blackcode_sa/metaestetics-api 1.14.44 → 1.14.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.d.mts +21 -5
- package/dist/admin/index.d.ts +21 -5
- package/dist/index.d.mts +53 -5
- package/dist/index.d.ts +53 -5
- package/dist/index.js +184 -14
- package/dist/index.mjs +184 -14
- package/package.json +1 -1
- package/src/services/appointment/appointment.service.ts +167 -5
- package/src/services/appointment/utils/zone-management.utils.ts +5 -1
- package/src/services/appointment/utils/zone-photo.utils.ts +91 -3
- package/src/types/appointment/index.ts +21 -5
- package/src/validations/appointment.schema.ts +10 -4
|
@@ -7,6 +7,30 @@ import {
|
|
|
7
7
|
import { getAppointmentOrThrow } from './zone-management.utils';
|
|
8
8
|
import { MediaResource } from '../../media/media.service';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Updates visibility fields with audit trail
|
|
12
|
+
* @param updates Partial updates object
|
|
13
|
+
* @param doctorId ID of the doctor making the change
|
|
14
|
+
*/
|
|
15
|
+
function addVisibilityAudit(
|
|
16
|
+
updates: Partial<BeforeAfterPerZone>,
|
|
17
|
+
doctorId: string,
|
|
18
|
+
): Partial<BeforeAfterPerZone> {
|
|
19
|
+
// Only add audit fields if visibility-related fields are being updated
|
|
20
|
+
if (
|
|
21
|
+
updates.showToPatient !== undefined ||
|
|
22
|
+
updates.beforeNoteVisibleToPatient !== undefined ||
|
|
23
|
+
updates.afterNoteVisibleToPatient !== undefined
|
|
24
|
+
) {
|
|
25
|
+
return {
|
|
26
|
+
...updates,
|
|
27
|
+
visibilityUpdatedAt: serverTimestamp() as any,
|
|
28
|
+
visibilityUpdatedBy: doctorId,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return updates;
|
|
32
|
+
}
|
|
33
|
+
|
|
10
34
|
/**
|
|
11
35
|
* Updates a specific photo entry in a zone by index
|
|
12
36
|
* Can update before/after photos and their notes
|
|
@@ -16,6 +40,7 @@ import { MediaResource } from '../../media/media.service';
|
|
|
16
40
|
* @param zoneId Zone ID
|
|
17
41
|
* @param photoIndex Index of the photo entry to update
|
|
18
42
|
* @param updates Partial updates to apply
|
|
43
|
+
* @param doctorId Optional doctor ID for audit trail (required if updating visibility)
|
|
19
44
|
* @returns Updated appointment
|
|
20
45
|
*/
|
|
21
46
|
export async function updateZonePhotoEntryUtil(
|
|
@@ -23,7 +48,8 @@ export async function updateZonePhotoEntryUtil(
|
|
|
23
48
|
appointmentId: string,
|
|
24
49
|
zoneId: string,
|
|
25
50
|
photoIndex: number,
|
|
26
|
-
updates: Partial<BeforeAfterPerZone
|
|
51
|
+
updates: Partial<BeforeAfterPerZone>,
|
|
52
|
+
doctorId?: string,
|
|
27
53
|
): Promise<Appointment> {
|
|
28
54
|
const appointment = await getAppointmentOrThrow(db, appointmentId);
|
|
29
55
|
|
|
@@ -41,12 +67,16 @@ export async function updateZonePhotoEntryUtil(
|
|
|
41
67
|
throw new Error(`Invalid photo index ${photoIndex} for zone ${zoneId}. Must be between 0 and ${zoneArray.length - 1}`);
|
|
42
68
|
}
|
|
43
69
|
|
|
44
|
-
// Update the entry
|
|
70
|
+
// Update the entry with audit trail if visibility is being changed
|
|
71
|
+
const updatesWithAudit = doctorId
|
|
72
|
+
? addVisibilityAudit(updates, doctorId)
|
|
73
|
+
: updates;
|
|
74
|
+
|
|
45
75
|
const updatedZonePhotos = { ...zonePhotos };
|
|
46
76
|
updatedZonePhotos[zoneId] = [...zoneArray];
|
|
47
77
|
updatedZonePhotos[zoneId][photoIndex] = {
|
|
48
78
|
...zoneArray[photoIndex],
|
|
49
|
-
...
|
|
79
|
+
...updatesWithAudit,
|
|
50
80
|
};
|
|
51
81
|
|
|
52
82
|
// Update appointment
|
|
@@ -171,3 +201,61 @@ export async function getZonePhotoEntryUtil(
|
|
|
171
201
|
return zoneArray[photoIndex];
|
|
172
202
|
}
|
|
173
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Updates visibility of a photo pair (before AND after together)
|
|
206
|
+
*
|
|
207
|
+
* @param db Firestore instance
|
|
208
|
+
* @param appointmentId Appointment ID
|
|
209
|
+
* @param zoneId Zone ID
|
|
210
|
+
* @param photoIndex Index of the photo entry
|
|
211
|
+
* @param showToPatient Whether the photo pair should be visible to patient
|
|
212
|
+
* @param doctorId ID of the doctor making the change (for audit trail)
|
|
213
|
+
* @returns Updated appointment
|
|
214
|
+
*/
|
|
215
|
+
export async function updateZonePhotoVisibilityUtil(
|
|
216
|
+
db: Firestore,
|
|
217
|
+
appointmentId: string,
|
|
218
|
+
zoneId: string,
|
|
219
|
+
photoIndex: number,
|
|
220
|
+
showToPatient: boolean,
|
|
221
|
+
doctorId: string,
|
|
222
|
+
): Promise<Appointment> {
|
|
223
|
+
return updateZonePhotoEntryUtil(
|
|
224
|
+
db,
|
|
225
|
+
appointmentId,
|
|
226
|
+
zoneId,
|
|
227
|
+
photoIndex,
|
|
228
|
+
{ showToPatient },
|
|
229
|
+
doctorId,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Updates visibility of a photo note (before or after)
|
|
235
|
+
*
|
|
236
|
+
* @param db Firestore instance
|
|
237
|
+
* @param appointmentId Appointment ID
|
|
238
|
+
* @param zoneId Zone ID
|
|
239
|
+
* @param photoIndex Index of the photo entry
|
|
240
|
+
* @param noteType Type of note ('before' or 'after')
|
|
241
|
+
* @param visibleToPatient Whether the note should be visible to patient
|
|
242
|
+
* @param doctorId ID of the doctor making the change (for audit trail)
|
|
243
|
+
* @returns Updated appointment
|
|
244
|
+
*/
|
|
245
|
+
export async function updateZonePhotoNoteVisibilityUtil(
|
|
246
|
+
db: Firestore,
|
|
247
|
+
appointmentId: string,
|
|
248
|
+
zoneId: string,
|
|
249
|
+
photoIndex: number,
|
|
250
|
+
noteType: 'before' | 'after',
|
|
251
|
+
visibleToPatient: boolean,
|
|
252
|
+
doctorId: string,
|
|
253
|
+
): Promise<Appointment> {
|
|
254
|
+
const updates: Partial<BeforeAfterPerZone> =
|
|
255
|
+
noteType === 'before'
|
|
256
|
+
? { beforeNoteVisibleToPatient: visibleToPatient }
|
|
257
|
+
: { afterNoteVisibleToPatient: visibleToPatient };
|
|
258
|
+
|
|
259
|
+
return updateZonePhotoEntryUtil(db, appointmentId, zoneId, photoIndex, updates, doctorId);
|
|
260
|
+
}
|
|
261
|
+
|
|
@@ -120,9 +120,20 @@ export interface BeforeAfterPerZone {
|
|
|
120
120
|
before: MediaResource | null;
|
|
121
121
|
/** URL for after photo or null if not available */
|
|
122
122
|
after: MediaResource | null;
|
|
123
|
-
/** Optional note for the
|
|
124
|
-
afterNote?: string | null;
|
|
123
|
+
/** Optional note for the before photo */
|
|
125
124
|
beforeNote?: string | null;
|
|
125
|
+
/** Optional note for the after photo */
|
|
126
|
+
afterNote?: string | null;
|
|
127
|
+
/** Whether this photo pair (before AND after) should be visible to the patient */
|
|
128
|
+
showToPatient?: boolean;
|
|
129
|
+
/** Whether the before note should be visible to the patient */
|
|
130
|
+
beforeNoteVisibleToPatient?: boolean;
|
|
131
|
+
/** Whether the after note should be visible to the patient */
|
|
132
|
+
afterNoteVisibleToPatient?: boolean;
|
|
133
|
+
/** Timestamp when visibility was last updated */
|
|
134
|
+
visibilityUpdatedAt?: Timestamp;
|
|
135
|
+
/** ID of the doctor who last updated visibility */
|
|
136
|
+
visibilityUpdatedBy?: string;
|
|
126
137
|
}
|
|
127
138
|
|
|
128
139
|
/**
|
|
@@ -157,8 +168,6 @@ export interface ZoneItemData {
|
|
|
157
168
|
notes?: string;
|
|
158
169
|
subtotal?: number;
|
|
159
170
|
ionNumber?: string;
|
|
160
|
-
lotNumber?: string; // Optional lot/batch number for the product
|
|
161
|
-
expiryDate?: string; // Optional expiry date (ISO date string)
|
|
162
171
|
createdAt?: string; // ISO timestamp
|
|
163
172
|
updatedAt?: string; // ISO timestamp
|
|
164
173
|
}
|
|
@@ -249,7 +258,14 @@ export interface AppointmentMetadata {
|
|
|
249
258
|
extendedProcedures?: ExtendedProcedureInfo[];
|
|
250
259
|
recommendedProcedures: RecommendedProcedure[]
|
|
251
260
|
finalbilling: FinalBilling | null;
|
|
252
|
-
|
|
261
|
+
/** Final treatment notes shared with patient */
|
|
262
|
+
finalizationNotesShared?: string | null;
|
|
263
|
+
/** Final treatment notes for internal use only (not shared with patient) */
|
|
264
|
+
finalizationNotesInternal?: string | null;
|
|
265
|
+
/**
|
|
266
|
+
* @deprecated Use finalizationNotesShared instead. Kept for backward compatibility during migration.
|
|
267
|
+
*/
|
|
268
|
+
finalizationNotes?: string | null;
|
|
253
269
|
|
|
254
270
|
/**
|
|
255
271
|
* @deprecated Use zonesData instead
|
|
@@ -143,8 +143,13 @@ export const finalizedDetailsSchema = z.object({
|
|
|
143
143
|
export const beforeAfterPerZoneSchema = z.object({
|
|
144
144
|
before: mediaResourceSchema.nullable(),
|
|
145
145
|
after: mediaResourceSchema.nullable(),
|
|
146
|
-
afterNote: z.string().nullable().optional(),
|
|
147
146
|
beforeNote: z.string().nullable().optional(),
|
|
147
|
+
afterNote: z.string().nullable().optional(),
|
|
148
|
+
showToPatient: z.boolean().optional().default(false),
|
|
149
|
+
beforeNoteVisibleToPatient: z.boolean().optional().default(false),
|
|
150
|
+
afterNoteVisibleToPatient: z.boolean().optional().default(false),
|
|
151
|
+
visibilityUpdatedAt: z.any().optional(), // Timestamp
|
|
152
|
+
visibilityUpdatedBy: z.string().optional(),
|
|
148
153
|
});
|
|
149
154
|
|
|
150
155
|
/**
|
|
@@ -220,10 +225,9 @@ export const zoneItemDataSchema = z
|
|
|
220
225
|
},
|
|
221
226
|
),
|
|
222
227
|
notes: z.string().max(MAX_STRING_LENGTH_LONG, 'Notes too long').optional(),
|
|
228
|
+
notesVisibleToPatient: z.boolean().optional().default(false),
|
|
223
229
|
subtotal: z.number().min(0, 'Subtotal must be non-negative').optional(),
|
|
224
230
|
ionNumber: z.string().optional(),
|
|
225
|
-
lotNumber: z.string().max(MAX_STRING_LENGTH, 'Lot number too long').optional(),
|
|
226
|
-
expiryDate: z.string().optional(), // ISO date string (YYYY-MM-DD format)
|
|
227
231
|
createdAt: z.string().optional(),
|
|
228
232
|
updatedAt: z.string().optional(),
|
|
229
233
|
})
|
|
@@ -302,7 +306,9 @@ export const appointmentMetadataSchema = z.object({
|
|
|
302
306
|
recommendedProcedures: z.array(recommendedProcedureSchema).optional().default([]),
|
|
303
307
|
zoneBilling: z.record(z.string(), billingPerZoneSchema).nullable().optional(),
|
|
304
308
|
finalbilling: finalBillingSchema.nullable(),
|
|
305
|
-
|
|
309
|
+
finalizationNotesShared: z.string().nullable().optional(),
|
|
310
|
+
finalizationNotesInternal: z.string().nullable().optional(),
|
|
311
|
+
finalizationNotes: z.string().nullable().optional(), // @deprecated - kept for backward compatibility
|
|
306
312
|
});
|
|
307
313
|
|
|
308
314
|
// --- Main Appointment Schemas ---
|