@blackcode_sa/metaestetics-api 1.7.47 → 1.8.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 +1815 -1667
- package/dist/admin/index.d.ts +1815 -1667
- package/dist/admin/index.js +6993 -6535
- package/dist/admin/index.mjs +6991 -6532
- package/dist/backoffice/index.d.mts +1418 -1418
- package/dist/backoffice/index.d.ts +1418 -1418
- package/dist/backoffice/index.js +1464 -1454
- package/dist/backoffice/index.mjs +1509 -1499
- package/dist/index.d.mts +16217 -14582
- package/dist/index.d.ts +16217 -14582
- package/dist/index.js +11419 -13806
- package/dist/index.mjs +12081 -14593
- package/package.json +5 -5
- package/src/admin/aggregation/appointment/index.ts +1 -0
- package/src/admin/aggregation/clinic/index.ts +1 -0
- package/src/admin/aggregation/forms/index.ts +1 -0
- package/src/admin/aggregation/index.ts +8 -0
- package/src/admin/aggregation/patient/index.ts +1 -0
- package/src/admin/aggregation/practitioner/index.ts +1 -0
- package/src/admin/aggregation/practitioner-invite/index.ts +1 -0
- package/src/admin/aggregation/procedure/index.ts +1 -0
- package/src/admin/aggregation/reviews/index.ts +1 -0
- package/src/admin/booking/index.ts +1 -1
- package/src/admin/calendar/index.ts +1 -0
- package/src/admin/documentation-templates/index.ts +1 -0
- package/src/admin/free-consultation/index.ts +1 -0
- package/src/admin/index.ts +23 -118
- package/src/admin/mailing/appointment/index.ts +1 -0
- package/src/admin/mailing/index.ts +1 -2
- package/src/admin/mailing/practitionerInvite/index.ts +1 -0
- package/src/admin/notifications/index.ts +1 -0
- package/src/admin/requirements/index.ts +1 -0
- package/src/admin/users/index.ts +1 -0
- package/src/admin/users/user-profile.admin.ts +1 -0
- package/src/backoffice/constants/index.ts +1 -0
- package/src/backoffice/errors/index.ts +1 -0
- package/src/backoffice/index.ts +5 -14
- package/src/backoffice/services/index.ts +7 -0
- package/src/backoffice/validations/index.ts +1 -0
- package/src/index.backup.ts +407 -0
- package/src/index.ts +5 -406
- package/src/services/PATIENTAUTH.MD +197 -0
- package/src/services/__tests__/auth/auth.setup.ts +2 -2
- package/src/services/__tests__/auth.service.test.ts +1 -1
- package/src/services/__tests__/user.service.test.ts +1 -1
- package/src/services/appointment/index.ts +1 -2
- package/src/services/{auth.service.ts → auth/auth.service.ts} +36 -22
- package/src/services/{auth.v2.service.ts → auth/auth.v2.service.ts} +17 -17
- package/src/services/auth/index.ts +2 -16
- package/src/services/calendar/calendar-refactored.service.ts +1 -1
- package/src/services/calendar/index.ts +5 -0
- package/src/services/clinic/index.ts +4 -0
- package/src/services/index.ts +12 -0
- package/src/services/media/index.ts +1 -0
- package/src/services/notifications/index.ts +1 -0
- package/src/services/patient/README.md +48 -0
- package/src/services/patient/To-Do.md +43 -0
- package/src/services/patient/index.ts +2 -0
- package/src/services/patient/patient.service.ts +289 -34
- package/src/services/patient/utils/index.ts +9 -0
- package/src/services/patient/utils/medical.utils.ts +114 -157
- package/src/services/patient/utils/profile.utils.ts +9 -0
- package/src/services/patient/utils/sensitive.utils.ts +79 -14
- package/src/services/patient/utils/token.utils.ts +211 -0
- package/src/services/practitioner/index.ts +1 -0
- package/src/services/procedure/index.ts +1 -0
- package/src/services/reviews/index.ts +1 -0
- package/src/services/user/index.ts +1 -0
- package/src/services/{user.service.ts → user/user.service.ts} +61 -12
- package/src/services/{user.v2.service.ts → user/user.v2.service.ts} +12 -12
- package/src/types/index.ts +42 -42
- package/src/types/patient/index.ts +33 -6
- package/src/types/patient/token.types.ts +61 -0
- package/src/types/user/index.ts +38 -0
- package/src/utils/index.ts +1 -0
- package/src/validations/calendar.schema.ts +6 -45
- package/src/validations/documentation-templates/index.ts +1 -0
- package/src/validations/documentation-templates.schema.ts +1 -1
- package/src/validations/index.ts +20 -0
- package/src/validations/patient/token.schema.ts +29 -0
- package/src/validations/patient.schema.ts +23 -6
- package/src/validations/profile-info.schema.ts +1 -1
- package/src/validations/schemas.ts +24 -24
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
SearchPatientsParams,
|
|
38
38
|
RequesterInfo,
|
|
39
39
|
PatientProfileForDoctor,
|
|
40
|
+
CreateManualPatientData,
|
|
40
41
|
} from "../../types/patient";
|
|
41
42
|
import { Auth } from "firebase/auth";
|
|
42
43
|
import { Firestore } from "firebase/firestore";
|
|
@@ -55,22 +56,13 @@ import {
|
|
|
55
56
|
updatePatientProfileByUserRefUtil,
|
|
56
57
|
searchPatientsUtil,
|
|
57
58
|
getAllPatientsUtil,
|
|
58
|
-
} from "./utils/profile.utils";
|
|
59
|
-
|
|
60
|
-
import {
|
|
61
59
|
updatePatientLocationUtil,
|
|
62
60
|
createLocationInfoUtil,
|
|
63
61
|
getLocationInfoUtil,
|
|
64
62
|
updateLocationInfoUtil,
|
|
65
|
-
} from "./utils/location.utils";
|
|
66
|
-
|
|
67
|
-
import {
|
|
68
63
|
createSensitiveInfoUtil,
|
|
69
64
|
getSensitiveInfoUtil,
|
|
70
65
|
updateSensitiveInfoUtil,
|
|
71
|
-
} from "./utils/sensitive.utils";
|
|
72
|
-
|
|
73
|
-
import {
|
|
74
66
|
createMedicalInfoUtil,
|
|
75
67
|
getMedicalInfoUtil,
|
|
76
68
|
updateVitalStatsUtil,
|
|
@@ -86,27 +78,28 @@ import {
|
|
|
86
78
|
addMedicationUtil,
|
|
87
79
|
updateMedicationUtil,
|
|
88
80
|
removeMedicationUtil,
|
|
89
|
-
} from "./utils/medical.utils";
|
|
90
|
-
|
|
91
|
-
import {
|
|
92
81
|
getPatientDocRef,
|
|
93
82
|
getSensitiveInfoDocRef,
|
|
94
83
|
getLocationInfoDocRef,
|
|
95
84
|
getMedicalInfoDocRef,
|
|
96
|
-
} from "./utils/docs.utils";
|
|
97
|
-
|
|
98
|
-
import {
|
|
99
85
|
addDoctorUtil,
|
|
100
86
|
removeDoctorUtil,
|
|
101
87
|
addClinicUtil,
|
|
102
88
|
removeClinicUtil,
|
|
103
|
-
} from "./utils/medical-stuff.utils";
|
|
104
|
-
|
|
105
|
-
import {
|
|
106
89
|
getPatientsByPractitionerUtil,
|
|
107
90
|
getPatientsByPractitionerWithDetailsUtil,
|
|
108
|
-
|
|
109
|
-
|
|
91
|
+
getPatientsByClinicUtil,
|
|
92
|
+
createPatientTokenUtil,
|
|
93
|
+
validatePatientTokenUtil,
|
|
94
|
+
markPatientTokenAsUsedUtil,
|
|
95
|
+
getActiveInviteTokensByClinicUtil,
|
|
96
|
+
getActiveInviteTokensByPatientUtil,
|
|
97
|
+
} from "./utils";
|
|
98
|
+
|
|
99
|
+
import {
|
|
100
|
+
CreatePatientTokenData,
|
|
101
|
+
PatientToken,
|
|
102
|
+
} from "../../types/patient/token.types";
|
|
110
103
|
|
|
111
104
|
export class PatientService extends BaseService {
|
|
112
105
|
private mediaService: MediaService;
|
|
@@ -127,6 +120,111 @@ export class PatientService extends BaseService {
|
|
|
127
120
|
return getPatientProfileUtil(this.db, patientId);
|
|
128
121
|
}
|
|
129
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Manually creates a new patient profile, typically initiated by a clinic admin.
|
|
125
|
+
* This creates a patient record that is not initially linked to an authenticated user.
|
|
126
|
+
*
|
|
127
|
+
* @param {CreateManualPatientData} data - The data for the new patient.
|
|
128
|
+
* @param {RequesterInfo} requester - Information about the user creating the patient (must be a clinic admin).
|
|
129
|
+
* @returns {Promise<PatientProfile>} The newly created patient profile.
|
|
130
|
+
* @throws {Error} If the requester is not a valid clinic admin.
|
|
131
|
+
*/
|
|
132
|
+
async createManualPatient(
|
|
133
|
+
data: CreateManualPatientData,
|
|
134
|
+
requester: RequesterInfo
|
|
135
|
+
): Promise<PatientProfile> {
|
|
136
|
+
console.log(
|
|
137
|
+
`[PatientService.createManualPatient] Attempting to create manual patient by requester:`,
|
|
138
|
+
requester
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// Security Check: Ensure the requester is a clinic admin
|
|
142
|
+
if (
|
|
143
|
+
requester.role !== "clinic_admin" ||
|
|
144
|
+
!requester.associatedClinicId ||
|
|
145
|
+
requester.associatedClinicId !== data.clinicId
|
|
146
|
+
) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
"Unauthorized: Requester must be a clinic admin and can only add patients to their own clinic."
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const patientId = this.generateId();
|
|
153
|
+
const batch = writeBatch(this.db);
|
|
154
|
+
const now = Timestamp.now();
|
|
155
|
+
|
|
156
|
+
// 1. Create Patient Profile
|
|
157
|
+
const patientProfileRef = getPatientDocRef(this.db, patientId);
|
|
158
|
+
const newProfile: PatientProfile = {
|
|
159
|
+
id: patientId,
|
|
160
|
+
displayName: `${data.firstName} ${data.lastName.charAt(0)}.`,
|
|
161
|
+
expoTokens: [],
|
|
162
|
+
gamification: { level: 1, points: 0 },
|
|
163
|
+
isActive: true,
|
|
164
|
+
isVerified: false, // Manual profiles are not verified by default
|
|
165
|
+
isManual: true,
|
|
166
|
+
doctors: [],
|
|
167
|
+
clinics: [
|
|
168
|
+
{
|
|
169
|
+
clinicId: data.clinicId,
|
|
170
|
+
assignedAt: now,
|
|
171
|
+
assignedBy: requester.id,
|
|
172
|
+
isActive: true,
|
|
173
|
+
notes: data.notes,
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
doctorIds: [],
|
|
177
|
+
clinicIds: [data.clinicId],
|
|
178
|
+
createdAt: now,
|
|
179
|
+
updatedAt: now,
|
|
180
|
+
phoneNumber: data.phoneNumber,
|
|
181
|
+
dateOfBirth: data.dateOfBirth,
|
|
182
|
+
};
|
|
183
|
+
batch.set(patientProfileRef, newProfile);
|
|
184
|
+
|
|
185
|
+
// 2. Create Patient Sensitive Info
|
|
186
|
+
const sensitiveInfoRef = getSensitiveInfoDocRef(this.db, patientId);
|
|
187
|
+
const newSensitiveInfo: Omit<PatientSensitiveInfo, "photoUrl"> = {
|
|
188
|
+
patientId,
|
|
189
|
+
firstName: data.firstName,
|
|
190
|
+
lastName: data.lastName,
|
|
191
|
+
dateOfBirth: data.dateOfBirth,
|
|
192
|
+
gender: data.gender,
|
|
193
|
+
email: data.email,
|
|
194
|
+
phoneNumber: data.phoneNumber,
|
|
195
|
+
addressData: data.addressData,
|
|
196
|
+
emergencyContacts: [],
|
|
197
|
+
createdAt: now,
|
|
198
|
+
updatedAt: now,
|
|
199
|
+
};
|
|
200
|
+
batch.set(sensitiveInfoRef, newSensitiveInfo);
|
|
201
|
+
|
|
202
|
+
// 3. Create Patient Medical Info
|
|
203
|
+
const medicalInfoRef = getMedicalInfoDocRef(this.db, patientId);
|
|
204
|
+
const newMedicalInfo: PatientMedicalInfo = {
|
|
205
|
+
patientId,
|
|
206
|
+
vitalStats: {},
|
|
207
|
+
blockingConditions: [],
|
|
208
|
+
contraindications: [],
|
|
209
|
+
allergies: [],
|
|
210
|
+
currentMedications: [],
|
|
211
|
+
emergencyNotes: "",
|
|
212
|
+
lastUpdated: now,
|
|
213
|
+
updatedBy: requester.id, // The admin who created the record
|
|
214
|
+
verifiedAt: undefined,
|
|
215
|
+
verifiedBy: undefined,
|
|
216
|
+
};
|
|
217
|
+
batch.set(medicalInfoRef, newMedicalInfo);
|
|
218
|
+
|
|
219
|
+
await batch.commit();
|
|
220
|
+
|
|
221
|
+
console.log(
|
|
222
|
+
`[PatientService.createManualPatient] Successfully created manual patient with ID: ${patientId}`
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
return newProfile;
|
|
226
|
+
}
|
|
227
|
+
|
|
130
228
|
async getPatientProfileByUserRef(
|
|
131
229
|
userRef: string
|
|
132
230
|
): Promise<PatientProfile | null> {
|
|
@@ -188,10 +286,16 @@ export class PatientService extends BaseService {
|
|
|
188
286
|
data: CreatePatientSensitiveInfoData,
|
|
189
287
|
requesterUserId: string
|
|
190
288
|
): Promise<PatientSensitiveInfo> {
|
|
289
|
+
const currentUser = await this.getCurrentUser();
|
|
290
|
+
if (currentUser.uid !== requesterUserId) {
|
|
291
|
+
throw new Error("Requester does not match authenticated user.");
|
|
292
|
+
}
|
|
293
|
+
|
|
191
294
|
return createSensitiveInfoUtil(
|
|
192
295
|
this.db,
|
|
193
296
|
data,
|
|
194
297
|
requesterUserId,
|
|
298
|
+
currentUser.roles,
|
|
195
299
|
this.mediaService
|
|
196
300
|
);
|
|
197
301
|
}
|
|
@@ -200,7 +304,17 @@ export class PatientService extends BaseService {
|
|
|
200
304
|
patientId: string,
|
|
201
305
|
requesterUserId: string
|
|
202
306
|
): Promise<PatientSensitiveInfo | null> {
|
|
203
|
-
|
|
307
|
+
const currentUser = await this.getCurrentUser();
|
|
308
|
+
if (currentUser.uid !== requesterUserId) {
|
|
309
|
+
// Allow for read-only access if authorized, but for now we check identity
|
|
310
|
+
// This could be expanded later based on practitioner/admin roles
|
|
311
|
+
}
|
|
312
|
+
return getSensitiveInfoUtil(
|
|
313
|
+
this.db,
|
|
314
|
+
patientId,
|
|
315
|
+
requesterUserId,
|
|
316
|
+
currentUser.roles
|
|
317
|
+
);
|
|
204
318
|
}
|
|
205
319
|
|
|
206
320
|
async getSensitiveInfoByUserRef(
|
|
@@ -209,6 +323,7 @@ export class PatientService extends BaseService {
|
|
|
209
323
|
): Promise<PatientSensitiveInfo | null> {
|
|
210
324
|
const profile = await this.getPatientProfileByUserRef(userRef);
|
|
211
325
|
if (!profile) return null;
|
|
326
|
+
// We pass requesterUserId which is the UID of the one asking.
|
|
212
327
|
return this.getSensitiveInfo(profile.id, requesterUserId);
|
|
213
328
|
}
|
|
214
329
|
|
|
@@ -217,11 +332,16 @@ export class PatientService extends BaseService {
|
|
|
217
332
|
data: UpdatePatientSensitiveInfoData,
|
|
218
333
|
requesterUserId: string
|
|
219
334
|
): Promise<PatientSensitiveInfo> {
|
|
335
|
+
const currentUser = await this.getCurrentUser();
|
|
336
|
+
if (currentUser.uid !== requesterUserId) {
|
|
337
|
+
throw new Error("Requester does not match authenticated user.");
|
|
338
|
+
}
|
|
220
339
|
return updateSensitiveInfoUtil(
|
|
221
340
|
this.db,
|
|
222
341
|
patientId,
|
|
223
342
|
data,
|
|
224
343
|
requesterUserId,
|
|
344
|
+
currentUser.roles,
|
|
225
345
|
this.mediaService
|
|
226
346
|
);
|
|
227
347
|
}
|
|
@@ -263,13 +383,25 @@ export class PatientService extends BaseService {
|
|
|
263
383
|
data: UpdateVitalStatsData
|
|
264
384
|
): Promise<void> {
|
|
265
385
|
const currentUser = await this.getCurrentUser();
|
|
266
|
-
await updateVitalStatsUtil(
|
|
386
|
+
await updateVitalStatsUtil(
|
|
387
|
+
this.db,
|
|
388
|
+
patientId,
|
|
389
|
+
data,
|
|
390
|
+
currentUser.uid,
|
|
391
|
+
currentUser.roles
|
|
392
|
+
);
|
|
267
393
|
}
|
|
268
394
|
|
|
269
395
|
// Metode za rad sa alergijama
|
|
270
396
|
async addAllergy(patientId: string, data: AddAllergyData): Promise<void> {
|
|
271
397
|
const currentUser = await this.getCurrentUser();
|
|
272
|
-
await addAllergyUtil(
|
|
398
|
+
await addAllergyUtil(
|
|
399
|
+
this.db,
|
|
400
|
+
patientId,
|
|
401
|
+
data,
|
|
402
|
+
currentUser.uid,
|
|
403
|
+
currentUser.roles
|
|
404
|
+
);
|
|
273
405
|
}
|
|
274
406
|
|
|
275
407
|
async updateAllergy(
|
|
@@ -277,12 +409,24 @@ export class PatientService extends BaseService {
|
|
|
277
409
|
data: UpdateAllergyData
|
|
278
410
|
): Promise<void> {
|
|
279
411
|
const currentUser = await this.getCurrentUser();
|
|
280
|
-
await updateAllergyUtil(
|
|
412
|
+
await updateAllergyUtil(
|
|
413
|
+
this.db,
|
|
414
|
+
patientId,
|
|
415
|
+
data,
|
|
416
|
+
currentUser.uid,
|
|
417
|
+
currentUser.roles
|
|
418
|
+
);
|
|
281
419
|
}
|
|
282
420
|
|
|
283
421
|
async removeAllergy(patientId: string, allergyIndex: number): Promise<void> {
|
|
284
422
|
const currentUser = await this.getCurrentUser();
|
|
285
|
-
await removeAllergyUtil(
|
|
423
|
+
await removeAllergyUtil(
|
|
424
|
+
this.db,
|
|
425
|
+
patientId,
|
|
426
|
+
allergyIndex,
|
|
427
|
+
currentUser.uid,
|
|
428
|
+
currentUser.roles
|
|
429
|
+
);
|
|
286
430
|
}
|
|
287
431
|
|
|
288
432
|
// Metode za rad sa blocking conditions
|
|
@@ -291,7 +435,13 @@ export class PatientService extends BaseService {
|
|
|
291
435
|
data: AddBlockingConditionData
|
|
292
436
|
): Promise<void> {
|
|
293
437
|
const currentUser = await this.getCurrentUser();
|
|
294
|
-
await addBlockingConditionUtil(
|
|
438
|
+
await addBlockingConditionUtil(
|
|
439
|
+
this.db,
|
|
440
|
+
patientId,
|
|
441
|
+
data,
|
|
442
|
+
currentUser.uid,
|
|
443
|
+
currentUser.roles
|
|
444
|
+
);
|
|
295
445
|
}
|
|
296
446
|
|
|
297
447
|
async updateBlockingCondition(
|
|
@@ -303,7 +453,8 @@ export class PatientService extends BaseService {
|
|
|
303
453
|
this.db,
|
|
304
454
|
patientId,
|
|
305
455
|
data,
|
|
306
|
-
currentUser.uid
|
|
456
|
+
currentUser.uid,
|
|
457
|
+
currentUser.roles
|
|
307
458
|
);
|
|
308
459
|
}
|
|
309
460
|
|
|
@@ -316,7 +467,8 @@ export class PatientService extends BaseService {
|
|
|
316
467
|
this.db,
|
|
317
468
|
patientId,
|
|
318
469
|
conditionIndex,
|
|
319
|
-
currentUser.uid
|
|
470
|
+
currentUser.uid,
|
|
471
|
+
currentUser.roles
|
|
320
472
|
);
|
|
321
473
|
}
|
|
322
474
|
|
|
@@ -326,7 +478,13 @@ export class PatientService extends BaseService {
|
|
|
326
478
|
data: AddContraindicationData
|
|
327
479
|
): Promise<void> {
|
|
328
480
|
const currentUser = await this.getCurrentUser();
|
|
329
|
-
await addContraindicationUtil(
|
|
481
|
+
await addContraindicationUtil(
|
|
482
|
+
this.db,
|
|
483
|
+
patientId,
|
|
484
|
+
data,
|
|
485
|
+
currentUser.uid,
|
|
486
|
+
currentUser.roles
|
|
487
|
+
);
|
|
330
488
|
}
|
|
331
489
|
|
|
332
490
|
async updateContraindication(
|
|
@@ -334,7 +492,13 @@ export class PatientService extends BaseService {
|
|
|
334
492
|
data: UpdateContraindicationData
|
|
335
493
|
): Promise<void> {
|
|
336
494
|
const currentUser = await this.getCurrentUser();
|
|
337
|
-
await updateContraindicationUtil(
|
|
495
|
+
await updateContraindicationUtil(
|
|
496
|
+
this.db,
|
|
497
|
+
patientId,
|
|
498
|
+
data,
|
|
499
|
+
currentUser.uid,
|
|
500
|
+
currentUser.roles
|
|
501
|
+
);
|
|
338
502
|
}
|
|
339
503
|
|
|
340
504
|
async removeContraindication(
|
|
@@ -346,7 +510,8 @@ export class PatientService extends BaseService {
|
|
|
346
510
|
this.db,
|
|
347
511
|
patientId,
|
|
348
512
|
contraindicationIndex,
|
|
349
|
-
currentUser.uid
|
|
513
|
+
currentUser.uid,
|
|
514
|
+
currentUser.roles
|
|
350
515
|
);
|
|
351
516
|
}
|
|
352
517
|
|
|
@@ -356,7 +521,13 @@ export class PatientService extends BaseService {
|
|
|
356
521
|
data: AddMedicationData
|
|
357
522
|
): Promise<void> {
|
|
358
523
|
const currentUser = await this.getCurrentUser();
|
|
359
|
-
await addMedicationUtil(
|
|
524
|
+
await addMedicationUtil(
|
|
525
|
+
this.db,
|
|
526
|
+
patientId,
|
|
527
|
+
data,
|
|
528
|
+
currentUser.uid,
|
|
529
|
+
currentUser.roles
|
|
530
|
+
);
|
|
360
531
|
}
|
|
361
532
|
|
|
362
533
|
async updateMedication(
|
|
@@ -364,7 +535,13 @@ export class PatientService extends BaseService {
|
|
|
364
535
|
data: UpdateMedicationData
|
|
365
536
|
): Promise<void> {
|
|
366
537
|
const currentUser = await this.getCurrentUser();
|
|
367
|
-
await updateMedicationUtil(
|
|
538
|
+
await updateMedicationUtil(
|
|
539
|
+
this.db,
|
|
540
|
+
patientId,
|
|
541
|
+
data,
|
|
542
|
+
currentUser.uid,
|
|
543
|
+
currentUser.roles
|
|
544
|
+
);
|
|
368
545
|
}
|
|
369
546
|
|
|
370
547
|
async removeMedication(
|
|
@@ -376,7 +553,8 @@ export class PatientService extends BaseService {
|
|
|
376
553
|
this.db,
|
|
377
554
|
patientId,
|
|
378
555
|
medicationIndex,
|
|
379
|
-
currentUser.uid
|
|
556
|
+
currentUser.uid,
|
|
557
|
+
currentUser.roles
|
|
380
558
|
);
|
|
381
559
|
}
|
|
382
560
|
|
|
@@ -746,4 +924,81 @@ export class PatientService extends BaseService {
|
|
|
746
924
|
);
|
|
747
925
|
return getPatientsByClinicUtil(this.db, clinicId, options);
|
|
748
926
|
}
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Creates a token for inviting a patient to claim their profile.
|
|
930
|
+
*
|
|
931
|
+
* @param {CreatePatientTokenData} data - Data for creating the token.
|
|
932
|
+
* @param {string} createdBy - ID of the admin user creating the token.
|
|
933
|
+
* @returns {Promise<PatientToken>} The created token.
|
|
934
|
+
*/
|
|
935
|
+
async createPatientToken(
|
|
936
|
+
data: CreatePatientTokenData,
|
|
937
|
+
createdBy: string
|
|
938
|
+
): Promise<PatientToken> {
|
|
939
|
+
// We assume the 'createdBy' user is validated to be a clinic admin
|
|
940
|
+
// in the calling context (e.g., a cloud function or API endpoint).
|
|
941
|
+
return createPatientTokenUtil(
|
|
942
|
+
this.db,
|
|
943
|
+
data,
|
|
944
|
+
createdBy,
|
|
945
|
+
() => this.generateId() // Pass the ID generation function
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
/**
|
|
950
|
+
* Validates a patient invitation token.
|
|
951
|
+
*
|
|
952
|
+
* @param {string} tokenString - The token string to validate.
|
|
953
|
+
* @returns {Promise<PatientToken | null>} The token if found and valid, otherwise null.
|
|
954
|
+
*/
|
|
955
|
+
async validatePatientToken(
|
|
956
|
+
tokenString: string
|
|
957
|
+
): Promise<PatientToken | null> {
|
|
958
|
+
return validatePatientTokenUtil(this.db, tokenString);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* Marks a patient invitation token as used.
|
|
963
|
+
*
|
|
964
|
+
* @param {string} tokenId - The ID of the token to mark as used.
|
|
965
|
+
* @param {string} patientId - The ID of the patient associated with the token.
|
|
966
|
+
* @param {string} userId - The ID of the user who is using the token.
|
|
967
|
+
* @returns {Promise<void>}
|
|
968
|
+
*/
|
|
969
|
+
async markPatientTokenAsUsed(
|
|
970
|
+
tokenId: string,
|
|
971
|
+
patientId: string,
|
|
972
|
+
userId: string
|
|
973
|
+
): Promise<void> {
|
|
974
|
+
return markPatientTokenAsUsedUtil(this.db, tokenId, patientId, userId);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* Retrieves all active invitation tokens for a specific clinic.
|
|
979
|
+
* NOTE: This should be protected and only exposed to authorized clinic admins.
|
|
980
|
+
*
|
|
981
|
+
* @param {string} clinicId - The ID of the clinic.
|
|
982
|
+
* @returns {Promise<PatientToken[]>} An array of active tokens for the clinic.
|
|
983
|
+
*/
|
|
984
|
+
async getActiveInviteTokensByClinic(
|
|
985
|
+
clinicId: string
|
|
986
|
+
): Promise<PatientToken[]> {
|
|
987
|
+
return getActiveInviteTokensByClinicUtil(this.db, clinicId);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* Retrieves all active invitation tokens for a specific patient.
|
|
992
|
+
* NOTE: This should be protected and only exposed to authorized clinic admins.
|
|
993
|
+
*
|
|
994
|
+
* @param {string} patientId - The ID of the patient.
|
|
995
|
+
* @returns {Promise<PatientToken[]>} An array of active tokens for the patient.
|
|
996
|
+
*/
|
|
997
|
+
async getActiveInviteTokensByPatient(
|
|
998
|
+
patientId: string
|
|
999
|
+
): Promise<PatientToken[]> {
|
|
1000
|
+
// Security check should be done in the calling context to ensure
|
|
1001
|
+
// the admin has permission to view this patient's tokens.
|
|
1002
|
+
return getActiveInviteTokensByPatientUtil(this.db, patientId);
|
|
1003
|
+
}
|
|
749
1004
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./clinic.utils";
|
|
2
|
+
export * from "./docs.utils";
|
|
3
|
+
export * from "./location.utils";
|
|
4
|
+
export * from "./medical-stuff.utils";
|
|
5
|
+
export * from "./medical.utils";
|
|
6
|
+
export * from "./practitioner.utils";
|
|
7
|
+
export * from "./profile.utils";
|
|
8
|
+
export * from "./sensitive.utils";
|
|
9
|
+
export * from "./token.utils";
|