@blackcode_sa/metaestetics-api 1.13.8 → 1.13.11
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 +127 -125
- package/dist/admin/index.d.ts +127 -125
- package/dist/backoffice/index.d.mts +23 -23
- package/dist/backoffice/index.d.ts +23 -23
- package/dist/index.d.mts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +64 -16
- package/dist/index.mjs +64 -16
- package/package.json +1 -1
- package/src/services/procedure/procedure.service.ts +81 -17
- package/src/types/clinic/index.ts +3 -0
package/dist/admin/index.d.mts
CHANGED
|
@@ -843,6 +843,131 @@ interface ProcedureSummaryInfo {
|
|
|
843
843
|
practitionerName: string;
|
|
844
844
|
}
|
|
845
845
|
|
|
846
|
+
/**
|
|
847
|
+
* Osnovne informacije o zdravstvenom radniku
|
|
848
|
+
*/
|
|
849
|
+
interface PractitionerBasicInfo {
|
|
850
|
+
firstName: string;
|
|
851
|
+
lastName: string;
|
|
852
|
+
title: string;
|
|
853
|
+
email: string;
|
|
854
|
+
phoneNumber: string | null;
|
|
855
|
+
dateOfBirth: Timestamp | Date | null;
|
|
856
|
+
gender: "male" | "female" | "other";
|
|
857
|
+
profileImageUrl?: MediaResource | null;
|
|
858
|
+
bio?: string;
|
|
859
|
+
languages: string[];
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Sertifikacija zdravstvenog radnika
|
|
863
|
+
*/
|
|
864
|
+
interface PractitionerCertification {
|
|
865
|
+
level: CertificationLevel;
|
|
866
|
+
specialties: CertificationSpecialty[];
|
|
867
|
+
licenseNumber: string;
|
|
868
|
+
issuingAuthority: string;
|
|
869
|
+
issueDate: Timestamp | Date;
|
|
870
|
+
expiryDate?: Timestamp | Date | null;
|
|
871
|
+
verificationStatus: "pending" | "verified" | "rejected";
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Interfejs za radno vreme zdravstvenog radnika u klinici
|
|
875
|
+
*/
|
|
876
|
+
interface PractitionerClinicWorkingHours {
|
|
877
|
+
clinicId: string;
|
|
878
|
+
workingHours: {
|
|
879
|
+
monday: {
|
|
880
|
+
start: string;
|
|
881
|
+
end: string;
|
|
882
|
+
} | null;
|
|
883
|
+
tuesday: {
|
|
884
|
+
start: string;
|
|
885
|
+
end: string;
|
|
886
|
+
} | null;
|
|
887
|
+
wednesday: {
|
|
888
|
+
start: string;
|
|
889
|
+
end: string;
|
|
890
|
+
} | null;
|
|
891
|
+
thursday: {
|
|
892
|
+
start: string;
|
|
893
|
+
end: string;
|
|
894
|
+
} | null;
|
|
895
|
+
friday: {
|
|
896
|
+
start: string;
|
|
897
|
+
end: string;
|
|
898
|
+
} | null;
|
|
899
|
+
saturday: {
|
|
900
|
+
start: string;
|
|
901
|
+
end: string;
|
|
902
|
+
} | null;
|
|
903
|
+
sunday: {
|
|
904
|
+
start: string;
|
|
905
|
+
end: string;
|
|
906
|
+
} | null;
|
|
907
|
+
};
|
|
908
|
+
isActive: boolean;
|
|
909
|
+
createdAt: Timestamp | Date;
|
|
910
|
+
updatedAt: Timestamp | Date;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Status of practitioner profile
|
|
914
|
+
*/
|
|
915
|
+
declare enum PractitionerStatus {
|
|
916
|
+
DRAFT = "draft",
|
|
917
|
+
ACTIVE = "active"
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Token status for practitioner invitations
|
|
921
|
+
*/
|
|
922
|
+
declare enum PractitionerTokenStatus {
|
|
923
|
+
ACTIVE = "active",
|
|
924
|
+
USED = "used",
|
|
925
|
+
EXPIRED = "expired",
|
|
926
|
+
REVOKED = "revoked"
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Interfejs za zdravstvenog radnika
|
|
930
|
+
*/
|
|
931
|
+
interface Practitioner {
|
|
932
|
+
id: string;
|
|
933
|
+
userRef: string;
|
|
934
|
+
basicInfo: PractitionerBasicInfo;
|
|
935
|
+
fullNameLower: string;
|
|
936
|
+
certification: PractitionerCertification;
|
|
937
|
+
clinics: string[];
|
|
938
|
+
clinicWorkingHours: PractitionerClinicWorkingHours[];
|
|
939
|
+
clinicsInfo: ClinicInfo[];
|
|
940
|
+
procedures: string[];
|
|
941
|
+
freeConsultations?: Record<string, string> | null;
|
|
942
|
+
proceduresInfo: ProcedureSummaryInfo[];
|
|
943
|
+
reviewInfo: PractitionerReviewInfo;
|
|
944
|
+
isActive: boolean;
|
|
945
|
+
isVerified: boolean;
|
|
946
|
+
status: PractitionerStatus;
|
|
947
|
+
createdAt: Timestamp;
|
|
948
|
+
updatedAt: Timestamp;
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Token za pozivanje zdravstvenog radnika
|
|
952
|
+
*/
|
|
953
|
+
interface PractitionerToken {
|
|
954
|
+
id: string;
|
|
955
|
+
token: string;
|
|
956
|
+
practitionerId: string;
|
|
957
|
+
email: string;
|
|
958
|
+
clinicId: string;
|
|
959
|
+
status: PractitionerTokenStatus;
|
|
960
|
+
createdBy: string;
|
|
961
|
+
createdAt: Timestamp;
|
|
962
|
+
expiresAt: Timestamp;
|
|
963
|
+
usedBy?: string;
|
|
964
|
+
usedAt?: Timestamp;
|
|
965
|
+
emailSent?: boolean;
|
|
966
|
+
emailSentAt?: Timestamp;
|
|
967
|
+
emailError?: string;
|
|
968
|
+
emailErrorAt?: Timestamp;
|
|
969
|
+
}
|
|
970
|
+
|
|
846
971
|
/**
|
|
847
972
|
* Enum for all possible clinic tags
|
|
848
973
|
*/
|
|
@@ -1141,6 +1266,8 @@ interface DoctorInfo {
|
|
|
1141
1266
|
photo: string | null;
|
|
1142
1267
|
rating: number;
|
|
1143
1268
|
services: string[];
|
|
1269
|
+
status?: PractitionerStatus;
|
|
1270
|
+
isActive?: boolean;
|
|
1144
1271
|
}
|
|
1145
1272
|
/**
|
|
1146
1273
|
* Interface for clinic
|
|
@@ -1174,131 +1301,6 @@ interface Clinic {
|
|
|
1174
1301
|
logo?: MediaResource | null;
|
|
1175
1302
|
}
|
|
1176
1303
|
|
|
1177
|
-
/**
|
|
1178
|
-
* Osnovne informacije o zdravstvenom radniku
|
|
1179
|
-
*/
|
|
1180
|
-
interface PractitionerBasicInfo {
|
|
1181
|
-
firstName: string;
|
|
1182
|
-
lastName: string;
|
|
1183
|
-
title: string;
|
|
1184
|
-
email: string;
|
|
1185
|
-
phoneNumber: string | null;
|
|
1186
|
-
dateOfBirth: Timestamp | Date | null;
|
|
1187
|
-
gender: "male" | "female" | "other";
|
|
1188
|
-
profileImageUrl?: MediaResource | null;
|
|
1189
|
-
bio?: string;
|
|
1190
|
-
languages: string[];
|
|
1191
|
-
}
|
|
1192
|
-
/**
|
|
1193
|
-
* Sertifikacija zdravstvenog radnika
|
|
1194
|
-
*/
|
|
1195
|
-
interface PractitionerCertification {
|
|
1196
|
-
level: CertificationLevel;
|
|
1197
|
-
specialties: CertificationSpecialty[];
|
|
1198
|
-
licenseNumber: string;
|
|
1199
|
-
issuingAuthority: string;
|
|
1200
|
-
issueDate: Timestamp | Date;
|
|
1201
|
-
expiryDate?: Timestamp | Date | null;
|
|
1202
|
-
verificationStatus: "pending" | "verified" | "rejected";
|
|
1203
|
-
}
|
|
1204
|
-
/**
|
|
1205
|
-
* Interfejs za radno vreme zdravstvenog radnika u klinici
|
|
1206
|
-
*/
|
|
1207
|
-
interface PractitionerClinicWorkingHours {
|
|
1208
|
-
clinicId: string;
|
|
1209
|
-
workingHours: {
|
|
1210
|
-
monday: {
|
|
1211
|
-
start: string;
|
|
1212
|
-
end: string;
|
|
1213
|
-
} | null;
|
|
1214
|
-
tuesday: {
|
|
1215
|
-
start: string;
|
|
1216
|
-
end: string;
|
|
1217
|
-
} | null;
|
|
1218
|
-
wednesday: {
|
|
1219
|
-
start: string;
|
|
1220
|
-
end: string;
|
|
1221
|
-
} | null;
|
|
1222
|
-
thursday: {
|
|
1223
|
-
start: string;
|
|
1224
|
-
end: string;
|
|
1225
|
-
} | null;
|
|
1226
|
-
friday: {
|
|
1227
|
-
start: string;
|
|
1228
|
-
end: string;
|
|
1229
|
-
} | null;
|
|
1230
|
-
saturday: {
|
|
1231
|
-
start: string;
|
|
1232
|
-
end: string;
|
|
1233
|
-
} | null;
|
|
1234
|
-
sunday: {
|
|
1235
|
-
start: string;
|
|
1236
|
-
end: string;
|
|
1237
|
-
} | null;
|
|
1238
|
-
};
|
|
1239
|
-
isActive: boolean;
|
|
1240
|
-
createdAt: Timestamp | Date;
|
|
1241
|
-
updatedAt: Timestamp | Date;
|
|
1242
|
-
}
|
|
1243
|
-
/**
|
|
1244
|
-
* Status of practitioner profile
|
|
1245
|
-
*/
|
|
1246
|
-
declare enum PractitionerStatus {
|
|
1247
|
-
DRAFT = "draft",
|
|
1248
|
-
ACTIVE = "active"
|
|
1249
|
-
}
|
|
1250
|
-
/**
|
|
1251
|
-
* Token status for practitioner invitations
|
|
1252
|
-
*/
|
|
1253
|
-
declare enum PractitionerTokenStatus {
|
|
1254
|
-
ACTIVE = "active",
|
|
1255
|
-
USED = "used",
|
|
1256
|
-
EXPIRED = "expired",
|
|
1257
|
-
REVOKED = "revoked"
|
|
1258
|
-
}
|
|
1259
|
-
/**
|
|
1260
|
-
* Interfejs za zdravstvenog radnika
|
|
1261
|
-
*/
|
|
1262
|
-
interface Practitioner {
|
|
1263
|
-
id: string;
|
|
1264
|
-
userRef: string;
|
|
1265
|
-
basicInfo: PractitionerBasicInfo;
|
|
1266
|
-
fullNameLower: string;
|
|
1267
|
-
certification: PractitionerCertification;
|
|
1268
|
-
clinics: string[];
|
|
1269
|
-
clinicWorkingHours: PractitionerClinicWorkingHours[];
|
|
1270
|
-
clinicsInfo: ClinicInfo[];
|
|
1271
|
-
procedures: string[];
|
|
1272
|
-
freeConsultations?: Record<string, string> | null;
|
|
1273
|
-
proceduresInfo: ProcedureSummaryInfo[];
|
|
1274
|
-
reviewInfo: PractitionerReviewInfo;
|
|
1275
|
-
isActive: boolean;
|
|
1276
|
-
isVerified: boolean;
|
|
1277
|
-
status: PractitionerStatus;
|
|
1278
|
-
createdAt: Timestamp;
|
|
1279
|
-
updatedAt: Timestamp;
|
|
1280
|
-
}
|
|
1281
|
-
/**
|
|
1282
|
-
* Token za pozivanje zdravstvenog radnika
|
|
1283
|
-
*/
|
|
1284
|
-
interface PractitionerToken {
|
|
1285
|
-
id: string;
|
|
1286
|
-
token: string;
|
|
1287
|
-
practitionerId: string;
|
|
1288
|
-
email: string;
|
|
1289
|
-
clinicId: string;
|
|
1290
|
-
status: PractitionerTokenStatus;
|
|
1291
|
-
createdBy: string;
|
|
1292
|
-
createdAt: Timestamp;
|
|
1293
|
-
expiresAt: Timestamp;
|
|
1294
|
-
usedBy?: string;
|
|
1295
|
-
usedAt?: Timestamp;
|
|
1296
|
-
emailSent?: boolean;
|
|
1297
|
-
emailSentAt?: Timestamp;
|
|
1298
|
-
emailError?: string;
|
|
1299
|
-
emailErrorAt?: Timestamp;
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
1304
|
declare enum AllergyType {
|
|
1303
1305
|
MEDICATION = "medication",
|
|
1304
1306
|
FOOD = "food",
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -843,6 +843,131 @@ interface ProcedureSummaryInfo {
|
|
|
843
843
|
practitionerName: string;
|
|
844
844
|
}
|
|
845
845
|
|
|
846
|
+
/**
|
|
847
|
+
* Osnovne informacije o zdravstvenom radniku
|
|
848
|
+
*/
|
|
849
|
+
interface PractitionerBasicInfo {
|
|
850
|
+
firstName: string;
|
|
851
|
+
lastName: string;
|
|
852
|
+
title: string;
|
|
853
|
+
email: string;
|
|
854
|
+
phoneNumber: string | null;
|
|
855
|
+
dateOfBirth: Timestamp | Date | null;
|
|
856
|
+
gender: "male" | "female" | "other";
|
|
857
|
+
profileImageUrl?: MediaResource | null;
|
|
858
|
+
bio?: string;
|
|
859
|
+
languages: string[];
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Sertifikacija zdravstvenog radnika
|
|
863
|
+
*/
|
|
864
|
+
interface PractitionerCertification {
|
|
865
|
+
level: CertificationLevel;
|
|
866
|
+
specialties: CertificationSpecialty[];
|
|
867
|
+
licenseNumber: string;
|
|
868
|
+
issuingAuthority: string;
|
|
869
|
+
issueDate: Timestamp | Date;
|
|
870
|
+
expiryDate?: Timestamp | Date | null;
|
|
871
|
+
verificationStatus: "pending" | "verified" | "rejected";
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Interfejs za radno vreme zdravstvenog radnika u klinici
|
|
875
|
+
*/
|
|
876
|
+
interface PractitionerClinicWorkingHours {
|
|
877
|
+
clinicId: string;
|
|
878
|
+
workingHours: {
|
|
879
|
+
monday: {
|
|
880
|
+
start: string;
|
|
881
|
+
end: string;
|
|
882
|
+
} | null;
|
|
883
|
+
tuesday: {
|
|
884
|
+
start: string;
|
|
885
|
+
end: string;
|
|
886
|
+
} | null;
|
|
887
|
+
wednesday: {
|
|
888
|
+
start: string;
|
|
889
|
+
end: string;
|
|
890
|
+
} | null;
|
|
891
|
+
thursday: {
|
|
892
|
+
start: string;
|
|
893
|
+
end: string;
|
|
894
|
+
} | null;
|
|
895
|
+
friday: {
|
|
896
|
+
start: string;
|
|
897
|
+
end: string;
|
|
898
|
+
} | null;
|
|
899
|
+
saturday: {
|
|
900
|
+
start: string;
|
|
901
|
+
end: string;
|
|
902
|
+
} | null;
|
|
903
|
+
sunday: {
|
|
904
|
+
start: string;
|
|
905
|
+
end: string;
|
|
906
|
+
} | null;
|
|
907
|
+
};
|
|
908
|
+
isActive: boolean;
|
|
909
|
+
createdAt: Timestamp | Date;
|
|
910
|
+
updatedAt: Timestamp | Date;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Status of practitioner profile
|
|
914
|
+
*/
|
|
915
|
+
declare enum PractitionerStatus {
|
|
916
|
+
DRAFT = "draft",
|
|
917
|
+
ACTIVE = "active"
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Token status for practitioner invitations
|
|
921
|
+
*/
|
|
922
|
+
declare enum PractitionerTokenStatus {
|
|
923
|
+
ACTIVE = "active",
|
|
924
|
+
USED = "used",
|
|
925
|
+
EXPIRED = "expired",
|
|
926
|
+
REVOKED = "revoked"
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Interfejs za zdravstvenog radnika
|
|
930
|
+
*/
|
|
931
|
+
interface Practitioner {
|
|
932
|
+
id: string;
|
|
933
|
+
userRef: string;
|
|
934
|
+
basicInfo: PractitionerBasicInfo;
|
|
935
|
+
fullNameLower: string;
|
|
936
|
+
certification: PractitionerCertification;
|
|
937
|
+
clinics: string[];
|
|
938
|
+
clinicWorkingHours: PractitionerClinicWorkingHours[];
|
|
939
|
+
clinicsInfo: ClinicInfo[];
|
|
940
|
+
procedures: string[];
|
|
941
|
+
freeConsultations?: Record<string, string> | null;
|
|
942
|
+
proceduresInfo: ProcedureSummaryInfo[];
|
|
943
|
+
reviewInfo: PractitionerReviewInfo;
|
|
944
|
+
isActive: boolean;
|
|
945
|
+
isVerified: boolean;
|
|
946
|
+
status: PractitionerStatus;
|
|
947
|
+
createdAt: Timestamp;
|
|
948
|
+
updatedAt: Timestamp;
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Token za pozivanje zdravstvenog radnika
|
|
952
|
+
*/
|
|
953
|
+
interface PractitionerToken {
|
|
954
|
+
id: string;
|
|
955
|
+
token: string;
|
|
956
|
+
practitionerId: string;
|
|
957
|
+
email: string;
|
|
958
|
+
clinicId: string;
|
|
959
|
+
status: PractitionerTokenStatus;
|
|
960
|
+
createdBy: string;
|
|
961
|
+
createdAt: Timestamp;
|
|
962
|
+
expiresAt: Timestamp;
|
|
963
|
+
usedBy?: string;
|
|
964
|
+
usedAt?: Timestamp;
|
|
965
|
+
emailSent?: boolean;
|
|
966
|
+
emailSentAt?: Timestamp;
|
|
967
|
+
emailError?: string;
|
|
968
|
+
emailErrorAt?: Timestamp;
|
|
969
|
+
}
|
|
970
|
+
|
|
846
971
|
/**
|
|
847
972
|
* Enum for all possible clinic tags
|
|
848
973
|
*/
|
|
@@ -1141,6 +1266,8 @@ interface DoctorInfo {
|
|
|
1141
1266
|
photo: string | null;
|
|
1142
1267
|
rating: number;
|
|
1143
1268
|
services: string[];
|
|
1269
|
+
status?: PractitionerStatus;
|
|
1270
|
+
isActive?: boolean;
|
|
1144
1271
|
}
|
|
1145
1272
|
/**
|
|
1146
1273
|
* Interface for clinic
|
|
@@ -1174,131 +1301,6 @@ interface Clinic {
|
|
|
1174
1301
|
logo?: MediaResource | null;
|
|
1175
1302
|
}
|
|
1176
1303
|
|
|
1177
|
-
/**
|
|
1178
|
-
* Osnovne informacije o zdravstvenom radniku
|
|
1179
|
-
*/
|
|
1180
|
-
interface PractitionerBasicInfo {
|
|
1181
|
-
firstName: string;
|
|
1182
|
-
lastName: string;
|
|
1183
|
-
title: string;
|
|
1184
|
-
email: string;
|
|
1185
|
-
phoneNumber: string | null;
|
|
1186
|
-
dateOfBirth: Timestamp | Date | null;
|
|
1187
|
-
gender: "male" | "female" | "other";
|
|
1188
|
-
profileImageUrl?: MediaResource | null;
|
|
1189
|
-
bio?: string;
|
|
1190
|
-
languages: string[];
|
|
1191
|
-
}
|
|
1192
|
-
/**
|
|
1193
|
-
* Sertifikacija zdravstvenog radnika
|
|
1194
|
-
*/
|
|
1195
|
-
interface PractitionerCertification {
|
|
1196
|
-
level: CertificationLevel;
|
|
1197
|
-
specialties: CertificationSpecialty[];
|
|
1198
|
-
licenseNumber: string;
|
|
1199
|
-
issuingAuthority: string;
|
|
1200
|
-
issueDate: Timestamp | Date;
|
|
1201
|
-
expiryDate?: Timestamp | Date | null;
|
|
1202
|
-
verificationStatus: "pending" | "verified" | "rejected";
|
|
1203
|
-
}
|
|
1204
|
-
/**
|
|
1205
|
-
* Interfejs za radno vreme zdravstvenog radnika u klinici
|
|
1206
|
-
*/
|
|
1207
|
-
interface PractitionerClinicWorkingHours {
|
|
1208
|
-
clinicId: string;
|
|
1209
|
-
workingHours: {
|
|
1210
|
-
monday: {
|
|
1211
|
-
start: string;
|
|
1212
|
-
end: string;
|
|
1213
|
-
} | null;
|
|
1214
|
-
tuesday: {
|
|
1215
|
-
start: string;
|
|
1216
|
-
end: string;
|
|
1217
|
-
} | null;
|
|
1218
|
-
wednesday: {
|
|
1219
|
-
start: string;
|
|
1220
|
-
end: string;
|
|
1221
|
-
} | null;
|
|
1222
|
-
thursday: {
|
|
1223
|
-
start: string;
|
|
1224
|
-
end: string;
|
|
1225
|
-
} | null;
|
|
1226
|
-
friday: {
|
|
1227
|
-
start: string;
|
|
1228
|
-
end: string;
|
|
1229
|
-
} | null;
|
|
1230
|
-
saturday: {
|
|
1231
|
-
start: string;
|
|
1232
|
-
end: string;
|
|
1233
|
-
} | null;
|
|
1234
|
-
sunday: {
|
|
1235
|
-
start: string;
|
|
1236
|
-
end: string;
|
|
1237
|
-
} | null;
|
|
1238
|
-
};
|
|
1239
|
-
isActive: boolean;
|
|
1240
|
-
createdAt: Timestamp | Date;
|
|
1241
|
-
updatedAt: Timestamp | Date;
|
|
1242
|
-
}
|
|
1243
|
-
/**
|
|
1244
|
-
* Status of practitioner profile
|
|
1245
|
-
*/
|
|
1246
|
-
declare enum PractitionerStatus {
|
|
1247
|
-
DRAFT = "draft",
|
|
1248
|
-
ACTIVE = "active"
|
|
1249
|
-
}
|
|
1250
|
-
/**
|
|
1251
|
-
* Token status for practitioner invitations
|
|
1252
|
-
*/
|
|
1253
|
-
declare enum PractitionerTokenStatus {
|
|
1254
|
-
ACTIVE = "active",
|
|
1255
|
-
USED = "used",
|
|
1256
|
-
EXPIRED = "expired",
|
|
1257
|
-
REVOKED = "revoked"
|
|
1258
|
-
}
|
|
1259
|
-
/**
|
|
1260
|
-
* Interfejs za zdravstvenog radnika
|
|
1261
|
-
*/
|
|
1262
|
-
interface Practitioner {
|
|
1263
|
-
id: string;
|
|
1264
|
-
userRef: string;
|
|
1265
|
-
basicInfo: PractitionerBasicInfo;
|
|
1266
|
-
fullNameLower: string;
|
|
1267
|
-
certification: PractitionerCertification;
|
|
1268
|
-
clinics: string[];
|
|
1269
|
-
clinicWorkingHours: PractitionerClinicWorkingHours[];
|
|
1270
|
-
clinicsInfo: ClinicInfo[];
|
|
1271
|
-
procedures: string[];
|
|
1272
|
-
freeConsultations?: Record<string, string> | null;
|
|
1273
|
-
proceduresInfo: ProcedureSummaryInfo[];
|
|
1274
|
-
reviewInfo: PractitionerReviewInfo;
|
|
1275
|
-
isActive: boolean;
|
|
1276
|
-
isVerified: boolean;
|
|
1277
|
-
status: PractitionerStatus;
|
|
1278
|
-
createdAt: Timestamp;
|
|
1279
|
-
updatedAt: Timestamp;
|
|
1280
|
-
}
|
|
1281
|
-
/**
|
|
1282
|
-
* Token za pozivanje zdravstvenog radnika
|
|
1283
|
-
*/
|
|
1284
|
-
interface PractitionerToken {
|
|
1285
|
-
id: string;
|
|
1286
|
-
token: string;
|
|
1287
|
-
practitionerId: string;
|
|
1288
|
-
email: string;
|
|
1289
|
-
clinicId: string;
|
|
1290
|
-
status: PractitionerTokenStatus;
|
|
1291
|
-
createdBy: string;
|
|
1292
|
-
createdAt: Timestamp;
|
|
1293
|
-
expiresAt: Timestamp;
|
|
1294
|
-
usedBy?: string;
|
|
1295
|
-
usedAt?: Timestamp;
|
|
1296
|
-
emailSent?: boolean;
|
|
1297
|
-
emailSentAt?: Timestamp;
|
|
1298
|
-
emailError?: string;
|
|
1299
|
-
emailErrorAt?: Timestamp;
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
1304
|
declare enum AllergyType {
|
|
1303
1305
|
MEDICATION = "medication",
|
|
1304
1306
|
FOOD = "food",
|
|
@@ -1307,29 +1307,6 @@ interface ProcedureSummaryInfo {
|
|
|
1307
1307
|
practitionerName: string;
|
|
1308
1308
|
}
|
|
1309
1309
|
|
|
1310
|
-
/**
|
|
1311
|
-
* Interface for clinic contact information
|
|
1312
|
-
*/
|
|
1313
|
-
interface ClinicContactInfo {
|
|
1314
|
-
email: string;
|
|
1315
|
-
phoneNumber: string;
|
|
1316
|
-
alternativePhoneNumber?: string | null;
|
|
1317
|
-
website?: string | null;
|
|
1318
|
-
}
|
|
1319
|
-
/**
|
|
1320
|
-
* Interface for clinic location
|
|
1321
|
-
*/
|
|
1322
|
-
interface ClinicLocation {
|
|
1323
|
-
address: string;
|
|
1324
|
-
city: string;
|
|
1325
|
-
country: string;
|
|
1326
|
-
postalCode: string;
|
|
1327
|
-
latitude: number;
|
|
1328
|
-
longitude: number;
|
|
1329
|
-
geohash?: string | null;
|
|
1330
|
-
tz?: string | null;
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
1310
|
/**
|
|
1334
1311
|
* Osnovne informacije o zdravstvenom radniku
|
|
1335
1312
|
*/
|
|
@@ -1426,6 +1403,29 @@ interface Practitioner {
|
|
|
1426
1403
|
updatedAt: Timestamp;
|
|
1427
1404
|
}
|
|
1428
1405
|
|
|
1406
|
+
/**
|
|
1407
|
+
* Interface for clinic contact information
|
|
1408
|
+
*/
|
|
1409
|
+
interface ClinicContactInfo {
|
|
1410
|
+
email: string;
|
|
1411
|
+
phoneNumber: string;
|
|
1412
|
+
alternativePhoneNumber?: string | null;
|
|
1413
|
+
website?: string | null;
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Interface for clinic location
|
|
1417
|
+
*/
|
|
1418
|
+
interface ClinicLocation {
|
|
1419
|
+
address: string;
|
|
1420
|
+
city: string;
|
|
1421
|
+
country: string;
|
|
1422
|
+
postalCode: string;
|
|
1423
|
+
latitude: number;
|
|
1424
|
+
longitude: number;
|
|
1425
|
+
geohash?: string | null;
|
|
1426
|
+
tz?: string | null;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
1429
|
/**
|
|
1430
1430
|
* Interface for clinic profile information
|
|
1431
1431
|
*/
|
|
@@ -1307,29 +1307,6 @@ interface ProcedureSummaryInfo {
|
|
|
1307
1307
|
practitionerName: string;
|
|
1308
1308
|
}
|
|
1309
1309
|
|
|
1310
|
-
/**
|
|
1311
|
-
* Interface for clinic contact information
|
|
1312
|
-
*/
|
|
1313
|
-
interface ClinicContactInfo {
|
|
1314
|
-
email: string;
|
|
1315
|
-
phoneNumber: string;
|
|
1316
|
-
alternativePhoneNumber?: string | null;
|
|
1317
|
-
website?: string | null;
|
|
1318
|
-
}
|
|
1319
|
-
/**
|
|
1320
|
-
* Interface for clinic location
|
|
1321
|
-
*/
|
|
1322
|
-
interface ClinicLocation {
|
|
1323
|
-
address: string;
|
|
1324
|
-
city: string;
|
|
1325
|
-
country: string;
|
|
1326
|
-
postalCode: string;
|
|
1327
|
-
latitude: number;
|
|
1328
|
-
longitude: number;
|
|
1329
|
-
geohash?: string | null;
|
|
1330
|
-
tz?: string | null;
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
1310
|
/**
|
|
1334
1311
|
* Osnovne informacije o zdravstvenom radniku
|
|
1335
1312
|
*/
|
|
@@ -1426,6 +1403,29 @@ interface Practitioner {
|
|
|
1426
1403
|
updatedAt: Timestamp;
|
|
1427
1404
|
}
|
|
1428
1405
|
|
|
1406
|
+
/**
|
|
1407
|
+
* Interface for clinic contact information
|
|
1408
|
+
*/
|
|
1409
|
+
interface ClinicContactInfo {
|
|
1410
|
+
email: string;
|
|
1411
|
+
phoneNumber: string;
|
|
1412
|
+
alternativePhoneNumber?: string | null;
|
|
1413
|
+
website?: string | null;
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Interface for clinic location
|
|
1417
|
+
*/
|
|
1418
|
+
interface ClinicLocation {
|
|
1419
|
+
address: string;
|
|
1420
|
+
city: string;
|
|
1421
|
+
country: string;
|
|
1422
|
+
postalCode: string;
|
|
1423
|
+
latitude: number;
|
|
1424
|
+
longitude: number;
|
|
1425
|
+
geohash?: string | null;
|
|
1426
|
+
tz?: string | null;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
1429
|
/**
|
|
1430
1430
|
* Interface for clinic profile information
|
|
1431
1431
|
*/
|
package/dist/index.d.mts
CHANGED
|
@@ -5300,6 +5300,8 @@ interface DoctorInfo {
|
|
|
5300
5300
|
photo: string | null;
|
|
5301
5301
|
rating: number;
|
|
5302
5302
|
services: string[];
|
|
5303
|
+
status?: PractitionerStatus;
|
|
5304
|
+
isActive?: boolean;
|
|
5303
5305
|
}
|
|
5304
5306
|
/**
|
|
5305
5307
|
* Interface for clinic
|
|
@@ -6697,9 +6699,17 @@ declare class ProcedureService extends BaseService {
|
|
|
6697
6699
|
constructor(db: Firestore, auth: Auth, app: FirebaseApp, categoryService: CategoryService, subcategoryService: SubcategoryService, technologyService: TechnologyService, productService: ProductService, mediaService: MediaService);
|
|
6698
6700
|
setPractitionerService(practitionerService: PractitionerService): void;
|
|
6699
6701
|
/**
|
|
6700
|
-
* Filters out procedures
|
|
6702
|
+
* Filters out procedures that should not be visible to patients:
|
|
6703
|
+
* 1. Procedures with no practitioner (missing practitionerId)
|
|
6704
|
+
* 2. Procedures where practitioner doesn't exist
|
|
6705
|
+
* 3. Procedures from draft practitioners
|
|
6706
|
+
* 4. Procedures from inactive practitioners (isActive === false)
|
|
6707
|
+
*
|
|
6708
|
+
* Note: Each procedure has ONE practitionerId. If that practitioner is inactive/draft/missing,
|
|
6709
|
+
* the procedure is filtered out.
|
|
6710
|
+
*
|
|
6701
6711
|
* @param procedures - Array of procedures to filter
|
|
6702
|
-
* @returns Filtered array of procedures (excluding
|
|
6712
|
+
* @returns Filtered array of procedures (excluding invalid/inactive/draft practitioners)
|
|
6703
6713
|
*/
|
|
6704
6714
|
private filterDraftPractitionerProcedures;
|
|
6705
6715
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -5300,6 +5300,8 @@ interface DoctorInfo {
|
|
|
5300
5300
|
photo: string | null;
|
|
5301
5301
|
rating: number;
|
|
5302
5302
|
services: string[];
|
|
5303
|
+
status?: PractitionerStatus;
|
|
5304
|
+
isActive?: boolean;
|
|
5303
5305
|
}
|
|
5304
5306
|
/**
|
|
5305
5307
|
* Interface for clinic
|
|
@@ -6697,9 +6699,17 @@ declare class ProcedureService extends BaseService {
|
|
|
6697
6699
|
constructor(db: Firestore, auth: Auth, app: FirebaseApp, categoryService: CategoryService, subcategoryService: SubcategoryService, technologyService: TechnologyService, productService: ProductService, mediaService: MediaService);
|
|
6698
6700
|
setPractitionerService(practitionerService: PractitionerService): void;
|
|
6699
6701
|
/**
|
|
6700
|
-
* Filters out procedures
|
|
6702
|
+
* Filters out procedures that should not be visible to patients:
|
|
6703
|
+
* 1. Procedures with no practitioner (missing practitionerId)
|
|
6704
|
+
* 2. Procedures where practitioner doesn't exist
|
|
6705
|
+
* 3. Procedures from draft practitioners
|
|
6706
|
+
* 4. Procedures from inactive practitioners (isActive === false)
|
|
6707
|
+
*
|
|
6708
|
+
* Note: Each procedure has ONE practitionerId. If that practitioner is inactive/draft/missing,
|
|
6709
|
+
* the procedure is filtered out.
|
|
6710
|
+
*
|
|
6701
6711
|
* @param procedures - Array of procedures to filter
|
|
6702
|
-
* @returns Filtered array of procedures (excluding
|
|
6712
|
+
* @returns Filtered array of procedures (excluding invalid/inactive/draft practitioners)
|
|
6703
6713
|
*/
|
|
6704
6714
|
private filterDraftPractitionerProcedures;
|
|
6705
6715
|
/**
|
package/dist/index.js
CHANGED
|
@@ -20022,44 +20022,82 @@ var ProcedureService = class extends BaseService {
|
|
|
20022
20022
|
this.practitionerService = practitionerService;
|
|
20023
20023
|
}
|
|
20024
20024
|
/**
|
|
20025
|
-
* Filters out procedures
|
|
20025
|
+
* Filters out procedures that should not be visible to patients:
|
|
20026
|
+
* 1. Procedures with no practitioner (missing practitionerId)
|
|
20027
|
+
* 2. Procedures where practitioner doesn't exist
|
|
20028
|
+
* 3. Procedures from draft practitioners
|
|
20029
|
+
* 4. Procedures from inactive practitioners (isActive === false)
|
|
20030
|
+
*
|
|
20031
|
+
* Note: Each procedure has ONE practitionerId. If that practitioner is inactive/draft/missing,
|
|
20032
|
+
* the procedure is filtered out.
|
|
20033
|
+
*
|
|
20026
20034
|
* @param procedures - Array of procedures to filter
|
|
20027
|
-
* @returns Filtered array of procedures (excluding
|
|
20035
|
+
* @returns Filtered array of procedures (excluding invalid/inactive/draft practitioners)
|
|
20028
20036
|
*/
|
|
20029
20037
|
async filterDraftPractitionerProcedures(procedures) {
|
|
20030
20038
|
if (!this.practitionerService || procedures.length === 0) {
|
|
20031
20039
|
return procedures;
|
|
20032
20040
|
}
|
|
20033
20041
|
try {
|
|
20042
|
+
const proceduresWithPractitioner = procedures.filter(
|
|
20043
|
+
(p) => p.practitionerId && p.practitionerId.trim() !== ""
|
|
20044
|
+
);
|
|
20045
|
+
if (proceduresWithPractitioner.length === 0) {
|
|
20046
|
+
console.log(
|
|
20047
|
+
`[ProcedureService] All ${procedures.length} procedures have no practitionerId - filtering out`
|
|
20048
|
+
);
|
|
20049
|
+
return [];
|
|
20050
|
+
}
|
|
20034
20051
|
const practitionerIds = Array.from(
|
|
20035
|
-
new Set(
|
|
20052
|
+
new Set(proceduresWithPractitioner.map((p) => p.practitionerId).filter(Boolean))
|
|
20036
20053
|
);
|
|
20037
20054
|
if (practitionerIds.length === 0) {
|
|
20038
|
-
return
|
|
20055
|
+
return [];
|
|
20039
20056
|
}
|
|
20040
20057
|
const practitionerPromises = practitionerIds.map(
|
|
20041
20058
|
(id) => this.practitionerService.getPractitioner(id).catch(() => null)
|
|
20042
20059
|
);
|
|
20043
20060
|
const practitioners = await Promise.all(practitionerPromises);
|
|
20044
|
-
const
|
|
20061
|
+
const practitionerMap = /* @__PURE__ */ new Map();
|
|
20045
20062
|
practitioners.forEach((practitioner, index) => {
|
|
20046
20063
|
if (practitioner) {
|
|
20047
|
-
|
|
20064
|
+
practitionerMap.set(practitionerIds[index], practitioner);
|
|
20048
20065
|
}
|
|
20049
20066
|
});
|
|
20050
|
-
const filteredProcedures =
|
|
20051
|
-
const
|
|
20052
|
-
|
|
20067
|
+
const filteredProcedures = proceduresWithPractitioner.filter((procedure) => {
|
|
20068
|
+
const practitioner = practitionerMap.get(procedure.practitionerId);
|
|
20069
|
+
if (!practitioner) {
|
|
20070
|
+
console.log(
|
|
20071
|
+
`[ProcedureService] Filtering out procedure ${procedure.id} - practitioner ${procedure.practitionerId} not found`
|
|
20072
|
+
);
|
|
20073
|
+
return false;
|
|
20074
|
+
}
|
|
20075
|
+
if (practitioner.status === "draft" /* DRAFT */) {
|
|
20076
|
+
console.log(
|
|
20077
|
+
`[ProcedureService] Filtering out procedure ${procedure.id} - practitioner ${procedure.practitionerId} is DRAFT`
|
|
20078
|
+
);
|
|
20079
|
+
return false;
|
|
20080
|
+
}
|
|
20081
|
+
if (!practitioner.isActive) {
|
|
20082
|
+
console.log(
|
|
20083
|
+
`[ProcedureService] Filtering out procedure ${procedure.id} - practitioner ${procedure.practitionerId} is not active`
|
|
20084
|
+
);
|
|
20085
|
+
return false;
|
|
20086
|
+
}
|
|
20087
|
+
return true;
|
|
20053
20088
|
});
|
|
20054
|
-
|
|
20089
|
+
const filteredCount = procedures.length - filteredProcedures.length;
|
|
20090
|
+
if (filteredCount > 0) {
|
|
20091
|
+
const noPractitionerCount = procedures.length - proceduresWithPractitioner.length;
|
|
20092
|
+
const invalidPractitionerCount = proceduresWithPractitioner.length - filteredProcedures.length;
|
|
20055
20093
|
console.log(
|
|
20056
|
-
`[ProcedureService] Filtered out ${procedures
|
|
20094
|
+
`[ProcedureService] Filtered out ${filteredCount} procedures: ${noPractitionerCount} with no practitionerId, ${invalidPractitionerCount} with missing/draft/inactive practitioners`
|
|
20057
20095
|
);
|
|
20058
20096
|
}
|
|
20059
20097
|
return filteredProcedures;
|
|
20060
20098
|
} catch (error) {
|
|
20061
20099
|
console.error(
|
|
20062
|
-
"[ProcedureService] Error filtering
|
|
20100
|
+
"[ProcedureService] Error filtering practitioner procedures:",
|
|
20063
20101
|
error
|
|
20064
20102
|
);
|
|
20065
20103
|
return procedures;
|
|
@@ -20233,7 +20271,11 @@ var ProcedureService = class extends BaseService {
|
|
|
20233
20271
|
photo: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : "",
|
|
20234
20272
|
// Default to empty string if not a processed URL
|
|
20235
20273
|
rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
|
|
20236
|
-
services: practitioner.procedures || []
|
|
20274
|
+
services: practitioner.procedures || [],
|
|
20275
|
+
status: practitioner.status,
|
|
20276
|
+
// Include practitioner status for client-side filtering
|
|
20277
|
+
isActive: practitioner.isActive
|
|
20278
|
+
// Include isActive flag for client-side filtering
|
|
20237
20279
|
};
|
|
20238
20280
|
const { productsMetadata: _, productId: __, photos: ___, ...validatedDataWithoutProductsMetadata } = validatedData;
|
|
20239
20281
|
const newProcedure = {
|
|
@@ -20392,7 +20434,9 @@ var ProcedureService = class extends BaseService {
|
|
|
20392
20434
|
description: practitioner.basicInfo.bio || "",
|
|
20393
20435
|
photo: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : "",
|
|
20394
20436
|
rating: ((_c = practitioner.reviewInfo) == null ? void 0 : _c.averageRating) || 0,
|
|
20395
|
-
services: practitioner.procedures || []
|
|
20437
|
+
services: practitioner.procedures || [],
|
|
20438
|
+
status: practitioner.status,
|
|
20439
|
+
isActive: practitioner.isActive
|
|
20396
20440
|
};
|
|
20397
20441
|
const newProcedure = {
|
|
20398
20442
|
...sourceProcedure,
|
|
@@ -20769,7 +20813,8 @@ var ProcedureService = class extends BaseService {
|
|
|
20769
20813
|
(0, import_firestore58.where)("isActive", "==", true)
|
|
20770
20814
|
);
|
|
20771
20815
|
const snapshot = await (0, import_firestore58.getDocs)(q);
|
|
20772
|
-
|
|
20816
|
+
const procedures = snapshot.docs.map((doc47) => doc47.data());
|
|
20817
|
+
return await this.filterDraftPractitionerProcedures(procedures);
|
|
20773
20818
|
}
|
|
20774
20819
|
/**
|
|
20775
20820
|
* Gets all procedures for a practitioner
|
|
@@ -20888,7 +20933,9 @@ var ProcedureService = class extends BaseService {
|
|
|
20888
20933
|
photo: typeof newPractitioner.basicInfo.profileImageUrl === "string" ? newPractitioner.basicInfo.profileImageUrl : "",
|
|
20889
20934
|
// Default to empty string if not a processed URL
|
|
20890
20935
|
rating: ((_b = newPractitioner.reviewInfo) == null ? void 0 : _b.averageRating) || 0,
|
|
20891
|
-
services: newPractitioner.procedures || []
|
|
20936
|
+
services: newPractitioner.procedures || [],
|
|
20937
|
+
status: newPractitioner.status,
|
|
20938
|
+
isActive: newPractitioner.isActive
|
|
20892
20939
|
};
|
|
20893
20940
|
}
|
|
20894
20941
|
if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
|
|
@@ -21172,6 +21219,7 @@ var ProcedureService = class extends BaseService {
|
|
|
21172
21219
|
if (hasNestedFilters) {
|
|
21173
21220
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
21174
21221
|
}
|
|
21222
|
+
procedures = await this.filterDraftPractitionerProcedures(procedures);
|
|
21175
21223
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
21176
21224
|
console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
|
|
21177
21225
|
if (procedures.length < (filters.pagination || 10)) {
|
package/dist/index.mjs
CHANGED
|
@@ -20258,44 +20258,82 @@ var ProcedureService = class extends BaseService {
|
|
|
20258
20258
|
this.practitionerService = practitionerService;
|
|
20259
20259
|
}
|
|
20260
20260
|
/**
|
|
20261
|
-
* Filters out procedures
|
|
20261
|
+
* Filters out procedures that should not be visible to patients:
|
|
20262
|
+
* 1. Procedures with no practitioner (missing practitionerId)
|
|
20263
|
+
* 2. Procedures where practitioner doesn't exist
|
|
20264
|
+
* 3. Procedures from draft practitioners
|
|
20265
|
+
* 4. Procedures from inactive practitioners (isActive === false)
|
|
20266
|
+
*
|
|
20267
|
+
* Note: Each procedure has ONE practitionerId. If that practitioner is inactive/draft/missing,
|
|
20268
|
+
* the procedure is filtered out.
|
|
20269
|
+
*
|
|
20262
20270
|
* @param procedures - Array of procedures to filter
|
|
20263
|
-
* @returns Filtered array of procedures (excluding
|
|
20271
|
+
* @returns Filtered array of procedures (excluding invalid/inactive/draft practitioners)
|
|
20264
20272
|
*/
|
|
20265
20273
|
async filterDraftPractitionerProcedures(procedures) {
|
|
20266
20274
|
if (!this.practitionerService || procedures.length === 0) {
|
|
20267
20275
|
return procedures;
|
|
20268
20276
|
}
|
|
20269
20277
|
try {
|
|
20278
|
+
const proceduresWithPractitioner = procedures.filter(
|
|
20279
|
+
(p) => p.practitionerId && p.practitionerId.trim() !== ""
|
|
20280
|
+
);
|
|
20281
|
+
if (proceduresWithPractitioner.length === 0) {
|
|
20282
|
+
console.log(
|
|
20283
|
+
`[ProcedureService] All ${procedures.length} procedures have no practitionerId - filtering out`
|
|
20284
|
+
);
|
|
20285
|
+
return [];
|
|
20286
|
+
}
|
|
20270
20287
|
const practitionerIds = Array.from(
|
|
20271
|
-
new Set(
|
|
20288
|
+
new Set(proceduresWithPractitioner.map((p) => p.practitionerId).filter(Boolean))
|
|
20272
20289
|
);
|
|
20273
20290
|
if (practitionerIds.length === 0) {
|
|
20274
|
-
return
|
|
20291
|
+
return [];
|
|
20275
20292
|
}
|
|
20276
20293
|
const practitionerPromises = practitionerIds.map(
|
|
20277
20294
|
(id) => this.practitionerService.getPractitioner(id).catch(() => null)
|
|
20278
20295
|
);
|
|
20279
20296
|
const practitioners = await Promise.all(practitionerPromises);
|
|
20280
|
-
const
|
|
20297
|
+
const practitionerMap = /* @__PURE__ */ new Map();
|
|
20281
20298
|
practitioners.forEach((practitioner, index) => {
|
|
20282
20299
|
if (practitioner) {
|
|
20283
|
-
|
|
20300
|
+
practitionerMap.set(practitionerIds[index], practitioner);
|
|
20284
20301
|
}
|
|
20285
20302
|
});
|
|
20286
|
-
const filteredProcedures =
|
|
20287
|
-
const
|
|
20288
|
-
|
|
20303
|
+
const filteredProcedures = proceduresWithPractitioner.filter((procedure) => {
|
|
20304
|
+
const practitioner = practitionerMap.get(procedure.practitionerId);
|
|
20305
|
+
if (!practitioner) {
|
|
20306
|
+
console.log(
|
|
20307
|
+
`[ProcedureService] Filtering out procedure ${procedure.id} - practitioner ${procedure.practitionerId} not found`
|
|
20308
|
+
);
|
|
20309
|
+
return false;
|
|
20310
|
+
}
|
|
20311
|
+
if (practitioner.status === "draft" /* DRAFT */) {
|
|
20312
|
+
console.log(
|
|
20313
|
+
`[ProcedureService] Filtering out procedure ${procedure.id} - practitioner ${procedure.practitionerId} is DRAFT`
|
|
20314
|
+
);
|
|
20315
|
+
return false;
|
|
20316
|
+
}
|
|
20317
|
+
if (!practitioner.isActive) {
|
|
20318
|
+
console.log(
|
|
20319
|
+
`[ProcedureService] Filtering out procedure ${procedure.id} - practitioner ${procedure.practitionerId} is not active`
|
|
20320
|
+
);
|
|
20321
|
+
return false;
|
|
20322
|
+
}
|
|
20323
|
+
return true;
|
|
20289
20324
|
});
|
|
20290
|
-
|
|
20325
|
+
const filteredCount = procedures.length - filteredProcedures.length;
|
|
20326
|
+
if (filteredCount > 0) {
|
|
20327
|
+
const noPractitionerCount = procedures.length - proceduresWithPractitioner.length;
|
|
20328
|
+
const invalidPractitionerCount = proceduresWithPractitioner.length - filteredProcedures.length;
|
|
20291
20329
|
console.log(
|
|
20292
|
-
`[ProcedureService] Filtered out ${procedures
|
|
20330
|
+
`[ProcedureService] Filtered out ${filteredCount} procedures: ${noPractitionerCount} with no practitionerId, ${invalidPractitionerCount} with missing/draft/inactive practitioners`
|
|
20293
20331
|
);
|
|
20294
20332
|
}
|
|
20295
20333
|
return filteredProcedures;
|
|
20296
20334
|
} catch (error) {
|
|
20297
20335
|
console.error(
|
|
20298
|
-
"[ProcedureService] Error filtering
|
|
20336
|
+
"[ProcedureService] Error filtering practitioner procedures:",
|
|
20299
20337
|
error
|
|
20300
20338
|
);
|
|
20301
20339
|
return procedures;
|
|
@@ -20469,7 +20507,11 @@ var ProcedureService = class extends BaseService {
|
|
|
20469
20507
|
photo: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : "",
|
|
20470
20508
|
// Default to empty string if not a processed URL
|
|
20471
20509
|
rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
|
|
20472
|
-
services: practitioner.procedures || []
|
|
20510
|
+
services: practitioner.procedures || [],
|
|
20511
|
+
status: practitioner.status,
|
|
20512
|
+
// Include practitioner status for client-side filtering
|
|
20513
|
+
isActive: practitioner.isActive
|
|
20514
|
+
// Include isActive flag for client-side filtering
|
|
20473
20515
|
};
|
|
20474
20516
|
const { productsMetadata: _, productId: __, photos: ___, ...validatedDataWithoutProductsMetadata } = validatedData;
|
|
20475
20517
|
const newProcedure = {
|
|
@@ -20628,7 +20670,9 @@ var ProcedureService = class extends BaseService {
|
|
|
20628
20670
|
description: practitioner.basicInfo.bio || "",
|
|
20629
20671
|
photo: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : "",
|
|
20630
20672
|
rating: ((_c = practitioner.reviewInfo) == null ? void 0 : _c.averageRating) || 0,
|
|
20631
|
-
services: practitioner.procedures || []
|
|
20673
|
+
services: practitioner.procedures || [],
|
|
20674
|
+
status: practitioner.status,
|
|
20675
|
+
isActive: practitioner.isActive
|
|
20632
20676
|
};
|
|
20633
20677
|
const newProcedure = {
|
|
20634
20678
|
...sourceProcedure,
|
|
@@ -21005,7 +21049,8 @@ var ProcedureService = class extends BaseService {
|
|
|
21005
21049
|
where33("isActive", "==", true)
|
|
21006
21050
|
);
|
|
21007
21051
|
const snapshot = await getDocs33(q);
|
|
21008
|
-
|
|
21052
|
+
const procedures = snapshot.docs.map((doc47) => doc47.data());
|
|
21053
|
+
return await this.filterDraftPractitionerProcedures(procedures);
|
|
21009
21054
|
}
|
|
21010
21055
|
/**
|
|
21011
21056
|
* Gets all procedures for a practitioner
|
|
@@ -21124,7 +21169,9 @@ var ProcedureService = class extends BaseService {
|
|
|
21124
21169
|
photo: typeof newPractitioner.basicInfo.profileImageUrl === "string" ? newPractitioner.basicInfo.profileImageUrl : "",
|
|
21125
21170
|
// Default to empty string if not a processed URL
|
|
21126
21171
|
rating: ((_b = newPractitioner.reviewInfo) == null ? void 0 : _b.averageRating) || 0,
|
|
21127
|
-
services: newPractitioner.procedures || []
|
|
21172
|
+
services: newPractitioner.procedures || [],
|
|
21173
|
+
status: newPractitioner.status,
|
|
21174
|
+
isActive: newPractitioner.isActive
|
|
21128
21175
|
};
|
|
21129
21176
|
}
|
|
21130
21177
|
if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
|
|
@@ -21408,6 +21455,7 @@ var ProcedureService = class extends BaseService {
|
|
|
21408
21455
|
if (hasNestedFilters) {
|
|
21409
21456
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
21410
21457
|
}
|
|
21458
|
+
procedures = await this.filterDraftPractitionerProcedures(procedures);
|
|
21411
21459
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
21412
21460
|
console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
|
|
21413
21461
|
if (procedures.length < (filters.pagination || 10)) {
|
package/package.json
CHANGED
|
@@ -90,9 +90,17 @@ export class ProcedureService extends BaseService {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
* Filters out procedures
|
|
93
|
+
* Filters out procedures that should not be visible to patients:
|
|
94
|
+
* 1. Procedures with no practitioner (missing practitionerId)
|
|
95
|
+
* 2. Procedures where practitioner doesn't exist
|
|
96
|
+
* 3. Procedures from draft practitioners
|
|
97
|
+
* 4. Procedures from inactive practitioners (isActive === false)
|
|
98
|
+
*
|
|
99
|
+
* Note: Each procedure has ONE practitionerId. If that practitioner is inactive/draft/missing,
|
|
100
|
+
* the procedure is filtered out.
|
|
101
|
+
*
|
|
94
102
|
* @param procedures - Array of procedures to filter
|
|
95
|
-
* @returns Filtered array of procedures (excluding
|
|
103
|
+
* @returns Filtered array of procedures (excluding invalid/inactive/draft practitioners)
|
|
96
104
|
*/
|
|
97
105
|
private async filterDraftPractitionerProcedures(
|
|
98
106
|
procedures: Procedure[]
|
|
@@ -102,13 +110,25 @@ export class ProcedureService extends BaseService {
|
|
|
102
110
|
}
|
|
103
111
|
|
|
104
112
|
try {
|
|
113
|
+
// First, filter out procedures with no practitionerId
|
|
114
|
+
const proceduresWithPractitioner = procedures.filter((p) =>
|
|
115
|
+
p.practitionerId && p.practitionerId.trim() !== ''
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
if (proceduresWithPractitioner.length === 0) {
|
|
119
|
+
console.log(
|
|
120
|
+
`[ProcedureService] All ${procedures.length} procedures have no practitionerId - filtering out`
|
|
121
|
+
);
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
|
|
105
125
|
// Get unique practitioner IDs from procedures
|
|
106
126
|
const practitionerIds = Array.from(
|
|
107
|
-
new Set(
|
|
127
|
+
new Set(proceduresWithPractitioner.map((p) => p.practitionerId).filter(Boolean))
|
|
108
128
|
);
|
|
109
129
|
|
|
110
130
|
if (practitionerIds.length === 0) {
|
|
111
|
-
return
|
|
131
|
+
return [];
|
|
112
132
|
}
|
|
113
133
|
|
|
114
134
|
// Fetch all practitioners in parallel
|
|
@@ -117,32 +137,64 @@ export class ProcedureService extends BaseService {
|
|
|
117
137
|
);
|
|
118
138
|
const practitioners = await Promise.all(practitionerPromises);
|
|
119
139
|
|
|
120
|
-
// Create a map of practitioner ID to
|
|
121
|
-
const
|
|
140
|
+
// Create a map of practitioner ID to practitioner data
|
|
141
|
+
const practitionerMap = new Map<string, Practitioner>();
|
|
122
142
|
practitioners.forEach((practitioner, index) => {
|
|
123
143
|
if (practitioner) {
|
|
124
|
-
|
|
144
|
+
practitionerMap.set(practitionerIds[index], practitioner);
|
|
125
145
|
}
|
|
126
146
|
});
|
|
127
147
|
|
|
128
|
-
// Filter out procedures
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
148
|
+
// Filter out procedures that:
|
|
149
|
+
// 1. Have no practitionerId (already filtered above, but double-check)
|
|
150
|
+
// 2. Have a practitioner that doesn't exist
|
|
151
|
+
// 3. Have a practitioner with DRAFT status
|
|
152
|
+
// 4. Have a practitioner that is not active (isActive === false)
|
|
153
|
+
const filteredProcedures = proceduresWithPractitioner.filter((procedure) => {
|
|
154
|
+
// Check if practitioner exists
|
|
155
|
+
const practitioner = practitionerMap.get(procedure.practitionerId);
|
|
156
|
+
|
|
157
|
+
if (!practitioner) {
|
|
158
|
+
console.log(
|
|
159
|
+
`[ProcedureService] Filtering out procedure ${procedure.id} - practitioner ${procedure.practitionerId} not found`
|
|
160
|
+
);
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Check if practitioner is DRAFT
|
|
165
|
+
if (practitioner.status === PractitionerStatus.DRAFT) {
|
|
166
|
+
console.log(
|
|
167
|
+
`[ProcedureService] Filtering out procedure ${procedure.id} - practitioner ${procedure.practitionerId} is DRAFT`
|
|
168
|
+
);
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Check if practitioner is active (must be true to show procedure)
|
|
173
|
+
if (!practitioner.isActive) {
|
|
174
|
+
console.log(
|
|
175
|
+
`[ProcedureService] Filtering out procedure ${procedure.id} - practitioner ${procedure.practitionerId} is not active`
|
|
176
|
+
);
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return true;
|
|
132
181
|
});
|
|
133
182
|
|
|
134
|
-
|
|
183
|
+
const filteredCount = procedures.length - filteredProcedures.length;
|
|
184
|
+
if (filteredCount > 0) {
|
|
185
|
+
const noPractitionerCount = procedures.length - proceduresWithPractitioner.length;
|
|
186
|
+
const invalidPractitionerCount = proceduresWithPractitioner.length - filteredProcedures.length;
|
|
135
187
|
console.log(
|
|
136
|
-
`[ProcedureService] Filtered out ${
|
|
137
|
-
|
|
138
|
-
}
|
|
188
|
+
`[ProcedureService] Filtered out ${filteredCount} procedures: ` +
|
|
189
|
+
`${noPractitionerCount} with no practitionerId, ` +
|
|
190
|
+
`${invalidPractitionerCount} with missing/draft/inactive practitioners`
|
|
139
191
|
);
|
|
140
192
|
}
|
|
141
193
|
|
|
142
194
|
return filteredProcedures;
|
|
143
195
|
} catch (error) {
|
|
144
196
|
console.error(
|
|
145
|
-
'[ProcedureService] Error filtering
|
|
197
|
+
'[ProcedureService] Error filtering practitioner procedures:',
|
|
146
198
|
error
|
|
147
199
|
);
|
|
148
200
|
// On error, return original procedures to avoid breaking functionality
|
|
@@ -387,6 +439,8 @@ export class ProcedureService extends BaseService {
|
|
|
387
439
|
: '', // Default to empty string if not a processed URL
|
|
388
440
|
rating: practitioner.reviewInfo?.averageRating || 0,
|
|
389
441
|
services: practitioner.procedures || [],
|
|
442
|
+
status: practitioner.status, // Include practitioner status for client-side filtering
|
|
443
|
+
isActive: practitioner.isActive, // Include isActive flag for client-side filtering
|
|
390
444
|
};
|
|
391
445
|
|
|
392
446
|
// Create the procedure object
|
|
@@ -576,6 +630,8 @@ export class ProcedureService extends BaseService {
|
|
|
576
630
|
: '',
|
|
577
631
|
rating: practitioner.reviewInfo?.averageRating || 0,
|
|
578
632
|
services: practitioner.procedures || [],
|
|
633
|
+
status: practitioner.status,
|
|
634
|
+
isActive: practitioner.isActive,
|
|
579
635
|
};
|
|
580
636
|
|
|
581
637
|
// Construct the new procedure object
|
|
@@ -1062,7 +1118,10 @@ export class ProcedureService extends BaseService {
|
|
|
1062
1118
|
where('isActive', '==', true),
|
|
1063
1119
|
);
|
|
1064
1120
|
const snapshot = await getDocs(q);
|
|
1065
|
-
|
|
1121
|
+
const procedures = snapshot.docs.map(doc => doc.data() as Procedure);
|
|
1122
|
+
|
|
1123
|
+
// Filter out procedures from draft practitioners
|
|
1124
|
+
return await this.filterDraftPractitionerProcedures(procedures);
|
|
1066
1125
|
}
|
|
1067
1126
|
|
|
1068
1127
|
/**
|
|
@@ -1210,6 +1269,8 @@ export class ProcedureService extends BaseService {
|
|
|
1210
1269
|
: '', // Default to empty string if not a processed URL
|
|
1211
1270
|
rating: newPractitioner.reviewInfo?.averageRating || 0,
|
|
1212
1271
|
services: newPractitioner.procedures || [],
|
|
1272
|
+
status: newPractitioner.status,
|
|
1273
|
+
isActive: newPractitioner.isActive,
|
|
1213
1274
|
};
|
|
1214
1275
|
}
|
|
1215
1276
|
|
|
@@ -1591,6 +1652,9 @@ export class ProcedureService extends BaseService {
|
|
|
1591
1652
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
1592
1653
|
}
|
|
1593
1654
|
|
|
1655
|
+
// Filter out procedures from draft practitioners
|
|
1656
|
+
procedures = await this.filterDraftPractitionerProcedures(procedures);
|
|
1657
|
+
|
|
1594
1658
|
const lastDoc =
|
|
1595
1659
|
querySnapshot.docs.length > 0
|
|
1596
1660
|
? querySnapshot.docs[querySnapshot.docs.length - 1]
|
|
@@ -3,6 +3,7 @@ import { Timestamp, FieldValue } from 'firebase/firestore';
|
|
|
3
3
|
import type { ClinicInfo } from '../profile';
|
|
4
4
|
import { ClinicReviewInfo } from '../reviews';
|
|
5
5
|
import { ProcedureSummaryInfo } from '../procedure';
|
|
6
|
+
import { PractitionerStatus } from '../practitioner';
|
|
6
7
|
|
|
7
8
|
export const CLINIC_GROUPS_COLLECTION = 'clinic_groups';
|
|
8
9
|
export const CLINIC_ADMINS_COLLECTION = 'clinic_admins';
|
|
@@ -351,6 +352,8 @@ export interface DoctorInfo {
|
|
|
351
352
|
photo: string | null;
|
|
352
353
|
rating: number;
|
|
353
354
|
services: string[]; // Used for search and filtering
|
|
355
|
+
status?: PractitionerStatus; // Practitioner status (DRAFT, ACTIVE, etc.)
|
|
356
|
+
isActive?: boolean; // Whether practitioner is active
|
|
354
357
|
// TODO: Add aggregated fields, like rating, reviews, services this doctor provides in this clinic and similar
|
|
355
358
|
}
|
|
356
359
|
|