@blackcode_sa/metaestetics-api 1.8.6 → 1.8.7
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 +1 -67
- package/dist/index.d.ts +1 -67
- package/dist/index.js +1329 -1363
- package/dist/index.mjs +1115 -1141
- package/package.json +1 -1
- package/src/admin/calendar/README.md +7 -0
- package/src/services/auth/index.ts +1 -1
- package/src/services/calendar/index.ts +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1878,685 +1878,6 @@ var AppointmentService = class extends BaseService {
|
|
|
1878
1878
|
}
|
|
1879
1879
|
};
|
|
1880
1880
|
|
|
1881
|
-
// src/services/auth/utils/firebase.utils.ts
|
|
1882
|
-
import { fetchSignInMethodsForEmail } from "firebase/auth";
|
|
1883
|
-
var checkEmailExists = async (auth, email) => {
|
|
1884
|
-
try {
|
|
1885
|
-
const methods = await fetchSignInMethodsForEmail(auth, email);
|
|
1886
|
-
return methods.length > 0;
|
|
1887
|
-
} catch (error) {
|
|
1888
|
-
console.warn(
|
|
1889
|
-
"[FIREBASE] Could not check email existence, allowing signup to proceed:",
|
|
1890
|
-
error
|
|
1891
|
-
);
|
|
1892
|
-
return false;
|
|
1893
|
-
}
|
|
1894
|
-
};
|
|
1895
|
-
var cleanupFirebaseUser = async (firebaseUser) => {
|
|
1896
|
-
try {
|
|
1897
|
-
console.log("[FIREBASE] Cleaning up Firebase user", {
|
|
1898
|
-
uid: firebaseUser.uid
|
|
1899
|
-
});
|
|
1900
|
-
await firebaseUser.delete();
|
|
1901
|
-
console.log("[FIREBASE] Firebase user cleanup successful");
|
|
1902
|
-
} catch (cleanupError) {
|
|
1903
|
-
console.error("[FIREBASE] Failed to cleanup Firebase user:", cleanupError);
|
|
1904
|
-
}
|
|
1905
|
-
};
|
|
1906
|
-
|
|
1907
|
-
// src/services/auth/utils/error.utils.ts
|
|
1908
|
-
import { z as z4 } from "zod";
|
|
1909
|
-
|
|
1910
|
-
// src/errors/auth.errors.ts
|
|
1911
|
-
var AuthError = class extends Error {
|
|
1912
|
-
constructor(message, code, status = 400) {
|
|
1913
|
-
super(message);
|
|
1914
|
-
this.code = code;
|
|
1915
|
-
this.status = status;
|
|
1916
|
-
this.name = "AuthError";
|
|
1917
|
-
}
|
|
1918
|
-
};
|
|
1919
|
-
var AUTH_ERRORS = {
|
|
1920
|
-
// Basic validation errors
|
|
1921
|
-
INVALID_EMAIL: new AuthError(
|
|
1922
|
-
"Email address is not in a valid format",
|
|
1923
|
-
"AUTH/INVALID_EMAIL",
|
|
1924
|
-
400
|
|
1925
|
-
),
|
|
1926
|
-
INVALID_PASSWORD: new AuthError(
|
|
1927
|
-
"Password must contain at least 8 characters, one uppercase letter, one number, and one special character",
|
|
1928
|
-
"AUTH/INVALID_PASSWORD",
|
|
1929
|
-
400
|
|
1930
|
-
),
|
|
1931
|
-
INVALID_ROLE: new AuthError(
|
|
1932
|
-
"Specified user role is not valid",
|
|
1933
|
-
"AUTH/INVALID_ROLE",
|
|
1934
|
-
400
|
|
1935
|
-
),
|
|
1936
|
-
// Authentication errors
|
|
1937
|
-
NOT_AUTHENTICATED: new AuthError(
|
|
1938
|
-
"User is not authenticated",
|
|
1939
|
-
"AUTH/NOT_AUTHENTICATED",
|
|
1940
|
-
401
|
|
1941
|
-
),
|
|
1942
|
-
SESSION_EXPIRED: new AuthError(
|
|
1943
|
-
"Your session has expired. Please sign in again",
|
|
1944
|
-
"AUTH/SESSION_EXPIRED",
|
|
1945
|
-
401
|
|
1946
|
-
),
|
|
1947
|
-
INVALID_TOKEN: new AuthError(
|
|
1948
|
-
"Invalid authentication token",
|
|
1949
|
-
"AUTH/INVALID_TOKEN",
|
|
1950
|
-
401
|
|
1951
|
-
),
|
|
1952
|
-
// User state errors
|
|
1953
|
-
USER_NOT_FOUND: new AuthError(
|
|
1954
|
-
"User not found in the system",
|
|
1955
|
-
"AUTH/USER_NOT_FOUND",
|
|
1956
|
-
404
|
|
1957
|
-
),
|
|
1958
|
-
EMAIL_ALREADY_EXISTS: new AuthError(
|
|
1959
|
-
"An account with this email already exists",
|
|
1960
|
-
"AUTH/EMAIL_EXISTS",
|
|
1961
|
-
409
|
|
1962
|
-
),
|
|
1963
|
-
USER_DISABLED: new AuthError(
|
|
1964
|
-
"This account has been disabled",
|
|
1965
|
-
"AUTH/USER_DISABLED",
|
|
1966
|
-
403
|
|
1967
|
-
),
|
|
1968
|
-
// Rate limiting and security
|
|
1969
|
-
TOO_MANY_REQUESTS: new AuthError(
|
|
1970
|
-
"Too many login attempts. Please try again later",
|
|
1971
|
-
"AUTH/TOO_MANY_REQUESTS",
|
|
1972
|
-
429
|
|
1973
|
-
),
|
|
1974
|
-
ACCOUNT_LOCKED: new AuthError(
|
|
1975
|
-
"Account temporarily locked due to too many failed login attempts",
|
|
1976
|
-
"AUTH/ACCOUNT_LOCKED",
|
|
1977
|
-
403
|
|
1978
|
-
),
|
|
1979
|
-
// Social auth specific
|
|
1980
|
-
POPUP_CLOSED: new AuthError(
|
|
1981
|
-
"Authentication popup was closed before completion",
|
|
1982
|
-
"AUTH/POPUP_CLOSED",
|
|
1983
|
-
400
|
|
1984
|
-
),
|
|
1985
|
-
POPUP_BLOCKED: new AuthError(
|
|
1986
|
-
"Authentication popup was blocked by the browser",
|
|
1987
|
-
"AUTH/POPUP_BLOCKED",
|
|
1988
|
-
400
|
|
1989
|
-
),
|
|
1990
|
-
ACCOUNT_EXISTS: new AuthError(
|
|
1991
|
-
"An account already exists with different credentials",
|
|
1992
|
-
"AUTH/ACCOUNT_EXISTS",
|
|
1993
|
-
409
|
|
1994
|
-
),
|
|
1995
|
-
// Anonymous auth specific
|
|
1996
|
-
NOT_ANONYMOUS: new AuthError(
|
|
1997
|
-
"Current user is not anonymous",
|
|
1998
|
-
"AUTH/NOT_ANONYMOUS_USER",
|
|
1999
|
-
400
|
|
2000
|
-
),
|
|
2001
|
-
ANONYMOUS_UPGRADE_FAILED: new AuthError(
|
|
2002
|
-
"Failed to upgrade anonymous account",
|
|
2003
|
-
"AUTH/ANONYMOUS_UPGRADE_FAILED",
|
|
2004
|
-
400
|
|
2005
|
-
),
|
|
2006
|
-
// General errors
|
|
2007
|
-
VALIDATION_ERROR: new AuthError(
|
|
2008
|
-
"Data validation error occurred",
|
|
2009
|
-
"AUTH/VALIDATION_ERROR",
|
|
2010
|
-
400
|
|
2011
|
-
),
|
|
2012
|
-
OPERATION_NOT_ALLOWED: new AuthError(
|
|
2013
|
-
"This operation is not allowed",
|
|
2014
|
-
"AUTH/OPERATION_NOT_ALLOWED",
|
|
2015
|
-
403
|
|
2016
|
-
),
|
|
2017
|
-
NETWORK_ERROR: new AuthError(
|
|
2018
|
-
"Network error occurred. Please check your connection",
|
|
2019
|
-
"AUTH/NETWORK_ERROR",
|
|
2020
|
-
503
|
|
2021
|
-
),
|
|
2022
|
-
REQUIRES_RECENT_LOGIN: new AuthError(
|
|
2023
|
-
"This operation requires recent authentication. Please sign in again",
|
|
2024
|
-
"AUTH/REQUIRES_RECENT_LOGIN",
|
|
2025
|
-
401
|
|
2026
|
-
),
|
|
2027
|
-
INVALID_PROVIDER: new AuthError(
|
|
2028
|
-
"Invalid authentication provider",
|
|
2029
|
-
"AUTH/INVALID_PROVIDER",
|
|
2030
|
-
400
|
|
2031
|
-
),
|
|
2032
|
-
INVALID_CREDENTIAL: new AuthError(
|
|
2033
|
-
"The provided credentials are invalid or expired",
|
|
2034
|
-
"AUTH/INVALID_CREDENTIAL",
|
|
2035
|
-
401
|
|
2036
|
-
),
|
|
2037
|
-
// Resource not found
|
|
2038
|
-
NOT_FOUND: new AuthError(
|
|
2039
|
-
"The requested resource was not found",
|
|
2040
|
-
"AUTH/NOT_FOUND",
|
|
2041
|
-
404
|
|
2042
|
-
),
|
|
2043
|
-
// Detailed password validation errors
|
|
2044
|
-
PASSWORD_LENGTH_ERROR: new AuthError(
|
|
2045
|
-
"Password must be at least 8 characters long",
|
|
2046
|
-
"AUTH/PASSWORD_LENGTH_ERROR",
|
|
2047
|
-
400
|
|
2048
|
-
),
|
|
2049
|
-
PASSWORD_UPPERCASE_ERROR: new AuthError(
|
|
2050
|
-
"Password must contain at least one uppercase letter",
|
|
2051
|
-
"AUTH/PASSWORD_UPPERCASE_ERROR",
|
|
2052
|
-
400
|
|
2053
|
-
),
|
|
2054
|
-
PASSWORD_NUMBER_ERROR: new AuthError(
|
|
2055
|
-
"Password must contain at least one number",
|
|
2056
|
-
"AUTH/PASSWORD_NUMBER_ERROR",
|
|
2057
|
-
400
|
|
2058
|
-
),
|
|
2059
|
-
PASSWORD_SPECIAL_CHAR_ERROR: new AuthError(
|
|
2060
|
-
"Password must contain at least one special character",
|
|
2061
|
-
"AUTH/PASSWORD_SPECIAL_CHAR_ERROR",
|
|
2062
|
-
400
|
|
2063
|
-
),
|
|
2064
|
-
// Detailed email validation errors
|
|
2065
|
-
EMAIL_FORMAT_ERROR: new AuthError(
|
|
2066
|
-
"Invalid email format. Please enter a valid email address",
|
|
2067
|
-
"AUTH/EMAIL_FORMAT_ERROR",
|
|
2068
|
-
400
|
|
2069
|
-
),
|
|
2070
|
-
PASSWORD_VALIDATION_ERROR: new AuthError(
|
|
2071
|
-
"Password validation failed. Please check all requirements",
|
|
2072
|
-
"AUTH/PASSWORD_VALIDATION_ERROR",
|
|
2073
|
-
400
|
|
2074
|
-
),
|
|
2075
|
-
// Password reset specific errors
|
|
2076
|
-
EXPIRED_ACTION_CODE: new AuthError(
|
|
2077
|
-
"Kod za resetovanje lozinke je istekao. Molimo zatra\u017Eite novi link za resetovanje.",
|
|
2078
|
-
"AUTH/EXPIRED_ACTION_CODE",
|
|
2079
|
-
400
|
|
2080
|
-
),
|
|
2081
|
-
INVALID_ACTION_CODE: new AuthError(
|
|
2082
|
-
"Kod za resetovanje lozinke je neva\u017Ee\u0107i ili je ve\u0107 iskori\u0161\u0107en. Molimo zatra\u017Eite novi link za resetovanje.",
|
|
2083
|
-
"AUTH/INVALID_ACTION_CODE",
|
|
2084
|
-
400
|
|
2085
|
-
),
|
|
2086
|
-
WEAK_PASSWORD: new AuthError(
|
|
2087
|
-
"Lozinka je previ\u0161e slaba. Molimo koristite ja\u010Du lozinku.",
|
|
2088
|
-
"AUTH/WEAK_PASSWORD",
|
|
2089
|
-
400
|
|
2090
|
-
)
|
|
2091
|
-
};
|
|
2092
|
-
|
|
2093
|
-
// src/services/auth/utils/error.utils.ts
|
|
2094
|
-
var handleFirebaseError = (error) => {
|
|
2095
|
-
const firebaseError = error;
|
|
2096
|
-
switch (firebaseError.code) {
|
|
2097
|
-
case "auth/email-already-in-use" /* EMAIL_ALREADY_IN_USE */:
|
|
2098
|
-
return AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
|
|
2099
|
-
case "auth/weak-password":
|
|
2100
|
-
return new Error(
|
|
2101
|
-
"Password is too weak. Please choose a stronger password."
|
|
2102
|
-
);
|
|
2103
|
-
case "auth/invalid-email":
|
|
2104
|
-
return new Error("Please enter a valid email address.");
|
|
2105
|
-
case "auth/network-request-failed":
|
|
2106
|
-
return new Error(
|
|
2107
|
-
"Network error. Please check your internet connection and try again."
|
|
2108
|
-
);
|
|
2109
|
-
default:
|
|
2110
|
-
return new Error(
|
|
2111
|
-
`Account creation failed: ${firebaseError.message || "Unknown error"}`
|
|
2112
|
-
);
|
|
2113
|
-
}
|
|
2114
|
-
};
|
|
2115
|
-
var handleSignupError = (error) => {
|
|
2116
|
-
if (error instanceof z4.ZodError) {
|
|
2117
|
-
const errorMessages = error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
2118
|
-
return new Error(`Validation failed: ${errorMessages}`);
|
|
2119
|
-
}
|
|
2120
|
-
if (error.code && error.code.startsWith("auth/")) {
|
|
2121
|
-
return handleFirebaseError(error);
|
|
2122
|
-
}
|
|
2123
|
-
if (error.message && error.message.includes("token")) {
|
|
2124
|
-
return new Error("Invalid or expired invitation token");
|
|
2125
|
-
}
|
|
2126
|
-
if (error.message && error.message.includes("validation")) {
|
|
2127
|
-
return new Error(`Invalid practitioner data: ${error.message}`);
|
|
2128
|
-
}
|
|
2129
|
-
return new Error(
|
|
2130
|
-
`Registration failed: ${error.message || "Unknown error occurred"}`
|
|
2131
|
-
);
|
|
2132
|
-
};
|
|
2133
|
-
var extractErrorMessage = (error) => {
|
|
2134
|
-
if (error instanceof Error) {
|
|
2135
|
-
return error.message;
|
|
2136
|
-
}
|
|
2137
|
-
if (typeof error === "string") {
|
|
2138
|
-
return error;
|
|
2139
|
-
}
|
|
2140
|
-
if (error == null ? void 0 : error.message) {
|
|
2141
|
-
return error.message;
|
|
2142
|
-
}
|
|
2143
|
-
return "Unknown error occurred";
|
|
2144
|
-
};
|
|
2145
|
-
|
|
2146
|
-
// src/backoffice/types/static/certification.types.ts
|
|
2147
|
-
var CertificationLevel = /* @__PURE__ */ ((CertificationLevel2) => {
|
|
2148
|
-
CertificationLevel2["AESTHETICIAN"] = "aesthetician";
|
|
2149
|
-
CertificationLevel2["NURSE_ASSISTANT"] = "nurse_assistant";
|
|
2150
|
-
CertificationLevel2["NURSE"] = "nurse";
|
|
2151
|
-
CertificationLevel2["NURSE_PRACTITIONER"] = "nurse_practitioner";
|
|
2152
|
-
CertificationLevel2["PHYSICIAN_ASSISTANT"] = "physician_assistant";
|
|
2153
|
-
CertificationLevel2["DOCTOR"] = "doctor";
|
|
2154
|
-
CertificationLevel2["SPECIALIST"] = "specialist";
|
|
2155
|
-
CertificationLevel2["PLASTIC_SURGEON"] = "plastic_surgeon";
|
|
2156
|
-
return CertificationLevel2;
|
|
2157
|
-
})(CertificationLevel || {});
|
|
2158
|
-
var CertificationSpecialty = /* @__PURE__ */ ((CertificationSpecialty3) => {
|
|
2159
|
-
CertificationSpecialty3["LASER"] = "laser";
|
|
2160
|
-
CertificationSpecialty3["INJECTABLES"] = "injectables";
|
|
2161
|
-
CertificationSpecialty3["CHEMICAL_PEELS"] = "chemical_peels";
|
|
2162
|
-
CertificationSpecialty3["MICRODERMABRASION"] = "microdermabrasion";
|
|
2163
|
-
CertificationSpecialty3["BODY_CONTOURING"] = "body_contouring";
|
|
2164
|
-
CertificationSpecialty3["SKIN_CARE"] = "skin_care";
|
|
2165
|
-
CertificationSpecialty3["WOUND_CARE"] = "wound_care";
|
|
2166
|
-
CertificationSpecialty3["ANESTHESIA"] = "anesthesia";
|
|
2167
|
-
return CertificationSpecialty3;
|
|
2168
|
-
})(CertificationSpecialty || {});
|
|
2169
|
-
|
|
2170
|
-
// src/services/auth/utils/practitioner.utils.ts
|
|
2171
|
-
import { z as z8 } from "zod";
|
|
2172
|
-
|
|
2173
|
-
// src/validations/practitioner.schema.ts
|
|
2174
|
-
import { z as z7 } from "zod";
|
|
2175
|
-
import { Timestamp as Timestamp3 } from "firebase/firestore";
|
|
2176
|
-
|
|
2177
|
-
// src/validations/reviews.schema.ts
|
|
2178
|
-
import { z as z5 } from "zod";
|
|
2179
|
-
var baseReviewSchema = z5.object({
|
|
2180
|
-
id: z5.string().min(1),
|
|
2181
|
-
patientId: z5.string().min(1),
|
|
2182
|
-
fullReviewId: z5.string().min(1),
|
|
2183
|
-
createdAt: z5.date(),
|
|
2184
|
-
updatedAt: z5.date(),
|
|
2185
|
-
comment: z5.string().min(1).max(2e3),
|
|
2186
|
-
isVerified: z5.boolean(),
|
|
2187
|
-
isPublished: z5.boolean()
|
|
2188
|
-
});
|
|
2189
|
-
var baseReviewCreateSchema = z5.object({
|
|
2190
|
-
patientId: z5.string().min(1),
|
|
2191
|
-
comment: z5.string().min(1).max(2e3),
|
|
2192
|
-
isVerified: z5.boolean().default(false),
|
|
2193
|
-
isPublished: z5.boolean().default(true)
|
|
2194
|
-
});
|
|
2195
|
-
var clinicReviewSchema = baseReviewSchema.extend({
|
|
2196
|
-
clinicId: z5.string().min(1),
|
|
2197
|
-
cleanliness: z5.number().min(1).max(5),
|
|
2198
|
-
facilities: z5.number().min(1).max(5),
|
|
2199
|
-
staffFriendliness: z5.number().min(1).max(5),
|
|
2200
|
-
waitingTime: z5.number().min(1).max(5),
|
|
2201
|
-
accessibility: z5.number().min(1).max(5),
|
|
2202
|
-
overallRating: z5.number().min(1).max(5),
|
|
2203
|
-
wouldRecommend: z5.boolean()
|
|
2204
|
-
});
|
|
2205
|
-
var createClinicReviewSchema = baseReviewCreateSchema.extend({
|
|
2206
|
-
clinicId: z5.string().min(1),
|
|
2207
|
-
cleanliness: z5.number().min(1).max(5),
|
|
2208
|
-
facilities: z5.number().min(1).max(5),
|
|
2209
|
-
staffFriendliness: z5.number().min(1).max(5),
|
|
2210
|
-
waitingTime: z5.number().min(1).max(5),
|
|
2211
|
-
accessibility: z5.number().min(1).max(5),
|
|
2212
|
-
wouldRecommend: z5.boolean()
|
|
2213
|
-
});
|
|
2214
|
-
var practitionerReviewSchema = baseReviewSchema.extend({
|
|
2215
|
-
practitionerId: z5.string().min(1),
|
|
2216
|
-
knowledgeAndExpertise: z5.number().min(1).max(5),
|
|
2217
|
-
communicationSkills: z5.number().min(1).max(5),
|
|
2218
|
-
bedSideManner: z5.number().min(1).max(5),
|
|
2219
|
-
thoroughness: z5.number().min(1).max(5),
|
|
2220
|
-
trustworthiness: z5.number().min(1).max(5),
|
|
2221
|
-
overallRating: z5.number().min(1).max(5),
|
|
2222
|
-
wouldRecommend: z5.boolean()
|
|
2223
|
-
});
|
|
2224
|
-
var createPractitionerReviewSchema = baseReviewCreateSchema.extend({
|
|
2225
|
-
practitionerId: z5.string().min(1),
|
|
2226
|
-
knowledgeAndExpertise: z5.number().min(1).max(5),
|
|
2227
|
-
communicationSkills: z5.number().min(1).max(5),
|
|
2228
|
-
bedSideManner: z5.number().min(1).max(5),
|
|
2229
|
-
thoroughness: z5.number().min(1).max(5),
|
|
2230
|
-
trustworthiness: z5.number().min(1).max(5),
|
|
2231
|
-
wouldRecommend: z5.boolean()
|
|
2232
|
-
});
|
|
2233
|
-
var procedureReviewSchema = baseReviewSchema.extend({
|
|
2234
|
-
procedureId: z5.string().min(1),
|
|
2235
|
-
effectivenessOfTreatment: z5.number().min(1).max(5),
|
|
2236
|
-
outcomeExplanation: z5.number().min(1).max(5),
|
|
2237
|
-
painManagement: z5.number().min(1).max(5),
|
|
2238
|
-
followUpCare: z5.number().min(1).max(5),
|
|
2239
|
-
valueForMoney: z5.number().min(1).max(5),
|
|
2240
|
-
overallRating: z5.number().min(1).max(5),
|
|
2241
|
-
wouldRecommend: z5.boolean()
|
|
2242
|
-
});
|
|
2243
|
-
var createProcedureReviewSchema = baseReviewCreateSchema.extend({
|
|
2244
|
-
procedureId: z5.string().min(1),
|
|
2245
|
-
effectivenessOfTreatment: z5.number().min(1).max(5),
|
|
2246
|
-
outcomeExplanation: z5.number().min(1).max(5),
|
|
2247
|
-
painManagement: z5.number().min(1).max(5),
|
|
2248
|
-
followUpCare: z5.number().min(1).max(5),
|
|
2249
|
-
valueForMoney: z5.number().min(1).max(5),
|
|
2250
|
-
wouldRecommend: z5.boolean()
|
|
2251
|
-
});
|
|
2252
|
-
var clinicReviewInfoSchema = z5.object({
|
|
2253
|
-
totalReviews: z5.number().min(0),
|
|
2254
|
-
averageRating: z5.number().min(0).max(5),
|
|
2255
|
-
cleanliness: z5.number().min(0).max(5),
|
|
2256
|
-
facilities: z5.number().min(0).max(5),
|
|
2257
|
-
staffFriendliness: z5.number().min(0).max(5),
|
|
2258
|
-
waitingTime: z5.number().min(0).max(5),
|
|
2259
|
-
accessibility: z5.number().min(0).max(5),
|
|
2260
|
-
recommendationPercentage: z5.number().min(0).max(100)
|
|
2261
|
-
});
|
|
2262
|
-
var practitionerReviewInfoSchema = z5.object({
|
|
2263
|
-
totalReviews: z5.number().min(0),
|
|
2264
|
-
averageRating: z5.number().min(0).max(5),
|
|
2265
|
-
knowledgeAndExpertise: z5.number().min(0).max(5),
|
|
2266
|
-
communicationSkills: z5.number().min(0).max(5),
|
|
2267
|
-
bedSideManner: z5.number().min(0).max(5),
|
|
2268
|
-
thoroughness: z5.number().min(0).max(5),
|
|
2269
|
-
trustworthiness: z5.number().min(0).max(5),
|
|
2270
|
-
recommendationPercentage: z5.number().min(0).max(100)
|
|
2271
|
-
});
|
|
2272
|
-
var procedureReviewInfoSchema = z5.object({
|
|
2273
|
-
totalReviews: z5.number().min(0),
|
|
2274
|
-
averageRating: z5.number().min(0).max(5),
|
|
2275
|
-
effectivenessOfTreatment: z5.number().min(0).max(5),
|
|
2276
|
-
outcomeExplanation: z5.number().min(0).max(5),
|
|
2277
|
-
painManagement: z5.number().min(0).max(5),
|
|
2278
|
-
followUpCare: z5.number().min(0).max(5),
|
|
2279
|
-
valueForMoney: z5.number().min(0).max(5),
|
|
2280
|
-
recommendationPercentage: z5.number().min(0).max(100)
|
|
2281
|
-
});
|
|
2282
|
-
var reviewSchema = z5.object({
|
|
2283
|
-
id: z5.string().min(1),
|
|
2284
|
-
appointmentId: z5.string().min(1),
|
|
2285
|
-
patientId: z5.string().min(1),
|
|
2286
|
-
createdAt: z5.date(),
|
|
2287
|
-
updatedAt: z5.date(),
|
|
2288
|
-
clinicReview: clinicReviewSchema.optional(),
|
|
2289
|
-
practitionerReview: practitionerReviewSchema.optional(),
|
|
2290
|
-
procedureReview: procedureReviewSchema.optional(),
|
|
2291
|
-
overallComment: z5.string().min(1).max(2e3),
|
|
2292
|
-
overallRating: z5.number().min(1).max(5)
|
|
2293
|
-
});
|
|
2294
|
-
var createReviewSchema = z5.object({
|
|
2295
|
-
patientId: z5.string().min(1),
|
|
2296
|
-
clinicReview: createClinicReviewSchema.optional(),
|
|
2297
|
-
practitionerReview: createPractitionerReviewSchema.optional(),
|
|
2298
|
-
procedureReview: createProcedureReviewSchema.optional(),
|
|
2299
|
-
overallComment: z5.string().min(1).max(2e3)
|
|
2300
|
-
}).refine(
|
|
2301
|
-
(data) => {
|
|
2302
|
-
return data.clinicReview || data.practitionerReview || data.procedureReview;
|
|
2303
|
-
},
|
|
2304
|
-
{
|
|
2305
|
-
message: "At least one review type (clinic, practitioner, or procedure) must be provided",
|
|
2306
|
-
path: ["reviewType"]
|
|
2307
|
-
}
|
|
2308
|
-
);
|
|
2309
|
-
|
|
2310
|
-
// src/validations/shared.schema.ts
|
|
2311
|
-
import { z as z6 } from "zod";
|
|
2312
|
-
|
|
2313
|
-
// src/backoffice/types/static/procedure-family.types.ts
|
|
2314
|
-
var ProcedureFamily = /* @__PURE__ */ ((ProcedureFamily2) => {
|
|
2315
|
-
ProcedureFamily2["AESTHETICS"] = "aesthetics";
|
|
2316
|
-
ProcedureFamily2["SURGERY"] = "surgery";
|
|
2317
|
-
return ProcedureFamily2;
|
|
2318
|
-
})(ProcedureFamily || {});
|
|
2319
|
-
|
|
2320
|
-
// src/validations/shared.schema.ts
|
|
2321
|
-
var sharedClinicContactInfoSchema = z6.object({
|
|
2322
|
-
email: z6.string().email(),
|
|
2323
|
-
phoneNumber: z6.string(),
|
|
2324
|
-
alternativePhoneNumber: z6.string().nullable().optional(),
|
|
2325
|
-
website: z6.string().nullable().optional()
|
|
2326
|
-
});
|
|
2327
|
-
var sharedClinicLocationSchema = z6.object({
|
|
2328
|
-
address: z6.string(),
|
|
2329
|
-
city: z6.string(),
|
|
2330
|
-
country: z6.string(),
|
|
2331
|
-
postalCode: z6.string(),
|
|
2332
|
-
latitude: z6.number().min(-90).max(90),
|
|
2333
|
-
longitude: z6.number().min(-180).max(180),
|
|
2334
|
-
geohash: z6.string().nullable().optional()
|
|
2335
|
-
});
|
|
2336
|
-
var procedureSummaryInfoSchema = z6.object({
|
|
2337
|
-
id: z6.string().min(1),
|
|
2338
|
-
name: z6.string().min(1),
|
|
2339
|
-
description: z6.string().optional(),
|
|
2340
|
-
photo: z6.string().optional(),
|
|
2341
|
-
family: z6.nativeEnum(ProcedureFamily),
|
|
2342
|
-
categoryName: z6.string(),
|
|
2343
|
-
subcategoryName: z6.string(),
|
|
2344
|
-
technologyName: z6.string(),
|
|
2345
|
-
price: z6.number().nonnegative(),
|
|
2346
|
-
pricingMeasure: z6.nativeEnum(PricingMeasure),
|
|
2347
|
-
currency: z6.nativeEnum(Currency),
|
|
2348
|
-
duration: z6.number().int().positive(),
|
|
2349
|
-
clinicId: z6.string().min(1),
|
|
2350
|
-
clinicName: z6.string().min(1),
|
|
2351
|
-
practitionerId: z6.string().min(1),
|
|
2352
|
-
practitionerName: z6.string().min(1)
|
|
2353
|
-
});
|
|
2354
|
-
var clinicInfoSchema = z6.object({
|
|
2355
|
-
id: z6.string(),
|
|
2356
|
-
featuredPhoto: z6.string(),
|
|
2357
|
-
name: z6.string(),
|
|
2358
|
-
description: z6.string().nullable().optional(),
|
|
2359
|
-
location: sharedClinicLocationSchema,
|
|
2360
|
-
contactInfo: sharedClinicContactInfoSchema
|
|
2361
|
-
});
|
|
2362
|
-
var doctorInfoSchema = z6.object({
|
|
2363
|
-
id: z6.string(),
|
|
2364
|
-
name: z6.string(),
|
|
2365
|
-
description: z6.string().nullable().optional(),
|
|
2366
|
-
photo: z6.string(),
|
|
2367
|
-
rating: z6.number().min(0).max(5),
|
|
2368
|
-
services: z6.array(z6.string())
|
|
2369
|
-
// List of procedure IDs practitioner offers
|
|
2370
|
-
});
|
|
2371
|
-
|
|
2372
|
-
// src/validations/practitioner.schema.ts
|
|
2373
|
-
var practitionerBasicInfoSchema = z7.object({
|
|
2374
|
-
firstName: z7.string().min(2).max(50),
|
|
2375
|
-
lastName: z7.string().min(2).max(50),
|
|
2376
|
-
title: z7.string().min(2).max(100),
|
|
2377
|
-
email: z7.string().email(),
|
|
2378
|
-
phoneNumber: z7.string().regex(/^\+?[1-9]\d{1,14}$/, "Invalid phone number").nullable(),
|
|
2379
|
-
dateOfBirth: z7.instanceof(Timestamp3).or(z7.date()).nullable(),
|
|
2380
|
-
gender: z7.enum(["male", "female", "other"]),
|
|
2381
|
-
profileImageUrl: mediaResourceSchema.optional().nullable(),
|
|
2382
|
-
bio: z7.string().max(1e3).optional(),
|
|
2383
|
-
languages: z7.array(z7.string()).min(1)
|
|
2384
|
-
});
|
|
2385
|
-
var practitionerCertificationSchema = z7.object({
|
|
2386
|
-
level: z7.nativeEnum(CertificationLevel),
|
|
2387
|
-
specialties: z7.array(z7.nativeEnum(CertificationSpecialty)),
|
|
2388
|
-
licenseNumber: z7.string().min(3).max(50),
|
|
2389
|
-
issuingAuthority: z7.string().min(2).max(100),
|
|
2390
|
-
issueDate: z7.instanceof(Timestamp3).or(z7.date()),
|
|
2391
|
-
expiryDate: z7.instanceof(Timestamp3).or(z7.date()).optional().nullable(),
|
|
2392
|
-
verificationStatus: z7.enum(["pending", "verified", "rejected"])
|
|
2393
|
-
});
|
|
2394
|
-
var timeSlotSchema = z7.object({
|
|
2395
|
-
start: z7.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/, "Invalid time format"),
|
|
2396
|
-
end: z7.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/, "Invalid time format")
|
|
2397
|
-
}).nullable();
|
|
2398
|
-
var practitionerWorkingHoursSchema = z7.object({
|
|
2399
|
-
practitionerId: z7.string().min(1),
|
|
2400
|
-
clinicId: z7.string().min(1),
|
|
2401
|
-
monday: timeSlotSchema,
|
|
2402
|
-
tuesday: timeSlotSchema,
|
|
2403
|
-
wednesday: timeSlotSchema,
|
|
2404
|
-
thursday: timeSlotSchema,
|
|
2405
|
-
friday: timeSlotSchema,
|
|
2406
|
-
saturday: timeSlotSchema,
|
|
2407
|
-
sunday: timeSlotSchema,
|
|
2408
|
-
createdAt: z7.instanceof(Timestamp3).or(z7.date()),
|
|
2409
|
-
updatedAt: z7.instanceof(Timestamp3).or(z7.date())
|
|
2410
|
-
});
|
|
2411
|
-
var practitionerClinicWorkingHoursSchema = z7.object({
|
|
2412
|
-
clinicId: z7.string().min(1),
|
|
2413
|
-
workingHours: z7.object({
|
|
2414
|
-
monday: timeSlotSchema,
|
|
2415
|
-
tuesday: timeSlotSchema,
|
|
2416
|
-
wednesday: timeSlotSchema,
|
|
2417
|
-
thursday: timeSlotSchema,
|
|
2418
|
-
friday: timeSlotSchema,
|
|
2419
|
-
saturday: timeSlotSchema,
|
|
2420
|
-
sunday: timeSlotSchema
|
|
2421
|
-
}),
|
|
2422
|
-
isActive: z7.boolean(),
|
|
2423
|
-
createdAt: z7.instanceof(Timestamp3).or(z7.date()),
|
|
2424
|
-
updatedAt: z7.instanceof(Timestamp3).or(z7.date())
|
|
2425
|
-
});
|
|
2426
|
-
var practitionerSchema = z7.object({
|
|
2427
|
-
id: z7.string().min(1),
|
|
2428
|
-
userRef: z7.string().min(1),
|
|
2429
|
-
basicInfo: practitionerBasicInfoSchema,
|
|
2430
|
-
certification: practitionerCertificationSchema,
|
|
2431
|
-
clinics: z7.array(z7.string()),
|
|
2432
|
-
clinicWorkingHours: z7.array(practitionerClinicWorkingHoursSchema),
|
|
2433
|
-
clinicsInfo: z7.array(clinicInfoSchema),
|
|
2434
|
-
procedures: z7.array(z7.string()),
|
|
2435
|
-
freeConsultations: z7.record(z7.string(), z7.string()).optional().nullable(),
|
|
2436
|
-
proceduresInfo: z7.array(procedureSummaryInfoSchema),
|
|
2437
|
-
reviewInfo: practitionerReviewInfoSchema,
|
|
2438
|
-
isActive: z7.boolean(),
|
|
2439
|
-
isVerified: z7.boolean(),
|
|
2440
|
-
status: z7.nativeEnum(PractitionerStatus),
|
|
2441
|
-
createdAt: z7.instanceof(Timestamp3).or(z7.date()),
|
|
2442
|
-
updatedAt: z7.instanceof(Timestamp3).or(z7.date())
|
|
2443
|
-
});
|
|
2444
|
-
var createPractitionerSchema = z7.object({
|
|
2445
|
-
userRef: z7.string().min(1),
|
|
2446
|
-
basicInfo: practitionerBasicInfoSchema,
|
|
2447
|
-
certification: practitionerCertificationSchema,
|
|
2448
|
-
clinics: z7.array(z7.string()).optional(),
|
|
2449
|
-
clinicWorkingHours: z7.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
2450
|
-
clinicsInfo: z7.array(clinicInfoSchema).optional(),
|
|
2451
|
-
freeConsultations: z7.record(z7.string(), z7.string()).optional().nullable(),
|
|
2452
|
-
proceduresInfo: z7.array(procedureSummaryInfoSchema).optional(),
|
|
2453
|
-
isActive: z7.boolean(),
|
|
2454
|
-
isVerified: z7.boolean(),
|
|
2455
|
-
status: z7.nativeEnum(PractitionerStatus).optional()
|
|
2456
|
-
});
|
|
2457
|
-
var createDraftPractitionerSchema = z7.object({
|
|
2458
|
-
basicInfo: practitionerBasicInfoSchema,
|
|
2459
|
-
certification: practitionerCertificationSchema,
|
|
2460
|
-
clinics: z7.array(z7.string()).optional(),
|
|
2461
|
-
clinicWorkingHours: z7.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
2462
|
-
clinicsInfo: z7.array(clinicInfoSchema).optional(),
|
|
2463
|
-
freeConsultations: z7.record(z7.string(), z7.string()).optional().nullable(),
|
|
2464
|
-
proceduresInfo: z7.array(procedureSummaryInfoSchema).optional(),
|
|
2465
|
-
isActive: z7.boolean().optional().default(false),
|
|
2466
|
-
isVerified: z7.boolean().optional().default(false)
|
|
2467
|
-
});
|
|
2468
|
-
var practitionerTokenSchema = z7.object({
|
|
2469
|
-
id: z7.string().min(1),
|
|
2470
|
-
token: z7.string().min(6),
|
|
2471
|
-
practitionerId: z7.string().min(1),
|
|
2472
|
-
email: z7.string().email(),
|
|
2473
|
-
clinicId: z7.string().min(1),
|
|
2474
|
-
status: z7.nativeEnum(PractitionerTokenStatus),
|
|
2475
|
-
createdBy: z7.string().min(1),
|
|
2476
|
-
createdAt: z7.instanceof(Timestamp3).or(z7.date()),
|
|
2477
|
-
expiresAt: z7.instanceof(Timestamp3).or(z7.date()),
|
|
2478
|
-
usedBy: z7.string().optional(),
|
|
2479
|
-
usedAt: z7.instanceof(Timestamp3).or(z7.date()).optional()
|
|
2480
|
-
});
|
|
2481
|
-
var createPractitionerTokenSchema = z7.object({
|
|
2482
|
-
practitionerId: z7.string().min(1),
|
|
2483
|
-
email: z7.string().email(),
|
|
2484
|
-
clinicId: z7.string().min(1),
|
|
2485
|
-
expiresAt: z7.date().optional()
|
|
2486
|
-
});
|
|
2487
|
-
var practitionerSignupSchema = z7.object({
|
|
2488
|
-
email: z7.string().email(),
|
|
2489
|
-
password: z7.string().min(8),
|
|
2490
|
-
firstName: z7.string().min(2).max(50).optional(),
|
|
2491
|
-
lastName: z7.string().min(2).max(50).optional(),
|
|
2492
|
-
token: z7.string().optional(),
|
|
2493
|
-
profileData: z7.object({
|
|
2494
|
-
basicInfo: z7.object({
|
|
2495
|
-
phoneNumber: z7.string().optional(),
|
|
2496
|
-
profileImageUrl: mediaResourceSchema.optional(),
|
|
2497
|
-
gender: z7.enum(["male", "female", "other"]).optional(),
|
|
2498
|
-
bio: z7.string().optional()
|
|
2499
|
-
}).optional(),
|
|
2500
|
-
certification: z7.any().optional()
|
|
2501
|
-
}).optional()
|
|
2502
|
-
});
|
|
2503
|
-
|
|
2504
|
-
// src/services/auth/utils/practitioner.utils.ts
|
|
2505
|
-
var profileDataSchema = z8.object({
|
|
2506
|
-
basicInfo: practitionerBasicInfoSchema.partial().optional(),
|
|
2507
|
-
certification: practitionerCertificationSchema.partial().optional()
|
|
2508
|
-
}).partial();
|
|
2509
|
-
var buildPractitionerData = (data, userRef) => {
|
|
2510
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
2511
|
-
const basicInfo = {
|
|
2512
|
-
firstName: data.firstName || "Name",
|
|
2513
|
-
lastName: data.lastName || "Surname",
|
|
2514
|
-
email: data.email,
|
|
2515
|
-
phoneNumber: ((_b = (_a = data.profileData) == null ? void 0 : _a.basicInfo) == null ? void 0 : _b.phoneNumber) || null,
|
|
2516
|
-
profileImageUrl: ((_d = (_c = data.profileData) == null ? void 0 : _c.basicInfo) == null ? void 0 : _d.profileImageUrl) || "",
|
|
2517
|
-
gender: ((_f = (_e = data.profileData) == null ? void 0 : _e.basicInfo) == null ? void 0 : _f.gender) || "other",
|
|
2518
|
-
bio: ((_h = (_g = data.profileData) == null ? void 0 : _g.basicInfo) == null ? void 0 : _h.bio) || "",
|
|
2519
|
-
title: "Practitioner",
|
|
2520
|
-
dateOfBirth: ((_j = (_i = data.profileData) == null ? void 0 : _i.basicInfo) == null ? void 0 : _j.dateOfBirth) || /* @__PURE__ */ new Date(),
|
|
2521
|
-
languages: ((_l = (_k = data.profileData) == null ? void 0 : _k.basicInfo) == null ? void 0 : _l.languages) || ["English"]
|
|
2522
|
-
};
|
|
2523
|
-
const certification = ((_m = data.profileData) == null ? void 0 : _m.certification) || {
|
|
2524
|
-
level: "aesthetician" /* AESTHETICIAN */,
|
|
2525
|
-
specialties: [],
|
|
2526
|
-
licenseNumber: "Pending",
|
|
2527
|
-
issuingAuthority: "Pending",
|
|
2528
|
-
issueDate: /* @__PURE__ */ new Date(),
|
|
2529
|
-
verificationStatus: "pending"
|
|
2530
|
-
};
|
|
2531
|
-
return {
|
|
2532
|
-
userRef,
|
|
2533
|
-
basicInfo,
|
|
2534
|
-
certification,
|
|
2535
|
-
status: "active" /* ACTIVE */,
|
|
2536
|
-
isActive: true,
|
|
2537
|
-
isVerified: false
|
|
2538
|
-
};
|
|
2539
|
-
};
|
|
2540
|
-
var validatePractitionerProfileData = async (profileData) => {
|
|
2541
|
-
try {
|
|
2542
|
-
await profileDataSchema.parseAsync(profileData);
|
|
2543
|
-
} catch (error) {
|
|
2544
|
-
if (error instanceof z8.ZodError) {
|
|
2545
|
-
const errorMessages = error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
2546
|
-
throw new Error(
|
|
2547
|
-
`Practitioner profile validation failed: ${errorMessages}`
|
|
2548
|
-
);
|
|
2549
|
-
}
|
|
2550
|
-
throw error;
|
|
2551
|
-
}
|
|
2552
|
-
};
|
|
2553
|
-
var isPractitionerDataComplete = (practitioner) => {
|
|
2554
|
-
const { basicInfo, certification } = practitioner;
|
|
2555
|
-
const hasRequiredBasicInfo = basicInfo.firstName && basicInfo.lastName && basicInfo.email && basicInfo.phoneNumber;
|
|
2556
|
-
const hasRequiredCertification = certification.licenseNumber && certification.licenseNumber !== "Pending" && certification.issuingAuthority && certification.issuingAuthority !== "Pending";
|
|
2557
|
-
return !!(hasRequiredBasicInfo && hasRequiredCertification);
|
|
2558
|
-
};
|
|
2559
|
-
|
|
2560
1881
|
// src/services/auth/auth.service.ts
|
|
2561
1882
|
import {
|
|
2562
1883
|
signInWithEmailAndPassword,
|
|
@@ -2718,18 +2039,18 @@ var REVIEWS_COLLECTION = "reviews";
|
|
|
2718
2039
|
import { z as z23 } from "zod";
|
|
2719
2040
|
|
|
2720
2041
|
// src/validations/schemas.ts
|
|
2721
|
-
import { z as
|
|
2722
|
-
var emailSchema =
|
|
2723
|
-
var passwordSchema =
|
|
2042
|
+
import { z as z4 } from "zod";
|
|
2043
|
+
var emailSchema = z4.string().email("Invalid email format").min(5, "Email must be at least 5 characters").max(255, "Email must be less than 255 characters");
|
|
2044
|
+
var passwordSchema = z4.string().min(8, "Password must be at least 8 characters").max(100, "Password must be less than 100 characters").regex(
|
|
2724
2045
|
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d\w\W]{8,}$/,
|
|
2725
2046
|
"Password must contain at least one uppercase letter, one lowercase letter, and one number"
|
|
2726
2047
|
);
|
|
2727
|
-
var userRoleSchema =
|
|
2728
|
-
var userRolesSchema =
|
|
2729
|
-
var clinicAdminOptionsSchema =
|
|
2730
|
-
isGroupOwner:
|
|
2731
|
-
groupToken:
|
|
2732
|
-
groupId:
|
|
2048
|
+
var userRoleSchema = z4.nativeEnum(UserRole);
|
|
2049
|
+
var userRolesSchema = z4.array(userRoleSchema).min(1, "User must have at least one role").max(3, "User cannot have more than 3 roles");
|
|
2050
|
+
var clinicAdminOptionsSchema = z4.object({
|
|
2051
|
+
isGroupOwner: z4.boolean(),
|
|
2052
|
+
groupToken: z4.string().optional(),
|
|
2053
|
+
groupId: z4.string().optional()
|
|
2733
2054
|
}).refine(
|
|
2734
2055
|
(data) => {
|
|
2735
2056
|
if (!data.isGroupOwner && (!data.groupToken || !data.groupId)) {
|
|
@@ -2744,22 +2065,205 @@ var clinicAdminOptionsSchema = z9.object({
|
|
|
2744
2065
|
message: "Invalid clinic admin options configuration"
|
|
2745
2066
|
}
|
|
2746
2067
|
);
|
|
2747
|
-
var createUserOptionsSchema =
|
|
2068
|
+
var createUserOptionsSchema = z4.object({
|
|
2748
2069
|
clinicAdminData: clinicAdminOptionsSchema.optional()
|
|
2749
2070
|
});
|
|
2750
|
-
var userSchema =
|
|
2751
|
-
uid:
|
|
2752
|
-
email:
|
|
2753
|
-
roles:
|
|
2754
|
-
isAnonymous:
|
|
2755
|
-
createdAt:
|
|
2756
|
-
updatedAt:
|
|
2757
|
-
lastLoginAt:
|
|
2758
|
-
patientProfile:
|
|
2759
|
-
practitionerProfile:
|
|
2760
|
-
adminProfile:
|
|
2071
|
+
var userSchema = z4.object({
|
|
2072
|
+
uid: z4.string(),
|
|
2073
|
+
email: z4.string().email().nullable(),
|
|
2074
|
+
roles: z4.array(userRoleSchema),
|
|
2075
|
+
isAnonymous: z4.boolean(),
|
|
2076
|
+
createdAt: z4.any(),
|
|
2077
|
+
updatedAt: z4.any(),
|
|
2078
|
+
lastLoginAt: z4.any(),
|
|
2079
|
+
patientProfile: z4.string().optional(),
|
|
2080
|
+
practitionerProfile: z4.string().optional(),
|
|
2081
|
+
adminProfile: z4.string().optional()
|
|
2761
2082
|
});
|
|
2762
2083
|
|
|
2084
|
+
// src/errors/auth.errors.ts
|
|
2085
|
+
var AuthError = class extends Error {
|
|
2086
|
+
constructor(message, code, status = 400) {
|
|
2087
|
+
super(message);
|
|
2088
|
+
this.code = code;
|
|
2089
|
+
this.status = status;
|
|
2090
|
+
this.name = "AuthError";
|
|
2091
|
+
}
|
|
2092
|
+
};
|
|
2093
|
+
var AUTH_ERRORS = {
|
|
2094
|
+
// Basic validation errors
|
|
2095
|
+
INVALID_EMAIL: new AuthError(
|
|
2096
|
+
"Email address is not in a valid format",
|
|
2097
|
+
"AUTH/INVALID_EMAIL",
|
|
2098
|
+
400
|
|
2099
|
+
),
|
|
2100
|
+
INVALID_PASSWORD: new AuthError(
|
|
2101
|
+
"Password must contain at least 8 characters, one uppercase letter, one number, and one special character",
|
|
2102
|
+
"AUTH/INVALID_PASSWORD",
|
|
2103
|
+
400
|
|
2104
|
+
),
|
|
2105
|
+
INVALID_ROLE: new AuthError(
|
|
2106
|
+
"Specified user role is not valid",
|
|
2107
|
+
"AUTH/INVALID_ROLE",
|
|
2108
|
+
400
|
|
2109
|
+
),
|
|
2110
|
+
// Authentication errors
|
|
2111
|
+
NOT_AUTHENTICATED: new AuthError(
|
|
2112
|
+
"User is not authenticated",
|
|
2113
|
+
"AUTH/NOT_AUTHENTICATED",
|
|
2114
|
+
401
|
|
2115
|
+
),
|
|
2116
|
+
SESSION_EXPIRED: new AuthError(
|
|
2117
|
+
"Your session has expired. Please sign in again",
|
|
2118
|
+
"AUTH/SESSION_EXPIRED",
|
|
2119
|
+
401
|
|
2120
|
+
),
|
|
2121
|
+
INVALID_TOKEN: new AuthError(
|
|
2122
|
+
"Invalid authentication token",
|
|
2123
|
+
"AUTH/INVALID_TOKEN",
|
|
2124
|
+
401
|
|
2125
|
+
),
|
|
2126
|
+
// User state errors
|
|
2127
|
+
USER_NOT_FOUND: new AuthError(
|
|
2128
|
+
"User not found in the system",
|
|
2129
|
+
"AUTH/USER_NOT_FOUND",
|
|
2130
|
+
404
|
|
2131
|
+
),
|
|
2132
|
+
EMAIL_ALREADY_EXISTS: new AuthError(
|
|
2133
|
+
"An account with this email already exists",
|
|
2134
|
+
"AUTH/EMAIL_EXISTS",
|
|
2135
|
+
409
|
|
2136
|
+
),
|
|
2137
|
+
USER_DISABLED: new AuthError(
|
|
2138
|
+
"This account has been disabled",
|
|
2139
|
+
"AUTH/USER_DISABLED",
|
|
2140
|
+
403
|
|
2141
|
+
),
|
|
2142
|
+
// Rate limiting and security
|
|
2143
|
+
TOO_MANY_REQUESTS: new AuthError(
|
|
2144
|
+
"Too many login attempts. Please try again later",
|
|
2145
|
+
"AUTH/TOO_MANY_REQUESTS",
|
|
2146
|
+
429
|
|
2147
|
+
),
|
|
2148
|
+
ACCOUNT_LOCKED: new AuthError(
|
|
2149
|
+
"Account temporarily locked due to too many failed login attempts",
|
|
2150
|
+
"AUTH/ACCOUNT_LOCKED",
|
|
2151
|
+
403
|
|
2152
|
+
),
|
|
2153
|
+
// Social auth specific
|
|
2154
|
+
POPUP_CLOSED: new AuthError(
|
|
2155
|
+
"Authentication popup was closed before completion",
|
|
2156
|
+
"AUTH/POPUP_CLOSED",
|
|
2157
|
+
400
|
|
2158
|
+
),
|
|
2159
|
+
POPUP_BLOCKED: new AuthError(
|
|
2160
|
+
"Authentication popup was blocked by the browser",
|
|
2161
|
+
"AUTH/POPUP_BLOCKED",
|
|
2162
|
+
400
|
|
2163
|
+
),
|
|
2164
|
+
ACCOUNT_EXISTS: new AuthError(
|
|
2165
|
+
"An account already exists with different credentials",
|
|
2166
|
+
"AUTH/ACCOUNT_EXISTS",
|
|
2167
|
+
409
|
|
2168
|
+
),
|
|
2169
|
+
// Anonymous auth specific
|
|
2170
|
+
NOT_ANONYMOUS: new AuthError(
|
|
2171
|
+
"Current user is not anonymous",
|
|
2172
|
+
"AUTH/NOT_ANONYMOUS_USER",
|
|
2173
|
+
400
|
|
2174
|
+
),
|
|
2175
|
+
ANONYMOUS_UPGRADE_FAILED: new AuthError(
|
|
2176
|
+
"Failed to upgrade anonymous account",
|
|
2177
|
+
"AUTH/ANONYMOUS_UPGRADE_FAILED",
|
|
2178
|
+
400
|
|
2179
|
+
),
|
|
2180
|
+
// General errors
|
|
2181
|
+
VALIDATION_ERROR: new AuthError(
|
|
2182
|
+
"Data validation error occurred",
|
|
2183
|
+
"AUTH/VALIDATION_ERROR",
|
|
2184
|
+
400
|
|
2185
|
+
),
|
|
2186
|
+
OPERATION_NOT_ALLOWED: new AuthError(
|
|
2187
|
+
"This operation is not allowed",
|
|
2188
|
+
"AUTH/OPERATION_NOT_ALLOWED",
|
|
2189
|
+
403
|
|
2190
|
+
),
|
|
2191
|
+
NETWORK_ERROR: new AuthError(
|
|
2192
|
+
"Network error occurred. Please check your connection",
|
|
2193
|
+
"AUTH/NETWORK_ERROR",
|
|
2194
|
+
503
|
|
2195
|
+
),
|
|
2196
|
+
REQUIRES_RECENT_LOGIN: new AuthError(
|
|
2197
|
+
"This operation requires recent authentication. Please sign in again",
|
|
2198
|
+
"AUTH/REQUIRES_RECENT_LOGIN",
|
|
2199
|
+
401
|
|
2200
|
+
),
|
|
2201
|
+
INVALID_PROVIDER: new AuthError(
|
|
2202
|
+
"Invalid authentication provider",
|
|
2203
|
+
"AUTH/INVALID_PROVIDER",
|
|
2204
|
+
400
|
|
2205
|
+
),
|
|
2206
|
+
INVALID_CREDENTIAL: new AuthError(
|
|
2207
|
+
"The provided credentials are invalid or expired",
|
|
2208
|
+
"AUTH/INVALID_CREDENTIAL",
|
|
2209
|
+
401
|
|
2210
|
+
),
|
|
2211
|
+
// Resource not found
|
|
2212
|
+
NOT_FOUND: new AuthError(
|
|
2213
|
+
"The requested resource was not found",
|
|
2214
|
+
"AUTH/NOT_FOUND",
|
|
2215
|
+
404
|
|
2216
|
+
),
|
|
2217
|
+
// Detailed password validation errors
|
|
2218
|
+
PASSWORD_LENGTH_ERROR: new AuthError(
|
|
2219
|
+
"Password must be at least 8 characters long",
|
|
2220
|
+
"AUTH/PASSWORD_LENGTH_ERROR",
|
|
2221
|
+
400
|
|
2222
|
+
),
|
|
2223
|
+
PASSWORD_UPPERCASE_ERROR: new AuthError(
|
|
2224
|
+
"Password must contain at least one uppercase letter",
|
|
2225
|
+
"AUTH/PASSWORD_UPPERCASE_ERROR",
|
|
2226
|
+
400
|
|
2227
|
+
),
|
|
2228
|
+
PASSWORD_NUMBER_ERROR: new AuthError(
|
|
2229
|
+
"Password must contain at least one number",
|
|
2230
|
+
"AUTH/PASSWORD_NUMBER_ERROR",
|
|
2231
|
+
400
|
|
2232
|
+
),
|
|
2233
|
+
PASSWORD_SPECIAL_CHAR_ERROR: new AuthError(
|
|
2234
|
+
"Password must contain at least one special character",
|
|
2235
|
+
"AUTH/PASSWORD_SPECIAL_CHAR_ERROR",
|
|
2236
|
+
400
|
|
2237
|
+
),
|
|
2238
|
+
// Detailed email validation errors
|
|
2239
|
+
EMAIL_FORMAT_ERROR: new AuthError(
|
|
2240
|
+
"Invalid email format. Please enter a valid email address",
|
|
2241
|
+
"AUTH/EMAIL_FORMAT_ERROR",
|
|
2242
|
+
400
|
|
2243
|
+
),
|
|
2244
|
+
PASSWORD_VALIDATION_ERROR: new AuthError(
|
|
2245
|
+
"Password validation failed. Please check all requirements",
|
|
2246
|
+
"AUTH/PASSWORD_VALIDATION_ERROR",
|
|
2247
|
+
400
|
|
2248
|
+
),
|
|
2249
|
+
// Password reset specific errors
|
|
2250
|
+
EXPIRED_ACTION_CODE: new AuthError(
|
|
2251
|
+
"Kod za resetovanje lozinke je istekao. Molimo zatra\u017Eite novi link za resetovanje.",
|
|
2252
|
+
"AUTH/EXPIRED_ACTION_CODE",
|
|
2253
|
+
400
|
|
2254
|
+
),
|
|
2255
|
+
INVALID_ACTION_CODE: new AuthError(
|
|
2256
|
+
"Kod za resetovanje lozinke je neva\u017Ee\u0107i ili je ve\u0107 iskori\u0161\u0107en. Molimo zatra\u017Eite novi link za resetovanje.",
|
|
2257
|
+
"AUTH/INVALID_ACTION_CODE",
|
|
2258
|
+
400
|
|
2259
|
+
),
|
|
2260
|
+
WEAK_PASSWORD: new AuthError(
|
|
2261
|
+
"Lozinka je previ\u0161e slaba. Molimo koristite ja\u010Du lozinku.",
|
|
2262
|
+
"AUTH/WEAK_PASSWORD",
|
|
2263
|
+
400
|
|
2264
|
+
)
|
|
2265
|
+
};
|
|
2266
|
+
|
|
2763
2267
|
// src/services/user/user.service.ts
|
|
2764
2268
|
import {
|
|
2765
2269
|
collection as collection11,
|
|
@@ -2868,7 +2372,7 @@ var USER_ERRORS = {
|
|
|
2868
2372
|
};
|
|
2869
2373
|
|
|
2870
2374
|
// src/services/user/user.service.ts
|
|
2871
|
-
import { z as
|
|
2375
|
+
import { z as z17 } from "zod";
|
|
2872
2376
|
|
|
2873
2377
|
// src/services/patient/patient.service.ts
|
|
2874
2378
|
import {
|
|
@@ -2880,7 +2384,7 @@ import {
|
|
|
2880
2384
|
} from "firebase/firestore";
|
|
2881
2385
|
|
|
2882
2386
|
// src/services/media/media.service.ts
|
|
2883
|
-
import { Timestamp as
|
|
2387
|
+
import { Timestamp as Timestamp3 } from "firebase/firestore";
|
|
2884
2388
|
import {
|
|
2885
2389
|
ref,
|
|
2886
2390
|
uploadBytes,
|
|
@@ -2941,7 +2445,7 @@ var MediaService = class extends BaseService {
|
|
|
2941
2445
|
url: downloadURL,
|
|
2942
2446
|
contentType: file.type,
|
|
2943
2447
|
size: file.size,
|
|
2944
|
-
createdAt:
|
|
2448
|
+
createdAt: Timestamp3.now(),
|
|
2945
2449
|
accessLevel,
|
|
2946
2450
|
ownerId,
|
|
2947
2451
|
collectionName,
|
|
@@ -3050,8 +2554,8 @@ var MediaService = class extends BaseService {
|
|
|
3050
2554
|
);
|
|
3051
2555
|
const metadataDocRef = doc2(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
3052
2556
|
try {
|
|
3053
|
-
await updateDoc2(metadataDocRef, { updatedAt:
|
|
3054
|
-
return { ...metadata, updatedAt:
|
|
2557
|
+
await updateDoc2(metadataDocRef, { updatedAt: Timestamp3.now() });
|
|
2558
|
+
return { ...metadata, updatedAt: Timestamp3.now() };
|
|
3055
2559
|
} catch (error) {
|
|
3056
2560
|
console.error(
|
|
3057
2561
|
`[MediaService] Error updating timestamp for media ID ${mediaId}:`,
|
|
@@ -3089,7 +2593,7 @@ var MediaService = class extends BaseService {
|
|
|
3089
2593
|
accessLevel: newAccessLevel,
|
|
3090
2594
|
path: newStoragePath,
|
|
3091
2595
|
url: newDownloadURL,
|
|
3092
|
-
updatedAt:
|
|
2596
|
+
updatedAt: Timestamp3.now()
|
|
3093
2597
|
};
|
|
3094
2598
|
const metadataDocRef = doc2(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
3095
2599
|
console.log(
|
|
@@ -3196,7 +2700,7 @@ var MediaService = class extends BaseService {
|
|
|
3196
2700
|
};
|
|
3197
2701
|
|
|
3198
2702
|
// src/services/patient/patient.service.ts
|
|
3199
|
-
import { Timestamp as
|
|
2703
|
+
import { Timestamp as Timestamp12 } from "firebase/firestore";
|
|
3200
2704
|
|
|
3201
2705
|
// src/services/patient/utils/clinic.utils.ts
|
|
3202
2706
|
import {
|
|
@@ -3270,11 +2774,11 @@ import {
|
|
|
3270
2774
|
} from "firebase/firestore";
|
|
3271
2775
|
|
|
3272
2776
|
// src/validations/patient.schema.ts
|
|
3273
|
-
import { z as
|
|
3274
|
-
import { Timestamp as
|
|
2777
|
+
import { z as z7 } from "zod";
|
|
2778
|
+
import { Timestamp as Timestamp5 } from "firebase/firestore";
|
|
3275
2779
|
|
|
3276
2780
|
// src/validations/patient/medical-info.schema.ts
|
|
3277
|
-
import { z as
|
|
2781
|
+
import { z as z6 } from "zod";
|
|
3278
2782
|
|
|
3279
2783
|
// src/backoffice/types/static/blocking-condition.types.ts
|
|
3280
2784
|
var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
|
|
@@ -3314,85 +2818,85 @@ var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
|
|
|
3314
2818
|
})(Contraindication || {});
|
|
3315
2819
|
|
|
3316
2820
|
// src/validations/common.schema.ts
|
|
3317
|
-
import { z as
|
|
3318
|
-
import { Timestamp as
|
|
3319
|
-
var timestampSchema =
|
|
3320
|
-
|
|
3321
|
-
seconds:
|
|
3322
|
-
nanoseconds:
|
|
2821
|
+
import { z as z5 } from "zod";
|
|
2822
|
+
import { Timestamp as Timestamp4 } from "firebase/firestore";
|
|
2823
|
+
var timestampSchema = z5.union([
|
|
2824
|
+
z5.object({
|
|
2825
|
+
seconds: z5.number(),
|
|
2826
|
+
nanoseconds: z5.number()
|
|
3323
2827
|
}),
|
|
3324
|
-
|
|
3325
|
-
|
|
2828
|
+
z5.instanceof(Timestamp4),
|
|
2829
|
+
z5.instanceof(Date)
|
|
3326
2830
|
// Add support for Date objects that Firestore returns on client
|
|
3327
2831
|
]).transform((data) => {
|
|
3328
|
-
if (data instanceof
|
|
2832
|
+
if (data instanceof Timestamp4) {
|
|
3329
2833
|
return data;
|
|
3330
2834
|
}
|
|
3331
2835
|
if (data instanceof Date) {
|
|
3332
|
-
return
|
|
2836
|
+
return Timestamp4.fromDate(data);
|
|
3333
2837
|
}
|
|
3334
|
-
return new
|
|
2838
|
+
return new Timestamp4(data.seconds, data.nanoseconds);
|
|
3335
2839
|
});
|
|
3336
2840
|
|
|
3337
2841
|
// src/validations/patient/medical-info.schema.ts
|
|
3338
|
-
var allergySubtypeSchema =
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
2842
|
+
var allergySubtypeSchema = z6.union([
|
|
2843
|
+
z6.nativeEnum(MedicationAllergySubtype),
|
|
2844
|
+
z6.nativeEnum(FoodAllergySubtype),
|
|
2845
|
+
z6.nativeEnum(EnvironmentalAllergySubtype),
|
|
2846
|
+
z6.nativeEnum(CosmeticAllergySubtype),
|
|
2847
|
+
z6.literal("other")
|
|
3344
2848
|
]);
|
|
3345
|
-
var allergySchema =
|
|
3346
|
-
type:
|
|
2849
|
+
var allergySchema = z6.object({
|
|
2850
|
+
type: z6.nativeEnum(AllergyType),
|
|
3347
2851
|
subtype: allergySubtypeSchema,
|
|
3348
|
-
name:
|
|
3349
|
-
severity:
|
|
3350
|
-
reaction:
|
|
2852
|
+
name: z6.string().optional().nullable(),
|
|
2853
|
+
severity: z6.enum(["mild", "moderate", "severe"]).optional(),
|
|
2854
|
+
reaction: z6.string().optional().nullable(),
|
|
3351
2855
|
diagnosed: timestampSchema.optional().nullable(),
|
|
3352
|
-
notes:
|
|
2856
|
+
notes: z6.string().optional().nullable()
|
|
3353
2857
|
});
|
|
3354
|
-
var vitalStatsSchema =
|
|
3355
|
-
height:
|
|
3356
|
-
weight:
|
|
3357
|
-
bloodType:
|
|
3358
|
-
bloodPressure:
|
|
3359
|
-
systolic:
|
|
3360
|
-
diastolic:
|
|
2858
|
+
var vitalStatsSchema = z6.object({
|
|
2859
|
+
height: z6.number().positive().optional(),
|
|
2860
|
+
weight: z6.number().positive().optional(),
|
|
2861
|
+
bloodType: z6.enum(["A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"]).optional(),
|
|
2862
|
+
bloodPressure: z6.object({
|
|
2863
|
+
systolic: z6.number().min(70).max(200),
|
|
2864
|
+
diastolic: z6.number().min(40).max(130),
|
|
3361
2865
|
lastMeasured: timestampSchema
|
|
3362
2866
|
}).optional()
|
|
3363
2867
|
});
|
|
3364
|
-
var blockingConditionSchema =
|
|
3365
|
-
condition:
|
|
2868
|
+
var blockingConditionSchema = z6.object({
|
|
2869
|
+
condition: z6.nativeEnum(BlockingCondition),
|
|
3366
2870
|
diagnosedAt: timestampSchema,
|
|
3367
|
-
notes:
|
|
3368
|
-
isActive:
|
|
2871
|
+
notes: z6.string().optional().nullable(),
|
|
2872
|
+
isActive: z6.boolean()
|
|
3369
2873
|
});
|
|
3370
|
-
var contraindicationSchema =
|
|
3371
|
-
condition:
|
|
2874
|
+
var contraindicationSchema = z6.object({
|
|
2875
|
+
condition: z6.nativeEnum(Contraindication),
|
|
3372
2876
|
lastOccurrence: timestampSchema,
|
|
3373
|
-
frequency:
|
|
3374
|
-
notes:
|
|
3375
|
-
isActive:
|
|
2877
|
+
frequency: z6.enum(["rare", "occasional", "frequent"]),
|
|
2878
|
+
notes: z6.string().optional().nullable(),
|
|
2879
|
+
isActive: z6.boolean()
|
|
3376
2880
|
});
|
|
3377
|
-
var medicationSchema =
|
|
3378
|
-
name:
|
|
3379
|
-
dosage:
|
|
3380
|
-
frequency:
|
|
2881
|
+
var medicationSchema = z6.object({
|
|
2882
|
+
name: z6.string().min(1),
|
|
2883
|
+
dosage: z6.string().min(1),
|
|
2884
|
+
frequency: z6.string().min(1),
|
|
3381
2885
|
startDate: timestampSchema.optional().nullable(),
|
|
3382
2886
|
endDate: timestampSchema.optional().nullable(),
|
|
3383
|
-
prescribedBy:
|
|
2887
|
+
prescribedBy: z6.string().optional().nullable()
|
|
3384
2888
|
});
|
|
3385
|
-
var patientMedicalInfoSchema =
|
|
3386
|
-
patientId:
|
|
2889
|
+
var patientMedicalInfoSchema = z6.object({
|
|
2890
|
+
patientId: z6.string(),
|
|
3387
2891
|
vitalStats: vitalStatsSchema,
|
|
3388
|
-
blockingConditions:
|
|
3389
|
-
contraindications:
|
|
3390
|
-
allergies:
|
|
3391
|
-
currentMedications:
|
|
3392
|
-
emergencyNotes:
|
|
2892
|
+
blockingConditions: z6.array(blockingConditionSchema),
|
|
2893
|
+
contraindications: z6.array(contraindicationSchema),
|
|
2894
|
+
allergies: z6.array(allergySchema),
|
|
2895
|
+
currentMedications: z6.array(medicationSchema),
|
|
2896
|
+
emergencyNotes: z6.string().optional(),
|
|
3393
2897
|
lastUpdated: timestampSchema,
|
|
3394
|
-
updatedBy:
|
|
3395
|
-
verifiedBy:
|
|
2898
|
+
updatedBy: z6.string(),
|
|
2899
|
+
verifiedBy: z6.string().optional(),
|
|
3396
2900
|
verifiedAt: timestampSchema.optional()
|
|
3397
2901
|
});
|
|
3398
2902
|
var createPatientMedicalInfoSchema = patientMedicalInfoSchema.omit({
|
|
@@ -3406,155 +2910,155 @@ var updatePatientMedicalInfoSchema = createPatientMedicalInfoSchema.partial();
|
|
|
3406
2910
|
var updateVitalStatsSchema = vitalStatsSchema;
|
|
3407
2911
|
var addAllergySchema = allergySchema;
|
|
3408
2912
|
var updateAllergySchema = allergySchema.partial().extend({
|
|
3409
|
-
allergyIndex:
|
|
2913
|
+
allergyIndex: z6.number().min(0)
|
|
3410
2914
|
});
|
|
3411
2915
|
var addBlockingConditionSchema = blockingConditionSchema;
|
|
3412
2916
|
var updateBlockingConditionSchema = blockingConditionSchema.partial().extend({
|
|
3413
|
-
conditionIndex:
|
|
2917
|
+
conditionIndex: z6.number().min(0)
|
|
3414
2918
|
});
|
|
3415
2919
|
var addContraindicationSchema = contraindicationSchema;
|
|
3416
2920
|
var updateContraindicationSchema = contraindicationSchema.partial().extend({
|
|
3417
|
-
contraindicationIndex:
|
|
2921
|
+
contraindicationIndex: z6.number().min(0)
|
|
3418
2922
|
});
|
|
3419
2923
|
var addMedicationSchema = medicationSchema;
|
|
3420
2924
|
var updateMedicationSchema = medicationSchema.partial().extend({
|
|
3421
|
-
medicationIndex:
|
|
2925
|
+
medicationIndex: z6.number().min(0)
|
|
3422
2926
|
});
|
|
3423
2927
|
|
|
3424
2928
|
// src/validations/patient.schema.ts
|
|
3425
|
-
var locationDataSchema =
|
|
3426
|
-
latitude:
|
|
3427
|
-
longitude:
|
|
3428
|
-
geohash:
|
|
2929
|
+
var locationDataSchema = z7.object({
|
|
2930
|
+
latitude: z7.number().min(-90).max(90),
|
|
2931
|
+
longitude: z7.number().min(-180).max(180),
|
|
2932
|
+
geohash: z7.string().optional()
|
|
3429
2933
|
});
|
|
3430
|
-
var addressDataSchema =
|
|
3431
|
-
address:
|
|
3432
|
-
city:
|
|
3433
|
-
country:
|
|
3434
|
-
postalCode:
|
|
2934
|
+
var addressDataSchema = z7.object({
|
|
2935
|
+
address: z7.string(),
|
|
2936
|
+
city: z7.string(),
|
|
2937
|
+
country: z7.string(),
|
|
2938
|
+
postalCode: z7.string()
|
|
3435
2939
|
});
|
|
3436
|
-
var emergencyContactSchema =
|
|
3437
|
-
name:
|
|
3438
|
-
relationship:
|
|
3439
|
-
phoneNumber:
|
|
3440
|
-
isNotifiable:
|
|
2940
|
+
var emergencyContactSchema = z7.object({
|
|
2941
|
+
name: z7.string(),
|
|
2942
|
+
relationship: z7.string(),
|
|
2943
|
+
phoneNumber: z7.string(),
|
|
2944
|
+
isNotifiable: z7.boolean()
|
|
3441
2945
|
});
|
|
3442
|
-
var gamificationSchema =
|
|
3443
|
-
level:
|
|
3444
|
-
points:
|
|
2946
|
+
var gamificationSchema = z7.object({
|
|
2947
|
+
level: z7.number(),
|
|
2948
|
+
points: z7.number()
|
|
3445
2949
|
});
|
|
3446
|
-
var patientLocationInfoSchema =
|
|
3447
|
-
patientId:
|
|
3448
|
-
userRef:
|
|
2950
|
+
var patientLocationInfoSchema = z7.object({
|
|
2951
|
+
patientId: z7.string(),
|
|
2952
|
+
userRef: z7.string().optional(),
|
|
3449
2953
|
locationData: locationDataSchema,
|
|
3450
|
-
createdAt:
|
|
3451
|
-
updatedAt:
|
|
2954
|
+
createdAt: z7.instanceof(Timestamp5),
|
|
2955
|
+
updatedAt: z7.instanceof(Timestamp5)
|
|
3452
2956
|
});
|
|
3453
|
-
var createPatientLocationInfoSchema =
|
|
3454
|
-
patientId:
|
|
3455
|
-
userRef:
|
|
2957
|
+
var createPatientLocationInfoSchema = z7.object({
|
|
2958
|
+
patientId: z7.string(),
|
|
2959
|
+
userRef: z7.string().optional(),
|
|
3456
2960
|
locationData: locationDataSchema
|
|
3457
2961
|
});
|
|
3458
|
-
var patientSensitiveInfoSchema =
|
|
3459
|
-
patientId:
|
|
3460
|
-
userRef:
|
|
3461
|
-
photoUrl:
|
|
3462
|
-
firstName:
|
|
3463
|
-
lastName:
|
|
3464
|
-
dateOfBirth:
|
|
3465
|
-
gender:
|
|
3466
|
-
email:
|
|
3467
|
-
phoneNumber:
|
|
3468
|
-
alternativePhoneNumber:
|
|
2962
|
+
var patientSensitiveInfoSchema = z7.object({
|
|
2963
|
+
patientId: z7.string(),
|
|
2964
|
+
userRef: z7.string().optional(),
|
|
2965
|
+
photoUrl: z7.string().nullable().optional(),
|
|
2966
|
+
firstName: z7.string().min(2),
|
|
2967
|
+
lastName: z7.string().min(2),
|
|
2968
|
+
dateOfBirth: z7.instanceof(Timestamp5).nullable(),
|
|
2969
|
+
gender: z7.nativeEnum(Gender),
|
|
2970
|
+
email: z7.string().email().optional(),
|
|
2971
|
+
phoneNumber: z7.string().optional(),
|
|
2972
|
+
alternativePhoneNumber: z7.string().optional(),
|
|
3469
2973
|
addressData: addressDataSchema.optional(),
|
|
3470
|
-
emergencyContacts:
|
|
3471
|
-
createdAt:
|
|
3472
|
-
updatedAt:
|
|
2974
|
+
emergencyContacts: z7.array(emergencyContactSchema).optional(),
|
|
2975
|
+
createdAt: z7.instanceof(Timestamp5),
|
|
2976
|
+
updatedAt: z7.instanceof(Timestamp5)
|
|
3473
2977
|
});
|
|
3474
|
-
var patientDoctorSchema =
|
|
3475
|
-
userRef:
|
|
3476
|
-
assignedAt:
|
|
3477
|
-
assignedBy:
|
|
3478
|
-
isActive:
|
|
3479
|
-
notes:
|
|
2978
|
+
var patientDoctorSchema = z7.object({
|
|
2979
|
+
userRef: z7.string(),
|
|
2980
|
+
assignedAt: z7.instanceof(Timestamp5),
|
|
2981
|
+
assignedBy: z7.string().optional(),
|
|
2982
|
+
isActive: z7.boolean(),
|
|
2983
|
+
notes: z7.string().optional()
|
|
3480
2984
|
});
|
|
3481
|
-
var patientClinicSchema =
|
|
3482
|
-
clinicId:
|
|
3483
|
-
assignedAt:
|
|
3484
|
-
assignedBy:
|
|
3485
|
-
isActive:
|
|
3486
|
-
notes:
|
|
2985
|
+
var patientClinicSchema = z7.object({
|
|
2986
|
+
clinicId: z7.string(),
|
|
2987
|
+
assignedAt: z7.instanceof(Timestamp5),
|
|
2988
|
+
assignedBy: z7.string().optional(),
|
|
2989
|
+
isActive: z7.boolean(),
|
|
2990
|
+
notes: z7.string().optional()
|
|
3487
2991
|
});
|
|
3488
|
-
var patientProfileSchema =
|
|
3489
|
-
id:
|
|
3490
|
-
userRef:
|
|
3491
|
-
displayName:
|
|
2992
|
+
var patientProfileSchema = z7.object({
|
|
2993
|
+
id: z7.string(),
|
|
2994
|
+
userRef: z7.string().optional(),
|
|
2995
|
+
displayName: z7.string(),
|
|
3492
2996
|
gamification: gamificationSchema,
|
|
3493
|
-
expoTokens:
|
|
3494
|
-
isActive:
|
|
3495
|
-
isVerified:
|
|
3496
|
-
isManual:
|
|
2997
|
+
expoTokens: z7.array(z7.string()),
|
|
2998
|
+
isActive: z7.boolean(),
|
|
2999
|
+
isVerified: z7.boolean(),
|
|
3000
|
+
isManual: z7.boolean().default(false),
|
|
3497
3001
|
// Default to false if missing
|
|
3498
|
-
phoneNumber:
|
|
3499
|
-
dateOfBirth:
|
|
3500
|
-
doctors:
|
|
3501
|
-
clinics:
|
|
3502
|
-
doctorIds:
|
|
3503
|
-
clinicIds:
|
|
3504
|
-
createdAt:
|
|
3505
|
-
updatedAt:
|
|
3002
|
+
phoneNumber: z7.string().nullable().optional(),
|
|
3003
|
+
dateOfBirth: z7.instanceof(Timestamp5).nullable().optional(),
|
|
3004
|
+
doctors: z7.array(patientDoctorSchema),
|
|
3005
|
+
clinics: z7.array(patientClinicSchema),
|
|
3006
|
+
doctorIds: z7.array(z7.string()),
|
|
3007
|
+
clinicIds: z7.array(z7.string()),
|
|
3008
|
+
createdAt: z7.instanceof(Timestamp5),
|
|
3009
|
+
updatedAt: z7.instanceof(Timestamp5)
|
|
3506
3010
|
});
|
|
3507
|
-
var createPatientProfileSchema =
|
|
3508
|
-
userRef:
|
|
3509
|
-
displayName:
|
|
3510
|
-
expoTokens:
|
|
3011
|
+
var createPatientProfileSchema = z7.object({
|
|
3012
|
+
userRef: z7.string().optional(),
|
|
3013
|
+
displayName: z7.string(),
|
|
3014
|
+
expoTokens: z7.array(z7.string()),
|
|
3511
3015
|
gamification: gamificationSchema.optional(),
|
|
3512
|
-
isActive:
|
|
3513
|
-
isVerified:
|
|
3514
|
-
isManual:
|
|
3515
|
-
doctors:
|
|
3516
|
-
clinics:
|
|
3517
|
-
doctorIds:
|
|
3518
|
-
clinicIds:
|
|
3016
|
+
isActive: z7.boolean(),
|
|
3017
|
+
isVerified: z7.boolean(),
|
|
3018
|
+
isManual: z7.boolean().default(false),
|
|
3019
|
+
doctors: z7.array(patientDoctorSchema).optional(),
|
|
3020
|
+
clinics: z7.array(patientClinicSchema).optional(),
|
|
3021
|
+
doctorIds: z7.array(z7.string()).optional(),
|
|
3022
|
+
clinicIds: z7.array(z7.string()).optional()
|
|
3519
3023
|
});
|
|
3520
|
-
var createPatientSensitiveInfoSchema =
|
|
3521
|
-
patientId:
|
|
3522
|
-
userRef:
|
|
3024
|
+
var createPatientSensitiveInfoSchema = z7.object({
|
|
3025
|
+
patientId: z7.string(),
|
|
3026
|
+
userRef: z7.string().optional(),
|
|
3523
3027
|
photoUrl: mediaResourceSchema.nullable().optional(),
|
|
3524
|
-
firstName:
|
|
3525
|
-
lastName:
|
|
3526
|
-
dateOfBirth:
|
|
3527
|
-
gender:
|
|
3528
|
-
email:
|
|
3529
|
-
phoneNumber:
|
|
3530
|
-
alternativePhoneNumber:
|
|
3028
|
+
firstName: z7.string().min(2),
|
|
3029
|
+
lastName: z7.string().min(2),
|
|
3030
|
+
dateOfBirth: z7.instanceof(Timestamp5).nullable(),
|
|
3031
|
+
gender: z7.nativeEnum(Gender),
|
|
3032
|
+
email: z7.string().email().optional(),
|
|
3033
|
+
phoneNumber: z7.string().optional(),
|
|
3034
|
+
alternativePhoneNumber: z7.string().optional(),
|
|
3531
3035
|
addressData: addressDataSchema.optional(),
|
|
3532
|
-
emergencyContacts:
|
|
3036
|
+
emergencyContacts: z7.array(emergencyContactSchema).optional()
|
|
3533
3037
|
});
|
|
3534
|
-
var createManualPatientSchema =
|
|
3535
|
-
clinicId:
|
|
3536
|
-
firstName:
|
|
3537
|
-
lastName:
|
|
3538
|
-
dateOfBirth:
|
|
3539
|
-
gender:
|
|
3540
|
-
phoneNumber:
|
|
3541
|
-
email:
|
|
3038
|
+
var createManualPatientSchema = z7.object({
|
|
3039
|
+
clinicId: z7.string().min(1, "Clinic ID is required"),
|
|
3040
|
+
firstName: z7.string().min(2, "First name is required"),
|
|
3041
|
+
lastName: z7.string().min(2, "Last name is required"),
|
|
3042
|
+
dateOfBirth: z7.instanceof(Timestamp5).nullable(),
|
|
3043
|
+
gender: z7.nativeEnum(Gender),
|
|
3044
|
+
phoneNumber: z7.string().optional(),
|
|
3045
|
+
email: z7.string().email().optional(),
|
|
3542
3046
|
addressData: addressDataSchema.optional(),
|
|
3543
|
-
notes:
|
|
3047
|
+
notes: z7.string().optional()
|
|
3544
3048
|
});
|
|
3545
|
-
var searchPatientsSchema =
|
|
3546
|
-
clinicId:
|
|
3547
|
-
practitionerId:
|
|
3049
|
+
var searchPatientsSchema = z7.object({
|
|
3050
|
+
clinicId: z7.string().optional(),
|
|
3051
|
+
practitionerId: z7.string().optional()
|
|
3548
3052
|
}).refine((data) => data.clinicId || data.practitionerId, {
|
|
3549
3053
|
message: "At least one of clinicId or practitionerId must be provided",
|
|
3550
3054
|
path: []
|
|
3551
3055
|
// Optional: specify a path like ['clinicId'] or ['practitionerId']
|
|
3552
3056
|
});
|
|
3553
|
-
var requesterInfoSchema =
|
|
3554
|
-
id:
|
|
3555
|
-
role:
|
|
3556
|
-
associatedClinicId:
|
|
3557
|
-
associatedPractitionerId:
|
|
3057
|
+
var requesterInfoSchema = z7.object({
|
|
3058
|
+
id: z7.string(),
|
|
3059
|
+
role: z7.enum(["clinic_admin", "practitioner"]),
|
|
3060
|
+
associatedClinicId: z7.string().optional(),
|
|
3061
|
+
associatedPractitionerId: z7.string().optional()
|
|
3558
3062
|
}).refine(
|
|
3559
3063
|
(data) => {
|
|
3560
3064
|
if (data.role === "clinic_admin") {
|
|
@@ -3571,7 +3075,7 @@ var requesterInfoSchema = z12.object({
|
|
|
3571
3075
|
);
|
|
3572
3076
|
|
|
3573
3077
|
// src/services/patient/utils/sensitive.utils.ts
|
|
3574
|
-
import { z as
|
|
3078
|
+
import { z as z11 } from "zod";
|
|
3575
3079
|
|
|
3576
3080
|
// src/services/patient/utils/practitioner.utils.ts
|
|
3577
3081
|
import {
|
|
@@ -3703,52 +3207,249 @@ var getPractitionerProfileByUserRef = async (db, userRef) => {
|
|
|
3703
3207
|
`Failed to retrieve practitioner by userRef: ${error instanceof Error ? error.message : String(error)}`
|
|
3704
3208
|
);
|
|
3705
3209
|
}
|
|
3706
|
-
};
|
|
3210
|
+
};
|
|
3211
|
+
|
|
3212
|
+
// src/services/clinic/utils/admin.utils.ts
|
|
3213
|
+
import {
|
|
3214
|
+
collection as collection6,
|
|
3215
|
+
doc as doc5,
|
|
3216
|
+
getDoc as getDoc5,
|
|
3217
|
+
getDocs as getDocs6,
|
|
3218
|
+
query as query6,
|
|
3219
|
+
where as where6,
|
|
3220
|
+
updateDoc as updateDoc3,
|
|
3221
|
+
setDoc as setDoc3,
|
|
3222
|
+
deleteDoc as deleteDoc2,
|
|
3223
|
+
Timestamp as Timestamp7,
|
|
3224
|
+
serverTimestamp as serverTimestamp3
|
|
3225
|
+
} from "firebase/firestore";
|
|
3226
|
+
|
|
3227
|
+
// src/validations/clinic.schema.ts
|
|
3228
|
+
import { z as z10 } from "zod";
|
|
3229
|
+
import { Timestamp as Timestamp6 } from "firebase/firestore";
|
|
3230
|
+
|
|
3231
|
+
// src/validations/reviews.schema.ts
|
|
3232
|
+
import { z as z8 } from "zod";
|
|
3233
|
+
var baseReviewSchema = z8.object({
|
|
3234
|
+
id: z8.string().min(1),
|
|
3235
|
+
patientId: z8.string().min(1),
|
|
3236
|
+
fullReviewId: z8.string().min(1),
|
|
3237
|
+
createdAt: z8.date(),
|
|
3238
|
+
updatedAt: z8.date(),
|
|
3239
|
+
comment: z8.string().min(1).max(2e3),
|
|
3240
|
+
isVerified: z8.boolean(),
|
|
3241
|
+
isPublished: z8.boolean()
|
|
3242
|
+
});
|
|
3243
|
+
var baseReviewCreateSchema = z8.object({
|
|
3244
|
+
patientId: z8.string().min(1),
|
|
3245
|
+
comment: z8.string().min(1).max(2e3),
|
|
3246
|
+
isVerified: z8.boolean().default(false),
|
|
3247
|
+
isPublished: z8.boolean().default(true)
|
|
3248
|
+
});
|
|
3249
|
+
var clinicReviewSchema = baseReviewSchema.extend({
|
|
3250
|
+
clinicId: z8.string().min(1),
|
|
3251
|
+
cleanliness: z8.number().min(1).max(5),
|
|
3252
|
+
facilities: z8.number().min(1).max(5),
|
|
3253
|
+
staffFriendliness: z8.number().min(1).max(5),
|
|
3254
|
+
waitingTime: z8.number().min(1).max(5),
|
|
3255
|
+
accessibility: z8.number().min(1).max(5),
|
|
3256
|
+
overallRating: z8.number().min(1).max(5),
|
|
3257
|
+
wouldRecommend: z8.boolean()
|
|
3258
|
+
});
|
|
3259
|
+
var createClinicReviewSchema = baseReviewCreateSchema.extend({
|
|
3260
|
+
clinicId: z8.string().min(1),
|
|
3261
|
+
cleanliness: z8.number().min(1).max(5),
|
|
3262
|
+
facilities: z8.number().min(1).max(5),
|
|
3263
|
+
staffFriendliness: z8.number().min(1).max(5),
|
|
3264
|
+
waitingTime: z8.number().min(1).max(5),
|
|
3265
|
+
accessibility: z8.number().min(1).max(5),
|
|
3266
|
+
wouldRecommend: z8.boolean()
|
|
3267
|
+
});
|
|
3268
|
+
var practitionerReviewSchema = baseReviewSchema.extend({
|
|
3269
|
+
practitionerId: z8.string().min(1),
|
|
3270
|
+
knowledgeAndExpertise: z8.number().min(1).max(5),
|
|
3271
|
+
communicationSkills: z8.number().min(1).max(5),
|
|
3272
|
+
bedSideManner: z8.number().min(1).max(5),
|
|
3273
|
+
thoroughness: z8.number().min(1).max(5),
|
|
3274
|
+
trustworthiness: z8.number().min(1).max(5),
|
|
3275
|
+
overallRating: z8.number().min(1).max(5),
|
|
3276
|
+
wouldRecommend: z8.boolean()
|
|
3277
|
+
});
|
|
3278
|
+
var createPractitionerReviewSchema = baseReviewCreateSchema.extend({
|
|
3279
|
+
practitionerId: z8.string().min(1),
|
|
3280
|
+
knowledgeAndExpertise: z8.number().min(1).max(5),
|
|
3281
|
+
communicationSkills: z8.number().min(1).max(5),
|
|
3282
|
+
bedSideManner: z8.number().min(1).max(5),
|
|
3283
|
+
thoroughness: z8.number().min(1).max(5),
|
|
3284
|
+
trustworthiness: z8.number().min(1).max(5),
|
|
3285
|
+
wouldRecommend: z8.boolean()
|
|
3286
|
+
});
|
|
3287
|
+
var procedureReviewSchema = baseReviewSchema.extend({
|
|
3288
|
+
procedureId: z8.string().min(1),
|
|
3289
|
+
effectivenessOfTreatment: z8.number().min(1).max(5),
|
|
3290
|
+
outcomeExplanation: z8.number().min(1).max(5),
|
|
3291
|
+
painManagement: z8.number().min(1).max(5),
|
|
3292
|
+
followUpCare: z8.number().min(1).max(5),
|
|
3293
|
+
valueForMoney: z8.number().min(1).max(5),
|
|
3294
|
+
overallRating: z8.number().min(1).max(5),
|
|
3295
|
+
wouldRecommend: z8.boolean()
|
|
3296
|
+
});
|
|
3297
|
+
var createProcedureReviewSchema = baseReviewCreateSchema.extend({
|
|
3298
|
+
procedureId: z8.string().min(1),
|
|
3299
|
+
effectivenessOfTreatment: z8.number().min(1).max(5),
|
|
3300
|
+
outcomeExplanation: z8.number().min(1).max(5),
|
|
3301
|
+
painManagement: z8.number().min(1).max(5),
|
|
3302
|
+
followUpCare: z8.number().min(1).max(5),
|
|
3303
|
+
valueForMoney: z8.number().min(1).max(5),
|
|
3304
|
+
wouldRecommend: z8.boolean()
|
|
3305
|
+
});
|
|
3306
|
+
var clinicReviewInfoSchema = z8.object({
|
|
3307
|
+
totalReviews: z8.number().min(0),
|
|
3308
|
+
averageRating: z8.number().min(0).max(5),
|
|
3309
|
+
cleanliness: z8.number().min(0).max(5),
|
|
3310
|
+
facilities: z8.number().min(0).max(5),
|
|
3311
|
+
staffFriendliness: z8.number().min(0).max(5),
|
|
3312
|
+
waitingTime: z8.number().min(0).max(5),
|
|
3313
|
+
accessibility: z8.number().min(0).max(5),
|
|
3314
|
+
recommendationPercentage: z8.number().min(0).max(100)
|
|
3315
|
+
});
|
|
3316
|
+
var practitionerReviewInfoSchema = z8.object({
|
|
3317
|
+
totalReviews: z8.number().min(0),
|
|
3318
|
+
averageRating: z8.number().min(0).max(5),
|
|
3319
|
+
knowledgeAndExpertise: z8.number().min(0).max(5),
|
|
3320
|
+
communicationSkills: z8.number().min(0).max(5),
|
|
3321
|
+
bedSideManner: z8.number().min(0).max(5),
|
|
3322
|
+
thoroughness: z8.number().min(0).max(5),
|
|
3323
|
+
trustworthiness: z8.number().min(0).max(5),
|
|
3324
|
+
recommendationPercentage: z8.number().min(0).max(100)
|
|
3325
|
+
});
|
|
3326
|
+
var procedureReviewInfoSchema = z8.object({
|
|
3327
|
+
totalReviews: z8.number().min(0),
|
|
3328
|
+
averageRating: z8.number().min(0).max(5),
|
|
3329
|
+
effectivenessOfTreatment: z8.number().min(0).max(5),
|
|
3330
|
+
outcomeExplanation: z8.number().min(0).max(5),
|
|
3331
|
+
painManagement: z8.number().min(0).max(5),
|
|
3332
|
+
followUpCare: z8.number().min(0).max(5),
|
|
3333
|
+
valueForMoney: z8.number().min(0).max(5),
|
|
3334
|
+
recommendationPercentage: z8.number().min(0).max(100)
|
|
3335
|
+
});
|
|
3336
|
+
var reviewSchema = z8.object({
|
|
3337
|
+
id: z8.string().min(1),
|
|
3338
|
+
appointmentId: z8.string().min(1),
|
|
3339
|
+
patientId: z8.string().min(1),
|
|
3340
|
+
createdAt: z8.date(),
|
|
3341
|
+
updatedAt: z8.date(),
|
|
3342
|
+
clinicReview: clinicReviewSchema.optional(),
|
|
3343
|
+
practitionerReview: practitionerReviewSchema.optional(),
|
|
3344
|
+
procedureReview: procedureReviewSchema.optional(),
|
|
3345
|
+
overallComment: z8.string().min(1).max(2e3),
|
|
3346
|
+
overallRating: z8.number().min(1).max(5)
|
|
3347
|
+
});
|
|
3348
|
+
var createReviewSchema = z8.object({
|
|
3349
|
+
patientId: z8.string().min(1),
|
|
3350
|
+
clinicReview: createClinicReviewSchema.optional(),
|
|
3351
|
+
practitionerReview: createPractitionerReviewSchema.optional(),
|
|
3352
|
+
procedureReview: createProcedureReviewSchema.optional(),
|
|
3353
|
+
overallComment: z8.string().min(1).max(2e3)
|
|
3354
|
+
}).refine(
|
|
3355
|
+
(data) => {
|
|
3356
|
+
return data.clinicReview || data.practitionerReview || data.procedureReview;
|
|
3357
|
+
},
|
|
3358
|
+
{
|
|
3359
|
+
message: "At least one review type (clinic, practitioner, or procedure) must be provided",
|
|
3360
|
+
path: ["reviewType"]
|
|
3361
|
+
}
|
|
3362
|
+
);
|
|
3707
3363
|
|
|
3708
|
-
// src/
|
|
3709
|
-
import {
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3364
|
+
// src/validations/shared.schema.ts
|
|
3365
|
+
import { z as z9 } from "zod";
|
|
3366
|
+
|
|
3367
|
+
// src/backoffice/types/static/procedure-family.types.ts
|
|
3368
|
+
var ProcedureFamily = /* @__PURE__ */ ((ProcedureFamily2) => {
|
|
3369
|
+
ProcedureFamily2["AESTHETICS"] = "aesthetics";
|
|
3370
|
+
ProcedureFamily2["SURGERY"] = "surgery";
|
|
3371
|
+
return ProcedureFamily2;
|
|
3372
|
+
})(ProcedureFamily || {});
|
|
3373
|
+
|
|
3374
|
+
// src/validations/shared.schema.ts
|
|
3375
|
+
var sharedClinicContactInfoSchema = z9.object({
|
|
3376
|
+
email: z9.string().email(),
|
|
3377
|
+
phoneNumber: z9.string(),
|
|
3378
|
+
alternativePhoneNumber: z9.string().nullable().optional(),
|
|
3379
|
+
website: z9.string().nullable().optional()
|
|
3380
|
+
});
|
|
3381
|
+
var sharedClinicLocationSchema = z9.object({
|
|
3382
|
+
address: z9.string(),
|
|
3383
|
+
city: z9.string(),
|
|
3384
|
+
country: z9.string(),
|
|
3385
|
+
postalCode: z9.string(),
|
|
3386
|
+
latitude: z9.number().min(-90).max(90),
|
|
3387
|
+
longitude: z9.number().min(-180).max(180),
|
|
3388
|
+
geohash: z9.string().nullable().optional()
|
|
3389
|
+
});
|
|
3390
|
+
var procedureSummaryInfoSchema = z9.object({
|
|
3391
|
+
id: z9.string().min(1),
|
|
3392
|
+
name: z9.string().min(1),
|
|
3393
|
+
description: z9.string().optional(),
|
|
3394
|
+
photo: z9.string().optional(),
|
|
3395
|
+
family: z9.nativeEnum(ProcedureFamily),
|
|
3396
|
+
categoryName: z9.string(),
|
|
3397
|
+
subcategoryName: z9.string(),
|
|
3398
|
+
technologyName: z9.string(),
|
|
3399
|
+
price: z9.number().nonnegative(),
|
|
3400
|
+
pricingMeasure: z9.nativeEnum(PricingMeasure),
|
|
3401
|
+
currency: z9.nativeEnum(Currency),
|
|
3402
|
+
duration: z9.number().int().positive(),
|
|
3403
|
+
clinicId: z9.string().min(1),
|
|
3404
|
+
clinicName: z9.string().min(1),
|
|
3405
|
+
practitionerId: z9.string().min(1),
|
|
3406
|
+
practitionerName: z9.string().min(1)
|
|
3407
|
+
});
|
|
3408
|
+
var clinicInfoSchema = z9.object({
|
|
3409
|
+
id: z9.string(),
|
|
3410
|
+
featuredPhoto: z9.string(),
|
|
3411
|
+
name: z9.string(),
|
|
3412
|
+
description: z9.string().nullable().optional(),
|
|
3413
|
+
location: sharedClinicLocationSchema,
|
|
3414
|
+
contactInfo: sharedClinicContactInfoSchema
|
|
3415
|
+
});
|
|
3416
|
+
var doctorInfoSchema = z9.object({
|
|
3417
|
+
id: z9.string(),
|
|
3418
|
+
name: z9.string(),
|
|
3419
|
+
description: z9.string().nullable().optional(),
|
|
3420
|
+
photo: z9.string(),
|
|
3421
|
+
rating: z9.number().min(0).max(5),
|
|
3422
|
+
services: z9.array(z9.string())
|
|
3423
|
+
// List of procedure IDs practitioner offers
|
|
3424
|
+
});
|
|
3722
3425
|
|
|
3723
3426
|
// src/validations/clinic.schema.ts
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
alternativePhoneNumber: z13.string().nullable().optional(),
|
|
3730
|
-
website: z13.string().nullable().optional()
|
|
3427
|
+
var clinicContactInfoSchema = z10.object({
|
|
3428
|
+
email: z10.string().email(),
|
|
3429
|
+
phoneNumber: z10.string(),
|
|
3430
|
+
alternativePhoneNumber: z10.string().nullable().optional(),
|
|
3431
|
+
website: z10.string().nullable().optional()
|
|
3731
3432
|
});
|
|
3732
|
-
var clinicLocationSchema =
|
|
3733
|
-
address:
|
|
3734
|
-
city:
|
|
3735
|
-
country:
|
|
3736
|
-
postalCode:
|
|
3737
|
-
latitude:
|
|
3738
|
-
longitude:
|
|
3739
|
-
geohash:
|
|
3433
|
+
var clinicLocationSchema = z10.object({
|
|
3434
|
+
address: z10.string(),
|
|
3435
|
+
city: z10.string(),
|
|
3436
|
+
country: z10.string(),
|
|
3437
|
+
postalCode: z10.string(),
|
|
3438
|
+
latitude: z10.number().min(-90).max(90),
|
|
3439
|
+
longitude: z10.number().min(-180).max(180),
|
|
3440
|
+
geohash: z10.string().nullable().optional()
|
|
3740
3441
|
});
|
|
3741
|
-
var workingHoursTimeSchema =
|
|
3742
|
-
open:
|
|
3743
|
-
close:
|
|
3744
|
-
breaks:
|
|
3745
|
-
|
|
3746
|
-
start:
|
|
3747
|
-
end:
|
|
3442
|
+
var workingHoursTimeSchema = z10.object({
|
|
3443
|
+
open: z10.string(),
|
|
3444
|
+
close: z10.string(),
|
|
3445
|
+
breaks: z10.array(
|
|
3446
|
+
z10.object({
|
|
3447
|
+
start: z10.string(),
|
|
3448
|
+
end: z10.string()
|
|
3748
3449
|
})
|
|
3749
3450
|
).optional()
|
|
3750
3451
|
});
|
|
3751
|
-
var workingHoursSchema =
|
|
3452
|
+
var workingHoursSchema = z10.object({
|
|
3752
3453
|
monday: workingHoursTimeSchema.nullable(),
|
|
3753
3454
|
tuesday: workingHoursTimeSchema.nullable(),
|
|
3754
3455
|
wednesday: workingHoursTimeSchema.nullable(),
|
|
@@ -3757,255 +3458,255 @@ var workingHoursSchema = z13.object({
|
|
|
3757
3458
|
saturday: workingHoursTimeSchema.nullable(),
|
|
3758
3459
|
sunday: workingHoursTimeSchema.nullable()
|
|
3759
3460
|
});
|
|
3760
|
-
var clinicTagsSchema =
|
|
3761
|
-
tags:
|
|
3461
|
+
var clinicTagsSchema = z10.object({
|
|
3462
|
+
tags: z10.array(z10.nativeEnum(ClinicTag))
|
|
3762
3463
|
});
|
|
3763
|
-
var contactPersonSchema =
|
|
3764
|
-
firstName:
|
|
3765
|
-
lastName:
|
|
3766
|
-
title:
|
|
3767
|
-
email:
|
|
3768
|
-
phoneNumber:
|
|
3464
|
+
var contactPersonSchema = z10.object({
|
|
3465
|
+
firstName: z10.string(),
|
|
3466
|
+
lastName: z10.string(),
|
|
3467
|
+
title: z10.string().nullable().optional(),
|
|
3468
|
+
email: z10.string().email(),
|
|
3469
|
+
phoneNumber: z10.string().nullable().optional()
|
|
3769
3470
|
});
|
|
3770
|
-
var adminInfoSchema =
|
|
3771
|
-
id:
|
|
3772
|
-
name:
|
|
3773
|
-
email:
|
|
3471
|
+
var adminInfoSchema = z10.object({
|
|
3472
|
+
id: z10.string(),
|
|
3473
|
+
name: z10.string(),
|
|
3474
|
+
email: z10.string().email()
|
|
3774
3475
|
});
|
|
3775
|
-
var clinicAdminSchema =
|
|
3776
|
-
id:
|
|
3777
|
-
userRef:
|
|
3778
|
-
clinicGroupId:
|
|
3779
|
-
isGroupOwner:
|
|
3780
|
-
clinicsManaged:
|
|
3781
|
-
clinicsManagedInfo:
|
|
3476
|
+
var clinicAdminSchema = z10.object({
|
|
3477
|
+
id: z10.string(),
|
|
3478
|
+
userRef: z10.string(),
|
|
3479
|
+
clinicGroupId: z10.string(),
|
|
3480
|
+
isGroupOwner: z10.boolean(),
|
|
3481
|
+
clinicsManaged: z10.array(z10.string()),
|
|
3482
|
+
clinicsManagedInfo: z10.array(clinicInfoSchema),
|
|
3782
3483
|
contactInfo: contactPersonSchema,
|
|
3783
|
-
roleTitle:
|
|
3784
|
-
createdAt:
|
|
3785
|
-
updatedAt:
|
|
3786
|
-
isActive:
|
|
3484
|
+
roleTitle: z10.string(),
|
|
3485
|
+
createdAt: z10.instanceof(Date).or(z10.instanceof(Timestamp6)),
|
|
3486
|
+
updatedAt: z10.instanceof(Date).or(z10.instanceof(Timestamp6)),
|
|
3487
|
+
isActive: z10.boolean()
|
|
3787
3488
|
});
|
|
3788
|
-
var adminTokenSchema =
|
|
3789
|
-
id:
|
|
3790
|
-
token:
|
|
3791
|
-
email:
|
|
3792
|
-
status:
|
|
3793
|
-
usedByUserRef:
|
|
3794
|
-
createdAt:
|
|
3489
|
+
var adminTokenSchema = z10.object({
|
|
3490
|
+
id: z10.string(),
|
|
3491
|
+
token: z10.string(),
|
|
3492
|
+
email: z10.string().email().optional().nullable(),
|
|
3493
|
+
status: z10.nativeEnum(AdminTokenStatus),
|
|
3494
|
+
usedByUserRef: z10.string().optional(),
|
|
3495
|
+
createdAt: z10.instanceof(Date).or(z10.instanceof(Timestamp6)),
|
|
3795
3496
|
// Timestamp
|
|
3796
|
-
expiresAt:
|
|
3497
|
+
expiresAt: z10.instanceof(Date).or(z10.instanceof(Timestamp6))
|
|
3797
3498
|
// Timestamp
|
|
3798
3499
|
});
|
|
3799
|
-
var createAdminTokenSchema =
|
|
3800
|
-
expiresInDays:
|
|
3801
|
-
email:
|
|
3500
|
+
var createAdminTokenSchema = z10.object({
|
|
3501
|
+
expiresInDays: z10.number().min(1).max(30).optional(),
|
|
3502
|
+
email: z10.string().email().optional().nullable()
|
|
3802
3503
|
});
|
|
3803
|
-
var clinicGroupSchema =
|
|
3804
|
-
id:
|
|
3805
|
-
name:
|
|
3806
|
-
description:
|
|
3504
|
+
var clinicGroupSchema = z10.object({
|
|
3505
|
+
id: z10.string(),
|
|
3506
|
+
name: z10.string(),
|
|
3507
|
+
description: z10.string().nullable().optional(),
|
|
3807
3508
|
hqLocation: clinicLocationSchema,
|
|
3808
3509
|
contactInfo: clinicContactInfoSchema,
|
|
3809
3510
|
contactPerson: contactPersonSchema,
|
|
3810
|
-
clinics:
|
|
3811
|
-
clinicsInfo:
|
|
3812
|
-
admins:
|
|
3813
|
-
adminsInfo:
|
|
3814
|
-
adminTokens:
|
|
3815
|
-
ownerId:
|
|
3816
|
-
createdAt:
|
|
3511
|
+
clinics: z10.array(z10.string()),
|
|
3512
|
+
clinicsInfo: z10.array(clinicInfoSchema),
|
|
3513
|
+
admins: z10.array(z10.string()),
|
|
3514
|
+
adminsInfo: z10.array(adminInfoSchema),
|
|
3515
|
+
adminTokens: z10.array(adminTokenSchema),
|
|
3516
|
+
ownerId: z10.string().nullable(),
|
|
3517
|
+
createdAt: z10.instanceof(Date).or(z10.instanceof(Timestamp6)),
|
|
3817
3518
|
// Timestamp
|
|
3818
|
-
updatedAt:
|
|
3519
|
+
updatedAt: z10.instanceof(Date).or(z10.instanceof(Timestamp6)),
|
|
3819
3520
|
// Timestamp
|
|
3820
|
-
isActive:
|
|
3521
|
+
isActive: z10.boolean(),
|
|
3821
3522
|
logo: mediaResourceSchema.optional().nullable(),
|
|
3822
|
-
practiceType:
|
|
3823
|
-
languages:
|
|
3824
|
-
subscriptionModel:
|
|
3825
|
-
calendarSyncEnabled:
|
|
3826
|
-
autoConfirmAppointments:
|
|
3827
|
-
businessIdentificationNumber:
|
|
3828
|
-
onboarding:
|
|
3829
|
-
completed:
|
|
3830
|
-
step:
|
|
3523
|
+
practiceType: z10.nativeEnum(PracticeType).optional(),
|
|
3524
|
+
languages: z10.array(z10.nativeEnum(Language)).optional(),
|
|
3525
|
+
subscriptionModel: z10.nativeEnum(SubscriptionModel),
|
|
3526
|
+
calendarSyncEnabled: z10.boolean().optional(),
|
|
3527
|
+
autoConfirmAppointments: z10.boolean().optional(),
|
|
3528
|
+
businessIdentificationNumber: z10.string().optional().nullable(),
|
|
3529
|
+
onboarding: z10.object({
|
|
3530
|
+
completed: z10.boolean().optional().default(false),
|
|
3531
|
+
step: z10.number().optional().default(1)
|
|
3831
3532
|
}).optional()
|
|
3832
3533
|
});
|
|
3833
|
-
var clinicSchema =
|
|
3834
|
-
id:
|
|
3835
|
-
clinicGroupId:
|
|
3836
|
-
name:
|
|
3837
|
-
description:
|
|
3534
|
+
var clinicSchema = z10.object({
|
|
3535
|
+
id: z10.string(),
|
|
3536
|
+
clinicGroupId: z10.string(),
|
|
3537
|
+
name: z10.string(),
|
|
3538
|
+
description: z10.string().nullable().optional(),
|
|
3838
3539
|
location: clinicLocationSchema,
|
|
3839
3540
|
contactInfo: clinicContactInfoSchema,
|
|
3840
3541
|
workingHours: workingHoursSchema,
|
|
3841
|
-
tags:
|
|
3842
|
-
featuredPhotos:
|
|
3542
|
+
tags: z10.array(z10.nativeEnum(ClinicTag)),
|
|
3543
|
+
featuredPhotos: z10.array(mediaResourceSchema),
|
|
3843
3544
|
coverPhoto: mediaResourceSchema.nullable(),
|
|
3844
|
-
photosWithTags:
|
|
3845
|
-
|
|
3545
|
+
photosWithTags: z10.array(
|
|
3546
|
+
z10.object({
|
|
3846
3547
|
url: mediaResourceSchema,
|
|
3847
|
-
tag:
|
|
3548
|
+
tag: z10.string()
|
|
3848
3549
|
})
|
|
3849
3550
|
).optional(),
|
|
3850
|
-
doctors:
|
|
3551
|
+
doctors: z10.array(z10.string()),
|
|
3851
3552
|
// List of practitioner IDs
|
|
3852
|
-
doctorsInfo:
|
|
3553
|
+
doctorsInfo: z10.array(doctorInfoSchema),
|
|
3853
3554
|
// Aggregated doctor info
|
|
3854
|
-
procedures:
|
|
3555
|
+
procedures: z10.array(z10.string()),
|
|
3855
3556
|
// List of procedure IDs offered by clinic
|
|
3856
|
-
proceduresInfo:
|
|
3557
|
+
proceduresInfo: z10.array(procedureSummaryInfoSchema),
|
|
3857
3558
|
// Use the correct schema for aggregated procedure info
|
|
3858
3559
|
reviewInfo: clinicReviewInfoSchema,
|
|
3859
|
-
admins:
|
|
3860
|
-
createdAt:
|
|
3560
|
+
admins: z10.array(z10.string()),
|
|
3561
|
+
createdAt: z10.instanceof(Date).or(z10.instanceof(Timestamp6)),
|
|
3861
3562
|
// Timestamp
|
|
3862
|
-
updatedAt:
|
|
3563
|
+
updatedAt: z10.instanceof(Date).or(z10.instanceof(Timestamp6)),
|
|
3863
3564
|
// Timestamp
|
|
3864
|
-
isActive:
|
|
3865
|
-
isVerified:
|
|
3565
|
+
isActive: z10.boolean(),
|
|
3566
|
+
isVerified: z10.boolean(),
|
|
3866
3567
|
logo: mediaResourceSchema.optional().nullable()
|
|
3867
3568
|
});
|
|
3868
|
-
var createClinicAdminSchema =
|
|
3869
|
-
userRef:
|
|
3870
|
-
clinicGroupId:
|
|
3871
|
-
isGroupOwner:
|
|
3872
|
-
clinicsManaged:
|
|
3569
|
+
var createClinicAdminSchema = z10.object({
|
|
3570
|
+
userRef: z10.string(),
|
|
3571
|
+
clinicGroupId: z10.string().optional(),
|
|
3572
|
+
isGroupOwner: z10.boolean(),
|
|
3573
|
+
clinicsManaged: z10.array(z10.string()),
|
|
3873
3574
|
contactInfo: contactPersonSchema,
|
|
3874
|
-
roleTitle:
|
|
3875
|
-
isActive:
|
|
3575
|
+
roleTitle: z10.string(),
|
|
3576
|
+
isActive: z10.boolean()
|
|
3876
3577
|
// clinicsManagedInfo is aggregated, not provided on creation
|
|
3877
3578
|
});
|
|
3878
|
-
var createClinicGroupSchema =
|
|
3879
|
-
name:
|
|
3880
|
-
description:
|
|
3579
|
+
var createClinicGroupSchema = z10.object({
|
|
3580
|
+
name: z10.string(),
|
|
3581
|
+
description: z10.string().optional(),
|
|
3881
3582
|
hqLocation: clinicLocationSchema,
|
|
3882
3583
|
contactInfo: clinicContactInfoSchema,
|
|
3883
3584
|
contactPerson: contactPersonSchema,
|
|
3884
|
-
ownerId:
|
|
3885
|
-
isActive:
|
|
3585
|
+
ownerId: z10.string().nullable(),
|
|
3586
|
+
isActive: z10.boolean(),
|
|
3886
3587
|
logo: mediaResourceSchema.optional().nullable(),
|
|
3887
|
-
practiceType:
|
|
3888
|
-
languages:
|
|
3889
|
-
subscriptionModel:
|
|
3890
|
-
calendarSyncEnabled:
|
|
3891
|
-
autoConfirmAppointments:
|
|
3892
|
-
businessIdentificationNumber:
|
|
3893
|
-
onboarding:
|
|
3894
|
-
completed:
|
|
3895
|
-
step:
|
|
3588
|
+
practiceType: z10.nativeEnum(PracticeType).optional(),
|
|
3589
|
+
languages: z10.array(z10.nativeEnum(Language)).optional(),
|
|
3590
|
+
subscriptionModel: z10.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */),
|
|
3591
|
+
calendarSyncEnabled: z10.boolean().optional(),
|
|
3592
|
+
autoConfirmAppointments: z10.boolean().optional(),
|
|
3593
|
+
businessIdentificationNumber: z10.string().optional().nullable(),
|
|
3594
|
+
onboarding: z10.object({
|
|
3595
|
+
completed: z10.boolean().optional().default(false),
|
|
3596
|
+
step: z10.number().optional().default(1)
|
|
3896
3597
|
}).optional()
|
|
3897
3598
|
// clinics, clinicsInfo, admins, adminsInfo, adminTokens are managed internally
|
|
3898
3599
|
});
|
|
3899
|
-
var createClinicSchema =
|
|
3900
|
-
clinicGroupId:
|
|
3901
|
-
name:
|
|
3902
|
-
description:
|
|
3600
|
+
var createClinicSchema = z10.object({
|
|
3601
|
+
clinicGroupId: z10.string(),
|
|
3602
|
+
name: z10.string(),
|
|
3603
|
+
description: z10.string().optional(),
|
|
3903
3604
|
location: clinicLocationSchema,
|
|
3904
3605
|
contactInfo: clinicContactInfoSchema,
|
|
3905
3606
|
workingHours: workingHoursSchema,
|
|
3906
|
-
tags:
|
|
3607
|
+
tags: z10.array(z10.nativeEnum(ClinicTag)),
|
|
3907
3608
|
coverPhoto: mediaResourceSchema.nullable().optional(),
|
|
3908
|
-
photosWithTags:
|
|
3909
|
-
|
|
3609
|
+
photosWithTags: z10.array(
|
|
3610
|
+
z10.object({
|
|
3910
3611
|
url: mediaResourceSchema,
|
|
3911
|
-
tag:
|
|
3612
|
+
tag: z10.string()
|
|
3912
3613
|
})
|
|
3913
3614
|
).optional(),
|
|
3914
|
-
doctors:
|
|
3915
|
-
procedures:
|
|
3916
|
-
proceduresInfo:
|
|
3917
|
-
admins:
|
|
3918
|
-
isActive:
|
|
3919
|
-
isVerified:
|
|
3615
|
+
doctors: z10.array(z10.string()).optional().default([]),
|
|
3616
|
+
procedures: z10.array(z10.string()).optional().default([]),
|
|
3617
|
+
proceduresInfo: z10.array(procedureSummaryInfoSchema).optional(),
|
|
3618
|
+
admins: z10.array(z10.string()),
|
|
3619
|
+
isActive: z10.boolean().optional().default(true),
|
|
3620
|
+
isVerified: z10.boolean().optional().default(false),
|
|
3920
3621
|
logo: mediaResourceSchema.optional().nullable(),
|
|
3921
|
-
featuredPhotos:
|
|
3622
|
+
featuredPhotos: z10.array(mediaResourceSchema).optional().default([])
|
|
3922
3623
|
});
|
|
3923
|
-
var createDefaultClinicGroupSchema =
|
|
3924
|
-
name:
|
|
3925
|
-
ownerId:
|
|
3624
|
+
var createDefaultClinicGroupSchema = z10.object({
|
|
3625
|
+
name: z10.string(),
|
|
3626
|
+
ownerId: z10.string().nullable(),
|
|
3926
3627
|
contactPerson: contactPersonSchema,
|
|
3927
3628
|
contactInfo: clinicContactInfoSchema,
|
|
3928
3629
|
hqLocation: clinicLocationSchema,
|
|
3929
|
-
isActive:
|
|
3630
|
+
isActive: z10.boolean(),
|
|
3930
3631
|
logo: mediaResourceSchema.optional().nullable(),
|
|
3931
|
-
practiceType:
|
|
3932
|
-
languages:
|
|
3933
|
-
subscriptionModel:
|
|
3934
|
-
onboarding:
|
|
3935
|
-
completed:
|
|
3936
|
-
step:
|
|
3632
|
+
practiceType: z10.nativeEnum(PracticeType).optional(),
|
|
3633
|
+
languages: z10.array(z10.nativeEnum(Language)).optional(),
|
|
3634
|
+
subscriptionModel: z10.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */),
|
|
3635
|
+
onboarding: z10.object({
|
|
3636
|
+
completed: z10.boolean().optional().default(false),
|
|
3637
|
+
step: z10.number().optional().default(1)
|
|
3937
3638
|
}).optional()
|
|
3938
3639
|
});
|
|
3939
|
-
var clinicAdminSignupSchema =
|
|
3940
|
-
email:
|
|
3941
|
-
password:
|
|
3942
|
-
firstName:
|
|
3943
|
-
lastName:
|
|
3944
|
-
title:
|
|
3945
|
-
phoneNumber:
|
|
3946
|
-
isCreatingNewGroup:
|
|
3947
|
-
inviteToken:
|
|
3948
|
-
clinicGroupData:
|
|
3949
|
-
name:
|
|
3640
|
+
var clinicAdminSignupSchema = z10.object({
|
|
3641
|
+
email: z10.string().email(),
|
|
3642
|
+
password: z10.string().min(8),
|
|
3643
|
+
firstName: z10.string(),
|
|
3644
|
+
lastName: z10.string(),
|
|
3645
|
+
title: z10.string(),
|
|
3646
|
+
phoneNumber: z10.string(),
|
|
3647
|
+
isCreatingNewGroup: z10.boolean(),
|
|
3648
|
+
inviteToken: z10.string().optional(),
|
|
3649
|
+
clinicGroupData: z10.object({
|
|
3650
|
+
name: z10.string(),
|
|
3950
3651
|
hqLocation: clinicLocationSchema,
|
|
3951
3652
|
logo: mediaResourceSchema.optional(),
|
|
3952
3653
|
contactInfo: clinicContactInfoSchema,
|
|
3953
|
-
subscriptionModel:
|
|
3654
|
+
subscriptionModel: z10.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */)
|
|
3954
3655
|
}).optional()
|
|
3955
3656
|
});
|
|
3956
|
-
var clinicGroupSetupSchema =
|
|
3957
|
-
languages:
|
|
3958
|
-
practiceType:
|
|
3959
|
-
description:
|
|
3657
|
+
var clinicGroupSetupSchema = z10.object({
|
|
3658
|
+
languages: z10.array(z10.nativeEnum(Language)),
|
|
3659
|
+
practiceType: z10.nativeEnum(PracticeType),
|
|
3660
|
+
description: z10.string(),
|
|
3960
3661
|
logo: mediaResourceSchema,
|
|
3961
|
-
calendarSyncEnabled:
|
|
3962
|
-
autoConfirmAppointments:
|
|
3963
|
-
businessIdentificationNumber:
|
|
3964
|
-
onboarding:
|
|
3965
|
-
completed:
|
|
3966
|
-
step:
|
|
3662
|
+
calendarSyncEnabled: z10.boolean(),
|
|
3663
|
+
autoConfirmAppointments: z10.boolean(),
|
|
3664
|
+
businessIdentificationNumber: z10.string().optional().nullable(),
|
|
3665
|
+
onboarding: z10.object({
|
|
3666
|
+
completed: z10.boolean().optional().default(false),
|
|
3667
|
+
step: z10.number().optional().default(1)
|
|
3967
3668
|
}).optional()
|
|
3968
3669
|
});
|
|
3969
|
-
var clinicBranchSetupSchema =
|
|
3970
|
-
name:
|
|
3670
|
+
var clinicBranchSetupSchema = z10.object({
|
|
3671
|
+
name: z10.string(),
|
|
3971
3672
|
location: clinicLocationSchema,
|
|
3972
|
-
description:
|
|
3673
|
+
description: z10.string().optional(),
|
|
3973
3674
|
contactInfo: clinicContactInfoSchema,
|
|
3974
3675
|
workingHours: workingHoursSchema,
|
|
3975
|
-
tags:
|
|
3676
|
+
tags: z10.array(z10.nativeEnum(ClinicTag)),
|
|
3976
3677
|
logo: mediaResourceSchema.optional(),
|
|
3977
3678
|
coverPhoto: mediaResourceSchema.nullable().optional(),
|
|
3978
|
-
photosWithTags:
|
|
3979
|
-
|
|
3679
|
+
photosWithTags: z10.array(
|
|
3680
|
+
z10.object({
|
|
3980
3681
|
url: mediaResourceSchema,
|
|
3981
|
-
tag:
|
|
3682
|
+
tag: z10.string()
|
|
3982
3683
|
})
|
|
3983
3684
|
).optional(),
|
|
3984
|
-
featuredPhotos:
|
|
3685
|
+
featuredPhotos: z10.array(mediaResourceSchema).optional()
|
|
3985
3686
|
});
|
|
3986
3687
|
var updateClinicAdminSchema = createClinicAdminSchema.partial();
|
|
3987
3688
|
var updateClinicGroupSchema = createClinicGroupSchema.partial();
|
|
3988
|
-
var updateClinicSchema =
|
|
3989
|
-
name:
|
|
3990
|
-
description:
|
|
3689
|
+
var updateClinicSchema = z10.object({
|
|
3690
|
+
name: z10.string().optional(),
|
|
3691
|
+
description: z10.string().optional(),
|
|
3991
3692
|
location: clinicLocationSchema.optional(),
|
|
3992
3693
|
contactInfo: clinicContactInfoSchema.optional(),
|
|
3993
3694
|
workingHours: workingHoursSchema.optional(),
|
|
3994
|
-
tags:
|
|
3695
|
+
tags: z10.array(z10.nativeEnum(ClinicTag)).optional(),
|
|
3995
3696
|
coverPhoto: mediaResourceSchema.nullable().optional(),
|
|
3996
|
-
photosWithTags:
|
|
3997
|
-
|
|
3697
|
+
photosWithTags: z10.array(
|
|
3698
|
+
z10.object({
|
|
3998
3699
|
url: mediaResourceSchema,
|
|
3999
|
-
tag:
|
|
3700
|
+
tag: z10.string()
|
|
4000
3701
|
})
|
|
4001
3702
|
).optional(),
|
|
4002
|
-
doctors:
|
|
4003
|
-
procedures:
|
|
4004
|
-
proceduresInfo:
|
|
4005
|
-
isActive:
|
|
4006
|
-
isVerified:
|
|
3703
|
+
doctors: z10.array(z10.string()).optional(),
|
|
3704
|
+
procedures: z10.array(z10.string()).optional(),
|
|
3705
|
+
proceduresInfo: z10.array(procedureSummaryInfoSchema).optional(),
|
|
3706
|
+
isActive: z10.boolean().optional(),
|
|
3707
|
+
isVerified: z10.boolean().optional(),
|
|
4007
3708
|
logo: mediaResourceSchema.optional().nullable(),
|
|
4008
|
-
featuredPhotos:
|
|
3709
|
+
featuredPhotos: z10.array(mediaResourceSchema).optional()
|
|
4009
3710
|
});
|
|
4010
3711
|
|
|
4011
3712
|
// src/services/clinic/utils/admin.utils.ts
|
|
@@ -4101,8 +3802,8 @@ async function createClinicAdmin(db, data, clinicGroupService) {
|
|
|
4101
3802
|
try {
|
|
4102
3803
|
clinicAdminSchema.parse({
|
|
4103
3804
|
...adminData,
|
|
4104
|
-
createdAt:
|
|
4105
|
-
updatedAt:
|
|
3805
|
+
createdAt: Timestamp7.now(),
|
|
3806
|
+
updatedAt: Timestamp7.now()
|
|
4106
3807
|
});
|
|
4107
3808
|
console.log("[CLINIC_ADMIN] Admin object validation passed");
|
|
4108
3809
|
} catch (schemaError) {
|
|
@@ -4422,7 +4123,7 @@ var createSensitiveInfoUtil = async (db, data, requesterId, requesterRoles, medi
|
|
|
4422
4123
|
}
|
|
4423
4124
|
return createdDoc.data();
|
|
4424
4125
|
} catch (error) {
|
|
4425
|
-
if (error instanceof
|
|
4126
|
+
if (error instanceof z11.ZodError) {
|
|
4426
4127
|
throw new Error("Invalid sensitive info data: " + error.message);
|
|
4427
4128
|
}
|
|
4428
4129
|
throw error;
|
|
@@ -4566,7 +4267,7 @@ import {
|
|
|
4566
4267
|
setDoc as setDoc6,
|
|
4567
4268
|
serverTimestamp as serverTimestamp6
|
|
4568
4269
|
} from "firebase/firestore";
|
|
4569
|
-
import { z as
|
|
4270
|
+
import { z as z12 } from "zod";
|
|
4570
4271
|
import { geohashForLocation } from "geofire-common";
|
|
4571
4272
|
var updatePatientLocationUtil = async (db, patientId, latitude, longitude) => {
|
|
4572
4273
|
const locationData = {
|
|
@@ -4605,7 +4306,7 @@ var createLocationInfoUtil = async (db, data, requesterId) => {
|
|
|
4605
4306
|
}
|
|
4606
4307
|
return locationDoc.data();
|
|
4607
4308
|
} catch (error) {
|
|
4608
|
-
if (error instanceof
|
|
4309
|
+
if (error instanceof z12.ZodError) {
|
|
4609
4310
|
throw new Error("Invalid location data: " + error.message);
|
|
4610
4311
|
}
|
|
4611
4312
|
throw error;
|
|
@@ -4648,13 +4349,13 @@ import {
|
|
|
4648
4349
|
arrayUnion as arrayUnion2,
|
|
4649
4350
|
arrayRemove as arrayRemove2,
|
|
4650
4351
|
serverTimestamp as serverTimestamp7,
|
|
4651
|
-
Timestamp as
|
|
4352
|
+
Timestamp as Timestamp8
|
|
4652
4353
|
} from "firebase/firestore";
|
|
4653
4354
|
var addDoctorUtil = async (db, patientId, doctorRef, assignedBy) => {
|
|
4654
4355
|
var _a;
|
|
4655
4356
|
const newDoctor = {
|
|
4656
4357
|
userRef: doctorRef,
|
|
4657
|
-
assignedAt:
|
|
4358
|
+
assignedAt: Timestamp8.now(),
|
|
4658
4359
|
assignedBy,
|
|
4659
4360
|
isActive: true
|
|
4660
4361
|
};
|
|
@@ -4673,7 +4374,7 @@ var addDoctorUtil = async (db, patientId, doctorRef, assignedBy) => {
|
|
|
4673
4374
|
updatedDoctors[existingDoctorIndex] = {
|
|
4674
4375
|
...updatedDoctors[existingDoctorIndex],
|
|
4675
4376
|
isActive: true,
|
|
4676
|
-
assignedAt:
|
|
4377
|
+
assignedAt: Timestamp8.now(),
|
|
4677
4378
|
assignedBy
|
|
4678
4379
|
};
|
|
4679
4380
|
updates.doctors = updatedDoctors;
|
|
@@ -4701,7 +4402,7 @@ var addClinicUtil = async (db, patientId, clinicId, assignedBy) => {
|
|
|
4701
4402
|
var _a;
|
|
4702
4403
|
const newClinic = {
|
|
4703
4404
|
clinicId,
|
|
4704
|
-
assignedAt:
|
|
4405
|
+
assignedAt: Timestamp8.now(),
|
|
4705
4406
|
assignedBy,
|
|
4706
4407
|
isActive: true
|
|
4707
4408
|
};
|
|
@@ -4720,7 +4421,7 @@ var addClinicUtil = async (db, patientId, clinicId, assignedBy) => {
|
|
|
4720
4421
|
updatedClinics[existingClinicIndex] = {
|
|
4721
4422
|
...updatedClinics[existingClinicIndex],
|
|
4722
4423
|
isActive: true,
|
|
4723
|
-
assignedAt:
|
|
4424
|
+
assignedAt: Timestamp8.now(),
|
|
4724
4425
|
assignedBy
|
|
4725
4426
|
};
|
|
4726
4427
|
updates.clinics = updatedClinics;
|
|
@@ -5039,7 +4740,7 @@ import {
|
|
|
5039
4740
|
arrayRemove as arrayRemove4,
|
|
5040
4741
|
serverTimestamp as serverTimestamp9,
|
|
5041
4742
|
increment,
|
|
5042
|
-
Timestamp as
|
|
4743
|
+
Timestamp as Timestamp10,
|
|
5043
4744
|
collection as collection8,
|
|
5044
4745
|
query as query8,
|
|
5045
4746
|
where as where8,
|
|
@@ -5048,7 +4749,7 @@ import {
|
|
|
5048
4749
|
startAfter as startAfter5,
|
|
5049
4750
|
doc as doc8
|
|
5050
4751
|
} from "firebase/firestore";
|
|
5051
|
-
import { z as
|
|
4752
|
+
import { z as z13 } from "zod";
|
|
5052
4753
|
var createPatientProfileUtil = async (db, data, generateId2) => {
|
|
5053
4754
|
var _a, _b;
|
|
5054
4755
|
try {
|
|
@@ -5082,8 +4783,8 @@ var createPatientProfileUtil = async (db, data, generateId2) => {
|
|
|
5082
4783
|
};
|
|
5083
4784
|
patientProfileSchema.parse({
|
|
5084
4785
|
...patientData,
|
|
5085
|
-
createdAt:
|
|
5086
|
-
updatedAt:
|
|
4786
|
+
createdAt: Timestamp10.now(),
|
|
4787
|
+
updatedAt: Timestamp10.now()
|
|
5087
4788
|
});
|
|
5088
4789
|
await setDoc8(getPatientDocRef(db, patientId), patientData);
|
|
5089
4790
|
console.log(`[createPatientProfileUtil] Creating sensitive info document`);
|
|
@@ -5151,7 +4852,7 @@ var createPatientProfileUtil = async (db, data, generateId2) => {
|
|
|
5151
4852
|
`[createPatientProfileUtil] Error in patient profile creation:`,
|
|
5152
4853
|
error
|
|
5153
4854
|
);
|
|
5154
|
-
if (error instanceof
|
|
4855
|
+
if (error instanceof z13.ZodError) {
|
|
5155
4856
|
throw new Error("Invalid patient data: " + error.message);
|
|
5156
4857
|
}
|
|
5157
4858
|
throw error;
|
|
@@ -5237,12 +4938,12 @@ var testCreateSubDocuments = async (db, patientId, userRef) => {
|
|
|
5237
4938
|
photoUrl: "",
|
|
5238
4939
|
firstName: "Name",
|
|
5239
4940
|
lastName: "Surname",
|
|
5240
|
-
dateOfBirth:
|
|
4941
|
+
dateOfBirth: Timestamp10.now(),
|
|
5241
4942
|
gender: "prefer_not_to_say" /* PREFER_NOT_TO_SAY */,
|
|
5242
4943
|
email: "test@example.com",
|
|
5243
4944
|
phoneNumber: "",
|
|
5244
|
-
createdAt:
|
|
5245
|
-
updatedAt:
|
|
4945
|
+
createdAt: Timestamp10.now(),
|
|
4946
|
+
updatedAt: Timestamp10.now()
|
|
5246
4947
|
};
|
|
5247
4948
|
await setDoc8(sensitiveInfoRef, defaultSensitiveInfo);
|
|
5248
4949
|
console.log(
|
|
@@ -5256,7 +4957,7 @@ var testCreateSubDocuments = async (db, patientId, userRef) => {
|
|
|
5256
4957
|
const defaultMedicalInfo = {
|
|
5257
4958
|
...DEFAULT_MEDICAL_INFO,
|
|
5258
4959
|
patientId,
|
|
5259
|
-
lastUpdated:
|
|
4960
|
+
lastUpdated: Timestamp10.now(),
|
|
5260
4961
|
updatedBy: userRef
|
|
5261
4962
|
};
|
|
5262
4963
|
await setDoc8(medicalInfoRef, defaultMedicalInfo);
|
|
@@ -5374,33 +5075,33 @@ import {
|
|
|
5374
5075
|
where as where9,
|
|
5375
5076
|
setDoc as setDoc9,
|
|
5376
5077
|
updateDoc as updateDoc9,
|
|
5377
|
-
Timestamp as
|
|
5078
|
+
Timestamp as Timestamp11,
|
|
5378
5079
|
collectionGroup
|
|
5379
5080
|
} from "firebase/firestore";
|
|
5380
5081
|
|
|
5381
5082
|
// src/validations/patient/token.schema.ts
|
|
5382
|
-
import { z as
|
|
5383
|
-
var patientTokenSchema =
|
|
5384
|
-
id:
|
|
5385
|
-
token:
|
|
5386
|
-
patientId:
|
|
5387
|
-
email:
|
|
5388
|
-
clinicId:
|
|
5389
|
-
status:
|
|
5390
|
-
createdBy:
|
|
5391
|
-
createdAt:
|
|
5083
|
+
import { z as z14 } from "zod";
|
|
5084
|
+
var patientTokenSchema = z14.object({
|
|
5085
|
+
id: z14.string().min(1, "Token ID is required"),
|
|
5086
|
+
token: z14.string().min(1, "Token string is required"),
|
|
5087
|
+
patientId: z14.string().min(1, "Patient ID is required"),
|
|
5088
|
+
email: z14.string().email("Invalid email format"),
|
|
5089
|
+
clinicId: z14.string().min(1, "Clinic ID is required"),
|
|
5090
|
+
status: z14.nativeEnum(PatientTokenStatus),
|
|
5091
|
+
createdBy: z14.string().min(1, "Creator ID is required"),
|
|
5092
|
+
createdAt: z14.any(),
|
|
5392
5093
|
// Assuming Timestamp validated elsewhere
|
|
5393
|
-
expiresAt:
|
|
5094
|
+
expiresAt: z14.any(),
|
|
5394
5095
|
// Assuming Timestamp validated elsewhere
|
|
5395
|
-
usedBy:
|
|
5396
|
-
usedAt:
|
|
5096
|
+
usedBy: z14.string().optional(),
|
|
5097
|
+
usedAt: z14.any().optional()
|
|
5397
5098
|
// Assuming Timestamp validated elsewhere
|
|
5398
5099
|
});
|
|
5399
|
-
var createPatientTokenSchema =
|
|
5400
|
-
patientId:
|
|
5401
|
-
clinicId:
|
|
5402
|
-
email:
|
|
5403
|
-
expiresAt:
|
|
5100
|
+
var createPatientTokenSchema = z14.object({
|
|
5101
|
+
patientId: z14.string().min(1, "Patient ID is required"),
|
|
5102
|
+
clinicId: z14.string().min(1, "Clinic ID is required"),
|
|
5103
|
+
email: z14.string().email("Invalid email format"),
|
|
5104
|
+
expiresAt: z14.date().optional()
|
|
5404
5105
|
});
|
|
5405
5106
|
|
|
5406
5107
|
// src/services/patient/utils/token.utils.ts
|
|
@@ -5424,8 +5125,8 @@ var createPatientTokenUtil = async (db, data, createdBy, generateId2) => {
|
|
|
5424
5125
|
clinicId: validatedData.clinicId,
|
|
5425
5126
|
status: "active" /* ACTIVE */,
|
|
5426
5127
|
createdBy,
|
|
5427
|
-
createdAt:
|
|
5428
|
-
expiresAt:
|
|
5128
|
+
createdAt: Timestamp11.now(),
|
|
5129
|
+
expiresAt: Timestamp11.fromDate(expiration)
|
|
5429
5130
|
};
|
|
5430
5131
|
patientTokenSchema.parse(token);
|
|
5431
5132
|
const tokenRef = doc9(
|
|
@@ -5451,7 +5152,7 @@ var validatePatientTokenUtil = async (db, tokenString) => {
|
|
|
5451
5152
|
tokensRef,
|
|
5452
5153
|
where9("token", "==", tokenString),
|
|
5453
5154
|
where9("status", "==", "active" /* ACTIVE */),
|
|
5454
|
-
where9("expiresAt", ">",
|
|
5155
|
+
where9("expiresAt", ">", Timestamp11.now())
|
|
5455
5156
|
);
|
|
5456
5157
|
const tokenSnapshot = await getDocs9(q);
|
|
5457
5158
|
if (!tokenSnapshot.empty) {
|
|
@@ -5471,7 +5172,7 @@ var markPatientTokenAsUsedUtil = async (db, tokenId, patientId, userId) => {
|
|
|
5471
5172
|
await updateDoc9(tokenRef, {
|
|
5472
5173
|
status: "used" /* USED */,
|
|
5473
5174
|
usedBy: userId,
|
|
5474
|
-
usedAt:
|
|
5175
|
+
usedAt: Timestamp11.now()
|
|
5475
5176
|
});
|
|
5476
5177
|
};
|
|
5477
5178
|
var getActiveInviteTokensByClinicUtil = async (db, clinicId) => {
|
|
@@ -5479,7 +5180,7 @@ var getActiveInviteTokensByClinicUtil = async (db, clinicId) => {
|
|
|
5479
5180
|
collectionGroup(db, INVITE_TOKENS_COLLECTION),
|
|
5480
5181
|
where9("clinicId", "==", clinicId),
|
|
5481
5182
|
where9("status", "==", "active" /* ACTIVE */),
|
|
5482
|
-
where9("expiresAt", ">",
|
|
5183
|
+
where9("expiresAt", ">", Timestamp11.now())
|
|
5483
5184
|
);
|
|
5484
5185
|
const querySnapshot = await getDocs9(tokensQuery);
|
|
5485
5186
|
if (querySnapshot.empty) {
|
|
@@ -5497,7 +5198,7 @@ var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
|
|
|
5497
5198
|
const q = query9(
|
|
5498
5199
|
tokensRef,
|
|
5499
5200
|
where9("status", "==", "active" /* ACTIVE */),
|
|
5500
|
-
where9("expiresAt", ">",
|
|
5201
|
+
where9("expiresAt", ">", Timestamp11.now())
|
|
5501
5202
|
);
|
|
5502
5203
|
const querySnapshot = await getDocs9(q);
|
|
5503
5204
|
if (querySnapshot.empty) {
|
|
@@ -5540,7 +5241,7 @@ var PatientService = class extends BaseService {
|
|
|
5540
5241
|
}
|
|
5541
5242
|
const patientId = this.generateId();
|
|
5542
5243
|
const batch = writeBatch(this.db);
|
|
5543
|
-
const now =
|
|
5244
|
+
const now = Timestamp12.now();
|
|
5544
5245
|
const patientProfileRef = getPatientDocRef(this.db, patientId);
|
|
5545
5246
|
const newProfile = {
|
|
5546
5247
|
id: patientId,
|
|
@@ -6305,7 +6006,169 @@ import {
|
|
|
6305
6006
|
arrayUnion as arrayUnion6,
|
|
6306
6007
|
arrayRemove as arrayRemove5
|
|
6307
6008
|
} from "firebase/firestore";
|
|
6308
|
-
|
|
6009
|
+
|
|
6010
|
+
// src/validations/practitioner.schema.ts
|
|
6011
|
+
import { z as z15 } from "zod";
|
|
6012
|
+
import { Timestamp as Timestamp13 } from "firebase/firestore";
|
|
6013
|
+
|
|
6014
|
+
// src/backoffice/types/static/certification.types.ts
|
|
6015
|
+
var CertificationLevel = /* @__PURE__ */ ((CertificationLevel2) => {
|
|
6016
|
+
CertificationLevel2["AESTHETICIAN"] = "aesthetician";
|
|
6017
|
+
CertificationLevel2["NURSE_ASSISTANT"] = "nurse_assistant";
|
|
6018
|
+
CertificationLevel2["NURSE"] = "nurse";
|
|
6019
|
+
CertificationLevel2["NURSE_PRACTITIONER"] = "nurse_practitioner";
|
|
6020
|
+
CertificationLevel2["PHYSICIAN_ASSISTANT"] = "physician_assistant";
|
|
6021
|
+
CertificationLevel2["DOCTOR"] = "doctor";
|
|
6022
|
+
CertificationLevel2["SPECIALIST"] = "specialist";
|
|
6023
|
+
CertificationLevel2["PLASTIC_SURGEON"] = "plastic_surgeon";
|
|
6024
|
+
return CertificationLevel2;
|
|
6025
|
+
})(CertificationLevel || {});
|
|
6026
|
+
var CertificationSpecialty = /* @__PURE__ */ ((CertificationSpecialty3) => {
|
|
6027
|
+
CertificationSpecialty3["LASER"] = "laser";
|
|
6028
|
+
CertificationSpecialty3["INJECTABLES"] = "injectables";
|
|
6029
|
+
CertificationSpecialty3["CHEMICAL_PEELS"] = "chemical_peels";
|
|
6030
|
+
CertificationSpecialty3["MICRODERMABRASION"] = "microdermabrasion";
|
|
6031
|
+
CertificationSpecialty3["BODY_CONTOURING"] = "body_contouring";
|
|
6032
|
+
CertificationSpecialty3["SKIN_CARE"] = "skin_care";
|
|
6033
|
+
CertificationSpecialty3["WOUND_CARE"] = "wound_care";
|
|
6034
|
+
CertificationSpecialty3["ANESTHESIA"] = "anesthesia";
|
|
6035
|
+
return CertificationSpecialty3;
|
|
6036
|
+
})(CertificationSpecialty || {});
|
|
6037
|
+
|
|
6038
|
+
// src/validations/practitioner.schema.ts
|
|
6039
|
+
var practitionerBasicInfoSchema = z15.object({
|
|
6040
|
+
firstName: z15.string().min(2).max(50),
|
|
6041
|
+
lastName: z15.string().min(2).max(50),
|
|
6042
|
+
title: z15.string().min(2).max(100),
|
|
6043
|
+
email: z15.string().email(),
|
|
6044
|
+
phoneNumber: z15.string().regex(/^\+?[1-9]\d{1,14}$/, "Invalid phone number").nullable(),
|
|
6045
|
+
dateOfBirth: z15.instanceof(Timestamp13).or(z15.date()).nullable(),
|
|
6046
|
+
gender: z15.enum(["male", "female", "other"]),
|
|
6047
|
+
profileImageUrl: mediaResourceSchema.optional().nullable(),
|
|
6048
|
+
bio: z15.string().max(1e3).optional(),
|
|
6049
|
+
languages: z15.array(z15.string()).min(1)
|
|
6050
|
+
});
|
|
6051
|
+
var practitionerCertificationSchema = z15.object({
|
|
6052
|
+
level: z15.nativeEnum(CertificationLevel),
|
|
6053
|
+
specialties: z15.array(z15.nativeEnum(CertificationSpecialty)),
|
|
6054
|
+
licenseNumber: z15.string().min(3).max(50),
|
|
6055
|
+
issuingAuthority: z15.string().min(2).max(100),
|
|
6056
|
+
issueDate: z15.instanceof(Timestamp13).or(z15.date()),
|
|
6057
|
+
expiryDate: z15.instanceof(Timestamp13).or(z15.date()).optional().nullable(),
|
|
6058
|
+
verificationStatus: z15.enum(["pending", "verified", "rejected"])
|
|
6059
|
+
});
|
|
6060
|
+
var timeSlotSchema = z15.object({
|
|
6061
|
+
start: z15.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/, "Invalid time format"),
|
|
6062
|
+
end: z15.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/, "Invalid time format")
|
|
6063
|
+
}).nullable();
|
|
6064
|
+
var practitionerWorkingHoursSchema = z15.object({
|
|
6065
|
+
practitionerId: z15.string().min(1),
|
|
6066
|
+
clinicId: z15.string().min(1),
|
|
6067
|
+
monday: timeSlotSchema,
|
|
6068
|
+
tuesday: timeSlotSchema,
|
|
6069
|
+
wednesday: timeSlotSchema,
|
|
6070
|
+
thursday: timeSlotSchema,
|
|
6071
|
+
friday: timeSlotSchema,
|
|
6072
|
+
saturday: timeSlotSchema,
|
|
6073
|
+
sunday: timeSlotSchema,
|
|
6074
|
+
createdAt: z15.instanceof(Timestamp13).or(z15.date()),
|
|
6075
|
+
updatedAt: z15.instanceof(Timestamp13).or(z15.date())
|
|
6076
|
+
});
|
|
6077
|
+
var practitionerClinicWorkingHoursSchema = z15.object({
|
|
6078
|
+
clinicId: z15.string().min(1),
|
|
6079
|
+
workingHours: z15.object({
|
|
6080
|
+
monday: timeSlotSchema,
|
|
6081
|
+
tuesday: timeSlotSchema,
|
|
6082
|
+
wednesday: timeSlotSchema,
|
|
6083
|
+
thursday: timeSlotSchema,
|
|
6084
|
+
friday: timeSlotSchema,
|
|
6085
|
+
saturday: timeSlotSchema,
|
|
6086
|
+
sunday: timeSlotSchema
|
|
6087
|
+
}),
|
|
6088
|
+
isActive: z15.boolean(),
|
|
6089
|
+
createdAt: z15.instanceof(Timestamp13).or(z15.date()),
|
|
6090
|
+
updatedAt: z15.instanceof(Timestamp13).or(z15.date())
|
|
6091
|
+
});
|
|
6092
|
+
var practitionerSchema = z15.object({
|
|
6093
|
+
id: z15.string().min(1),
|
|
6094
|
+
userRef: z15.string().min(1),
|
|
6095
|
+
basicInfo: practitionerBasicInfoSchema,
|
|
6096
|
+
certification: practitionerCertificationSchema,
|
|
6097
|
+
clinics: z15.array(z15.string()),
|
|
6098
|
+
clinicWorkingHours: z15.array(practitionerClinicWorkingHoursSchema),
|
|
6099
|
+
clinicsInfo: z15.array(clinicInfoSchema),
|
|
6100
|
+
procedures: z15.array(z15.string()),
|
|
6101
|
+
freeConsultations: z15.record(z15.string(), z15.string()).optional().nullable(),
|
|
6102
|
+
proceduresInfo: z15.array(procedureSummaryInfoSchema),
|
|
6103
|
+
reviewInfo: practitionerReviewInfoSchema,
|
|
6104
|
+
isActive: z15.boolean(),
|
|
6105
|
+
isVerified: z15.boolean(),
|
|
6106
|
+
status: z15.nativeEnum(PractitionerStatus),
|
|
6107
|
+
createdAt: z15.instanceof(Timestamp13).or(z15.date()),
|
|
6108
|
+
updatedAt: z15.instanceof(Timestamp13).or(z15.date())
|
|
6109
|
+
});
|
|
6110
|
+
var createPractitionerSchema = z15.object({
|
|
6111
|
+
userRef: z15.string().min(1),
|
|
6112
|
+
basicInfo: practitionerBasicInfoSchema,
|
|
6113
|
+
certification: practitionerCertificationSchema,
|
|
6114
|
+
clinics: z15.array(z15.string()).optional(),
|
|
6115
|
+
clinicWorkingHours: z15.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
6116
|
+
clinicsInfo: z15.array(clinicInfoSchema).optional(),
|
|
6117
|
+
freeConsultations: z15.record(z15.string(), z15.string()).optional().nullable(),
|
|
6118
|
+
proceduresInfo: z15.array(procedureSummaryInfoSchema).optional(),
|
|
6119
|
+
isActive: z15.boolean(),
|
|
6120
|
+
isVerified: z15.boolean(),
|
|
6121
|
+
status: z15.nativeEnum(PractitionerStatus).optional()
|
|
6122
|
+
});
|
|
6123
|
+
var createDraftPractitionerSchema = z15.object({
|
|
6124
|
+
basicInfo: practitionerBasicInfoSchema,
|
|
6125
|
+
certification: practitionerCertificationSchema,
|
|
6126
|
+
clinics: z15.array(z15.string()).optional(),
|
|
6127
|
+
clinicWorkingHours: z15.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
6128
|
+
clinicsInfo: z15.array(clinicInfoSchema).optional(),
|
|
6129
|
+
freeConsultations: z15.record(z15.string(), z15.string()).optional().nullable(),
|
|
6130
|
+
proceduresInfo: z15.array(procedureSummaryInfoSchema).optional(),
|
|
6131
|
+
isActive: z15.boolean().optional().default(false),
|
|
6132
|
+
isVerified: z15.boolean().optional().default(false)
|
|
6133
|
+
});
|
|
6134
|
+
var practitionerTokenSchema = z15.object({
|
|
6135
|
+
id: z15.string().min(1),
|
|
6136
|
+
token: z15.string().min(6),
|
|
6137
|
+
practitionerId: z15.string().min(1),
|
|
6138
|
+
email: z15.string().email(),
|
|
6139
|
+
clinicId: z15.string().min(1),
|
|
6140
|
+
status: z15.nativeEnum(PractitionerTokenStatus),
|
|
6141
|
+
createdBy: z15.string().min(1),
|
|
6142
|
+
createdAt: z15.instanceof(Timestamp13).or(z15.date()),
|
|
6143
|
+
expiresAt: z15.instanceof(Timestamp13).or(z15.date()),
|
|
6144
|
+
usedBy: z15.string().optional(),
|
|
6145
|
+
usedAt: z15.instanceof(Timestamp13).or(z15.date()).optional()
|
|
6146
|
+
});
|
|
6147
|
+
var createPractitionerTokenSchema = z15.object({
|
|
6148
|
+
practitionerId: z15.string().min(1),
|
|
6149
|
+
email: z15.string().email(),
|
|
6150
|
+
clinicId: z15.string().min(1),
|
|
6151
|
+
expiresAt: z15.date().optional()
|
|
6152
|
+
});
|
|
6153
|
+
var practitionerSignupSchema = z15.object({
|
|
6154
|
+
email: z15.string().email(),
|
|
6155
|
+
password: z15.string().min(8),
|
|
6156
|
+
firstName: z15.string().min(2).max(50).optional(),
|
|
6157
|
+
lastName: z15.string().min(2).max(50).optional(),
|
|
6158
|
+
token: z15.string().optional(),
|
|
6159
|
+
profileData: z15.object({
|
|
6160
|
+
basicInfo: z15.object({
|
|
6161
|
+
phoneNumber: z15.string().optional(),
|
|
6162
|
+
profileImageUrl: mediaResourceSchema.optional(),
|
|
6163
|
+
gender: z15.enum(["male", "female", "other"]).optional(),
|
|
6164
|
+
bio: z15.string().optional()
|
|
6165
|
+
}).optional(),
|
|
6166
|
+
certification: z15.any().optional()
|
|
6167
|
+
}).optional()
|
|
6168
|
+
});
|
|
6169
|
+
|
|
6170
|
+
// src/services/practitioner/practitioner.service.ts
|
|
6171
|
+
import { z as z16 } from "zod";
|
|
6309
6172
|
import { distanceBetween } from "geofire-common";
|
|
6310
6173
|
var PractitionerService = class extends BaseService {
|
|
6311
6174
|
constructor(db, auth, app, clinicService, procedureService) {
|
|
@@ -6435,7 +6298,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6435
6298
|
}
|
|
6436
6299
|
return createdPractitioner;
|
|
6437
6300
|
} catch (error) {
|
|
6438
|
-
if (error instanceof
|
|
6301
|
+
if (error instanceof z16.ZodError) {
|
|
6439
6302
|
throw new Error(`Invalid practitioner data: ${error.message}`);
|
|
6440
6303
|
}
|
|
6441
6304
|
console.error("Error creating practitioner:", error);
|
|
@@ -6551,7 +6414,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6551
6414
|
await setDoc10(doc11(this.db, tokenPath), token);
|
|
6552
6415
|
return { practitioner: savedPractitioner, token };
|
|
6553
6416
|
} catch (error) {
|
|
6554
|
-
if (error instanceof
|
|
6417
|
+
if (error instanceof z16.ZodError) {
|
|
6555
6418
|
throw new Error("Invalid practitioner data: " + error.message);
|
|
6556
6419
|
}
|
|
6557
6420
|
throw error;
|
|
@@ -6604,7 +6467,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6604
6467
|
await setDoc10(doc11(this.db, tokenPath), token);
|
|
6605
6468
|
return token;
|
|
6606
6469
|
} catch (error) {
|
|
6607
|
-
if (error instanceof
|
|
6470
|
+
if (error instanceof z16.ZodError) {
|
|
6608
6471
|
throw new Error("Invalid token data: " + error.message);
|
|
6609
6472
|
}
|
|
6610
6473
|
throw error;
|
|
@@ -6798,7 +6661,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6798
6661
|
}
|
|
6799
6662
|
return updatedPractitioner;
|
|
6800
6663
|
} catch (error) {
|
|
6801
|
-
if (error instanceof
|
|
6664
|
+
if (error instanceof z16.ZodError) {
|
|
6802
6665
|
throw new Error(`Invalid practitioner update data: ${error.message}`);
|
|
6803
6666
|
}
|
|
6804
6667
|
console.error(`Error updating practitioner ${practitionerId}:`, error);
|
|
@@ -7581,7 +7444,7 @@ var UserService = class extends BaseService {
|
|
|
7581
7444
|
});
|
|
7582
7445
|
return this.getUserById(uid);
|
|
7583
7446
|
} catch (error) {
|
|
7584
|
-
if (error instanceof
|
|
7447
|
+
if (error instanceof z17.ZodError) {
|
|
7585
7448
|
throw USER_ERRORS.VALIDATION_ERROR;
|
|
7586
7449
|
}
|
|
7587
7450
|
throw error;
|
|
@@ -7678,7 +7541,7 @@ import {
|
|
|
7678
7541
|
Timestamp as Timestamp16
|
|
7679
7542
|
} from "firebase/firestore";
|
|
7680
7543
|
import { geohashForLocation as geohashForLocation2 } from "geofire-common";
|
|
7681
|
-
import { z as
|
|
7544
|
+
import { z as z18 } from "zod";
|
|
7682
7545
|
|
|
7683
7546
|
// src/services/clinic/utils/photos.utils.ts
|
|
7684
7547
|
import {
|
|
@@ -7882,7 +7745,7 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
|
|
|
7882
7745
|
});
|
|
7883
7746
|
return groupData;
|
|
7884
7747
|
} catch (error) {
|
|
7885
|
-
if (error instanceof
|
|
7748
|
+
if (error instanceof z18.ZodError) {
|
|
7886
7749
|
console.error(
|
|
7887
7750
|
"[CLINIC_GROUP] Zod validation error:",
|
|
7888
7751
|
JSON.stringify(error.errors, null, 2)
|
|
@@ -8338,7 +8201,7 @@ import {
|
|
|
8338
8201
|
import {
|
|
8339
8202
|
geohashForLocation as geohashForLocation4
|
|
8340
8203
|
} from "geofire-common";
|
|
8341
|
-
import { z as
|
|
8204
|
+
import { z as z20 } from "zod";
|
|
8342
8205
|
|
|
8343
8206
|
// src/services/clinic/utils/clinic.utils.ts
|
|
8344
8207
|
import {
|
|
@@ -8359,7 +8222,7 @@ import {
|
|
|
8359
8222
|
distanceBetween as distanceBetween2,
|
|
8360
8223
|
geohashQueryBounds
|
|
8361
8224
|
} from "geofire-common";
|
|
8362
|
-
import { z as
|
|
8225
|
+
import { z as z19 } from "zod";
|
|
8363
8226
|
async function getClinic(db, clinicId) {
|
|
8364
8227
|
const docRef = doc14(db, CLINICS_COLLECTION, clinicId);
|
|
8365
8228
|
const docSnap = await getDoc17(docRef);
|
|
@@ -9136,7 +8999,7 @@ var ClinicService = class extends BaseService {
|
|
|
9136
8999
|
if (!savedClinic) throw new Error("Failed to retrieve created clinic");
|
|
9137
9000
|
return savedClinic;
|
|
9138
9001
|
} catch (error) {
|
|
9139
|
-
if (error instanceof
|
|
9002
|
+
if (error instanceof z20.ZodError) {
|
|
9140
9003
|
throw new Error("Invalid clinic data: " + error.message);
|
|
9141
9004
|
}
|
|
9142
9005
|
console.error("Error creating clinic:", error);
|
|
@@ -9216,7 +9079,7 @@ var ClinicService = class extends BaseService {
|
|
|
9216
9079
|
if (!updatedClinic) throw new Error("Failed to retrieve updated clinic");
|
|
9217
9080
|
return updatedClinic;
|
|
9218
9081
|
} catch (error) {
|
|
9219
|
-
if (error instanceof
|
|
9082
|
+
if (error instanceof z20.ZodError) {
|
|
9220
9083
|
throw new Error("Invalid clinic update data: " + error.message);
|
|
9221
9084
|
}
|
|
9222
9085
|
console.error(`Error updating clinic ${clinicId}:`, error);
|
|
@@ -9379,6 +9242,125 @@ var ClinicService = class extends BaseService {
|
|
|
9379
9242
|
}
|
|
9380
9243
|
};
|
|
9381
9244
|
|
|
9245
|
+
// src/services/auth/utils/firebase.utils.ts
|
|
9246
|
+
import { fetchSignInMethodsForEmail } from "firebase/auth";
|
|
9247
|
+
var checkEmailExists = async (auth, email) => {
|
|
9248
|
+
try {
|
|
9249
|
+
const methods = await fetchSignInMethodsForEmail(auth, email);
|
|
9250
|
+
return methods.length > 0;
|
|
9251
|
+
} catch (error) {
|
|
9252
|
+
console.warn(
|
|
9253
|
+
"[FIREBASE] Could not check email existence, allowing signup to proceed:",
|
|
9254
|
+
error
|
|
9255
|
+
);
|
|
9256
|
+
return false;
|
|
9257
|
+
}
|
|
9258
|
+
};
|
|
9259
|
+
var cleanupFirebaseUser = async (firebaseUser) => {
|
|
9260
|
+
try {
|
|
9261
|
+
console.log("[FIREBASE] Cleaning up Firebase user", {
|
|
9262
|
+
uid: firebaseUser.uid
|
|
9263
|
+
});
|
|
9264
|
+
await firebaseUser.delete();
|
|
9265
|
+
console.log("[FIREBASE] Firebase user cleanup successful");
|
|
9266
|
+
} catch (cleanupError) {
|
|
9267
|
+
console.error("[FIREBASE] Failed to cleanup Firebase user:", cleanupError);
|
|
9268
|
+
}
|
|
9269
|
+
};
|
|
9270
|
+
|
|
9271
|
+
// src/services/auth/utils/error.utils.ts
|
|
9272
|
+
import { z as z21 } from "zod";
|
|
9273
|
+
var handleFirebaseError = (error) => {
|
|
9274
|
+
const firebaseError = error;
|
|
9275
|
+
switch (firebaseError.code) {
|
|
9276
|
+
case "auth/email-already-in-use" /* EMAIL_ALREADY_IN_USE */:
|
|
9277
|
+
return AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
|
|
9278
|
+
case "auth/weak-password":
|
|
9279
|
+
return new Error(
|
|
9280
|
+
"Password is too weak. Please choose a stronger password."
|
|
9281
|
+
);
|
|
9282
|
+
case "auth/invalid-email":
|
|
9283
|
+
return new Error("Please enter a valid email address.");
|
|
9284
|
+
case "auth/network-request-failed":
|
|
9285
|
+
return new Error(
|
|
9286
|
+
"Network error. Please check your internet connection and try again."
|
|
9287
|
+
);
|
|
9288
|
+
default:
|
|
9289
|
+
return new Error(
|
|
9290
|
+
`Account creation failed: ${firebaseError.message || "Unknown error"}`
|
|
9291
|
+
);
|
|
9292
|
+
}
|
|
9293
|
+
};
|
|
9294
|
+
var handleSignupError = (error) => {
|
|
9295
|
+
if (error instanceof z21.ZodError) {
|
|
9296
|
+
const errorMessages = error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
9297
|
+
return new Error(`Validation failed: ${errorMessages}`);
|
|
9298
|
+
}
|
|
9299
|
+
if (error.code && error.code.startsWith("auth/")) {
|
|
9300
|
+
return handleFirebaseError(error);
|
|
9301
|
+
}
|
|
9302
|
+
if (error.message && error.message.includes("token")) {
|
|
9303
|
+
return new Error("Invalid or expired invitation token");
|
|
9304
|
+
}
|
|
9305
|
+
if (error.message && error.message.includes("validation")) {
|
|
9306
|
+
return new Error(`Invalid practitioner data: ${error.message}`);
|
|
9307
|
+
}
|
|
9308
|
+
return new Error(
|
|
9309
|
+
`Registration failed: ${error.message || "Unknown error occurred"}`
|
|
9310
|
+
);
|
|
9311
|
+
};
|
|
9312
|
+
|
|
9313
|
+
// src/services/auth/utils/practitioner.utils.ts
|
|
9314
|
+
import { z as z22 } from "zod";
|
|
9315
|
+
var profileDataSchema = z22.object({
|
|
9316
|
+
basicInfo: practitionerBasicInfoSchema.partial().optional(),
|
|
9317
|
+
certification: practitionerCertificationSchema.partial().optional()
|
|
9318
|
+
}).partial();
|
|
9319
|
+
var buildPractitionerData = (data, userRef) => {
|
|
9320
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
9321
|
+
const basicInfo = {
|
|
9322
|
+
firstName: data.firstName || "Name",
|
|
9323
|
+
lastName: data.lastName || "Surname",
|
|
9324
|
+
email: data.email,
|
|
9325
|
+
phoneNumber: ((_b = (_a = data.profileData) == null ? void 0 : _a.basicInfo) == null ? void 0 : _b.phoneNumber) || null,
|
|
9326
|
+
profileImageUrl: ((_d = (_c = data.profileData) == null ? void 0 : _c.basicInfo) == null ? void 0 : _d.profileImageUrl) || "",
|
|
9327
|
+
gender: ((_f = (_e = data.profileData) == null ? void 0 : _e.basicInfo) == null ? void 0 : _f.gender) || "other",
|
|
9328
|
+
bio: ((_h = (_g = data.profileData) == null ? void 0 : _g.basicInfo) == null ? void 0 : _h.bio) || "",
|
|
9329
|
+
title: "Practitioner",
|
|
9330
|
+
dateOfBirth: ((_j = (_i = data.profileData) == null ? void 0 : _i.basicInfo) == null ? void 0 : _j.dateOfBirth) || /* @__PURE__ */ new Date(),
|
|
9331
|
+
languages: ((_l = (_k = data.profileData) == null ? void 0 : _k.basicInfo) == null ? void 0 : _l.languages) || ["English"]
|
|
9332
|
+
};
|
|
9333
|
+
const certification = ((_m = data.profileData) == null ? void 0 : _m.certification) || {
|
|
9334
|
+
level: "aesthetician" /* AESTHETICIAN */,
|
|
9335
|
+
specialties: [],
|
|
9336
|
+
licenseNumber: "Pending",
|
|
9337
|
+
issuingAuthority: "Pending",
|
|
9338
|
+
issueDate: /* @__PURE__ */ new Date(),
|
|
9339
|
+
verificationStatus: "pending"
|
|
9340
|
+
};
|
|
9341
|
+
return {
|
|
9342
|
+
userRef,
|
|
9343
|
+
basicInfo,
|
|
9344
|
+
certification,
|
|
9345
|
+
status: "active" /* ACTIVE */,
|
|
9346
|
+
isActive: true,
|
|
9347
|
+
isVerified: false
|
|
9348
|
+
};
|
|
9349
|
+
};
|
|
9350
|
+
var validatePractitionerProfileData = async (profileData) => {
|
|
9351
|
+
try {
|
|
9352
|
+
await profileDataSchema.parseAsync(profileData);
|
|
9353
|
+
} catch (error) {
|
|
9354
|
+
if (error instanceof z22.ZodError) {
|
|
9355
|
+
const errorMessages = error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
9356
|
+
throw new Error(
|
|
9357
|
+
`Practitioner profile validation failed: ${errorMessages}`
|
|
9358
|
+
);
|
|
9359
|
+
}
|
|
9360
|
+
throw error;
|
|
9361
|
+
}
|
|
9362
|
+
};
|
|
9363
|
+
|
|
9382
9364
|
// src/services/auth/auth.service.ts
|
|
9383
9365
|
var AuthService = class extends BaseService {
|
|
9384
9366
|
constructor(db, auth, app, userService) {
|
|
@@ -17398,11 +17380,8 @@ export {
|
|
|
17398
17380
|
beforeAfterPerZoneSchema,
|
|
17399
17381
|
billingPerZoneSchema,
|
|
17400
17382
|
blockingConditionSchema,
|
|
17401
|
-
buildPractitionerData,
|
|
17402
17383
|
calendarEventSchema,
|
|
17403
17384
|
calendarEventTimeSchema,
|
|
17404
|
-
checkEmailExists,
|
|
17405
|
-
cleanupFirebaseUser,
|
|
17406
17385
|
clinicAdminOptionsSchema,
|
|
17407
17386
|
clinicAdminSchema,
|
|
17408
17387
|
clinicAdminSignupSchema,
|
|
@@ -17450,7 +17429,6 @@ export {
|
|
|
17450
17429
|
documentTemplateSchema,
|
|
17451
17430
|
emailSchema,
|
|
17452
17431
|
emergencyContactSchema,
|
|
17453
|
-
extractErrorMessage,
|
|
17454
17432
|
filledDocumentSchema,
|
|
17455
17433
|
filledDocumentStatusSchema,
|
|
17456
17434
|
finalBillingSchema,
|
|
@@ -17462,10 +17440,7 @@ export {
|
|
|
17462
17440
|
getFirebaseFunctions,
|
|
17463
17441
|
getFirebaseInstance,
|
|
17464
17442
|
getFirebaseStorage,
|
|
17465
|
-
handleFirebaseError,
|
|
17466
|
-
handleSignupError,
|
|
17467
17443
|
initializeFirebase,
|
|
17468
|
-
isPractitionerDataComplete,
|
|
17469
17444
|
linkedFormInfoSchema,
|
|
17470
17445
|
locationDataSchema,
|
|
17471
17446
|
mediaResourceSchema,
|
|
@@ -17537,7 +17512,6 @@ export {
|
|
|
17537
17512
|
userRoleSchema,
|
|
17538
17513
|
userRolesSchema,
|
|
17539
17514
|
userSchema,
|
|
17540
|
-
validatePractitionerProfileData,
|
|
17541
17515
|
vitalStatsSchema,
|
|
17542
17516
|
workingHoursSchema
|
|
17543
17517
|
};
|