@blackcode_sa/metaestetics-api 1.4.18 → 1.5.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/index.d.mts +7900 -4726
- package/dist/index.d.ts +7900 -4726
- package/dist/index.js +3029 -111
- package/dist/index.mjs +3059 -111
- package/package.json +4 -3
- package/src/index.ts +57 -2
- package/src/services/calendar/calendar-refactored.service.ts +1531 -0
- package/src/services/calendar/calendar.service.ts +1077 -0
- package/src/services/calendar/synced-calendars.service.ts +743 -0
- package/src/services/calendar/utils/appointment.utils.ts +314 -0
- package/src/services/calendar/utils/calendar-event.utils.ts +510 -0
- package/src/services/calendar/utils/clinic.utils.ts +237 -0
- package/src/services/calendar/utils/docs.utils.ts +157 -0
- package/src/services/calendar/utils/google-calendar.utils.ts +697 -0
- package/src/services/calendar/utils/index.ts +8 -0
- package/src/services/calendar/utils/patient.utils.ts +198 -0
- package/src/services/calendar/utils/practitioner.utils.ts +221 -0
- package/src/services/calendar/utils/synced-calendar.utils.ts +472 -0
- package/src/services/practitioner/practitioner.service.ts +346 -1
- package/src/types/calendar/index.ts +187 -0
- package/src/types/calendar/synced-calendar.types.ts +66 -0
- package/src/types/clinic/index.ts +1 -12
- package/src/types/index.ts +4 -0
- package/src/types/practitioner/index.ts +81 -0
- package/src/types/profile/index.ts +39 -0
- package/src/validations/calendar.schema.ts +223 -0
- package/src/validations/practitioner.schema.ts +66 -0
- package/src/validations/profile-info.schema.ts +41 -0
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
} from "../../backoffice/types/static/certification.types";
|
|
6
6
|
|
|
7
7
|
export const PRACTITIONERS_COLLECTION = "practitioners";
|
|
8
|
+
export const REGISTER_TOKENS_COLLECTION = "register_tokens";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Osnovne informacije o zdravstvenom radniku
|
|
@@ -35,6 +36,43 @@ export interface PractitionerCertification {
|
|
|
35
36
|
verificationStatus: "pending" | "verified" | "rejected";
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Interfejs za radno vreme zdravstvenog radnika u klinici
|
|
41
|
+
*/
|
|
42
|
+
export interface PractitionerClinicWorkingHours {
|
|
43
|
+
clinicId: string;
|
|
44
|
+
workingHours: {
|
|
45
|
+
monday: { start: string; end: string } | null;
|
|
46
|
+
tuesday: { start: string; end: string } | null;
|
|
47
|
+
wednesday: { start: string; end: string } | null;
|
|
48
|
+
thursday: { start: string; end: string } | null;
|
|
49
|
+
friday: { start: string; end: string } | null;
|
|
50
|
+
saturday: { start: string; end: string } | null;
|
|
51
|
+
sunday: { start: string; end: string } | null;
|
|
52
|
+
};
|
|
53
|
+
isActive: boolean;
|
|
54
|
+
createdAt: Timestamp;
|
|
55
|
+
updatedAt: Timestamp;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Status of practitioner profile
|
|
60
|
+
*/
|
|
61
|
+
export enum PractitionerStatus {
|
|
62
|
+
DRAFT = "draft",
|
|
63
|
+
ACTIVE = "active",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Token status for practitioner invitations
|
|
68
|
+
*/
|
|
69
|
+
export enum PractitionerTokenStatus {
|
|
70
|
+
ACTIVE = "active",
|
|
71
|
+
USED = "used",
|
|
72
|
+
EXPIRED = "expired",
|
|
73
|
+
REVOKED = "revoked",
|
|
74
|
+
}
|
|
75
|
+
|
|
38
76
|
/**
|
|
39
77
|
* Interfejs za zdravstvenog radnika
|
|
40
78
|
*/
|
|
@@ -44,8 +82,10 @@ export interface Practitioner {
|
|
|
44
82
|
basicInfo: PractitionerBasicInfo;
|
|
45
83
|
certification: PractitionerCertification;
|
|
46
84
|
clinics: string[]; // Reference na klinike gde radi
|
|
85
|
+
clinicWorkingHours: PractitionerClinicWorkingHours[]; // Radno vreme za svaku kliniku
|
|
47
86
|
isActive: boolean;
|
|
48
87
|
isVerified: boolean;
|
|
88
|
+
status: PractitionerStatus;
|
|
49
89
|
createdAt: Timestamp;
|
|
50
90
|
updatedAt: Timestamp;
|
|
51
91
|
}
|
|
@@ -58,8 +98,22 @@ export interface CreatePractitionerData {
|
|
|
58
98
|
basicInfo: PractitionerBasicInfo;
|
|
59
99
|
certification: PractitionerCertification;
|
|
60
100
|
clinics?: string[];
|
|
101
|
+
clinicWorkingHours?: PractitionerClinicWorkingHours[];
|
|
61
102
|
isActive: boolean;
|
|
62
103
|
isVerified: boolean;
|
|
104
|
+
status?: PractitionerStatus;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Tip za kreiranje draft profila zdravstvenog radnika
|
|
109
|
+
*/
|
|
110
|
+
export interface CreateDraftPractitionerData {
|
|
111
|
+
basicInfo: PractitionerBasicInfo;
|
|
112
|
+
certification: PractitionerCertification;
|
|
113
|
+
clinics?: string[];
|
|
114
|
+
clinicWorkingHours?: PractitionerClinicWorkingHours[];
|
|
115
|
+
isActive?: boolean;
|
|
116
|
+
isVerified?: boolean;
|
|
63
117
|
}
|
|
64
118
|
|
|
65
119
|
/**
|
|
@@ -113,3 +167,30 @@ export interface PractitionerWorkingHours {
|
|
|
113
167
|
createdAt: Timestamp;
|
|
114
168
|
updatedAt: Timestamp;
|
|
115
169
|
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Token za pozivanje zdravstvenog radnika
|
|
173
|
+
*/
|
|
174
|
+
export interface PractitionerToken {
|
|
175
|
+
id: string;
|
|
176
|
+
token: string;
|
|
177
|
+
practitionerId: string;
|
|
178
|
+
email: string;
|
|
179
|
+
clinicId: string;
|
|
180
|
+
status: PractitionerTokenStatus;
|
|
181
|
+
createdBy: string;
|
|
182
|
+
createdAt: Timestamp;
|
|
183
|
+
expiresAt: Timestamp;
|
|
184
|
+
usedBy?: string;
|
|
185
|
+
usedAt?: Timestamp;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Tip za kreiranje tokena za zdravstvenog radnika
|
|
190
|
+
*/
|
|
191
|
+
export interface CreatePractitionerTokenData {
|
|
192
|
+
practitionerId: string;
|
|
193
|
+
email: string;
|
|
194
|
+
clinicId: string;
|
|
195
|
+
expiresAt?: Date;
|
|
196
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Timestamp } from "firebase-admin/firestore";
|
|
2
|
+
import { ClinicLocation, ClinicContactInfo } from "../clinic";
|
|
3
|
+
import { PractitionerCertification } from "../practitioner";
|
|
4
|
+
import { Gender } from "../patient";
|
|
5
|
+
/**
|
|
6
|
+
* Interface for clinic profile information
|
|
7
|
+
*/
|
|
8
|
+
export interface ClinicInfo {
|
|
9
|
+
id: string;
|
|
10
|
+
featuredPhoto: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
location: ClinicLocation;
|
|
14
|
+
contactInfo: ClinicContactInfo;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Interface for practitioner profile information
|
|
19
|
+
*/
|
|
20
|
+
export interface PractitionerProfileInfo {
|
|
21
|
+
id: string;
|
|
22
|
+
practitionerPhoto: string | null;
|
|
23
|
+
name: string;
|
|
24
|
+
email: string;
|
|
25
|
+
phone: string | null;
|
|
26
|
+
certification: PractitionerCertification;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Interface for patient profile information
|
|
31
|
+
*/
|
|
32
|
+
export interface PatientProfileInfo {
|
|
33
|
+
id: string;
|
|
34
|
+
fullName: string;
|
|
35
|
+
email: string;
|
|
36
|
+
phone: string | null;
|
|
37
|
+
dateOfBirth: Timestamp;
|
|
38
|
+
gender: Gender;
|
|
39
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Timestamp, FieldValue } from "firebase/firestore";
|
|
3
|
+
import {
|
|
4
|
+
CalendarEventStatus,
|
|
5
|
+
CalendarEventType,
|
|
6
|
+
CalendarSyncStatus,
|
|
7
|
+
} from "../types/calendar";
|
|
8
|
+
import { SyncedCalendarProvider } from "../types/calendar/synced-calendar.types";
|
|
9
|
+
import {
|
|
10
|
+
Currency,
|
|
11
|
+
PricingMeasure,
|
|
12
|
+
} from "../backoffice/types/static/pricing.types";
|
|
13
|
+
import { clinicLocationSchema } from "./clinic.schema";
|
|
14
|
+
import {
|
|
15
|
+
clinicInfoSchema,
|
|
16
|
+
patientProfileInfoSchema,
|
|
17
|
+
practitionerProfileInfoSchema,
|
|
18
|
+
} from "./profile-info.schema";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Minimum appointment duration in minutes
|
|
22
|
+
*/
|
|
23
|
+
const MIN_APPOINTMENT_DURATION = 15;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Validation schema for calendar event time
|
|
27
|
+
*/
|
|
28
|
+
export const calendarEventTimeSchema = z
|
|
29
|
+
.object({
|
|
30
|
+
start: z.instanceof(Date).or(z.instanceof(Timestamp)),
|
|
31
|
+
end: z.instanceof(Date).or(z.instanceof(Timestamp)),
|
|
32
|
+
})
|
|
33
|
+
.refine(
|
|
34
|
+
(data) => {
|
|
35
|
+
// Convert to Date objects for comparison if they are Timestamps
|
|
36
|
+
const startDate =
|
|
37
|
+
data.start instanceof Timestamp ? data.start.toDate() : data.start;
|
|
38
|
+
const endDate =
|
|
39
|
+
data.end instanceof Timestamp ? data.end.toDate() : data.end;
|
|
40
|
+
|
|
41
|
+
// Ensure end time is after start time
|
|
42
|
+
return startDate < endDate;
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
message: "End time must be after start time",
|
|
46
|
+
path: ["end"],
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
.refine(
|
|
50
|
+
(data) => {
|
|
51
|
+
// Convert to Date objects for comparison if they are Timestamps
|
|
52
|
+
const startDate =
|
|
53
|
+
data.start instanceof Timestamp ? data.start.toDate() : data.start;
|
|
54
|
+
|
|
55
|
+
// Ensure start time is in the future
|
|
56
|
+
return startDate > new Date();
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
message: "Appointment must be scheduled in the future",
|
|
60
|
+
path: ["start"],
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Validation schema for time slot
|
|
66
|
+
*/
|
|
67
|
+
export const timeSlotSchema = z
|
|
68
|
+
.object({
|
|
69
|
+
start: z.date(),
|
|
70
|
+
end: z.date(),
|
|
71
|
+
isAvailable: z.boolean(),
|
|
72
|
+
})
|
|
73
|
+
.refine((data) => data.start < data.end, {
|
|
74
|
+
message: "End time must be after start time",
|
|
75
|
+
path: ["end"],
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Validation schema for synced calendar event
|
|
80
|
+
*/
|
|
81
|
+
export const syncedCalendarEventSchema = z.object({
|
|
82
|
+
eventId: z.string(),
|
|
83
|
+
syncedCalendarProvider: z.nativeEnum(SyncedCalendarProvider),
|
|
84
|
+
syncedAt: z.instanceof(Date).or(z.instanceof(Timestamp)),
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Validation schema for procedure info
|
|
89
|
+
*/
|
|
90
|
+
export const procedureInfoSchema = z.object({
|
|
91
|
+
name: z.string(),
|
|
92
|
+
description: z.string(),
|
|
93
|
+
duration: z.number().min(MIN_APPOINTMENT_DURATION),
|
|
94
|
+
price: z.number().min(0),
|
|
95
|
+
currency: z.nativeEnum(Currency),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Validation schema for procedure categorization
|
|
100
|
+
*/
|
|
101
|
+
export const procedureCategorizationSchema = z.object({
|
|
102
|
+
procedureFamily: z.string(), // Replace with proper enum when available
|
|
103
|
+
procedureCategory: z.string(), // Replace with proper enum when available
|
|
104
|
+
procedureSubcategory: z.string(), // Replace with proper enum when available
|
|
105
|
+
procedureTechnology: z.string(), // Replace with proper enum when available
|
|
106
|
+
procedureProduct: z.string(), // Replace with proper enum when available
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Validation schema for creating an appointment
|
|
111
|
+
*/
|
|
112
|
+
export const createAppointmentSchema = z
|
|
113
|
+
.object({
|
|
114
|
+
clinicId: z.string().min(1, "Clinic ID is required"),
|
|
115
|
+
doctorId: z.string().min(1, "Doctor ID is required"),
|
|
116
|
+
patientId: z.string().min(1, "Patient ID is required"),
|
|
117
|
+
procedureId: z.string().min(1, "Procedure ID is required"),
|
|
118
|
+
eventLocation: clinicLocationSchema,
|
|
119
|
+
eventTime: calendarEventTimeSchema,
|
|
120
|
+
description: z.string().optional(),
|
|
121
|
+
})
|
|
122
|
+
.refine(
|
|
123
|
+
(data) => {
|
|
124
|
+
// If we have access to the actual data, we could validate:
|
|
125
|
+
// - Doctor works at the clinic
|
|
126
|
+
// - Procedure is available at the clinic
|
|
127
|
+
// - Patient is eligible for the procedure
|
|
128
|
+
// These validations will be handled in the service layer
|
|
129
|
+
return true;
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
message: "Invalid appointment parameters",
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Validation schema for updating an appointment
|
|
138
|
+
*/
|
|
139
|
+
export const updateAppointmentSchema = z.object({
|
|
140
|
+
appointmentId: z.string().min(1, "Appointment ID is required"),
|
|
141
|
+
clinicId: z.string().min(1, "Clinic ID is required"),
|
|
142
|
+
doctorId: z.string().min(1, "Doctor ID is required"),
|
|
143
|
+
patientId: z.string().min(1, "Patient ID is required"),
|
|
144
|
+
eventTime: calendarEventTimeSchema.optional(),
|
|
145
|
+
description: z.string().optional(),
|
|
146
|
+
status: z.nativeEnum(CalendarEventStatus).optional(),
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Validation schema for creating a calendar event
|
|
151
|
+
*/
|
|
152
|
+
export const createCalendarEventSchema = z.object({
|
|
153
|
+
id: z.string(),
|
|
154
|
+
clinicBranchId: z.string().nullable().optional(),
|
|
155
|
+
clinicBranchInfo: z.any().nullable().optional(),
|
|
156
|
+
practitionerProfileId: z.string().nullable().optional(),
|
|
157
|
+
practitionerProfileInfo: practitionerProfileInfoSchema.nullable().optional(),
|
|
158
|
+
patientProfileId: z.string().nullable().optional(),
|
|
159
|
+
patientProfileInfo: patientProfileInfoSchema.nullable().optional(),
|
|
160
|
+
procedureId: z.string().nullable().optional(),
|
|
161
|
+
appointmentId: z.string().nullable().optional(),
|
|
162
|
+
syncedCalendarEventId: z
|
|
163
|
+
.array(syncedCalendarEventSchema)
|
|
164
|
+
.nullable()
|
|
165
|
+
.optional(),
|
|
166
|
+
eventName: z.string().min(1, "Event name is required"),
|
|
167
|
+
eventLocation: clinicLocationSchema.optional(),
|
|
168
|
+
eventTime: calendarEventTimeSchema,
|
|
169
|
+
description: z.string().optional(),
|
|
170
|
+
status: z.nativeEnum(CalendarEventStatus),
|
|
171
|
+
syncStatus: z.nativeEnum(CalendarSyncStatus),
|
|
172
|
+
eventType: z.nativeEnum(CalendarEventType),
|
|
173
|
+
createdAt: z.any(), // FieldValue for server timestamp
|
|
174
|
+
updatedAt: z.any(), // FieldValue for server timestamp
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Validation schema for updating a calendar event
|
|
179
|
+
*/
|
|
180
|
+
export const updateCalendarEventSchema = z.object({
|
|
181
|
+
syncedCalendarEventId: z
|
|
182
|
+
.array(syncedCalendarEventSchema)
|
|
183
|
+
.nullable()
|
|
184
|
+
.optional(),
|
|
185
|
+
appointmentId: z.string().nullable().optional(),
|
|
186
|
+
eventName: z.string().optional(),
|
|
187
|
+
eventTime: calendarEventTimeSchema.optional(),
|
|
188
|
+
description: z.string().optional(),
|
|
189
|
+
status: z.nativeEnum(CalendarEventStatus).optional(),
|
|
190
|
+
syncStatus: z.nativeEnum(CalendarSyncStatus).optional(),
|
|
191
|
+
eventType: z.nativeEnum(CalendarEventType).optional(),
|
|
192
|
+
updatedAt: z.any(), // FieldValue for server timestamp
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Validation schema for calendar event
|
|
197
|
+
*/
|
|
198
|
+
export const calendarEventSchema = z.object({
|
|
199
|
+
id: z.string(),
|
|
200
|
+
clinicBranchId: z.string().nullable().optional(),
|
|
201
|
+
clinicBranchInfo: z.any().nullable().optional(), // Will be replaced with proper clinic info schema
|
|
202
|
+
practitionerProfileId: z.string().nullable().optional(),
|
|
203
|
+
practitionerProfileInfo: practitionerProfileInfoSchema.nullable().optional(),
|
|
204
|
+
patientProfileId: z.string().nullable().optional(),
|
|
205
|
+
patientProfileInfo: patientProfileInfoSchema.nullable().optional(),
|
|
206
|
+
procedureId: z.string().nullable().optional(),
|
|
207
|
+
procedureInfo: procedureInfoSchema.nullable().optional(),
|
|
208
|
+
procedureCategorization: procedureCategorizationSchema.nullable().optional(),
|
|
209
|
+
appointmentId: z.string().nullable().optional(),
|
|
210
|
+
syncedCalendarEventId: z
|
|
211
|
+
.array(syncedCalendarEventSchema)
|
|
212
|
+
.nullable()
|
|
213
|
+
.optional(),
|
|
214
|
+
eventName: z.string(),
|
|
215
|
+
eventLocation: clinicLocationSchema.optional(),
|
|
216
|
+
eventTime: calendarEventTimeSchema,
|
|
217
|
+
description: z.string().optional(),
|
|
218
|
+
status: z.nativeEnum(CalendarEventStatus),
|
|
219
|
+
syncStatus: z.nativeEnum(CalendarSyncStatus),
|
|
220
|
+
eventType: z.nativeEnum(CalendarEventType),
|
|
221
|
+
createdAt: z.instanceof(Date).or(z.instanceof(Timestamp)),
|
|
222
|
+
updatedAt: z.instanceof(Date).or(z.instanceof(Timestamp)),
|
|
223
|
+
});
|
|
@@ -4,6 +4,10 @@ import {
|
|
|
4
4
|
CertificationLevel,
|
|
5
5
|
CertificationSpecialty,
|
|
6
6
|
} from "../backoffice/types/static/certification.types";
|
|
7
|
+
import {
|
|
8
|
+
PractitionerStatus,
|
|
9
|
+
PractitionerTokenStatus,
|
|
10
|
+
} from "../types/practitioner";
|
|
7
11
|
|
|
8
12
|
/**
|
|
9
13
|
* Šema za validaciju osnovnih informacija o zdravstvenom radniku
|
|
@@ -60,6 +64,25 @@ export const practitionerWorkingHoursSchema = z.object({
|
|
|
60
64
|
updatedAt: z.instanceof(Timestamp),
|
|
61
65
|
});
|
|
62
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Šema za validaciju radnog vremena u klinici
|
|
69
|
+
*/
|
|
70
|
+
export const practitionerClinicWorkingHoursSchema = z.object({
|
|
71
|
+
clinicId: z.string().min(1),
|
|
72
|
+
workingHours: z.object({
|
|
73
|
+
monday: timeSlotSchema,
|
|
74
|
+
tuesday: timeSlotSchema,
|
|
75
|
+
wednesday: timeSlotSchema,
|
|
76
|
+
thursday: timeSlotSchema,
|
|
77
|
+
friday: timeSlotSchema,
|
|
78
|
+
saturday: timeSlotSchema,
|
|
79
|
+
sunday: timeSlotSchema,
|
|
80
|
+
}),
|
|
81
|
+
isActive: z.boolean(),
|
|
82
|
+
createdAt: z.instanceof(Timestamp),
|
|
83
|
+
updatedAt: z.instanceof(Timestamp),
|
|
84
|
+
});
|
|
85
|
+
|
|
63
86
|
/**
|
|
64
87
|
* Šema za validaciju recenzije zdravstvenog radnika
|
|
65
88
|
*/
|
|
@@ -96,8 +119,10 @@ export const practitionerSchema = z.object({
|
|
|
96
119
|
basicInfo: practitionerBasicInfoSchema,
|
|
97
120
|
certification: practitionerCertificationSchema,
|
|
98
121
|
clinics: z.array(z.string()),
|
|
122
|
+
clinicWorkingHours: z.array(practitionerClinicWorkingHoursSchema),
|
|
99
123
|
isActive: z.boolean(),
|
|
100
124
|
isVerified: z.boolean(),
|
|
125
|
+
status: z.nativeEnum(PractitionerStatus),
|
|
101
126
|
createdAt: z.instanceof(Timestamp),
|
|
102
127
|
updatedAt: z.instanceof(Timestamp),
|
|
103
128
|
});
|
|
@@ -110,6 +135,47 @@ export const createPractitionerSchema = z.object({
|
|
|
110
135
|
basicInfo: practitionerBasicInfoSchema,
|
|
111
136
|
certification: practitionerCertificationSchema,
|
|
112
137
|
clinics: z.array(z.string()).optional(),
|
|
138
|
+
clinicWorkingHours: z.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
113
139
|
isActive: z.boolean(),
|
|
114
140
|
isVerified: z.boolean(),
|
|
141
|
+
status: z.nativeEnum(PractitionerStatus).optional(),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Šema za validaciju podataka pri kreiranju draft profila zdravstvenog radnika
|
|
146
|
+
*/
|
|
147
|
+
export const createDraftPractitionerSchema = z.object({
|
|
148
|
+
basicInfo: practitionerBasicInfoSchema,
|
|
149
|
+
certification: practitionerCertificationSchema,
|
|
150
|
+
clinics: z.array(z.string()).optional(),
|
|
151
|
+
clinicWorkingHours: z.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
152
|
+
isActive: z.boolean().optional().default(false),
|
|
153
|
+
isVerified: z.boolean().optional().default(false),
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Šema za validaciju tokena za zdravstvenog radnika
|
|
158
|
+
*/
|
|
159
|
+
export const practitionerTokenSchema = z.object({
|
|
160
|
+
id: z.string().min(1),
|
|
161
|
+
token: z.string().min(6),
|
|
162
|
+
practitionerId: z.string().min(1),
|
|
163
|
+
email: z.string().email(),
|
|
164
|
+
clinicId: z.string().min(1),
|
|
165
|
+
status: z.nativeEnum(PractitionerTokenStatus),
|
|
166
|
+
createdBy: z.string().min(1),
|
|
167
|
+
createdAt: z.instanceof(Timestamp),
|
|
168
|
+
expiresAt: z.instanceof(Timestamp),
|
|
169
|
+
usedBy: z.string().optional(),
|
|
170
|
+
usedAt: z.instanceof(Timestamp).optional(),
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Šema za validaciju podataka pri kreiranju tokena za zdravstvenog radnika
|
|
175
|
+
*/
|
|
176
|
+
export const createPractitionerTokenSchema = z.object({
|
|
177
|
+
practitionerId: z.string().min(1),
|
|
178
|
+
email: z.string().email(),
|
|
179
|
+
clinicId: z.string().min(1),
|
|
180
|
+
expiresAt: z.date().optional(),
|
|
115
181
|
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Timestamp } from "firebase/firestore";
|
|
3
|
+
import { clinicLocationSchema, clinicContactInfoSchema } from "./clinic.schema";
|
|
4
|
+
import { practitionerCertificationSchema } from "./practitioner.schema";
|
|
5
|
+
import { Gender } from "../types/patient";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validation schema for clinic info
|
|
9
|
+
*/
|
|
10
|
+
export const clinicInfoSchema = z.object({
|
|
11
|
+
id: z.string(),
|
|
12
|
+
featuredPhoto: z.string(),
|
|
13
|
+
name: z.string(),
|
|
14
|
+
description: z.string(),
|
|
15
|
+
location: clinicLocationSchema,
|
|
16
|
+
contactInfo: clinicContactInfoSchema,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validation schema for practitioner profile info
|
|
21
|
+
*/
|
|
22
|
+
export const practitionerProfileInfoSchema = z.object({
|
|
23
|
+
id: z.string(),
|
|
24
|
+
practitionerPhoto: z.string().nullable(),
|
|
25
|
+
name: z.string(),
|
|
26
|
+
email: z.string().email(),
|
|
27
|
+
phone: z.string().nullable(),
|
|
28
|
+
certification: practitionerCertificationSchema,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Validation schema for patient profile info
|
|
33
|
+
*/
|
|
34
|
+
export const patientProfileInfoSchema = z.object({
|
|
35
|
+
id: z.string(),
|
|
36
|
+
fullName: z.string(),
|
|
37
|
+
email: z.string().email(),
|
|
38
|
+
phone: z.string().nullable(),
|
|
39
|
+
dateOfBirth: z.instanceof(Timestamp),
|
|
40
|
+
gender: z.nativeEnum(Gender),
|
|
41
|
+
});
|