@blackcode_sa/metaestetics-api 1.12.62 → 1.12.64
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 +4 -2
- package/dist/admin/index.d.ts +4 -2
- package/dist/admin/index.js +4 -45
- package/dist/admin/index.mjs +4 -45
- package/dist/backoffice/index.d.mts +86 -1
- package/dist/backoffice/index.d.ts +86 -1
- package/dist/backoffice/index.js +308 -0
- package/dist/backoffice/index.mjs +306 -0
- package/dist/index.d.mts +99 -3
- package/dist/index.d.ts +99 -3
- package/dist/index.js +545 -281
- package/dist/index.mjs +867 -603
- package/package.json +119 -119
- package/src/__mocks__/firstore.ts +10 -10
- package/src/admin/aggregation/README.md +79 -79
- package/src/admin/aggregation/appointment/README.md +128 -128
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +1844 -1844
- package/src/admin/aggregation/appointment/index.ts +1 -1
- package/src/admin/aggregation/clinic/README.md +52 -52
- package/src/admin/aggregation/clinic/clinic.aggregation.service.ts +703 -703
- package/src/admin/aggregation/clinic/index.ts +1 -1
- package/src/admin/aggregation/forms/README.md +13 -13
- package/src/admin/aggregation/forms/filled-forms.aggregation.service.ts +322 -322
- package/src/admin/aggregation/forms/index.ts +1 -1
- package/src/admin/aggregation/index.ts +8 -8
- package/src/admin/aggregation/patient/README.md +27 -27
- package/src/admin/aggregation/patient/index.ts +1 -1
- package/src/admin/aggregation/patient/patient.aggregation.service.ts +141 -141
- package/src/admin/aggregation/practitioner/README.md +42 -42
- package/src/admin/aggregation/practitioner/index.ts +1 -1
- package/src/admin/aggregation/practitioner/practitioner.aggregation.service.ts +433 -433
- package/src/admin/aggregation/practitioner-invite/index.ts +1 -1
- package/src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts +961 -961
- package/src/admin/aggregation/procedure/README.md +43 -43
- package/src/admin/aggregation/procedure/index.ts +1 -1
- package/src/admin/aggregation/procedure/procedure.aggregation.service.ts +702 -702
- package/src/admin/aggregation/reviews/index.ts +1 -1
- package/src/admin/aggregation/reviews/reviews.aggregation.service.ts +641 -689
- package/src/admin/booking/README.md +125 -125
- package/src/admin/booking/booking.admin.ts +1037 -1037
- package/src/admin/booking/booking.calculator.ts +712 -712
- package/src/admin/booking/booking.types.ts +59 -59
- package/src/admin/booking/index.ts +3 -3
- package/src/admin/booking/timezones-problem.md +185 -185
- package/src/admin/calendar/README.md +7 -7
- package/src/admin/calendar/calendar.admin.service.ts +345 -345
- package/src/admin/calendar/index.ts +1 -1
- package/src/admin/documentation-templates/document-manager.admin.ts +260 -260
- package/src/admin/documentation-templates/index.ts +1 -1
- package/src/admin/free-consultation/free-consultation-utils.admin.ts +148 -148
- package/src/admin/free-consultation/index.ts +1 -1
- package/src/admin/index.ts +75 -75
- package/src/admin/logger/index.ts +78 -78
- package/src/admin/mailing/README.md +95 -95
- package/src/admin/mailing/appointment/appointment.mailing.service.ts +732 -732
- package/src/admin/mailing/appointment/index.ts +1 -1
- package/src/admin/mailing/appointment/templates/patient/appointment-confirmed.html +40 -40
- package/src/admin/mailing/base.mailing.service.ts +208 -208
- package/src/admin/mailing/index.ts +3 -3
- package/src/admin/mailing/practitionerInvite/existing-practitioner-invite.mailing.ts +611 -611
- package/src/admin/mailing/practitionerInvite/index.ts +2 -2
- package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +395 -395
- package/src/admin/mailing/practitionerInvite/templates/existing-practitioner-invitation.template.ts +155 -155
- package/src/admin/mailing/practitionerInvite/templates/invitation.template.ts +101 -101
- package/src/admin/mailing/practitionerInvite/templates/invite-accepted-notification.template.ts +228 -228
- package/src/admin/mailing/practitionerInvite/templates/invite-rejected-notification.template.ts +242 -242
- package/src/admin/notifications/index.ts +1 -1
- package/src/admin/notifications/notifications.admin.ts +710 -710
- package/src/admin/requirements/README.md +128 -128
- package/src/admin/requirements/index.ts +1 -1
- package/src/admin/requirements/patient-requirements.admin.service.ts +475 -475
- package/src/admin/users/index.ts +1 -1
- package/src/admin/users/user-profile.admin.ts +405 -405
- package/src/backoffice/constants/certification.constants.ts +13 -13
- package/src/backoffice/constants/index.ts +1 -1
- package/src/backoffice/errors/backoffice.errors.ts +181 -181
- package/src/backoffice/errors/index.ts +1 -1
- package/src/backoffice/expo-safe/README.md +26 -26
- package/src/backoffice/expo-safe/index.ts +41 -41
- package/src/backoffice/index.ts +5 -5
- package/src/backoffice/services/FIXES_README.md +102 -102
- package/src/backoffice/services/README.md +40 -40
- package/src/backoffice/services/brand.service.ts +256 -256
- package/src/backoffice/services/category.service.ts +318 -318
- package/src/backoffice/services/constants.service.ts +385 -385
- package/src/backoffice/services/documentation-template.service.ts +202 -202
- package/src/backoffice/services/index.ts +11 -8
- package/src/backoffice/services/migrate-products.ts +116 -116
- package/src/backoffice/services/product.service.ts +553 -553
- package/src/backoffice/services/requirement.service.ts +235 -235
- package/src/backoffice/services/subcategory.service.ts +395 -395
- package/src/backoffice/services/technology.service.ts +1083 -1070
- package/src/backoffice/types/README.md +12 -12
- package/src/backoffice/types/admin-constants.types.ts +69 -69
- package/src/backoffice/types/brand.types.ts +29 -29
- package/src/backoffice/types/category.types.ts +62 -62
- package/src/backoffice/types/documentation-templates.types.ts +28 -28
- package/src/backoffice/types/index.ts +10 -10
- package/src/backoffice/types/procedure-product.types.ts +38 -38
- package/src/backoffice/types/product.types.ts +240 -240
- package/src/backoffice/types/requirement.types.ts +63 -63
- package/src/backoffice/types/static/README.md +18 -18
- package/src/backoffice/types/static/blocking-condition.types.ts +21 -21
- package/src/backoffice/types/static/certification.types.ts +37 -37
- package/src/backoffice/types/static/contraindication.types.ts +19 -19
- package/src/backoffice/types/static/index.ts +6 -6
- package/src/backoffice/types/static/pricing.types.ts +16 -16
- package/src/backoffice/types/static/procedure-family.types.ts +14 -14
- package/src/backoffice/types/static/treatment-benefit.types.ts +22 -22
- package/src/backoffice/types/subcategory.types.ts +34 -34
- package/src/backoffice/types/technology.types.ts +163 -161
- package/src/backoffice/validations/index.ts +1 -1
- package/src/backoffice/validations/schemas.ts +164 -163
- package/src/config/__mocks__/firebase.ts +99 -99
- package/src/config/firebase.ts +78 -78
- package/src/config/index.ts +9 -9
- package/src/errors/auth.error.ts +6 -6
- package/src/errors/auth.errors.ts +200 -200
- package/src/errors/clinic.errors.ts +32 -32
- package/src/errors/firebase.errors.ts +47 -47
- package/src/errors/user.errors.ts +99 -99
- package/src/index.backup.ts +407 -407
- package/src/index.ts +6 -6
- package/src/locales/en.ts +31 -31
- package/src/recommender/admin/index.ts +1 -1
- package/src/recommender/admin/services/recommender.service.admin.ts +5 -5
- package/src/recommender/front/index.ts +1 -1
- package/src/recommender/front/services/onboarding.service.ts +5 -5
- package/src/recommender/front/services/recommender.service.ts +3 -3
- package/src/recommender/index.ts +1 -1
- package/src/services/PATIENTAUTH.MD +197 -197
- package/src/services/README.md +106 -106
- package/src/services/__tests__/auth/auth.mock.test.ts +17 -17
- package/src/services/__tests__/auth/auth.setup.ts +293 -293
- package/src/services/__tests__/auth.service.test.ts +346 -346
- package/src/services/__tests__/base.service.test.ts +77 -77
- package/src/services/__tests__/user.service.test.ts +528 -528
- package/src/services/appointment/README.md +17 -17
- package/src/services/appointment/appointment.service.ts +2505 -2082
- package/src/services/appointment/index.ts +1 -1
- package/src/services/appointment/utils/appointment.utils.ts +552 -552
- package/src/services/appointment/utils/extended-procedure.utils.ts +314 -314
- package/src/services/appointment/utils/form-initialization.utils.ts +225 -225
- package/src/services/appointment/utils/recommended-procedure.utils.ts +195 -195
- package/src/services/appointment/utils/zone-management.utils.ts +353 -353
- package/src/services/appointment/utils/zone-photo.utils.ts +152 -152
- package/src/services/auth/auth.service.ts +989 -989
- package/src/services/auth/auth.v2.service.ts +961 -961
- package/src/services/auth/index.ts +7 -7
- package/src/services/auth/utils/error.utils.ts +90 -90
- package/src/services/auth/utils/firebase.utils.ts +49 -49
- package/src/services/auth/utils/index.ts +21 -21
- package/src/services/auth/utils/practitioner.utils.ts +125 -125
- package/src/services/base.service.ts +41 -41
- package/src/services/calendar/calendar.service.ts +1077 -1077
- package/src/services/calendar/calendar.v2.service.ts +1683 -1683
- package/src/services/calendar/calendar.v3.service.ts +313 -313
- package/src/services/calendar/externalCalendar.service.ts +178 -178
- package/src/services/calendar/index.ts +5 -5
- package/src/services/calendar/synced-calendars.service.ts +743 -743
- package/src/services/calendar/utils/appointment.utils.ts +265 -265
- package/src/services/calendar/utils/calendar-event.utils.ts +646 -646
- package/src/services/calendar/utils/clinic.utils.ts +237 -237
- package/src/services/calendar/utils/docs.utils.ts +157 -157
- package/src/services/calendar/utils/google-calendar.utils.ts +697 -697
- package/src/services/calendar/utils/index.ts +8 -8
- package/src/services/calendar/utils/patient.utils.ts +198 -198
- package/src/services/calendar/utils/practitioner.utils.ts +221 -221
- package/src/services/calendar/utils/synced-calendar.utils.ts +472 -472
- package/src/services/clinic/README.md +204 -204
- package/src/services/clinic/__tests__/clinic-admin.service.test.ts +287 -287
- package/src/services/clinic/__tests__/clinic-group.service.test.ts +352 -352
- package/src/services/clinic/__tests__/clinic.service.test.ts +354 -354
- package/src/services/clinic/billing-transactions.service.ts +217 -217
- package/src/services/clinic/clinic-admin.service.ts +202 -202
- package/src/services/clinic/clinic-group.service.ts +310 -310
- package/src/services/clinic/clinic.service.ts +708 -708
- package/src/services/clinic/index.ts +5 -5
- package/src/services/clinic/practitioner-invite.service.ts +519 -519
- package/src/services/clinic/utils/admin.utils.ts +551 -551
- package/src/services/clinic/utils/clinic-group.utils.ts +646 -646
- package/src/services/clinic/utils/clinic.utils.ts +949 -949
- package/src/services/clinic/utils/filter.utils.d.ts +23 -23
- package/src/services/clinic/utils/filter.utils.ts +446 -446
- package/src/services/clinic/utils/index.ts +11 -11
- package/src/services/clinic/utils/photos.utils.ts +188 -188
- package/src/services/clinic/utils/search.utils.ts +84 -84
- package/src/services/clinic/utils/tag.utils.ts +124 -124
- package/src/services/documentation-templates/documentation-template.service.ts +537 -537
- package/src/services/documentation-templates/filled-document.service.ts +587 -587
- package/src/services/documentation-templates/index.ts +2 -2
- package/src/services/index.ts +13 -13
- package/src/services/media/index.ts +1 -1
- package/src/services/media/media.service.ts +418 -418
- package/src/services/notifications/__tests__/notification.service.test.ts +242 -242
- package/src/services/notifications/index.ts +1 -1
- package/src/services/notifications/notification.service.ts +215 -215
- package/src/services/patient/README.md +48 -48
- package/src/services/patient/To-Do.md +43 -43
- package/src/services/patient/__tests__/patient.service.test.ts +294 -294
- package/src/services/patient/index.ts +2 -2
- package/src/services/patient/patient.service.ts +883 -883
- package/src/services/patient/patientRequirements.service.ts +285 -285
- package/src/services/patient/utils/aesthetic-analysis.utils.ts +176 -176
- package/src/services/patient/utils/clinic.utils.ts +80 -80
- package/src/services/patient/utils/docs.utils.ts +142 -142
- package/src/services/patient/utils/index.ts +9 -9
- package/src/services/patient/utils/location.utils.ts +126 -126
- package/src/services/patient/utils/medical-stuff.utils.ts +143 -143
- package/src/services/patient/utils/medical.utils.ts +458 -458
- package/src/services/patient/utils/practitioner.utils.ts +260 -260
- package/src/services/patient/utils/profile.utils.ts +510 -510
- package/src/services/patient/utils/sensitive.utils.ts +260 -260
- package/src/services/patient/utils/token.utils.ts +211 -211
- package/src/services/practitioner/README.md +145 -145
- package/src/services/practitioner/index.ts +1 -1
- package/src/services/practitioner/practitioner.service.ts +1742 -1742
- package/src/services/procedure/README.md +163 -163
- package/src/services/procedure/index.ts +1 -1
- package/src/services/procedure/procedure.service.ts +1682 -1682
- package/src/services/reviews/index.ts +1 -1
- package/src/services/reviews/reviews.service.ts +636 -683
- package/src/services/user/index.ts +1 -1
- package/src/services/user/user.service.ts +489 -489
- package/src/services/user/user.v2.service.ts +466 -466
- package/src/types/appointment/index.ts +481 -453
- package/src/types/calendar/index.ts +258 -258
- package/src/types/calendar/synced-calendar.types.ts +66 -66
- package/src/types/clinic/index.ts +489 -489
- package/src/types/clinic/practitioner-invite.types.ts +91 -91
- package/src/types/clinic/preferences.types.ts +159 -159
- package/src/types/clinic/to-do +3 -3
- package/src/types/documentation-templates/index.ts +308 -308
- package/src/types/index.ts +44 -44
- package/src/types/notifications/README.md +77 -77
- package/src/types/notifications/index.ts +265 -265
- package/src/types/patient/aesthetic-analysis.types.ts +66 -66
- package/src/types/patient/allergies.ts +58 -58
- package/src/types/patient/index.ts +275 -273
- package/src/types/patient/medical-info.types.ts +152 -152
- package/src/types/patient/patient-requirements.ts +92 -92
- package/src/types/patient/token.types.ts +61 -61
- package/src/types/practitioner/index.ts +206 -206
- package/src/types/procedure/index.ts +181 -181
- package/src/types/profile/index.ts +39 -39
- package/src/types/reviews/index.ts +130 -132
- package/src/types/tz-lookup.d.ts +4 -4
- package/src/types/user/index.ts +38 -38
- package/src/utils/TIMESTAMPS.md +176 -176
- package/src/utils/TimestampUtils.ts +241 -241
- package/src/utils/index.ts +1 -1
- package/src/validations/appointment.schema.ts +574 -574
- package/src/validations/calendar.schema.ts +225 -225
- package/src/validations/clinic.schema.ts +493 -493
- package/src/validations/common.schema.ts +25 -25
- package/src/validations/documentation-templates/index.ts +1 -1
- package/src/validations/documentation-templates/template.schema.ts +220 -220
- package/src/validations/documentation-templates.schema.ts +10 -10
- package/src/validations/index.ts +20 -20
- package/src/validations/media.schema.ts +10 -10
- package/src/validations/notification.schema.ts +90 -90
- package/src/validations/patient/aesthetic-analysis.schema.ts +55 -55
- package/src/validations/patient/medical-info.schema.ts +125 -125
- package/src/validations/patient/patient-requirements.schema.ts +84 -84
- package/src/validations/patient/token.schema.ts +29 -29
- package/src/validations/patient.schema.ts +217 -216
- package/src/validations/practitioner.schema.ts +222 -222
- package/src/validations/procedure-product.schema.ts +41 -41
- package/src/validations/procedure.schema.ts +124 -124
- package/src/validations/profile-info.schema.ts +41 -41
- package/src/validations/reviews.schema.ts +189 -195
- package/src/validations/schemas.ts +104 -104
- package/src/validations/shared.schema.ts +78 -78
|
@@ -1,453 +1,481 @@
|
|
|
1
|
-
import { Timestamp, FieldValue } from 'firebase/firestore';
|
|
2
|
-
import { ClinicInfo, PractitionerProfileInfo, PatientProfileInfo } from '../profile';
|
|
3
|
-
import { ProcedureSummaryInfo } from '../procedure';
|
|
4
|
-
import { Currency, type PricingMeasure } from '../../backoffice/types/static/pricing.types';
|
|
5
|
-
import { BlockingCondition } from '../../backoffice/types/static/blocking-condition.types';
|
|
6
|
-
import { Requirement } from '../../backoffice/types/requirement.types';
|
|
7
|
-
import { FilledDocumentStatus } from '../documentation-templates';
|
|
8
|
-
import type { ContraindicationDynamic, ProcedureFamily } from '../../backoffice';
|
|
9
|
-
import type { MediaResource } from '../../services/media/media.service';
|
|
10
|
-
import { string } from 'zod/v4';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Enum defining the possible statuses of an appointment.
|
|
14
|
-
*/
|
|
15
|
-
export enum AppointmentStatus {
|
|
16
|
-
PENDING = 'pending', // Initial state after booking, before confirmation (if applicable)
|
|
17
|
-
CONFIRMED = 'confirmed', // Confirmed by clinic/practitioner
|
|
18
|
-
CHECKED_IN = 'checked_in', // Patient has arrived
|
|
19
|
-
IN_PROGRESS = 'in_progress', // Procedure has started
|
|
20
|
-
COMPLETED = 'completed', // Procedure finished successfully
|
|
21
|
-
CANCELED_PATIENT = 'canceled_patient', // Canceled by the patient
|
|
22
|
-
CANCELED_PATIENT_RESCHEDULED = 'canceled_patient_rescheduled', // Canceled by the patient and rescheduled by the clinic
|
|
23
|
-
CANCELED_CLINIC = 'canceled_clinic', // Canceled by the clinic/practitioner
|
|
24
|
-
NO_SHOW = 'no_show', // Patient did not attend
|
|
25
|
-
RESCHEDULED_BY_CLINIC = 'rescheduled_by_clinic', // When appointment is rescheduled by the clinic, waiting for patient confirmation or cancellation (when reschedule is accepted, status goes to confirmed, if not accepted, then status goes to canceled_patient_rescheduled)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Enum defining the payment status of an appointment.
|
|
30
|
-
*/
|
|
31
|
-
export enum PaymentStatus {
|
|
32
|
-
UNPAID = 'unpaid',
|
|
33
|
-
PAID = 'paid',
|
|
34
|
-
PARTIALLY_PAID = 'partially_paid',
|
|
35
|
-
REFUNDED = 'refunded',
|
|
36
|
-
NOT_APPLICABLE = 'not_applicable', // For free services or other scenarios
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Enum for different types of media that can be attached to an appointment.
|
|
41
|
-
*/
|
|
42
|
-
export enum MediaType {
|
|
43
|
-
BEFORE_PHOTO = 'before_photo',
|
|
44
|
-
AFTER_PHOTO = 'after_photo',
|
|
45
|
-
CONSENT_SCAN = 'consent_scan',
|
|
46
|
-
OTHER_DOCUMENT = 'other_document',
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Interface to describe a media file linked to an appointment.
|
|
51
|
-
*/
|
|
52
|
-
export interface AppointmentMediaItem {
|
|
53
|
-
id: string; // Auto-generated unique ID for the media item
|
|
54
|
-
type: MediaType;
|
|
55
|
-
url: string; // Cloud Storage URL
|
|
56
|
-
fileName?: string;
|
|
57
|
-
uploadedAt: Timestamp;
|
|
58
|
-
uploadedBy: string; // User ID (patient, practitioner, or clinic_admin)
|
|
59
|
-
description?: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Interface for procedure-specific information
|
|
64
|
-
*/
|
|
65
|
-
export interface ProcedureExtendedInfo {
|
|
66
|
-
id: string;
|
|
67
|
-
name: string;
|
|
68
|
-
description: string;
|
|
69
|
-
cost: number;
|
|
70
|
-
duration: number;
|
|
71
|
-
procedureFamily: ProcedureFamily;
|
|
72
|
-
procedureCategoryId: string;
|
|
73
|
-
procedureCategoryName: string;
|
|
74
|
-
procedureSubCategoryId: string;
|
|
75
|
-
procedureSubCategoryName: string;
|
|
76
|
-
procedureTechnologyId: string;
|
|
77
|
-
procedureTechnologyName: string;
|
|
78
|
-
procedureProductBrandId: string;
|
|
79
|
-
procedureProductBrandName: string;
|
|
80
|
-
procedureProducts: Array<{
|
|
81
|
-
productId: string;
|
|
82
|
-
productName: string;
|
|
83
|
-
brandId: string;
|
|
84
|
-
brandName: string;
|
|
85
|
-
}>;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Interface to describe a filled form linked to an appointment.
|
|
90
|
-
*/
|
|
91
|
-
export interface LinkedFormInfo {
|
|
92
|
-
formId: string; // ID of the FilledDocument
|
|
93
|
-
templateId: string;
|
|
94
|
-
templateVersion: number;
|
|
95
|
-
title: string; // For display, usually from DocumentTemplate.title
|
|
96
|
-
isUserForm: boolean;
|
|
97
|
-
isRequired?: boolean;
|
|
98
|
-
sortingOrder?: number;
|
|
99
|
-
status: FilledDocumentStatus; // Status of the filled form (e.g., draft, completed, signed)
|
|
100
|
-
path: string; // Full Firestore path to the filled document (e.g., appointments/{aid}/user-forms/{fid})
|
|
101
|
-
submittedAt?: Timestamp;
|
|
102
|
-
completedAt?: Timestamp; // When the form reached a final state like 'completed' or 'signed'
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Interface for summarized patient review information linked to an appointment.
|
|
107
|
-
*/
|
|
108
|
-
export interface PatientReviewInfo {
|
|
109
|
-
reviewId: string; // ID of the full review document/record if stored elsewhere
|
|
110
|
-
rating: number; // e.g., 1-5 stars
|
|
111
|
-
comment?: string; // A short snippet or the full comment
|
|
112
|
-
reviewedAt: Timestamp;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Interface for before/after photos and notes per zone
|
|
117
|
-
*/
|
|
118
|
-
export interface BeforeAfterPerZone {
|
|
119
|
-
/** URL for before photo or null if not available */
|
|
120
|
-
before: MediaResource | null;
|
|
121
|
-
/** URL for after photo or null if not available */
|
|
122
|
-
after: MediaResource | null;
|
|
123
|
-
/** Optional note for the zone */
|
|
124
|
-
afterNote?: string | null;
|
|
125
|
-
beforeNote?: string | null;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Interface for zone photo upload data
|
|
130
|
-
*/
|
|
131
|
-
export interface ZonePhotoUploadData {
|
|
132
|
-
appointmentId: string;
|
|
133
|
-
zoneId: string;
|
|
134
|
-
photoType: 'before' | 'after';
|
|
135
|
-
file: File | Blob;
|
|
136
|
-
notes?: string;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Interface for zone item data (products or notes per zone)
|
|
141
|
-
*/
|
|
142
|
-
export interface ZoneItemData {
|
|
143
|
-
productId?: string;
|
|
144
|
-
productName?: string;
|
|
145
|
-
productBrandId?: string;
|
|
146
|
-
productBrandName?: string;
|
|
147
|
-
belongingProcedureId: string;
|
|
148
|
-
type: 'item' | 'note';
|
|
149
|
-
stage?: 'before' | 'after'; // Stage of the note/item: 'before' for planning notes, 'after' for treatment notes
|
|
150
|
-
price?: number;
|
|
151
|
-
currency?: Currency;
|
|
152
|
-
unitOfMeasurement?: PricingMeasure;
|
|
153
|
-
priceOverrideAmount?: number; // If set, takes precedence over price
|
|
154
|
-
quantity?: number;
|
|
155
|
-
parentZone: string; // Zone key in format "category.zone" (e.g., "face.forehead")
|
|
156
|
-
subzones: string[];
|
|
157
|
-
notes?: string;
|
|
158
|
-
subtotal?: number;
|
|
159
|
-
ionNumber?: string;
|
|
160
|
-
createdAt?: string; // ISO timestamp
|
|
161
|
-
updatedAt?: string; // ISO timestamp
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* @deprecated Use ZoneItemData instead
|
|
166
|
-
*/
|
|
167
|
-
export interface BillingPerZone {
|
|
168
|
-
Product: string;
|
|
169
|
-
ProductId: string | null;
|
|
170
|
-
Quantity: number;
|
|
171
|
-
UnitOfMeasurement: PricingMeasure;
|
|
172
|
-
UnitPrice: number;
|
|
173
|
-
UnitCurency: Currency;
|
|
174
|
-
Subtotal: number;
|
|
175
|
-
Note: string | null;
|
|
176
|
-
IonNumber: string | null;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Interface for final billing calculations of the appointment
|
|
181
|
-
*/
|
|
182
|
-
export interface FinalBilling {
|
|
183
|
-
/** Total of all subtotals from all zones */
|
|
184
|
-
subtotalAll: number;
|
|
185
|
-
/** Tax rate as percentage (e.g., 0.20 for 20%) */
|
|
186
|
-
taxRate: number;
|
|
187
|
-
/** Calculated tax amount */
|
|
188
|
-
taxPrice: number;
|
|
189
|
-
/** Final price including tax */
|
|
190
|
-
finalPrice: number;
|
|
191
|
-
/** Currency for the final billing */
|
|
192
|
-
currency: Currency;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Interface for product metadata in appointment
|
|
197
|
-
*/
|
|
198
|
-
export interface AppointmentProductMetadata {
|
|
199
|
-
productId: string;
|
|
200
|
-
productName: string;
|
|
201
|
-
brandId: string;
|
|
202
|
-
brandName: string;
|
|
203
|
-
procedureId: string;
|
|
204
|
-
price: number;
|
|
205
|
-
currency: Currency;
|
|
206
|
-
unitOfMeasurement: PricingMeasure;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Interface for extended procedures in appointment
|
|
211
|
-
*/
|
|
212
|
-
export interface ExtendedProcedureInfo {
|
|
213
|
-
procedureId: string;
|
|
214
|
-
procedureName: string;
|
|
215
|
-
procedureFamily?: ProcedureFamily;
|
|
216
|
-
procedureCategoryId: string;
|
|
217
|
-
procedureCategoryName: string;
|
|
218
|
-
procedureSubCategoryId: string;
|
|
219
|
-
procedureSubCategoryName: string;
|
|
220
|
-
procedureTechnologyId: string;
|
|
221
|
-
procedureTechnologyName: string;
|
|
222
|
-
procedureProducts: Array<{
|
|
223
|
-
productId: string;
|
|
224
|
-
productName: string;
|
|
225
|
-
brandId: string;
|
|
226
|
-
brandName: string;
|
|
227
|
-
}>;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export interface RecommendedProcedure {
|
|
231
|
-
procedure: ExtendedProcedureInfo;
|
|
232
|
-
note: string;
|
|
233
|
-
timeframe: {
|
|
234
|
-
value: number;
|
|
235
|
-
unit: 'day' | 'week' | 'month' | 'year';
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Interface for appointment metadata containing zone-specific information
|
|
241
|
-
*/
|
|
242
|
-
export interface AppointmentMetadata {
|
|
243
|
-
selectedZones: string[] | null;
|
|
244
|
-
zonePhotos: Record<string, BeforeAfterPerZone[]> | null;
|
|
245
|
-
zonesData?: Record<string, ZoneItemData[]> | null;
|
|
246
|
-
appointmentProducts?: AppointmentProductMetadata[];
|
|
247
|
-
extendedProcedures?: ExtendedProcedureInfo[];
|
|
248
|
-
recommendedProcedures: RecommendedProcedure[]
|
|
249
|
-
finalbilling: FinalBilling | null;
|
|
250
|
-
finalizationNotes: string | null;
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* @deprecated Use zonesData instead
|
|
254
|
-
*/
|
|
255
|
-
zoneBilling?: Record<string, BillingPerZone> | null;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Represents a booked appointment, aggregating key information and relevant procedure rules.
|
|
260
|
-
*/
|
|
261
|
-
export interface Appointment {
|
|
262
|
-
/** Unique identifier for the appointment */
|
|
263
|
-
id: string;
|
|
264
|
-
/** Reference to the associated CalendarEvent */
|
|
265
|
-
calendarEventId: string;
|
|
266
|
-
|
|
267
|
-
/** ID of the clinic branch */
|
|
268
|
-
clinicBranchId: string;
|
|
269
|
-
/** Aggregated clinic information (snapshot) */
|
|
270
|
-
clinicInfo: ClinicInfo;
|
|
271
|
-
/** IANA timezone of the clinic */
|
|
272
|
-
clinic_tz: string;
|
|
273
|
-
|
|
274
|
-
/** ID of the practitioner */
|
|
275
|
-
practitionerId: string;
|
|
276
|
-
/** Aggregated practitioner information (snapshot) */
|
|
277
|
-
practitionerInfo: PractitionerProfileInfo;
|
|
278
|
-
|
|
279
|
-
/** ID of the patient */
|
|
280
|
-
patientId: string;
|
|
281
|
-
/** Aggregated patient information (snapshot) */
|
|
282
|
-
patientInfo: PatientProfileInfo;
|
|
283
|
-
|
|
284
|
-
/** ID of the procedure */
|
|
285
|
-
procedureId: string;
|
|
286
|
-
/** Aggregated procedure information including product/brand (snapshot) */
|
|
287
|
-
procedureInfo: ProcedureSummaryInfo; // Aggregated procedure information
|
|
288
|
-
/** Extended procedure information */
|
|
289
|
-
procedureExtendedInfo: ProcedureExtendedInfo; // Aggregated extended procedure information
|
|
290
|
-
|
|
291
|
-
/** Status of the appointment */
|
|
292
|
-
status: AppointmentStatus;
|
|
293
|
-
|
|
294
|
-
/** Timestamps */
|
|
295
|
-
bookingTime: Timestamp;
|
|
296
|
-
confirmationTime?: Timestamp | null;
|
|
297
|
-
cancellationTime?: Timestamp | null;
|
|
298
|
-
rescheduleTime?: Timestamp | null;
|
|
299
|
-
appointmentStartTime: Timestamp;
|
|
300
|
-
appointmentEndTime: Timestamp;
|
|
301
|
-
procedureActualStartTime?: Timestamp | null; // NEW: Actual start time of the procedure
|
|
302
|
-
actualDurationMinutes?: number;
|
|
303
|
-
|
|
304
|
-
/** Cancellation Details */
|
|
305
|
-
cancellationReason?: string | null;
|
|
306
|
-
canceledBy?: 'patient' | 'clinic' | 'practitioner' | 'system';
|
|
307
|
-
|
|
308
|
-
/** Notes */
|
|
309
|
-
internalNotes?: string | null;
|
|
310
|
-
patientNotes?: string | null;
|
|
311
|
-
|
|
312
|
-
/** Payment Details */
|
|
313
|
-
cost: number;
|
|
314
|
-
currency: Currency;
|
|
315
|
-
paymentStatus: PaymentStatus;
|
|
316
|
-
paymentTransactionId?: string | null;
|
|
317
|
-
|
|
318
|
-
/** Procedure-related conditions and requirements */
|
|
319
|
-
blockingConditions: BlockingCondition[];
|
|
320
|
-
contraindications: ContraindicationDynamic[];
|
|
321
|
-
preProcedureRequirements: Requirement[];
|
|
322
|
-
postProcedureRequirements: Requirement[];
|
|
323
|
-
|
|
324
|
-
/** Tracking information for requirements completion */
|
|
325
|
-
completedPreRequirements?: string[]; // IDs of completed pre-requirements
|
|
326
|
-
completedPostRequirements?: string[]; // IDs of completed post-requirements
|
|
327
|
-
|
|
328
|
-
/** NEW: Linked forms (consent, procedure-specific forms, etc.) */
|
|
329
|
-
linkedFormIds?: string[];
|
|
330
|
-
linkedForms?: LinkedFormInfo[];
|
|
331
|
-
pendingUserFormsIds?: string[]; // Determines if there are any user forms that are pending for this appointment, blocks the appointment from being checked in (only for user forms with isRequired = true)
|
|
332
|
-
|
|
333
|
-
/** NEW: Media items (before/after photos, scanned documents, etc.) */
|
|
334
|
-
media?: AppointmentMediaItem[];
|
|
335
|
-
|
|
336
|
-
/** NEW: Information about the patient's review for this appointment */
|
|
337
|
-
reviewInfo?: PatientReviewInfo | null;
|
|
338
|
-
|
|
339
|
-
/** NEW: Details about the finalization of the appointment by the practitioner */
|
|
340
|
-
finalizedDetails?: {
|
|
341
|
-
by: string; // Practitioner User ID
|
|
342
|
-
at: Timestamp;
|
|
343
|
-
notes?: string;
|
|
344
|
-
};
|
|
345
|
-
|
|
346
|
-
/** Timestamps for record creation and updates */
|
|
347
|
-
createdAt: Timestamp;
|
|
348
|
-
updatedAt: Timestamp;
|
|
349
|
-
|
|
350
|
-
/** Recurring appointment information */
|
|
351
|
-
isRecurring?: boolean;
|
|
352
|
-
recurringAppointmentId?: string | null;
|
|
353
|
-
|
|
354
|
-
/** NEW: Flag for soft deletion or archiving */
|
|
355
|
-
isArchived?: boolean;
|
|
356
|
-
|
|
357
|
-
/** NEW: Metadata for the appointment - used for area selection and photos */
|
|
358
|
-
metadata?: AppointmentMetadata;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Data needed to create a new Appointment
|
|
363
|
-
*/
|
|
364
|
-
export interface CreateAppointmentData {
|
|
365
|
-
clinicBranchId: string;
|
|
366
|
-
practitionerId: string;
|
|
367
|
-
patientId: string;
|
|
368
|
-
procedureId: string;
|
|
369
|
-
appointmentStartTime: Timestamp;
|
|
370
|
-
appointmentEndTime: Timestamp;
|
|
371
|
-
cost: number;
|
|
372
|
-
currency: Currency;
|
|
373
|
-
patientNotes?: string | null;
|
|
374
|
-
initialStatus: AppointmentStatus;
|
|
375
|
-
initialPaymentStatus?: PaymentStatus; // Defaults to UNPAID if not provided
|
|
376
|
-
clinic_tz: string;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* Data needed to create a new Appointment via CreateAppointmentHttp method
|
|
381
|
-
*/
|
|
382
|
-
export interface CreateAppointmentHttpData {
|
|
383
|
-
patientId: string;
|
|
384
|
-
procedureId: string;
|
|
385
|
-
appointmentStartTime: Timestamp;
|
|
386
|
-
appointmentEndTime: Timestamp;
|
|
387
|
-
patientNotes?: string | null;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Data allowed for updating an Appointment
|
|
392
|
-
*/
|
|
393
|
-
export interface UpdateAppointmentData {
|
|
394
|
-
status?: AppointmentStatus;
|
|
395
|
-
confirmationTime?: Timestamp | FieldValue | null;
|
|
396
|
-
cancellationTime?: Timestamp | FieldValue | null;
|
|
397
|
-
rescheduleTime?: Timestamp | FieldValue | null;
|
|
398
|
-
procedureActualStartTime?: Timestamp | FieldValue | null; // NEW
|
|
399
|
-
actualDurationMinutes?: number;
|
|
400
|
-
cancellationReason?: string | null;
|
|
401
|
-
canceledBy?: 'patient' | 'clinic' | 'practitioner' | 'system';
|
|
402
|
-
internalNotes?: string | null;
|
|
403
|
-
patientNotes?: string | FieldValue | null; // Allow FieldValue for deleting
|
|
404
|
-
paymentStatus?: PaymentStatus;
|
|
405
|
-
paymentTransactionId?: string | FieldValue | null;
|
|
406
|
-
completedPreRequirements?: string[] | FieldValue; // Allow FieldValue for arrayUnion/arrayRemove
|
|
407
|
-
completedPostRequirements?: string[] | FieldValue;
|
|
408
|
-
appointmentStartTime?: Timestamp; // For rescheduling
|
|
409
|
-
appointmentEndTime?: Timestamp; // For rescheduling
|
|
410
|
-
calendarEventId?: string; // If calendar event needs to be re-linked
|
|
411
|
-
cost?: number; // If cost is adjusted
|
|
412
|
-
clinicBranchId?: string; // If appointment is moved to another branch (complex scenario)
|
|
413
|
-
practitionerId?: string; // If practitioner is changed
|
|
414
|
-
clinic_tz?: string;
|
|
415
|
-
|
|
416
|
-
/** NEW: For updating linked forms - typically managed by dedicated methods */
|
|
417
|
-
linkedFormIds?: string[] | FieldValue;
|
|
418
|
-
linkedForms?: LinkedFormInfo[] | FieldValue;
|
|
419
|
-
|
|
420
|
-
/** NEW: For updating media items - typically managed by dedicated methods */
|
|
421
|
-
media?: AppointmentMediaItem[] | FieldValue;
|
|
422
|
-
|
|
423
|
-
/** NEW: For adding/updating review information */
|
|
424
|
-
reviewInfo?: PatientReviewInfo | FieldValue | null;
|
|
425
|
-
|
|
426
|
-
/** NEW: For setting practitioner finalization details */
|
|
427
|
-
finalizedDetails?: { by: string; at: Timestamp; notes?: string } | FieldValue;
|
|
428
|
-
|
|
429
|
-
/** NEW: For archiving/unarchiving */
|
|
430
|
-
isArchived?: boolean;
|
|
431
|
-
|
|
432
|
-
updatedAt?: FieldValue; // To set server timestamp
|
|
433
|
-
|
|
434
|
-
/** NEW: For updating metadata */
|
|
435
|
-
metadata?: AppointmentMetadata;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
* Parameters for searching appointments
|
|
440
|
-
*/
|
|
441
|
-
export interface SearchAppointmentsParams {
|
|
442
|
-
patientId?: string;
|
|
443
|
-
practitionerId?: string;
|
|
444
|
-
clinicBranchId?: string;
|
|
445
|
-
startDate?: Date;
|
|
446
|
-
endDate?: Date;
|
|
447
|
-
status?: AppointmentStatus | AppointmentStatus[];
|
|
448
|
-
limit?: number;
|
|
449
|
-
startAfter?: any;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/** Firestore collection name */
|
|
453
|
-
export const APPOINTMENTS_COLLECTION = 'appointments';
|
|
1
|
+
import { Timestamp, FieldValue } from 'firebase/firestore';
|
|
2
|
+
import { ClinicInfo, PractitionerProfileInfo, PatientProfileInfo } from '../profile';
|
|
3
|
+
import { ProcedureSummaryInfo } from '../procedure';
|
|
4
|
+
import { Currency, type PricingMeasure } from '../../backoffice/types/static/pricing.types';
|
|
5
|
+
import { BlockingCondition } from '../../backoffice/types/static/blocking-condition.types';
|
|
6
|
+
import { Requirement } from '../../backoffice/types/requirement.types';
|
|
7
|
+
import { FilledDocumentStatus } from '../documentation-templates';
|
|
8
|
+
import type { ContraindicationDynamic, ProcedureFamily } from '../../backoffice';
|
|
9
|
+
import type { MediaResource } from '../../services/media/media.service';
|
|
10
|
+
import { string } from 'zod/v4';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Enum defining the possible statuses of an appointment.
|
|
14
|
+
*/
|
|
15
|
+
export enum AppointmentStatus {
|
|
16
|
+
PENDING = 'pending', // Initial state after booking, before confirmation (if applicable)
|
|
17
|
+
CONFIRMED = 'confirmed', // Confirmed by clinic/practitioner
|
|
18
|
+
CHECKED_IN = 'checked_in', // Patient has arrived
|
|
19
|
+
IN_PROGRESS = 'in_progress', // Procedure has started
|
|
20
|
+
COMPLETED = 'completed', // Procedure finished successfully
|
|
21
|
+
CANCELED_PATIENT = 'canceled_patient', // Canceled by the patient
|
|
22
|
+
CANCELED_PATIENT_RESCHEDULED = 'canceled_patient_rescheduled', // Canceled by the patient and rescheduled by the clinic
|
|
23
|
+
CANCELED_CLINIC = 'canceled_clinic', // Canceled by the clinic/practitioner
|
|
24
|
+
NO_SHOW = 'no_show', // Patient did not attend
|
|
25
|
+
RESCHEDULED_BY_CLINIC = 'rescheduled_by_clinic', // When appointment is rescheduled by the clinic, waiting for patient confirmation or cancellation (when reschedule is accepted, status goes to confirmed, if not accepted, then status goes to canceled_patient_rescheduled)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Enum defining the payment status of an appointment.
|
|
30
|
+
*/
|
|
31
|
+
export enum PaymentStatus {
|
|
32
|
+
UNPAID = 'unpaid',
|
|
33
|
+
PAID = 'paid',
|
|
34
|
+
PARTIALLY_PAID = 'partially_paid',
|
|
35
|
+
REFUNDED = 'refunded',
|
|
36
|
+
NOT_APPLICABLE = 'not_applicable', // For free services or other scenarios
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Enum for different types of media that can be attached to an appointment.
|
|
41
|
+
*/
|
|
42
|
+
export enum MediaType {
|
|
43
|
+
BEFORE_PHOTO = 'before_photo',
|
|
44
|
+
AFTER_PHOTO = 'after_photo',
|
|
45
|
+
CONSENT_SCAN = 'consent_scan',
|
|
46
|
+
OTHER_DOCUMENT = 'other_document',
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Interface to describe a media file linked to an appointment.
|
|
51
|
+
*/
|
|
52
|
+
export interface AppointmentMediaItem {
|
|
53
|
+
id: string; // Auto-generated unique ID for the media item
|
|
54
|
+
type: MediaType;
|
|
55
|
+
url: string; // Cloud Storage URL
|
|
56
|
+
fileName?: string;
|
|
57
|
+
uploadedAt: Timestamp;
|
|
58
|
+
uploadedBy: string; // User ID (patient, practitioner, or clinic_admin)
|
|
59
|
+
description?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Interface for procedure-specific information
|
|
64
|
+
*/
|
|
65
|
+
export interface ProcedureExtendedInfo {
|
|
66
|
+
id: string;
|
|
67
|
+
name: string;
|
|
68
|
+
description: string;
|
|
69
|
+
cost: number;
|
|
70
|
+
duration: number;
|
|
71
|
+
procedureFamily: ProcedureFamily;
|
|
72
|
+
procedureCategoryId: string;
|
|
73
|
+
procedureCategoryName: string;
|
|
74
|
+
procedureSubCategoryId: string;
|
|
75
|
+
procedureSubCategoryName: string;
|
|
76
|
+
procedureTechnologyId: string;
|
|
77
|
+
procedureTechnologyName: string;
|
|
78
|
+
procedureProductBrandId: string;
|
|
79
|
+
procedureProductBrandName: string;
|
|
80
|
+
procedureProducts: Array<{
|
|
81
|
+
productId: string;
|
|
82
|
+
productName: string;
|
|
83
|
+
brandId: string;
|
|
84
|
+
brandName: string;
|
|
85
|
+
}>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Interface to describe a filled form linked to an appointment.
|
|
90
|
+
*/
|
|
91
|
+
export interface LinkedFormInfo {
|
|
92
|
+
formId: string; // ID of the FilledDocument
|
|
93
|
+
templateId: string;
|
|
94
|
+
templateVersion: number;
|
|
95
|
+
title: string; // For display, usually from DocumentTemplate.title
|
|
96
|
+
isUserForm: boolean;
|
|
97
|
+
isRequired?: boolean;
|
|
98
|
+
sortingOrder?: number;
|
|
99
|
+
status: FilledDocumentStatus; // Status of the filled form (e.g., draft, completed, signed)
|
|
100
|
+
path: string; // Full Firestore path to the filled document (e.g., appointments/{aid}/user-forms/{fid})
|
|
101
|
+
submittedAt?: Timestamp;
|
|
102
|
+
completedAt?: Timestamp; // When the form reached a final state like 'completed' or 'signed'
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Interface for summarized patient review information linked to an appointment.
|
|
107
|
+
*/
|
|
108
|
+
export interface PatientReviewInfo {
|
|
109
|
+
reviewId: string; // ID of the full review document/record if stored elsewhere
|
|
110
|
+
rating: number; // e.g., 1-5 stars
|
|
111
|
+
comment?: string; // A short snippet or the full comment
|
|
112
|
+
reviewedAt: Timestamp;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Interface for before/after photos and notes per zone
|
|
117
|
+
*/
|
|
118
|
+
export interface BeforeAfterPerZone {
|
|
119
|
+
/** URL for before photo or null if not available */
|
|
120
|
+
before: MediaResource | null;
|
|
121
|
+
/** URL for after photo or null if not available */
|
|
122
|
+
after: MediaResource | null;
|
|
123
|
+
/** Optional note for the zone */
|
|
124
|
+
afterNote?: string | null;
|
|
125
|
+
beforeNote?: string | null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Interface for zone photo upload data
|
|
130
|
+
*/
|
|
131
|
+
export interface ZonePhotoUploadData {
|
|
132
|
+
appointmentId: string;
|
|
133
|
+
zoneId: string;
|
|
134
|
+
photoType: 'before' | 'after';
|
|
135
|
+
file: File | Blob;
|
|
136
|
+
notes?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Interface for zone item data (products or notes per zone)
|
|
141
|
+
*/
|
|
142
|
+
export interface ZoneItemData {
|
|
143
|
+
productId?: string;
|
|
144
|
+
productName?: string;
|
|
145
|
+
productBrandId?: string;
|
|
146
|
+
productBrandName?: string;
|
|
147
|
+
belongingProcedureId: string;
|
|
148
|
+
type: 'item' | 'note';
|
|
149
|
+
stage?: 'before' | 'after'; // Stage of the note/item: 'before' for planning notes, 'after' for treatment notes
|
|
150
|
+
price?: number;
|
|
151
|
+
currency?: Currency;
|
|
152
|
+
unitOfMeasurement?: PricingMeasure;
|
|
153
|
+
priceOverrideAmount?: number; // If set, takes precedence over price
|
|
154
|
+
quantity?: number;
|
|
155
|
+
parentZone: string; // Zone key in format "category.zone" (e.g., "face.forehead")
|
|
156
|
+
subzones: string[];
|
|
157
|
+
notes?: string;
|
|
158
|
+
subtotal?: number;
|
|
159
|
+
ionNumber?: string;
|
|
160
|
+
createdAt?: string; // ISO timestamp
|
|
161
|
+
updatedAt?: string; // ISO timestamp
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* @deprecated Use ZoneItemData instead
|
|
166
|
+
*/
|
|
167
|
+
export interface BillingPerZone {
|
|
168
|
+
Product: string;
|
|
169
|
+
ProductId: string | null;
|
|
170
|
+
Quantity: number;
|
|
171
|
+
UnitOfMeasurement: PricingMeasure;
|
|
172
|
+
UnitPrice: number;
|
|
173
|
+
UnitCurency: Currency;
|
|
174
|
+
Subtotal: number;
|
|
175
|
+
Note: string | null;
|
|
176
|
+
IonNumber: string | null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Interface for final billing calculations of the appointment
|
|
181
|
+
*/
|
|
182
|
+
export interface FinalBilling {
|
|
183
|
+
/** Total of all subtotals from all zones */
|
|
184
|
+
subtotalAll: number;
|
|
185
|
+
/** Tax rate as percentage (e.g., 0.20 for 20%) */
|
|
186
|
+
taxRate: number;
|
|
187
|
+
/** Calculated tax amount */
|
|
188
|
+
taxPrice: number;
|
|
189
|
+
/** Final price including tax */
|
|
190
|
+
finalPrice: number;
|
|
191
|
+
/** Currency for the final billing */
|
|
192
|
+
currency: Currency;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Interface for product metadata in appointment
|
|
197
|
+
*/
|
|
198
|
+
export interface AppointmentProductMetadata {
|
|
199
|
+
productId: string;
|
|
200
|
+
productName: string;
|
|
201
|
+
brandId: string;
|
|
202
|
+
brandName: string;
|
|
203
|
+
procedureId: string;
|
|
204
|
+
price: number;
|
|
205
|
+
currency: Currency;
|
|
206
|
+
unitOfMeasurement: PricingMeasure;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Interface for extended procedures in appointment
|
|
211
|
+
*/
|
|
212
|
+
export interface ExtendedProcedureInfo {
|
|
213
|
+
procedureId: string;
|
|
214
|
+
procedureName: string;
|
|
215
|
+
procedureFamily?: ProcedureFamily;
|
|
216
|
+
procedureCategoryId: string;
|
|
217
|
+
procedureCategoryName: string;
|
|
218
|
+
procedureSubCategoryId: string;
|
|
219
|
+
procedureSubCategoryName: string;
|
|
220
|
+
procedureTechnologyId: string;
|
|
221
|
+
procedureTechnologyName: string;
|
|
222
|
+
procedureProducts: Array<{
|
|
223
|
+
productId: string;
|
|
224
|
+
productName: string;
|
|
225
|
+
brandId: string;
|
|
226
|
+
brandName: string;
|
|
227
|
+
}>;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface RecommendedProcedure {
|
|
231
|
+
procedure: ExtendedProcedureInfo;
|
|
232
|
+
note: string;
|
|
233
|
+
timeframe: {
|
|
234
|
+
value: number;
|
|
235
|
+
unit: 'day' | 'week' | 'month' | 'year';
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Interface for appointment metadata containing zone-specific information
|
|
241
|
+
*/
|
|
242
|
+
export interface AppointmentMetadata {
|
|
243
|
+
selectedZones: string[] | null;
|
|
244
|
+
zonePhotos: Record<string, BeforeAfterPerZone[]> | null;
|
|
245
|
+
zonesData?: Record<string, ZoneItemData[]> | null;
|
|
246
|
+
appointmentProducts?: AppointmentProductMetadata[];
|
|
247
|
+
extendedProcedures?: ExtendedProcedureInfo[];
|
|
248
|
+
recommendedProcedures: RecommendedProcedure[]
|
|
249
|
+
finalbilling: FinalBilling | null;
|
|
250
|
+
finalizationNotes: string | null;
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* @deprecated Use zonesData instead
|
|
254
|
+
*/
|
|
255
|
+
zoneBilling?: Record<string, BillingPerZone> | null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Represents a booked appointment, aggregating key information and relevant procedure rules.
|
|
260
|
+
*/
|
|
261
|
+
export interface Appointment {
|
|
262
|
+
/** Unique identifier for the appointment */
|
|
263
|
+
id: string;
|
|
264
|
+
/** Reference to the associated CalendarEvent */
|
|
265
|
+
calendarEventId: string;
|
|
266
|
+
|
|
267
|
+
/** ID of the clinic branch */
|
|
268
|
+
clinicBranchId: string;
|
|
269
|
+
/** Aggregated clinic information (snapshot) */
|
|
270
|
+
clinicInfo: ClinicInfo;
|
|
271
|
+
/** IANA timezone of the clinic */
|
|
272
|
+
clinic_tz: string;
|
|
273
|
+
|
|
274
|
+
/** ID of the practitioner */
|
|
275
|
+
practitionerId: string;
|
|
276
|
+
/** Aggregated practitioner information (snapshot) */
|
|
277
|
+
practitionerInfo: PractitionerProfileInfo;
|
|
278
|
+
|
|
279
|
+
/** ID of the patient */
|
|
280
|
+
patientId: string;
|
|
281
|
+
/** Aggregated patient information (snapshot) */
|
|
282
|
+
patientInfo: PatientProfileInfo;
|
|
283
|
+
|
|
284
|
+
/** ID of the procedure */
|
|
285
|
+
procedureId: string;
|
|
286
|
+
/** Aggregated procedure information including product/brand (snapshot) */
|
|
287
|
+
procedureInfo: ProcedureSummaryInfo; // Aggregated procedure information
|
|
288
|
+
/** Extended procedure information */
|
|
289
|
+
procedureExtendedInfo: ProcedureExtendedInfo; // Aggregated extended procedure information
|
|
290
|
+
|
|
291
|
+
/** Status of the appointment */
|
|
292
|
+
status: AppointmentStatus;
|
|
293
|
+
|
|
294
|
+
/** Timestamps */
|
|
295
|
+
bookingTime: Timestamp;
|
|
296
|
+
confirmationTime?: Timestamp | null;
|
|
297
|
+
cancellationTime?: Timestamp | null;
|
|
298
|
+
rescheduleTime?: Timestamp | null;
|
|
299
|
+
appointmentStartTime: Timestamp;
|
|
300
|
+
appointmentEndTime: Timestamp;
|
|
301
|
+
procedureActualStartTime?: Timestamp | null; // NEW: Actual start time of the procedure
|
|
302
|
+
actualDurationMinutes?: number;
|
|
303
|
+
|
|
304
|
+
/** Cancellation Details */
|
|
305
|
+
cancellationReason?: string | null;
|
|
306
|
+
canceledBy?: 'patient' | 'clinic' | 'practitioner' | 'system';
|
|
307
|
+
|
|
308
|
+
/** Notes */
|
|
309
|
+
internalNotes?: string | null;
|
|
310
|
+
patientNotes?: string | null;
|
|
311
|
+
|
|
312
|
+
/** Payment Details */
|
|
313
|
+
cost: number;
|
|
314
|
+
currency: Currency;
|
|
315
|
+
paymentStatus: PaymentStatus;
|
|
316
|
+
paymentTransactionId?: string | null;
|
|
317
|
+
|
|
318
|
+
/** Procedure-related conditions and requirements */
|
|
319
|
+
blockingConditions: BlockingCondition[];
|
|
320
|
+
contraindications: ContraindicationDynamic[];
|
|
321
|
+
preProcedureRequirements: Requirement[];
|
|
322
|
+
postProcedureRequirements: Requirement[];
|
|
323
|
+
|
|
324
|
+
/** Tracking information for requirements completion */
|
|
325
|
+
completedPreRequirements?: string[]; // IDs of completed pre-requirements
|
|
326
|
+
completedPostRequirements?: string[]; // IDs of completed post-requirements
|
|
327
|
+
|
|
328
|
+
/** NEW: Linked forms (consent, procedure-specific forms, etc.) */
|
|
329
|
+
linkedFormIds?: string[];
|
|
330
|
+
linkedForms?: LinkedFormInfo[];
|
|
331
|
+
pendingUserFormsIds?: string[]; // Determines if there are any user forms that are pending for this appointment, blocks the appointment from being checked in (only for user forms with isRequired = true)
|
|
332
|
+
|
|
333
|
+
/** NEW: Media items (before/after photos, scanned documents, etc.) */
|
|
334
|
+
media?: AppointmentMediaItem[];
|
|
335
|
+
|
|
336
|
+
/** NEW: Information about the patient's review for this appointment */
|
|
337
|
+
reviewInfo?: PatientReviewInfo | null;
|
|
338
|
+
|
|
339
|
+
/** NEW: Details about the finalization of the appointment by the practitioner */
|
|
340
|
+
finalizedDetails?: {
|
|
341
|
+
by: string; // Practitioner User ID
|
|
342
|
+
at: Timestamp;
|
|
343
|
+
notes?: string;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
/** Timestamps for record creation and updates */
|
|
347
|
+
createdAt: Timestamp;
|
|
348
|
+
updatedAt: Timestamp;
|
|
349
|
+
|
|
350
|
+
/** Recurring appointment information */
|
|
351
|
+
isRecurring?: boolean;
|
|
352
|
+
recurringAppointmentId?: string | null;
|
|
353
|
+
|
|
354
|
+
/** NEW: Flag for soft deletion or archiving */
|
|
355
|
+
isArchived?: boolean;
|
|
356
|
+
|
|
357
|
+
/** NEW: Metadata for the appointment - used for area selection and photos */
|
|
358
|
+
metadata?: AppointmentMetadata;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Data needed to create a new Appointment
|
|
363
|
+
*/
|
|
364
|
+
export interface CreateAppointmentData {
|
|
365
|
+
clinicBranchId: string;
|
|
366
|
+
practitionerId: string;
|
|
367
|
+
patientId: string;
|
|
368
|
+
procedureId: string;
|
|
369
|
+
appointmentStartTime: Timestamp;
|
|
370
|
+
appointmentEndTime: Timestamp;
|
|
371
|
+
cost: number;
|
|
372
|
+
currency: Currency;
|
|
373
|
+
patientNotes?: string | null;
|
|
374
|
+
initialStatus: AppointmentStatus;
|
|
375
|
+
initialPaymentStatus?: PaymentStatus; // Defaults to UNPAID if not provided
|
|
376
|
+
clinic_tz: string;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Data needed to create a new Appointment via CreateAppointmentHttp method
|
|
381
|
+
*/
|
|
382
|
+
export interface CreateAppointmentHttpData {
|
|
383
|
+
patientId: string;
|
|
384
|
+
procedureId: string;
|
|
385
|
+
appointmentStartTime: Timestamp;
|
|
386
|
+
appointmentEndTime: Timestamp;
|
|
387
|
+
patientNotes?: string | null;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Data allowed for updating an Appointment
|
|
392
|
+
*/
|
|
393
|
+
export interface UpdateAppointmentData {
|
|
394
|
+
status?: AppointmentStatus;
|
|
395
|
+
confirmationTime?: Timestamp | FieldValue | null;
|
|
396
|
+
cancellationTime?: Timestamp | FieldValue | null;
|
|
397
|
+
rescheduleTime?: Timestamp | FieldValue | null;
|
|
398
|
+
procedureActualStartTime?: Timestamp | FieldValue | null; // NEW
|
|
399
|
+
actualDurationMinutes?: number;
|
|
400
|
+
cancellationReason?: string | null;
|
|
401
|
+
canceledBy?: 'patient' | 'clinic' | 'practitioner' | 'system';
|
|
402
|
+
internalNotes?: string | null;
|
|
403
|
+
patientNotes?: string | FieldValue | null; // Allow FieldValue for deleting
|
|
404
|
+
paymentStatus?: PaymentStatus;
|
|
405
|
+
paymentTransactionId?: string | FieldValue | null;
|
|
406
|
+
completedPreRequirements?: string[] | FieldValue; // Allow FieldValue for arrayUnion/arrayRemove
|
|
407
|
+
completedPostRequirements?: string[] | FieldValue;
|
|
408
|
+
appointmentStartTime?: Timestamp; // For rescheduling
|
|
409
|
+
appointmentEndTime?: Timestamp; // For rescheduling
|
|
410
|
+
calendarEventId?: string; // If calendar event needs to be re-linked
|
|
411
|
+
cost?: number; // If cost is adjusted
|
|
412
|
+
clinicBranchId?: string; // If appointment is moved to another branch (complex scenario)
|
|
413
|
+
practitionerId?: string; // If practitioner is changed
|
|
414
|
+
clinic_tz?: string;
|
|
415
|
+
|
|
416
|
+
/** NEW: For updating linked forms - typically managed by dedicated methods */
|
|
417
|
+
linkedFormIds?: string[] | FieldValue;
|
|
418
|
+
linkedForms?: LinkedFormInfo[] | FieldValue;
|
|
419
|
+
|
|
420
|
+
/** NEW: For updating media items - typically managed by dedicated methods */
|
|
421
|
+
media?: AppointmentMediaItem[] | FieldValue;
|
|
422
|
+
|
|
423
|
+
/** NEW: For adding/updating review information */
|
|
424
|
+
reviewInfo?: PatientReviewInfo | FieldValue | null;
|
|
425
|
+
|
|
426
|
+
/** NEW: For setting practitioner finalization details */
|
|
427
|
+
finalizedDetails?: { by: string; at: Timestamp; notes?: string } | FieldValue;
|
|
428
|
+
|
|
429
|
+
/** NEW: For archiving/unarchiving */
|
|
430
|
+
isArchived?: boolean;
|
|
431
|
+
|
|
432
|
+
updatedAt?: FieldValue; // To set server timestamp
|
|
433
|
+
|
|
434
|
+
/** NEW: For updating metadata */
|
|
435
|
+
metadata?: AppointmentMetadata;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Parameters for searching appointments
|
|
440
|
+
*/
|
|
441
|
+
export interface SearchAppointmentsParams {
|
|
442
|
+
patientId?: string;
|
|
443
|
+
practitionerId?: string;
|
|
444
|
+
clinicBranchId?: string;
|
|
445
|
+
startDate?: Date;
|
|
446
|
+
endDate?: Date;
|
|
447
|
+
status?: AppointmentStatus | AppointmentStatus[];
|
|
448
|
+
limit?: number;
|
|
449
|
+
startAfter?: any;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/** Firestore collection name */
|
|
453
|
+
export const APPOINTMENTS_COLLECTION = 'appointments';
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Interface for next steps recommendation with context about when and who suggested it
|
|
457
|
+
*/
|
|
458
|
+
export interface NextStepsRecommendation {
|
|
459
|
+
/** Unique identifier for this recommendation (appointmentId + recommendationIndex) */
|
|
460
|
+
id: string;
|
|
461
|
+
/** The recommended procedure details */
|
|
462
|
+
recommendedProcedure: RecommendedProcedure;
|
|
463
|
+
/** ID of the appointment where this was recommended */
|
|
464
|
+
appointmentId: string;
|
|
465
|
+
/** Date of the appointment when this was recommended */
|
|
466
|
+
appointmentDate: Timestamp;
|
|
467
|
+
/** ID of the practitioner who made the recommendation */
|
|
468
|
+
practitionerId: string;
|
|
469
|
+
/** Name of the practitioner who made the recommendation */
|
|
470
|
+
practitionerName: string;
|
|
471
|
+
/** ID of the clinic where the appointment took place */
|
|
472
|
+
clinicBranchId: string;
|
|
473
|
+
/** Name of the clinic where the appointment took place */
|
|
474
|
+
clinicName: string;
|
|
475
|
+
/** Status of the appointment when recommendation was made */
|
|
476
|
+
appointmentStatus: AppointmentStatus;
|
|
477
|
+
/** Whether this recommendation has been dismissed by the patient */
|
|
478
|
+
isDismissed?: boolean;
|
|
479
|
+
/** When the recommendation was dismissed (if dismissed) */
|
|
480
|
+
dismissedAt?: Timestamp | null;
|
|
481
|
+
}
|