@blackcode_sa/metaestetics-api 1.4.18 → 1.5.0
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 +7405 -4795
- package/dist/index.d.ts +7405 -4795
- package/dist/index.js +2736 -109
- package/dist/index.mjs +2772 -109
- package/package.json +4 -3
- package/src/index.ts +48 -1
- 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 +1 -0
- 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 +21 -0
- package/src/types/profile/index.ts +39 -0
- package/src/validations/calendar.schema.ts +223 -0
- package/src/validations/practitioner.schema.ts +21 -0
- package/src/validations/profile-info.schema.ts +41 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Timestamp, FieldValue } from "firebase/firestore";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Enum for synced calendar provider
|
|
5
|
+
*/
|
|
6
|
+
export enum SyncedCalendarProvider {
|
|
7
|
+
GOOGLE = "google",
|
|
8
|
+
OUTLOOK = "outlook",
|
|
9
|
+
APPLE = "apple",
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Interface for synced calendar
|
|
14
|
+
*/
|
|
15
|
+
export interface SyncedCalendar {
|
|
16
|
+
id: string;
|
|
17
|
+
provider: SyncedCalendarProvider;
|
|
18
|
+
name: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
accessToken: string;
|
|
21
|
+
refreshToken: string;
|
|
22
|
+
tokenExpiry: Timestamp;
|
|
23
|
+
calendarId: string;
|
|
24
|
+
isActive: boolean;
|
|
25
|
+
lastSyncedAt?: Timestamp;
|
|
26
|
+
createdAt: Timestamp;
|
|
27
|
+
updatedAt: Timestamp;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Interface for creating a synced calendar
|
|
32
|
+
*/
|
|
33
|
+
export interface CreateSyncedCalendarData {
|
|
34
|
+
id: string;
|
|
35
|
+
provider: SyncedCalendarProvider;
|
|
36
|
+
name: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
accessToken: string;
|
|
39
|
+
refreshToken: string;
|
|
40
|
+
tokenExpiry: Timestamp;
|
|
41
|
+
calendarId: string;
|
|
42
|
+
isActive: boolean;
|
|
43
|
+
lastSyncedAt?: Timestamp;
|
|
44
|
+
createdAt: FieldValue;
|
|
45
|
+
updatedAt: FieldValue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Interface for updating a synced calendar
|
|
50
|
+
*/
|
|
51
|
+
export interface UpdateSyncedCalendarData {
|
|
52
|
+
name?: string;
|
|
53
|
+
description?: string;
|
|
54
|
+
accessToken?: string;
|
|
55
|
+
refreshToken?: string;
|
|
56
|
+
tokenExpiry?: Timestamp;
|
|
57
|
+
calendarId?: string;
|
|
58
|
+
isActive?: boolean;
|
|
59
|
+
lastSyncedAt?: Timestamp;
|
|
60
|
+
updatedAt: FieldValue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Collection name for synced calendars
|
|
65
|
+
*/
|
|
66
|
+
export const SYNCED_CALENDARS_COLLECTION = "syncedCalendars";
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
Currency,
|
|
6
6
|
PricingMeasure,
|
|
7
7
|
} from "../../backoffice/types/static/pricing.types";
|
|
8
|
+
import type { ClinicInfo } from "../profile";
|
|
8
9
|
|
|
9
10
|
export const CLINIC_GROUPS_COLLECTION = "clinic_groups";
|
|
10
11
|
export const CLINIC_ADMINS_COLLECTION = "clinic_admins";
|
|
@@ -94,18 +95,6 @@ export interface ContactPerson {
|
|
|
94
95
|
phoneNumber?: string | null;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
/**
|
|
98
|
-
* Interface for clinic information
|
|
99
|
-
*/
|
|
100
|
-
export interface ClinicInfo {
|
|
101
|
-
id: string;
|
|
102
|
-
featuredPhoto: string;
|
|
103
|
-
name: string;
|
|
104
|
-
description?: string;
|
|
105
|
-
location: ClinicLocation;
|
|
106
|
-
contactInfo: ClinicContactInfo;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
98
|
/**
|
|
110
99
|
* Interface for clinic admin
|
|
111
100
|
*/
|
package/src/types/index.ts
CHANGED
|
@@ -41,3 +41,7 @@ export type FirebaseUser = FirebaseAuthUser;
|
|
|
41
41
|
export * from "./documentation-templates";
|
|
42
42
|
export const DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
|
|
43
43
|
export const FILLED_DOCUMENTS_COLLECTION = "filled-documents";
|
|
44
|
+
|
|
45
|
+
// Calendar
|
|
46
|
+
export * from "./calendar";
|
|
47
|
+
export const CALENDAR_COLLECTION = "calendar";
|
|
@@ -35,6 +35,25 @@ export interface PractitionerCertification {
|
|
|
35
35
|
verificationStatus: "pending" | "verified" | "rejected";
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Interfejs za radno vreme zdravstvenog radnika u klinici
|
|
40
|
+
*/
|
|
41
|
+
export interface PractitionerClinicWorkingHours {
|
|
42
|
+
clinicId: string;
|
|
43
|
+
workingHours: {
|
|
44
|
+
monday: { start: string; end: string } | null;
|
|
45
|
+
tuesday: { start: string; end: string } | null;
|
|
46
|
+
wednesday: { start: string; end: string } | null;
|
|
47
|
+
thursday: { start: string; end: string } | null;
|
|
48
|
+
friday: { start: string; end: string } | null;
|
|
49
|
+
saturday: { start: string; end: string } | null;
|
|
50
|
+
sunday: { start: string; end: string } | null;
|
|
51
|
+
};
|
|
52
|
+
isActive: boolean;
|
|
53
|
+
createdAt: Timestamp;
|
|
54
|
+
updatedAt: Timestamp;
|
|
55
|
+
}
|
|
56
|
+
|
|
38
57
|
/**
|
|
39
58
|
* Interfejs za zdravstvenog radnika
|
|
40
59
|
*/
|
|
@@ -44,6 +63,7 @@ export interface Practitioner {
|
|
|
44
63
|
basicInfo: PractitionerBasicInfo;
|
|
45
64
|
certification: PractitionerCertification;
|
|
46
65
|
clinics: string[]; // Reference na klinike gde radi
|
|
66
|
+
clinicWorkingHours: PractitionerClinicWorkingHours[]; // Radno vreme za svaku kliniku
|
|
47
67
|
isActive: boolean;
|
|
48
68
|
isVerified: boolean;
|
|
49
69
|
createdAt: Timestamp;
|
|
@@ -58,6 +78,7 @@ export interface CreatePractitionerData {
|
|
|
58
78
|
basicInfo: PractitionerBasicInfo;
|
|
59
79
|
certification: PractitionerCertification;
|
|
60
80
|
clinics?: string[];
|
|
81
|
+
clinicWorkingHours?: PractitionerClinicWorkingHours[];
|
|
61
82
|
isActive: boolean;
|
|
62
83
|
isVerified: boolean;
|
|
63
84
|
}
|
|
@@ -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
|
+
});
|
|
@@ -60,6 +60,25 @@ export const practitionerWorkingHoursSchema = z.object({
|
|
|
60
60
|
updatedAt: z.instanceof(Timestamp),
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Šema za validaciju radnog vremena u klinici
|
|
65
|
+
*/
|
|
66
|
+
export const practitionerClinicWorkingHoursSchema = z.object({
|
|
67
|
+
clinicId: z.string().min(1),
|
|
68
|
+
workingHours: z.object({
|
|
69
|
+
monday: timeSlotSchema,
|
|
70
|
+
tuesday: timeSlotSchema,
|
|
71
|
+
wednesday: timeSlotSchema,
|
|
72
|
+
thursday: timeSlotSchema,
|
|
73
|
+
friday: timeSlotSchema,
|
|
74
|
+
saturday: timeSlotSchema,
|
|
75
|
+
sunday: timeSlotSchema,
|
|
76
|
+
}),
|
|
77
|
+
isActive: z.boolean(),
|
|
78
|
+
createdAt: z.instanceof(Timestamp),
|
|
79
|
+
updatedAt: z.instanceof(Timestamp),
|
|
80
|
+
});
|
|
81
|
+
|
|
63
82
|
/**
|
|
64
83
|
* Šema za validaciju recenzije zdravstvenog radnika
|
|
65
84
|
*/
|
|
@@ -96,6 +115,7 @@ export const practitionerSchema = z.object({
|
|
|
96
115
|
basicInfo: practitionerBasicInfoSchema,
|
|
97
116
|
certification: practitionerCertificationSchema,
|
|
98
117
|
clinics: z.array(z.string()),
|
|
118
|
+
clinicWorkingHours: z.array(practitionerClinicWorkingHoursSchema),
|
|
99
119
|
isActive: z.boolean(),
|
|
100
120
|
isVerified: z.boolean(),
|
|
101
121
|
createdAt: z.instanceof(Timestamp),
|
|
@@ -110,6 +130,7 @@ export const createPractitionerSchema = z.object({
|
|
|
110
130
|
basicInfo: practitionerBasicInfoSchema,
|
|
111
131
|
certification: practitionerCertificationSchema,
|
|
112
132
|
clinics: z.array(z.string()).optional(),
|
|
133
|
+
clinicWorkingHours: z.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
113
134
|
isActive: z.boolean(),
|
|
114
135
|
isVerified: z.boolean(),
|
|
115
136
|
});
|
|
@@ -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
|
+
});
|