@blackcode_sa/metaestetics-api 1.10.0 → 1.11.1
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 +337 -319
- package/dist/admin/index.d.ts +337 -319
- package/dist/admin/index.js +98 -79
- package/dist/admin/index.mjs +98 -79
- package/dist/backoffice/index.d.mts +284 -67
- package/dist/backoffice/index.d.ts +284 -67
- package/dist/backoffice/index.js +114 -6
- package/dist/backoffice/index.mjs +112 -6
- package/dist/index.d.mts +3145 -3065
- package/dist/index.d.ts +3145 -3065
- package/dist/index.js +460 -141
- package/dist/index.mjs +463 -143
- package/package.json +3 -1
- package/src/admin/booking/booking.admin.ts +2 -0
- package/src/admin/booking/booking.calculator.ts +121 -117
- package/src/admin/booking/booking.types.ts +3 -0
- package/src/backoffice/expo-safe/index.ts +2 -0
- package/src/backoffice/services/README.md +40 -0
- package/src/backoffice/services/constants.service.ts +268 -0
- package/src/backoffice/services/technology.service.ts +122 -10
- package/src/backoffice/types/admin-constants.types.ts +69 -0
- package/src/backoffice/types/index.ts +1 -0
- package/src/backoffice/types/product.types.ts +3 -1
- package/src/backoffice/types/technology.types.ts +4 -4
- package/src/backoffice/validations/schemas.ts +35 -9
- package/src/services/appointment/appointment.service.ts +0 -5
- package/src/services/appointment/utils/appointment.utils.ts +124 -113
- package/src/services/clinic/clinic.service.ts +163 -82
- package/src/services/procedure/procedure.service.ts +435 -234
- package/src/types/appointment/index.ts +9 -3
- package/src/types/clinic/index.ts +3 -6
- package/src/types/patient/medical-info.types.ts +3 -3
- package/src/types/procedure/index.ts +20 -17
- package/src/validations/appointment.schema.ts +2 -0
- package/src/validations/clinic.schema.ts +3 -6
- package/src/validations/patient/medical-info.schema.ts +7 -2
- package/src/validations/procedure.schema.ts +8 -10
- package/src/backoffice/services/__tests__/brand.service.test.ts +0 -196
- package/src/backoffice/services/__tests__/category.service.test.ts +0 -201
- package/src/backoffice/services/__tests__/product.service.test.ts +0 -358
- package/src/backoffice/services/__tests__/requirement.service.test.ts +0 -226
- package/src/backoffice/services/__tests__/subcategory.service.test.ts +0 -181
- package/src/backoffice/services/__tests__/technology.service.test.ts +0 -1097
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import {
|
|
2
|
+
arrayRemove,
|
|
3
|
+
arrayUnion,
|
|
4
|
+
collection,
|
|
5
|
+
doc,
|
|
6
|
+
getDoc,
|
|
7
|
+
setDoc,
|
|
8
|
+
updateDoc,
|
|
9
|
+
} from "firebase/firestore";
|
|
10
|
+
import { BaseService } from "../../services/base.service";
|
|
11
|
+
import {
|
|
12
|
+
ContraindicationDynamic,
|
|
13
|
+
ContraindicationsDocument,
|
|
14
|
+
TreatmentBenefitDynamic,
|
|
15
|
+
TreatmentBenefitsDocument,
|
|
16
|
+
} from "../types/admin-constants.types";
|
|
17
|
+
|
|
18
|
+
const ADMIN_CONSTANTS_COLLECTION = "admin-constants";
|
|
19
|
+
const TREATMENT_BENEFITS_DOC = "treatment-benefits";
|
|
20
|
+
const CONTRAINDICATIONS_DOC = "contraindications";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @class ConstantsService
|
|
24
|
+
* @description Service for managing administrative constants, such as treatment benefits and contraindications.
|
|
25
|
+
* These constants are stored in a single Firestore collection 'admin-constants',
|
|
26
|
+
* with each type of constant in its own document ('treatment-benefits', 'contraindications').
|
|
27
|
+
* The constants themselves are stored in an array within these documents.
|
|
28
|
+
* @extends {BaseService}
|
|
29
|
+
*/
|
|
30
|
+
export class ConstantsService extends BaseService {
|
|
31
|
+
/**
|
|
32
|
+
* @description Gets the reference to the document holding treatment benefits.
|
|
33
|
+
* @private
|
|
34
|
+
* @type {DocumentReference}
|
|
35
|
+
*/
|
|
36
|
+
private get treatmentBenefitsDocRef() {
|
|
37
|
+
return doc(this.db, ADMIN_CONSTANTS_COLLECTION, TREATMENT_BENEFITS_DOC);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @description Gets the reference to the document holding contraindications.
|
|
42
|
+
* @private
|
|
43
|
+
* @type {DocumentReference}
|
|
44
|
+
*/
|
|
45
|
+
private get contraindicationsDocRef() {
|
|
46
|
+
return doc(this.db, ADMIN_CONSTANTS_COLLECTION, CONTRAINDICATIONS_DOC);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// =================================================================
|
|
50
|
+
// Treatment Benefits
|
|
51
|
+
// =================================================================
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @description Retrieves all treatment benefits.
|
|
55
|
+
* @returns {Promise<TreatmentBenefitDynamic[]>} An array of all treatment benefits.
|
|
56
|
+
*/
|
|
57
|
+
async getAllBenefits(): Promise<TreatmentBenefitDynamic[]> {
|
|
58
|
+
const docSnap = await getDoc(this.treatmentBenefitsDocRef);
|
|
59
|
+
if (!docSnap.exists()) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
return (docSnap.data() as TreatmentBenefitsDocument).benefits;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @description Adds a new treatment benefit.
|
|
67
|
+
* @param {Omit<TreatmentBenefitDynamic, "id">} benefit - The treatment benefit to add, without an ID.
|
|
68
|
+
* @returns {Promise<TreatmentBenefitDynamic>} The newly created treatment benefit with its generated ID.
|
|
69
|
+
*/
|
|
70
|
+
async addTreatmentBenefit(
|
|
71
|
+
benefit: Omit<TreatmentBenefitDynamic, "id">
|
|
72
|
+
): Promise<TreatmentBenefitDynamic> {
|
|
73
|
+
const newBenefit: TreatmentBenefitDynamic = {
|
|
74
|
+
id: this.generateId(),
|
|
75
|
+
...benefit,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const docSnap = await getDoc(this.treatmentBenefitsDocRef);
|
|
79
|
+
if (!docSnap.exists()) {
|
|
80
|
+
await setDoc(this.treatmentBenefitsDocRef, { benefits: [newBenefit] });
|
|
81
|
+
} else {
|
|
82
|
+
await updateDoc(this.treatmentBenefitsDocRef, {
|
|
83
|
+
benefits: arrayUnion(newBenefit),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return newBenefit;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @description Retrieves a single treatment benefit by its ID.
|
|
92
|
+
* @param {string} benefitId - The ID of the treatment benefit to retrieve.
|
|
93
|
+
* @returns {Promise<TreatmentBenefitDynamic | undefined>} The found treatment benefit or undefined.
|
|
94
|
+
*/
|
|
95
|
+
async getBenefitById(
|
|
96
|
+
benefitId: string
|
|
97
|
+
): Promise<TreatmentBenefitDynamic | undefined> {
|
|
98
|
+
const benefits = await this.getAllBenefits();
|
|
99
|
+
return benefits.find((b) => b.id === benefitId);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @description Searches for treatment benefits by name (case-insensitive).
|
|
104
|
+
* @param {string} searchTerm - The term to search for in the benefit names.
|
|
105
|
+
* @returns {Promise<TreatmentBenefitDynamic[]>} An array of matching treatment benefits.
|
|
106
|
+
*/
|
|
107
|
+
async searchBenefitsByName(
|
|
108
|
+
searchTerm: string
|
|
109
|
+
): Promise<TreatmentBenefitDynamic[]> {
|
|
110
|
+
const benefits = await this.getAllBenefits();
|
|
111
|
+
const normalizedSearchTerm = searchTerm.toLowerCase();
|
|
112
|
+
return benefits.filter((b) =>
|
|
113
|
+
b.name.toLowerCase().includes(normalizedSearchTerm)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @description Updates an existing treatment benefit.
|
|
119
|
+
* @param {TreatmentBenefitDynamic} benefit - The treatment benefit with updated data. Its ID must match an existing benefit.
|
|
120
|
+
* @returns {Promise<TreatmentBenefitDynamic>} The updated treatment benefit.
|
|
121
|
+
* @throws {Error} If the treatment benefit is not found.
|
|
122
|
+
*/
|
|
123
|
+
async updateTreatmentBenefit(
|
|
124
|
+
benefit: TreatmentBenefitDynamic
|
|
125
|
+
): Promise<TreatmentBenefitDynamic> {
|
|
126
|
+
const benefits = await this.getAllBenefits();
|
|
127
|
+
const benefitIndex = benefits.findIndex((b) => b.id === benefit.id);
|
|
128
|
+
|
|
129
|
+
if (benefitIndex === -1) {
|
|
130
|
+
throw new Error("Treatment benefit not found.");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
benefits[benefitIndex] = benefit;
|
|
134
|
+
|
|
135
|
+
await updateDoc(this.treatmentBenefitsDocRef, { benefits });
|
|
136
|
+
return benefit;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @description Deletes a treatment benefit by its ID.
|
|
141
|
+
* @param {string} benefitId - The ID of the treatment benefit to delete.
|
|
142
|
+
* @returns {Promise<void>}
|
|
143
|
+
*/
|
|
144
|
+
async deleteTreatmentBenefit(benefitId: string): Promise<void> {
|
|
145
|
+
const benefits = await this.getAllBenefits();
|
|
146
|
+
const benefitToRemove = benefits.find((b) => b.id === benefitId);
|
|
147
|
+
|
|
148
|
+
if (!benefitToRemove) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
await updateDoc(this.treatmentBenefitsDocRef, {
|
|
153
|
+
benefits: arrayRemove(benefitToRemove),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// =================================================================
|
|
158
|
+
// Contraindications
|
|
159
|
+
// =================================================================
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @description Retrieves all contraindications.
|
|
163
|
+
* @returns {Promise<ContraindicationDynamic[]>} An array of all contraindications.
|
|
164
|
+
*/
|
|
165
|
+
async getAllContraindications(): Promise<ContraindicationDynamic[]> {
|
|
166
|
+
const docSnap = await getDoc(this.contraindicationsDocRef);
|
|
167
|
+
if (!docSnap.exists()) {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
return (docSnap.data() as ContraindicationsDocument).contraindications;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @description Adds a new contraindication.
|
|
175
|
+
* @param {Omit<ContraindicationDynamic, "id">} contraindication - The contraindication to add, without an ID.
|
|
176
|
+
* @returns {Promise<ContraindicationDynamic>} The newly created contraindication with its generated ID.
|
|
177
|
+
*/
|
|
178
|
+
async addContraindication(
|
|
179
|
+
contraindication: Omit<ContraindicationDynamic, "id">
|
|
180
|
+
): Promise<ContraindicationDynamic> {
|
|
181
|
+
const newContraindication: ContraindicationDynamic = {
|
|
182
|
+
id: this.generateId(),
|
|
183
|
+
...contraindication,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const docSnap = await getDoc(this.contraindicationsDocRef);
|
|
187
|
+
if (!docSnap.exists()) {
|
|
188
|
+
await setDoc(this.contraindicationsDocRef, {
|
|
189
|
+
contraindications: [newContraindication],
|
|
190
|
+
});
|
|
191
|
+
} else {
|
|
192
|
+
await updateDoc(this.contraindicationsDocRef, {
|
|
193
|
+
contraindications: arrayUnion(newContraindication),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return newContraindication;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @description Retrieves a single contraindication by its ID.
|
|
202
|
+
* @param {string} contraindicationId - The ID of the contraindication to retrieve.
|
|
203
|
+
* @returns {Promise<ContraindicationDynamic | undefined>} The found contraindication or undefined.
|
|
204
|
+
*/
|
|
205
|
+
async getContraindicationById(
|
|
206
|
+
contraindicationId: string
|
|
207
|
+
): Promise<ContraindicationDynamic | undefined> {
|
|
208
|
+
const contraindications = await this.getAllContraindications();
|
|
209
|
+
return contraindications.find((c) => c.id === contraindicationId);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @description Searches for contraindications by name (case-insensitive).
|
|
214
|
+
* @param {string} searchTerm - The term to search for in the contraindication names.
|
|
215
|
+
* @returns {Promise<ContraindicationDynamic[]>} An array of matching contraindications.
|
|
216
|
+
*/
|
|
217
|
+
async searchContraindicationsByName(
|
|
218
|
+
searchTerm: string
|
|
219
|
+
): Promise<ContraindicationDynamic[]> {
|
|
220
|
+
const contraindications = await this.getAllContraindications();
|
|
221
|
+
const normalizedSearchTerm = searchTerm.toLowerCase();
|
|
222
|
+
return contraindications.filter((c) =>
|
|
223
|
+
c.name.toLowerCase().includes(normalizedSearchTerm)
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* @description Updates an existing contraindication.
|
|
229
|
+
* @param {ContraindicationDynamic} contraindication - The contraindication with updated data. Its ID must match an existing one.
|
|
230
|
+
* @returns {Promise<ContraindicationDynamic>} The updated contraindication.
|
|
231
|
+
* @throws {Error} If the contraindication is not found.
|
|
232
|
+
*/
|
|
233
|
+
async updateContraindication(
|
|
234
|
+
contraindication: ContraindicationDynamic
|
|
235
|
+
): Promise<ContraindicationDynamic> {
|
|
236
|
+
const contraindications = await this.getAllContraindications();
|
|
237
|
+
const index = contraindications.findIndex(
|
|
238
|
+
(c) => c.id === contraindication.id
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
if (index === -1) {
|
|
242
|
+
throw new Error("Contraindication not found.");
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
contraindications[index] = contraindication;
|
|
246
|
+
|
|
247
|
+
await updateDoc(this.contraindicationsDocRef, { contraindications });
|
|
248
|
+
return contraindication;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* @description Deletes a contraindication by its ID.
|
|
253
|
+
* @param {string} contraindicationId - The ID of the contraindication to delete.
|
|
254
|
+
* @returns {Promise<void>}
|
|
255
|
+
*/
|
|
256
|
+
async deleteContraindication(contraindicationId: string): Promise<void> {
|
|
257
|
+
const contraindications = await this.getAllContraindications();
|
|
258
|
+
const toRemove = contraindications.find((c) => c.id === contraindicationId);
|
|
259
|
+
|
|
260
|
+
if (!toRemove) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
await updateDoc(this.contraindicationsDocRef, {
|
|
265
|
+
contraindications: arrayRemove(toRemove),
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
import { Technology, TECHNOLOGIES_COLLECTION } from "../types/technology.types";
|
|
15
15
|
import { Requirement, RequirementType } from "../types/requirement.types";
|
|
16
16
|
import { BlockingCondition } from "../types/static/blocking-condition.types";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { ContraindicationDynamic } from "../types/admin-constants.types";
|
|
18
|
+
import { TreatmentBenefitDynamic } from "../types/admin-constants.types";
|
|
19
19
|
import {
|
|
20
20
|
CertificationLevel,
|
|
21
21
|
CertificationSpecialty,
|
|
@@ -346,12 +346,21 @@ export class TechnologyService extends BaseService {
|
|
|
346
346
|
*/
|
|
347
347
|
async addContraindication(
|
|
348
348
|
technologyId: string,
|
|
349
|
-
contraindication:
|
|
349
|
+
contraindication: ContraindicationDynamic
|
|
350
350
|
) {
|
|
351
351
|
const docRef = doc(this.getTechnologiesRef(), technologyId);
|
|
352
|
+
const technology = await this.getById(technologyId);
|
|
353
|
+
if (!technology) {
|
|
354
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const existingContraindications = technology.contraindications || [];
|
|
358
|
+
if (existingContraindications.some((c) => c.id === contraindication.id)) {
|
|
359
|
+
return technology; // Already exists, do nothing
|
|
360
|
+
}
|
|
352
361
|
|
|
353
362
|
await updateDoc(docRef, {
|
|
354
|
-
contraindications:
|
|
363
|
+
contraindications: [...existingContraindications, contraindication],
|
|
355
364
|
updatedAt: new Date(),
|
|
356
365
|
});
|
|
357
366
|
|
|
@@ -366,12 +375,62 @@ export class TechnologyService extends BaseService {
|
|
|
366
375
|
*/
|
|
367
376
|
async removeContraindication(
|
|
368
377
|
technologyId: string,
|
|
369
|
-
contraindication:
|
|
378
|
+
contraindication: ContraindicationDynamic
|
|
370
379
|
) {
|
|
371
380
|
const docRef = doc(this.getTechnologiesRef(), technologyId);
|
|
381
|
+
const technology = await this.getById(technologyId);
|
|
382
|
+
if (!technology) {
|
|
383
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const updatedContraindications = (
|
|
387
|
+
technology.contraindications || []
|
|
388
|
+
).filter((c) => c.id !== contraindication.id);
|
|
389
|
+
|
|
390
|
+
await updateDoc(docRef, {
|
|
391
|
+
contraindications: updatedContraindications,
|
|
392
|
+
updatedAt: new Date(),
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
return this.getById(technologyId);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Updates an existing contraindication in a technology's list.
|
|
400
|
+
* If the contraindication does not exist, it will not be added.
|
|
401
|
+
* @param technologyId - ID of the technology
|
|
402
|
+
* @param contraindication - The updated contraindication object
|
|
403
|
+
* @returns The updated technology
|
|
404
|
+
*/
|
|
405
|
+
async updateContraindication(
|
|
406
|
+
technologyId: string,
|
|
407
|
+
contraindication: ContraindicationDynamic
|
|
408
|
+
) {
|
|
409
|
+
const docRef = doc(this.getTechnologiesRef(), technologyId);
|
|
410
|
+
const technology = await this.getById(technologyId);
|
|
411
|
+
if (!technology) {
|
|
412
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const contraindications = technology.contraindications || [];
|
|
416
|
+
const index = contraindications.findIndex(
|
|
417
|
+
(c) => c.id === contraindication.id
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
if (index === -1) {
|
|
421
|
+
// If contraindication doesn't exist, do not update
|
|
422
|
+
// Consider throwing an error if this is an unexpected state
|
|
423
|
+
console.warn(
|
|
424
|
+
`Contraindication with id ${contraindication.id} not found for technology ${technologyId}. No update performed.`
|
|
425
|
+
);
|
|
426
|
+
return technology;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const updatedContraindications = [...contraindications];
|
|
430
|
+
updatedContraindications[index] = contraindication;
|
|
372
431
|
|
|
373
432
|
await updateDoc(docRef, {
|
|
374
|
-
contraindications:
|
|
433
|
+
contraindications: updatedContraindications,
|
|
375
434
|
updatedAt: new Date(),
|
|
376
435
|
});
|
|
377
436
|
|
|
@@ -384,11 +443,20 @@ export class TechnologyService extends BaseService {
|
|
|
384
443
|
* @param benefit - Benefit koji se dodaje
|
|
385
444
|
* @returns Ažurirana tehnologija
|
|
386
445
|
*/
|
|
387
|
-
async addBenefit(technologyId: string, benefit:
|
|
446
|
+
async addBenefit(technologyId: string, benefit: TreatmentBenefitDynamic) {
|
|
388
447
|
const docRef = doc(this.getTechnologiesRef(), technologyId);
|
|
448
|
+
const technology = await this.getById(technologyId);
|
|
449
|
+
if (!technology) {
|
|
450
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const existingBenefits = technology.benefits || [];
|
|
454
|
+
if (existingBenefits.some((b) => b.id === benefit.id)) {
|
|
455
|
+
return technology; // Already exists, do nothing
|
|
456
|
+
}
|
|
389
457
|
|
|
390
458
|
await updateDoc(docRef, {
|
|
391
|
-
benefits:
|
|
459
|
+
benefits: [...existingBenefits, benefit],
|
|
392
460
|
updatedAt: new Date(),
|
|
393
461
|
});
|
|
394
462
|
|
|
@@ -401,11 +469,55 @@ export class TechnologyService extends BaseService {
|
|
|
401
469
|
* @param benefit - Benefit koji se uklanja
|
|
402
470
|
* @returns Ažurirana tehnologija
|
|
403
471
|
*/
|
|
404
|
-
async removeBenefit(technologyId: string, benefit:
|
|
472
|
+
async removeBenefit(technologyId: string, benefit: TreatmentBenefitDynamic) {
|
|
405
473
|
const docRef = doc(this.getTechnologiesRef(), technologyId);
|
|
474
|
+
const technology = await this.getById(technologyId);
|
|
475
|
+
if (!technology) {
|
|
476
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const updatedBenefits = (technology.benefits || []).filter(
|
|
480
|
+
(b) => b.id !== benefit.id
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
await updateDoc(docRef, {
|
|
484
|
+
benefits: updatedBenefits,
|
|
485
|
+
updatedAt: new Date(),
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
return this.getById(technologyId);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Updates an existing benefit in a technology's list.
|
|
493
|
+
* If the benefit does not exist, it will not be added.
|
|
494
|
+
* @param technologyId - ID of the technology
|
|
495
|
+
* @param benefit - The updated benefit object
|
|
496
|
+
* @returns The updated technology
|
|
497
|
+
*/
|
|
498
|
+
async updateBenefit(technologyId: string, benefit: TreatmentBenefitDynamic) {
|
|
499
|
+
const docRef = doc(this.getTechnologiesRef(), technologyId);
|
|
500
|
+
const technology = await this.getById(technologyId);
|
|
501
|
+
if (!technology) {
|
|
502
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const benefits = technology.benefits || [];
|
|
506
|
+
const index = benefits.findIndex((b) => b.id === benefit.id);
|
|
507
|
+
|
|
508
|
+
if (index === -1) {
|
|
509
|
+
// If benefit doesn't exist, do not update
|
|
510
|
+
console.warn(
|
|
511
|
+
`Benefit with id ${benefit.id} not found for technology ${technologyId}. No update performed.`
|
|
512
|
+
);
|
|
513
|
+
return technology;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const updatedBenefits = [...benefits];
|
|
517
|
+
updatedBenefits[index] = benefit;
|
|
406
518
|
|
|
407
519
|
await updateDoc(docRef, {
|
|
408
|
-
benefits:
|
|
520
|
+
benefits: updatedBenefits,
|
|
409
521
|
updatedAt: new Date(),
|
|
410
522
|
});
|
|
411
523
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Defines types for dynamically managed administrative constants,
|
|
3
|
+
* such as treatment benefits and contraindications. These are stored in
|
|
4
|
+
* the 'admin-constants' collection in Firestore.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents a single dynamic treatment benefit.
|
|
9
|
+
* These are positive effects or results a patient can expect from a treatment.
|
|
10
|
+
*/
|
|
11
|
+
export interface TreatmentBenefitDynamic {
|
|
12
|
+
/**
|
|
13
|
+
* A unique identifier for the benefit, typically in snake_case.
|
|
14
|
+
* @example "wrinkle_reduction"
|
|
15
|
+
*/
|
|
16
|
+
id: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A human-readable name for the treatment benefit.
|
|
20
|
+
* @example "Wrinkle Reduction"
|
|
21
|
+
*/
|
|
22
|
+
name: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A detailed description of the benefit.
|
|
26
|
+
*/
|
|
27
|
+
description?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Defines the structure of the document storing all treatment benefits
|
|
32
|
+
* in the 'admin-constants' collection.
|
|
33
|
+
* The document ID for this type should be 'treatment-benefits'.
|
|
34
|
+
*/
|
|
35
|
+
export interface TreatmentBenefitsDocument {
|
|
36
|
+
benefits: TreatmentBenefitDynamic[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Represents a single dynamic contraindication.
|
|
41
|
+
* These are conditions or factors that can affect a procedure and require special attention.
|
|
42
|
+
*/
|
|
43
|
+
export interface ContraindicationDynamic {
|
|
44
|
+
/**
|
|
45
|
+
* A unique identifier for the contraindication, typically in snake_case.
|
|
46
|
+
* @example "sensitive_skin"
|
|
47
|
+
*/
|
|
48
|
+
id: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A human-readable name for the contraindication.
|
|
52
|
+
* @example "Sensitive Skin"
|
|
53
|
+
*/
|
|
54
|
+
name: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A detailed description of the contraindication.
|
|
58
|
+
*/
|
|
59
|
+
description?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Defines the structure of the document storing all contraindications
|
|
64
|
+
* in the 'admin-constants' collection.
|
|
65
|
+
* The document ID for this type should be 'contraindications'.
|
|
66
|
+
*/
|
|
67
|
+
export interface ContraindicationsDocument {
|
|
68
|
+
contraindications: ContraindicationDynamic[];
|
|
69
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ContraindicationDynamic } from "./admin-constants.types";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Product used in procedures
|
|
3
5
|
* Can be consumables, equipment, or any other product needed for performing procedures
|
|
@@ -33,7 +35,7 @@ export interface Product {
|
|
|
33
35
|
dosage?: string;
|
|
34
36
|
composition?: string;
|
|
35
37
|
indications?: string[];
|
|
36
|
-
contraindications?:
|
|
38
|
+
contraindications?: ContraindicationDynamic[];
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
/**
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Requirement } from "./requirement.types";
|
|
2
2
|
import { BlockingCondition } from "./static/blocking-condition.types";
|
|
3
|
-
import { Contraindication } from "./static/contraindication.types";
|
|
4
|
-
import { TreatmentBenefit } from "./static/treatment-benefit.types";
|
|
5
3
|
import { CertificationRequirement } from "./static/certification.types";
|
|
6
4
|
import { DocumentTemplate } from "../../types/documentation-templates";
|
|
7
5
|
import { ProcedureFamily } from "./static/procedure-family.types";
|
|
6
|
+
import { ContraindicationDynamic } from "./admin-constants.types";
|
|
7
|
+
import { TreatmentBenefitDynamic } from "./admin-constants.types";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Reference to a documentation template with metadata
|
|
@@ -65,8 +65,8 @@ export interface Technology {
|
|
|
65
65
|
post: Requirement[];
|
|
66
66
|
};
|
|
67
67
|
blockingConditions: BlockingCondition[];
|
|
68
|
-
contraindications:
|
|
69
|
-
benefits:
|
|
68
|
+
contraindications: ContraindicationDynamic[];
|
|
69
|
+
benefits: TreatmentBenefitDynamic[];
|
|
70
70
|
certificationRequirement: CertificationRequirement;
|
|
71
71
|
documentationTemplates?: TechnologyDocumentationTemplate[];
|
|
72
72
|
isActive: boolean;
|
|
@@ -1,27 +1,53 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { ProcedureFamily } from "../types/static/procedure-family.types";
|
|
3
3
|
import { BlockingCondition } from "../types/static/blocking-condition.types";
|
|
4
|
-
import { Contraindication } from "../types/static/contraindication.types";
|
|
5
|
-
import { TreatmentBenefit } from "../types/static/treatment-benefit.types";
|
|
6
4
|
import { TimeUnit, RequirementType } from "../types/requirement.types";
|
|
7
5
|
import {
|
|
8
6
|
CertificationLevel,
|
|
9
7
|
CertificationSpecialty,
|
|
10
8
|
} from "../types/static/certification.types";
|
|
11
|
-
|
|
12
|
-
DocumentElementType,
|
|
13
|
-
HeadingLevel,
|
|
14
|
-
ListType,
|
|
15
|
-
} from "../types/documentation-templates.types";
|
|
9
|
+
|
|
16
10
|
import { documentTemplateSchema } from "../../validations/documentation-templates.schema";
|
|
17
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Zod validation schema for a single dynamic contraindication.
|
|
14
|
+
* @see ContraindicationDynamic in admin-constants.types.ts
|
|
15
|
+
*/
|
|
16
|
+
export const contraindicationDynamicSchema = z.object({
|
|
17
|
+
id: z
|
|
18
|
+
.string()
|
|
19
|
+
.min(1, "Contraindication ID is required")
|
|
20
|
+
.regex(
|
|
21
|
+
/^[a-z0-9_]+$/,
|
|
22
|
+
"ID must be in snake_case (lowercase, numbers, and underscores only)"
|
|
23
|
+
),
|
|
24
|
+
name: z.string().min(1, "Contraindication name is required"),
|
|
25
|
+
description: z.string().optional(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Zod validation schema for a single dynamic treatment benefit.
|
|
30
|
+
* @see TreatmentBenefitDynamic in admin-constants.types.ts
|
|
31
|
+
*/
|
|
32
|
+
export const treatmentBenefitDynamicSchema = z.object({
|
|
33
|
+
id: z
|
|
34
|
+
.string()
|
|
35
|
+
.min(1, "Benefit ID is required")
|
|
36
|
+
.regex(
|
|
37
|
+
/^[a-z0-9_]+$/,
|
|
38
|
+
"ID must be in snake_case (lowercase, numbers, and underscores only)"
|
|
39
|
+
),
|
|
40
|
+
name: z.string().min(1, "Benefit name is required"),
|
|
41
|
+
description: z.string().optional(),
|
|
42
|
+
});
|
|
43
|
+
|
|
18
44
|
/**
|
|
19
45
|
* Base validation schemas for enums
|
|
20
46
|
*/
|
|
21
47
|
export const blockingConditionSchemaBackoffice =
|
|
22
48
|
z.nativeEnum(BlockingCondition);
|
|
23
|
-
export const contraindicationSchemaBackoffice =
|
|
24
|
-
export const treatmentBenefitSchemaBackoffice =
|
|
49
|
+
export const contraindicationSchemaBackoffice = contraindicationDynamicSchema;
|
|
50
|
+
export const treatmentBenefitSchemaBackoffice = treatmentBenefitDynamicSchema;
|
|
25
51
|
export const procedureFamilySchemaBackoffice = z.nativeEnum(ProcedureFamily);
|
|
26
52
|
export const timeUnitSchemaBackoffice = z.nativeEnum(TimeUnit);
|
|
27
53
|
export const requirementTypeSchema = z.nativeEnum(RequirementType);
|
|
@@ -21,18 +21,15 @@ import { BaseService } from "../base.service";
|
|
|
21
21
|
import {
|
|
22
22
|
Appointment,
|
|
23
23
|
AppointmentStatus,
|
|
24
|
-
CreateAppointmentData,
|
|
25
24
|
UpdateAppointmentData,
|
|
26
25
|
SearchAppointmentsParams,
|
|
27
26
|
PaymentStatus,
|
|
28
27
|
AppointmentMediaItem,
|
|
29
28
|
PatientReviewInfo,
|
|
30
|
-
LinkedFormInfo,
|
|
31
29
|
type CreateAppointmentHttpData,
|
|
32
30
|
APPOINTMENTS_COLLECTION,
|
|
33
31
|
} from "../../types/appointment";
|
|
34
32
|
import {
|
|
35
|
-
createAppointmentSchema,
|
|
36
33
|
updateAppointmentSchema,
|
|
37
34
|
searchAppointmentsSchema,
|
|
38
35
|
rescheduleAppointmentSchema,
|
|
@@ -47,8 +44,6 @@ import { FilledDocumentService } from "../documentation-templates/filled-documen
|
|
|
47
44
|
|
|
48
45
|
// Import utility functions
|
|
49
46
|
import {
|
|
50
|
-
fetchAggregatedInfoUtil,
|
|
51
|
-
createAppointmentUtil,
|
|
52
47
|
updateAppointmentUtil,
|
|
53
48
|
getAppointmentByIdUtil,
|
|
54
49
|
searchAppointmentsUtil,
|