@blackcode_sa/metaestetics-api 1.10.0 → 1.11.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/admin/index.d.mts +9 -0
- package/dist/admin/index.d.ts +9 -0
- package/dist/admin/index.js +98 -79
- package/dist/admin/index.mjs +98 -79
- package/dist/backoffice/index.d.mts +1 -0
- package/dist/backoffice/index.d.ts +1 -0
- package/dist/index.d.mts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +91 -18
- package/dist/index.mjs +94 -19
- package/package.json +3 -1
- package/src/admin/booking/booking.admin.ts +2 -0
- package/src/admin/booking/booking.calculator.ts +121 -117
- package/src/admin/booking/booking.types.ts +3 -0
- package/src/services/clinic/clinic.service.ts +163 -82
- package/src/services/procedure/procedure.service.ts +3 -2
- package/src/types/appointment/index.ts +4 -0
- package/src/types/clinic/index.ts +2 -0
- package/src/validations/appointment.schema.ts +2 -0
- package/src/validations/clinic.schema.ts +2 -0
- package/src/validations/procedure.schema.ts +8 -10
package/dist/index.js
CHANGED
|
@@ -583,7 +583,8 @@ var createAppointmentSchema = import_zod3.z.object({
|
|
|
583
583
|
currency: import_zod3.z.string().min(1, "Currency is required"),
|
|
584
584
|
patientNotes: import_zod3.z.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
|
|
585
585
|
initialStatus: appointmentStatusSchema,
|
|
586
|
-
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
|
|
586
|
+
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */),
|
|
587
|
+
clinic_tz: import_zod3.z.string().min(1, "Timezone is required")
|
|
587
588
|
}).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
|
|
588
589
|
message: "Appointment end time must be after start time",
|
|
589
590
|
path: ["appointmentEndTime"]
|
|
@@ -617,6 +618,7 @@ var updateAppointmentSchema = import_zod3.z.object({
|
|
|
617
618
|
cost: import_zod3.z.number().min(0).optional(),
|
|
618
619
|
clinicBranchId: import_zod3.z.string().min(MIN_STRING_LENGTH).optional(),
|
|
619
620
|
practitionerId: import_zod3.z.string().min(MIN_STRING_LENGTH).optional(),
|
|
621
|
+
clinic_tz: import_zod3.z.string().min(MIN_STRING_LENGTH).optional(),
|
|
620
622
|
linkedForms: import_zod3.z.union([import_zod3.z.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), import_zod3.z.any()]).optional(),
|
|
621
623
|
media: import_zod3.z.union([
|
|
622
624
|
import_zod3.z.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
|
|
@@ -3453,7 +3455,8 @@ var clinicLocationSchema = import_zod10.z.object({
|
|
|
3453
3455
|
postalCode: import_zod10.z.string(),
|
|
3454
3456
|
latitude: import_zod10.z.number().min(-90).max(90),
|
|
3455
3457
|
longitude: import_zod10.z.number().min(-180).max(180),
|
|
3456
|
-
geohash: import_zod10.z.string().nullable().optional()
|
|
3458
|
+
geohash: import_zod10.z.string().nullable().optional(),
|
|
3459
|
+
tz: import_zod10.z.string().nullable().optional()
|
|
3457
3460
|
});
|
|
3458
3461
|
var workingHoursTimeSchema = import_zod10.z.object({
|
|
3459
3462
|
open: import_zod10.z.string(),
|
|
@@ -3607,6 +3610,7 @@ var createClinicGroupSchema = import_zod10.z.object({
|
|
|
3607
3610
|
calendarSyncEnabled: import_zod10.z.boolean().optional(),
|
|
3608
3611
|
autoConfirmAppointments: import_zod10.z.boolean().optional(),
|
|
3609
3612
|
businessIdentificationNumber: import_zod10.z.string().optional().nullable(),
|
|
3613
|
+
tz: import_zod10.z.string().nullable().optional(),
|
|
3610
3614
|
onboarding: import_zod10.z.object({
|
|
3611
3615
|
completed: import_zod10.z.boolean().optional().default(false),
|
|
3612
3616
|
step: import_zod10.z.number().optional().default(1)
|
|
@@ -8271,6 +8275,7 @@ var ClinicGroupService = class extends BaseService {
|
|
|
8271
8275
|
|
|
8272
8276
|
// src/services/clinic/clinic.service.ts
|
|
8273
8277
|
var import_firestore27 = require("firebase/firestore");
|
|
8278
|
+
var import_functions2 = require("firebase/functions");
|
|
8274
8279
|
var import_geofire_common7 = require("geofire-common");
|
|
8275
8280
|
var import_zod20 = require("zod");
|
|
8276
8281
|
|
|
@@ -9023,6 +9028,27 @@ var ClinicService = class extends BaseService {
|
|
|
9023
9028
|
this.clinicAdminService = clinicAdminService;
|
|
9024
9029
|
this.clinicGroupService = clinicGroupService;
|
|
9025
9030
|
this.mediaService = mediaService;
|
|
9031
|
+
this.functions = (0, import_functions2.getFunctions)(app);
|
|
9032
|
+
}
|
|
9033
|
+
/**
|
|
9034
|
+
* Get timezone from coordinates using the callable function
|
|
9035
|
+
* @param lat Latitude
|
|
9036
|
+
* @param lng Longitude
|
|
9037
|
+
* @returns IANA timezone string
|
|
9038
|
+
*/
|
|
9039
|
+
async getTimezone(lat, lng) {
|
|
9040
|
+
try {
|
|
9041
|
+
const getTimezoneFromCoordinates = (0, import_functions2.httpsCallable)(
|
|
9042
|
+
this.functions,
|
|
9043
|
+
"getTimezoneFromCoordinates"
|
|
9044
|
+
);
|
|
9045
|
+
const result = await getTimezoneFromCoordinates({ lat, lng });
|
|
9046
|
+
const data = result.data;
|
|
9047
|
+
return data.timezone;
|
|
9048
|
+
} catch (error) {
|
|
9049
|
+
console.error("Error getting timezone:", error);
|
|
9050
|
+
return null;
|
|
9051
|
+
}
|
|
9026
9052
|
}
|
|
9027
9053
|
/**
|
|
9028
9054
|
* Process media resource (string URL or File object)
|
|
@@ -9037,7 +9063,9 @@ var ClinicService = class extends BaseService {
|
|
|
9037
9063
|
return media;
|
|
9038
9064
|
}
|
|
9039
9065
|
if (media instanceof File || media instanceof Blob) {
|
|
9040
|
-
console.log(
|
|
9066
|
+
console.log(
|
|
9067
|
+
`[ClinicService] Uploading ${collectionName} media for ${ownerId}`
|
|
9068
|
+
);
|
|
9041
9069
|
const metadata = await this.mediaService.uploadMedia(
|
|
9042
9070
|
media,
|
|
9043
9071
|
ownerId,
|
|
@@ -9059,7 +9087,11 @@ var ClinicService = class extends BaseService {
|
|
|
9059
9087
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
9060
9088
|
const result = [];
|
|
9061
9089
|
for (const media of mediaArray) {
|
|
9062
|
-
const processedUrl = await this.processMedia(
|
|
9090
|
+
const processedUrl = await this.processMedia(
|
|
9091
|
+
media,
|
|
9092
|
+
ownerId,
|
|
9093
|
+
collectionName
|
|
9094
|
+
);
|
|
9063
9095
|
if (processedUrl) {
|
|
9064
9096
|
result.push(processedUrl);
|
|
9065
9097
|
}
|
|
@@ -9077,7 +9109,11 @@ var ClinicService = class extends BaseService {
|
|
|
9077
9109
|
if (!photosWithTags || photosWithTags.length === 0) return [];
|
|
9078
9110
|
const result = [];
|
|
9079
9111
|
for (const item of photosWithTags) {
|
|
9080
|
-
const processedUrl = await this.processMedia(
|
|
9112
|
+
const processedUrl = await this.processMedia(
|
|
9113
|
+
item.url,
|
|
9114
|
+
ownerId,
|
|
9115
|
+
collectionName
|
|
9116
|
+
);
|
|
9081
9117
|
if (processedUrl) {
|
|
9082
9118
|
result.push({
|
|
9083
9119
|
url: processedUrl,
|
|
@@ -9095,11 +9131,19 @@ var ClinicService = class extends BaseService {
|
|
|
9095
9131
|
try {
|
|
9096
9132
|
const clinicId = this.generateId();
|
|
9097
9133
|
const validatedData = createClinicSchema.parse(data);
|
|
9098
|
-
const group = await this.clinicGroupService.getClinicGroup(
|
|
9134
|
+
const group = await this.clinicGroupService.getClinicGroup(
|
|
9135
|
+
validatedData.clinicGroupId
|
|
9136
|
+
);
|
|
9099
9137
|
if (!group) {
|
|
9100
|
-
throw new Error(
|
|
9138
|
+
throw new Error(
|
|
9139
|
+
`Clinic group ${validatedData.clinicGroupId} not found`
|
|
9140
|
+
);
|
|
9101
9141
|
}
|
|
9102
|
-
const logoUrl = await this.processMedia(
|
|
9142
|
+
const logoUrl = await this.processMedia(
|
|
9143
|
+
validatedData.logo,
|
|
9144
|
+
clinicId,
|
|
9145
|
+
"clinic-logos"
|
|
9146
|
+
);
|
|
9103
9147
|
const coverPhotoUrl = await this.processMedia(
|
|
9104
9148
|
validatedData.coverPhoto,
|
|
9105
9149
|
clinicId,
|
|
@@ -9117,6 +9161,7 @@ var ClinicService = class extends BaseService {
|
|
|
9117
9161
|
);
|
|
9118
9162
|
const location = validatedData.location;
|
|
9119
9163
|
const hash = (0, import_geofire_common7.geohashForLocation)([location.latitude, location.longitude]);
|
|
9164
|
+
const tz = await this.getTimezone(location.latitude, location.longitude);
|
|
9120
9165
|
const defaultReviewInfo = {
|
|
9121
9166
|
totalReviews: 0,
|
|
9122
9167
|
averageRating: 0,
|
|
@@ -9134,7 +9179,7 @@ var ClinicService = class extends BaseService {
|
|
|
9134
9179
|
nameLower: validatedData.name.toLowerCase(),
|
|
9135
9180
|
// Add this line
|
|
9136
9181
|
description: validatedData.description,
|
|
9137
|
-
location: { ...location, geohash: hash },
|
|
9182
|
+
location: { ...location, geohash: hash, tz },
|
|
9138
9183
|
contactInfo: validatedData.contactInfo,
|
|
9139
9184
|
workingHours: validatedData.workingHours,
|
|
9140
9185
|
tags: validatedData.tags,
|
|
@@ -9189,7 +9234,11 @@ var ClinicService = class extends BaseService {
|
|
|
9189
9234
|
const validatedData = updateClinicSchema.parse(data);
|
|
9190
9235
|
const updatePayload = {};
|
|
9191
9236
|
if (validatedData.logo !== void 0) {
|
|
9192
|
-
updatePayload.logo = await this.processMedia(
|
|
9237
|
+
updatePayload.logo = await this.processMedia(
|
|
9238
|
+
validatedData.logo,
|
|
9239
|
+
clinicId,
|
|
9240
|
+
"clinic-logos"
|
|
9241
|
+
);
|
|
9193
9242
|
}
|
|
9194
9243
|
if (validatedData.coverPhoto !== void 0) {
|
|
9195
9244
|
updatePayload.coverPhoto = await this.processMedia(
|
|
@@ -9234,9 +9283,11 @@ var ClinicService = class extends BaseService {
|
|
|
9234
9283
|
}
|
|
9235
9284
|
if (validatedData.location) {
|
|
9236
9285
|
const loc = validatedData.location;
|
|
9286
|
+
const tz = await this.getTimezone(loc.latitude, loc.longitude);
|
|
9237
9287
|
updatePayload.location = {
|
|
9238
9288
|
...loc,
|
|
9239
|
-
geohash: (0, import_geofire_common7.geohashForLocation)([loc.latitude, loc.longitude])
|
|
9289
|
+
geohash: (0, import_geofire_common7.geohashForLocation)([loc.latitude, loc.longitude]),
|
|
9290
|
+
tz
|
|
9240
9291
|
};
|
|
9241
9292
|
}
|
|
9242
9293
|
updatePayload.updatedAt = (0, import_firestore27.serverTimestamp)();
|
|
@@ -9289,10 +9340,22 @@ var ClinicService = class extends BaseService {
|
|
|
9289
9340
|
* Pretražuje klinike u određenom radijusu
|
|
9290
9341
|
*/
|
|
9291
9342
|
async findClinicsInRadius(center, radiusInKm, filters) {
|
|
9292
|
-
return findClinicsInRadius(
|
|
9343
|
+
return findClinicsInRadius(
|
|
9344
|
+
this.db,
|
|
9345
|
+
center,
|
|
9346
|
+
radiusInKm,
|
|
9347
|
+
filters
|
|
9348
|
+
);
|
|
9293
9349
|
}
|
|
9294
9350
|
async addTags(clinicId, adminId, newTags) {
|
|
9295
|
-
return addTags(
|
|
9351
|
+
return addTags(
|
|
9352
|
+
this.db,
|
|
9353
|
+
clinicId,
|
|
9354
|
+
adminId,
|
|
9355
|
+
newTags,
|
|
9356
|
+
this.clinicAdminService,
|
|
9357
|
+
this.app
|
|
9358
|
+
);
|
|
9296
9359
|
}
|
|
9297
9360
|
async removeTags(clinicId, adminId, tagsToRemove) {
|
|
9298
9361
|
return removeTags(
|
|
@@ -9330,7 +9393,9 @@ var ClinicService = class extends BaseService {
|
|
|
9330
9393
|
clinicGroupId,
|
|
9331
9394
|
adminId
|
|
9332
9395
|
});
|
|
9333
|
-
const clinicGroup = await this.clinicGroupService.getClinicGroup(
|
|
9396
|
+
const clinicGroup = await this.clinicGroupService.getClinicGroup(
|
|
9397
|
+
clinicGroupId
|
|
9398
|
+
);
|
|
9334
9399
|
if (!clinicGroup) {
|
|
9335
9400
|
console.error("[CLINIC_SERVICE] Clinic group not found", {
|
|
9336
9401
|
clinicGroupId
|
|
@@ -9376,7 +9441,13 @@ var ClinicService = class extends BaseService {
|
|
|
9376
9441
|
return getAllClinics(this.db, pagination, lastDoc);
|
|
9377
9442
|
}
|
|
9378
9443
|
async getAllClinicsInRange(center, rangeInKm, pagination, lastDoc) {
|
|
9379
|
-
return getAllClinicsInRange(
|
|
9444
|
+
return getAllClinicsInRange(
|
|
9445
|
+
this.db,
|
|
9446
|
+
center,
|
|
9447
|
+
rangeInKm,
|
|
9448
|
+
pagination,
|
|
9449
|
+
lastDoc
|
|
9450
|
+
);
|
|
9380
9451
|
}
|
|
9381
9452
|
/**
|
|
9382
9453
|
* Get clinics based on multiple filtering criteria
|
|
@@ -14589,7 +14660,8 @@ var import_firestore45 = require("firebase/firestore");
|
|
|
14589
14660
|
var import_zod24 = require("zod");
|
|
14590
14661
|
var createProcedureSchema = import_zod24.z.object({
|
|
14591
14662
|
name: import_zod24.z.string().min(1).max(200),
|
|
14592
|
-
|
|
14663
|
+
// Optional: service will derive from name if not provided by client
|
|
14664
|
+
nameLower: import_zod24.z.string().min(1).max(200).optional(),
|
|
14593
14665
|
description: import_zod24.z.string().min(1).max(2e3),
|
|
14594
14666
|
family: import_zod24.z.nativeEnum(ProcedureFamily),
|
|
14595
14667
|
categoryId: import_zod24.z.string().min(1),
|
|
@@ -14769,6 +14841,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14769
14841
|
const newProcedure = {
|
|
14770
14842
|
id: procedureId,
|
|
14771
14843
|
...validatedData,
|
|
14844
|
+
// Ensure nameLower is always set even if omitted by client
|
|
14772
14845
|
nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
|
|
14773
14846
|
photos: processedPhotos,
|
|
14774
14847
|
category,
|
|
@@ -15902,7 +15975,7 @@ var import_auth9 = require("firebase/auth");
|
|
|
15902
15975
|
var import_analytics = require("firebase/analytics");
|
|
15903
15976
|
var import_react_native = require("react-native");
|
|
15904
15977
|
var import_storage4 = require("firebase/storage");
|
|
15905
|
-
var
|
|
15978
|
+
var import_functions3 = require("firebase/functions");
|
|
15906
15979
|
var firebaseInstance = null;
|
|
15907
15980
|
var initializeFirebase = (config) => {
|
|
15908
15981
|
if (!firebaseInstance) {
|
|
@@ -15910,7 +15983,7 @@ var initializeFirebase = (config) => {
|
|
|
15910
15983
|
const db = (0, import_firestore47.getFirestore)(app);
|
|
15911
15984
|
const auth = (0, import_auth9.getAuth)(app);
|
|
15912
15985
|
const storage = (0, import_storage4.getStorage)(app);
|
|
15913
|
-
const functions = (0,
|
|
15986
|
+
const functions = (0, import_functions3.getFunctions)(app);
|
|
15914
15987
|
let analytics = null;
|
|
15915
15988
|
if (typeof window !== "undefined" && import_react_native.Platform.OS === "web") {
|
|
15916
15989
|
analytics = (0, import_analytics.getAnalytics)(app);
|
package/dist/index.mjs
CHANGED
|
@@ -455,7 +455,8 @@ var createAppointmentSchema = z3.object({
|
|
|
455
455
|
currency: z3.string().min(1, "Currency is required"),
|
|
456
456
|
patientNotes: z3.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
|
|
457
457
|
initialStatus: appointmentStatusSchema,
|
|
458
|
-
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
|
|
458
|
+
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */),
|
|
459
|
+
clinic_tz: z3.string().min(1, "Timezone is required")
|
|
459
460
|
}).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
|
|
460
461
|
message: "Appointment end time must be after start time",
|
|
461
462
|
path: ["appointmentEndTime"]
|
|
@@ -489,6 +490,7 @@ var updateAppointmentSchema = z3.object({
|
|
|
489
490
|
cost: z3.number().min(0).optional(),
|
|
490
491
|
clinicBranchId: z3.string().min(MIN_STRING_LENGTH).optional(),
|
|
491
492
|
practitionerId: z3.string().min(MIN_STRING_LENGTH).optional(),
|
|
493
|
+
clinic_tz: z3.string().min(MIN_STRING_LENGTH).optional(),
|
|
492
494
|
linkedForms: z3.union([z3.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), z3.any()]).optional(),
|
|
493
495
|
media: z3.union([
|
|
494
496
|
z3.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
|
|
@@ -3437,7 +3439,8 @@ var clinicLocationSchema = z10.object({
|
|
|
3437
3439
|
postalCode: z10.string(),
|
|
3438
3440
|
latitude: z10.number().min(-90).max(90),
|
|
3439
3441
|
longitude: z10.number().min(-180).max(180),
|
|
3440
|
-
geohash: z10.string().nullable().optional()
|
|
3442
|
+
geohash: z10.string().nullable().optional(),
|
|
3443
|
+
tz: z10.string().nullable().optional()
|
|
3441
3444
|
});
|
|
3442
3445
|
var workingHoursTimeSchema = z10.object({
|
|
3443
3446
|
open: z10.string(),
|
|
@@ -3591,6 +3594,7 @@ var createClinicGroupSchema = z10.object({
|
|
|
3591
3594
|
calendarSyncEnabled: z10.boolean().optional(),
|
|
3592
3595
|
autoConfirmAppointments: z10.boolean().optional(),
|
|
3593
3596
|
businessIdentificationNumber: z10.string().optional().nullable(),
|
|
3597
|
+
tz: z10.string().nullable().optional(),
|
|
3594
3598
|
onboarding: z10.object({
|
|
3595
3599
|
completed: z10.boolean().optional().default(false),
|
|
3596
3600
|
step: z10.number().optional().default(1)
|
|
@@ -8342,7 +8346,10 @@ import {
|
|
|
8342
8346
|
writeBatch as writeBatch4,
|
|
8343
8347
|
arrayUnion as arrayUnion7
|
|
8344
8348
|
} from "firebase/firestore";
|
|
8345
|
-
import {
|
|
8349
|
+
import { getFunctions as getFunctions2, httpsCallable as httpsCallable2 } from "firebase/functions";
|
|
8350
|
+
import {
|
|
8351
|
+
geohashForLocation as geohashForLocation4
|
|
8352
|
+
} from "geofire-common";
|
|
8346
8353
|
import { z as z20 } from "zod";
|
|
8347
8354
|
|
|
8348
8355
|
// src/services/clinic/utils/clinic.utils.ts
|
|
@@ -9123,6 +9130,27 @@ var ClinicService = class extends BaseService {
|
|
|
9123
9130
|
this.clinicAdminService = clinicAdminService;
|
|
9124
9131
|
this.clinicGroupService = clinicGroupService;
|
|
9125
9132
|
this.mediaService = mediaService;
|
|
9133
|
+
this.functions = getFunctions2(app);
|
|
9134
|
+
}
|
|
9135
|
+
/**
|
|
9136
|
+
* Get timezone from coordinates using the callable function
|
|
9137
|
+
* @param lat Latitude
|
|
9138
|
+
* @param lng Longitude
|
|
9139
|
+
* @returns IANA timezone string
|
|
9140
|
+
*/
|
|
9141
|
+
async getTimezone(lat, lng) {
|
|
9142
|
+
try {
|
|
9143
|
+
const getTimezoneFromCoordinates = httpsCallable2(
|
|
9144
|
+
this.functions,
|
|
9145
|
+
"getTimezoneFromCoordinates"
|
|
9146
|
+
);
|
|
9147
|
+
const result = await getTimezoneFromCoordinates({ lat, lng });
|
|
9148
|
+
const data = result.data;
|
|
9149
|
+
return data.timezone;
|
|
9150
|
+
} catch (error) {
|
|
9151
|
+
console.error("Error getting timezone:", error);
|
|
9152
|
+
return null;
|
|
9153
|
+
}
|
|
9126
9154
|
}
|
|
9127
9155
|
/**
|
|
9128
9156
|
* Process media resource (string URL or File object)
|
|
@@ -9137,7 +9165,9 @@ var ClinicService = class extends BaseService {
|
|
|
9137
9165
|
return media;
|
|
9138
9166
|
}
|
|
9139
9167
|
if (media instanceof File || media instanceof Blob) {
|
|
9140
|
-
console.log(
|
|
9168
|
+
console.log(
|
|
9169
|
+
`[ClinicService] Uploading ${collectionName} media for ${ownerId}`
|
|
9170
|
+
);
|
|
9141
9171
|
const metadata = await this.mediaService.uploadMedia(
|
|
9142
9172
|
media,
|
|
9143
9173
|
ownerId,
|
|
@@ -9159,7 +9189,11 @@ var ClinicService = class extends BaseService {
|
|
|
9159
9189
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
9160
9190
|
const result = [];
|
|
9161
9191
|
for (const media of mediaArray) {
|
|
9162
|
-
const processedUrl = await this.processMedia(
|
|
9192
|
+
const processedUrl = await this.processMedia(
|
|
9193
|
+
media,
|
|
9194
|
+
ownerId,
|
|
9195
|
+
collectionName
|
|
9196
|
+
);
|
|
9163
9197
|
if (processedUrl) {
|
|
9164
9198
|
result.push(processedUrl);
|
|
9165
9199
|
}
|
|
@@ -9177,7 +9211,11 @@ var ClinicService = class extends BaseService {
|
|
|
9177
9211
|
if (!photosWithTags || photosWithTags.length === 0) return [];
|
|
9178
9212
|
const result = [];
|
|
9179
9213
|
for (const item of photosWithTags) {
|
|
9180
|
-
const processedUrl = await this.processMedia(
|
|
9214
|
+
const processedUrl = await this.processMedia(
|
|
9215
|
+
item.url,
|
|
9216
|
+
ownerId,
|
|
9217
|
+
collectionName
|
|
9218
|
+
);
|
|
9181
9219
|
if (processedUrl) {
|
|
9182
9220
|
result.push({
|
|
9183
9221
|
url: processedUrl,
|
|
@@ -9195,11 +9233,19 @@ var ClinicService = class extends BaseService {
|
|
|
9195
9233
|
try {
|
|
9196
9234
|
const clinicId = this.generateId();
|
|
9197
9235
|
const validatedData = createClinicSchema.parse(data);
|
|
9198
|
-
const group = await this.clinicGroupService.getClinicGroup(
|
|
9236
|
+
const group = await this.clinicGroupService.getClinicGroup(
|
|
9237
|
+
validatedData.clinicGroupId
|
|
9238
|
+
);
|
|
9199
9239
|
if (!group) {
|
|
9200
|
-
throw new Error(
|
|
9240
|
+
throw new Error(
|
|
9241
|
+
`Clinic group ${validatedData.clinicGroupId} not found`
|
|
9242
|
+
);
|
|
9201
9243
|
}
|
|
9202
|
-
const logoUrl = await this.processMedia(
|
|
9244
|
+
const logoUrl = await this.processMedia(
|
|
9245
|
+
validatedData.logo,
|
|
9246
|
+
clinicId,
|
|
9247
|
+
"clinic-logos"
|
|
9248
|
+
);
|
|
9203
9249
|
const coverPhotoUrl = await this.processMedia(
|
|
9204
9250
|
validatedData.coverPhoto,
|
|
9205
9251
|
clinicId,
|
|
@@ -9217,6 +9263,7 @@ var ClinicService = class extends BaseService {
|
|
|
9217
9263
|
);
|
|
9218
9264
|
const location = validatedData.location;
|
|
9219
9265
|
const hash = geohashForLocation4([location.latitude, location.longitude]);
|
|
9266
|
+
const tz = await this.getTimezone(location.latitude, location.longitude);
|
|
9220
9267
|
const defaultReviewInfo = {
|
|
9221
9268
|
totalReviews: 0,
|
|
9222
9269
|
averageRating: 0,
|
|
@@ -9234,7 +9281,7 @@ var ClinicService = class extends BaseService {
|
|
|
9234
9281
|
nameLower: validatedData.name.toLowerCase(),
|
|
9235
9282
|
// Add this line
|
|
9236
9283
|
description: validatedData.description,
|
|
9237
|
-
location: { ...location, geohash: hash },
|
|
9284
|
+
location: { ...location, geohash: hash, tz },
|
|
9238
9285
|
contactInfo: validatedData.contactInfo,
|
|
9239
9286
|
workingHours: validatedData.workingHours,
|
|
9240
9287
|
tags: validatedData.tags,
|
|
@@ -9289,7 +9336,11 @@ var ClinicService = class extends BaseService {
|
|
|
9289
9336
|
const validatedData = updateClinicSchema.parse(data);
|
|
9290
9337
|
const updatePayload = {};
|
|
9291
9338
|
if (validatedData.logo !== void 0) {
|
|
9292
|
-
updatePayload.logo = await this.processMedia(
|
|
9339
|
+
updatePayload.logo = await this.processMedia(
|
|
9340
|
+
validatedData.logo,
|
|
9341
|
+
clinicId,
|
|
9342
|
+
"clinic-logos"
|
|
9343
|
+
);
|
|
9293
9344
|
}
|
|
9294
9345
|
if (validatedData.coverPhoto !== void 0) {
|
|
9295
9346
|
updatePayload.coverPhoto = await this.processMedia(
|
|
@@ -9334,9 +9385,11 @@ var ClinicService = class extends BaseService {
|
|
|
9334
9385
|
}
|
|
9335
9386
|
if (validatedData.location) {
|
|
9336
9387
|
const loc = validatedData.location;
|
|
9388
|
+
const tz = await this.getTimezone(loc.latitude, loc.longitude);
|
|
9337
9389
|
updatePayload.location = {
|
|
9338
9390
|
...loc,
|
|
9339
|
-
geohash: geohashForLocation4([loc.latitude, loc.longitude])
|
|
9391
|
+
geohash: geohashForLocation4([loc.latitude, loc.longitude]),
|
|
9392
|
+
tz
|
|
9340
9393
|
};
|
|
9341
9394
|
}
|
|
9342
9395
|
updatePayload.updatedAt = serverTimestamp14();
|
|
@@ -9389,10 +9442,22 @@ var ClinicService = class extends BaseService {
|
|
|
9389
9442
|
* Pretražuje klinike u određenom radijusu
|
|
9390
9443
|
*/
|
|
9391
9444
|
async findClinicsInRadius(center, radiusInKm, filters) {
|
|
9392
|
-
return findClinicsInRadius(
|
|
9445
|
+
return findClinicsInRadius(
|
|
9446
|
+
this.db,
|
|
9447
|
+
center,
|
|
9448
|
+
radiusInKm,
|
|
9449
|
+
filters
|
|
9450
|
+
);
|
|
9393
9451
|
}
|
|
9394
9452
|
async addTags(clinicId, adminId, newTags) {
|
|
9395
|
-
return addTags(
|
|
9453
|
+
return addTags(
|
|
9454
|
+
this.db,
|
|
9455
|
+
clinicId,
|
|
9456
|
+
adminId,
|
|
9457
|
+
newTags,
|
|
9458
|
+
this.clinicAdminService,
|
|
9459
|
+
this.app
|
|
9460
|
+
);
|
|
9396
9461
|
}
|
|
9397
9462
|
async removeTags(clinicId, adminId, tagsToRemove) {
|
|
9398
9463
|
return removeTags(
|
|
@@ -9430,7 +9495,9 @@ var ClinicService = class extends BaseService {
|
|
|
9430
9495
|
clinicGroupId,
|
|
9431
9496
|
adminId
|
|
9432
9497
|
});
|
|
9433
|
-
const clinicGroup = await this.clinicGroupService.getClinicGroup(
|
|
9498
|
+
const clinicGroup = await this.clinicGroupService.getClinicGroup(
|
|
9499
|
+
clinicGroupId
|
|
9500
|
+
);
|
|
9434
9501
|
if (!clinicGroup) {
|
|
9435
9502
|
console.error("[CLINIC_SERVICE] Clinic group not found", {
|
|
9436
9503
|
clinicGroupId
|
|
@@ -9476,7 +9543,13 @@ var ClinicService = class extends BaseService {
|
|
|
9476
9543
|
return getAllClinics(this.db, pagination, lastDoc);
|
|
9477
9544
|
}
|
|
9478
9545
|
async getAllClinicsInRange(center, rangeInKm, pagination, lastDoc) {
|
|
9479
|
-
return getAllClinicsInRange(
|
|
9546
|
+
return getAllClinicsInRange(
|
|
9547
|
+
this.db,
|
|
9548
|
+
center,
|
|
9549
|
+
rangeInKm,
|
|
9550
|
+
pagination,
|
|
9551
|
+
lastDoc
|
|
9552
|
+
);
|
|
9480
9553
|
}
|
|
9481
9554
|
/**
|
|
9482
9555
|
* Get clinics based on multiple filtering criteria
|
|
@@ -14838,7 +14911,8 @@ import {
|
|
|
14838
14911
|
import { z as z24 } from "zod";
|
|
14839
14912
|
var createProcedureSchema = z24.object({
|
|
14840
14913
|
name: z24.string().min(1).max(200),
|
|
14841
|
-
|
|
14914
|
+
// Optional: service will derive from name if not provided by client
|
|
14915
|
+
nameLower: z24.string().min(1).max(200).optional(),
|
|
14842
14916
|
description: z24.string().min(1).max(2e3),
|
|
14843
14917
|
family: z24.nativeEnum(ProcedureFamily),
|
|
14844
14918
|
categoryId: z24.string().min(1),
|
|
@@ -15018,6 +15092,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15018
15092
|
const newProcedure = {
|
|
15019
15093
|
id: procedureId,
|
|
15020
15094
|
...validatedData,
|
|
15095
|
+
// Ensure nameLower is always set even if omitted by client
|
|
15021
15096
|
nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
|
|
15022
15097
|
photos: processedPhotos,
|
|
15023
15098
|
category,
|
|
@@ -16161,7 +16236,7 @@ import { getAuth } from "firebase/auth";
|
|
|
16161
16236
|
import { getAnalytics } from "firebase/analytics";
|
|
16162
16237
|
import { Platform } from "react-native";
|
|
16163
16238
|
import { getStorage as getStorage3 } from "firebase/storage";
|
|
16164
|
-
import { getFunctions as
|
|
16239
|
+
import { getFunctions as getFunctions3 } from "firebase/functions";
|
|
16165
16240
|
var firebaseInstance = null;
|
|
16166
16241
|
var initializeFirebase = (config) => {
|
|
16167
16242
|
if (!firebaseInstance) {
|
|
@@ -16169,7 +16244,7 @@ var initializeFirebase = (config) => {
|
|
|
16169
16244
|
const db = getFirestore2(app);
|
|
16170
16245
|
const auth = getAuth(app);
|
|
16171
16246
|
const storage = getStorage3(app);
|
|
16172
|
-
const functions =
|
|
16247
|
+
const functions = getFunctions3(app);
|
|
16173
16248
|
let analytics = null;
|
|
16174
16249
|
if (typeof window !== "undefined" && Platform.OS === "web") {
|
|
16175
16250
|
analytics = getAnalytics(app);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blackcode_sa/metaestetics-api",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.11.0",
|
|
5
5
|
"description": "Firebase authentication service with anonymous upgrade support",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@testing-library/jest-dom": "^6.6.3",
|
|
85
85
|
"@types/jest": "^29.5.14",
|
|
86
|
+
"@types/luxon": "^3.7.1",
|
|
86
87
|
"@types/mailgun-js": "^0.22.18",
|
|
87
88
|
"@types/node": "^20.17.13",
|
|
88
89
|
"@types/react": "^19.1.0",
|
|
@@ -98,6 +99,7 @@
|
|
|
98
99
|
"expo-server-sdk": "^3.13.0",
|
|
99
100
|
"firebase-admin": "^13.0.2",
|
|
100
101
|
"geofire-common": "^6.0.0",
|
|
102
|
+
"luxon": "^3.7.1",
|
|
101
103
|
"zod": "^3.24.1"
|
|
102
104
|
},
|
|
103
105
|
"optionalDependencies": {
|
|
@@ -233,6 +233,7 @@ export class BookingAdmin {
|
|
|
233
233
|
practitionerCalendarEvents: this.convertEventsTimestamps(
|
|
234
234
|
practitionerCalendarEvents
|
|
235
235
|
),
|
|
236
|
+
tz: clinic.location.tz || "UTC",
|
|
236
237
|
};
|
|
237
238
|
|
|
238
239
|
Logger.info("[BookingAdmin] Calling availability calculator", {
|
|
@@ -823,6 +824,7 @@ export class BookingAdmin {
|
|
|
823
824
|
calendarEventId: practitionerCalendarEventId,
|
|
824
825
|
clinicBranchId: procedure.clinicBranchId,
|
|
825
826
|
clinicInfo,
|
|
827
|
+
clinic_tz: clinicData.location.tz || "UTC",
|
|
826
828
|
practitionerId: procedure.practitionerId,
|
|
827
829
|
practitionerInfo,
|
|
828
830
|
patientId: data.patientId,
|