1import { DateTime } from "./chunk-XYSFEBQZ.js"; 2import { AuthenticationService, Firestore, Timestamp, collection2 as collection, collectionSnapshots, doc, endAt, environment, getCountFromServer, getDoc, getDocs2 as getDocs, limit2 as limit, orderBy, query2 as query, startAfter, where2 as where } from "./chunk-2TSZT3SZ.js"; 3import { HttpClient } from "./chunk-HE5ARQDU.js"; 4import { Injectable, __spreadProps, __spreadValues, catchError, concatMap, forkJoin, from, map, of, setClassMetadata, switchMap, take, throwError, toArray, ɵɵdefineInjectable, ɵɵinject } from "./chunk-ZGC4HH7K.js"; 5
6// src/app/_interfaces/office-worktime-command.interface.ts 7var MAX_OFFICE_WORK_TIME_REVIEW_RECORDS = 150; 8var MAX_OFFICE_MANUAL_WORK_INTERVALS = 24; 9
10// src/app/_services/work-time-records.service.ts 11var WorkTimeRecordsService = class _WorkTimeRecordsService { 12 constructor(firestore, http, authService) { 13 this.firestore = firestore; 14 this.http = http; 15 this.authService = authService; 16 } 17 // Approved work time records for a single employee within one week, identified by its `ddMMyyyy` 18 // day keys (⤠7, so a single `in` query is enough). Used by the work-schedule dialog to warn that 19 // days with an approved record won't be overwritten by edits to the work schedule. Failures resolve 20 // to an empty list so the dialog still works (the warning simply doesn't render). 21 getApprovedWorkTimeRecordsForWeek(employeeId, weekDateFormats) { 22 const dateFormats = Array.from(new Set(weekDateFormats.filter(Boolean))); 23 if (!employeeId || !dateFormats.length) return of([]); 24 return this.authService.getCurrentSession$().pipe(take(1), switchMap(({ 25 orgId 26 }) => { 27 const colRef = collection(this.firestore, "organizations", orgId, "workTimeRecords"); 28 return from(getDocs(query(colRef, where("employeeId", "==", employeeId), where("dateFormat", "in", dateFormats)))); 29 }), map(snap => snap.docs.map(d => __spreadProps(__spreadValues({}, d.data()), { 30 id: d.id, 31 exists: d.exists() 32 })).filter(record => record.approvalStatus === "approved").sort((a, b) => a.date.toMillis() - b.date.toMillis())), catchError(error => { 33 console.error("Failed to retrieve approved work time records.", error); 34 return of([]); 35 })); 36 } 37 // Returns every WorkTimeRecord for the given employees on the given `ddMMyyyy` day, 38 // regardless of approvalStatus. Used by live dashboard widgets that need to derive 39 // workforce status (clocked-in / sick / PTO / no-show) from the raw records. 40 // Employee ids are chunked at 30 to respect Firestore's `in` operator limit. 41 getWorkTimeRecordsByDateForEmployees(employeeIds, dateFormat) { 42 if (!employeeIds.length) return of([]); 43 return this.authService.getCurrentSession$().pipe(take(1), switchMap(session => { 44 const colRef = collection(this.firestore, "organizations", session.orgId, "workTimeRecords"); 45 const chunks = []; 46 for (let i = 0; i < employeeIds.length; i += 30) { 47 chunks.push(employeeIds.slice(i, i + 30)); 48 } 49 const requests = chunks.map(chunk => { 50 const q = query(colRef, where("employeeId", "in", chunk), where("dateFormat", "==", dateFormat)); 51 return from(getDocs(q)); 52 }); 53 return forkJoin(requests).pipe(map(snapshots => { 54 const records = []; 55 for (const snap of snapshots) { 56 for (const docSnap of snap.docs) { 57 records.push(__spreadProps(__spreadValues({}, docSnap.data()), { 58 id: docSnap.id, 59 exists: docSnap.exists() 60 })); 61 } 62 } 63 return records; 64 })); 65 })); 66 } 67 getPendingWorkTimeRecords(startDate, endDate, employeeId, employeeIds, teamId) { 68 const startOfDay = new Date(startDate.setHours(0, 0, 0, 0)); 69 const endOfDay = new Date(endDate.setHours(23, 59, 59, 999)); 70 return this.authService.getCurrentSession$().pipe(take(1), switchMap(session => { 71 const collectionRef = collection(this.firestore, "organizations", session.orgId, "workTimeRecords"); 72 let baseQuery = query(collectionRef, where("approvalStatus", "==", "pending"), where("date", ">=", Timestamp.fromDate(startOfDay)), where("date", "<=", Timestamp.fromDate(endOfDay))); 73 let allowedIds = null; 74 if (session.role === "MANAGER") { 75 if (Array.isArray(session.viewEmployeeIds) && session.viewEmployeeIds.length > 0) { 76 allowedIds = session.viewEmployeeIds; 77 } else { 78 return of([]); 79 } 80 } 81 let finalIds = null; 82 if (employeeId) { 83 finalIds = [employeeId]; 84 } else if (Array.isArray(employeeIds) && employeeIds.length > 0) { 85 finalIds = employeeIds; 86 } else if (allowedIds) { 87 finalIds = allowedIds; 88 } 89 if (teamId && !employeeIds?.length) return of([]); 90 if (!finalIds) { 91 return from(getDocs(baseQuery)).pipe(map(snap => snap.docs)); 92 }
93 const idChunks = this.chunkArray(finalIds, 30); 94 return from(idChunks).pipe(concatMap(chunk => { 95 const chunkQuery = query(baseQuery, where("employeeId", "in", chunk)); 96 return from(getDocs(chunkQuery)); 97 }), map(qSnap => qSnap.docs), toArray(), map(arrays => arrays.flat()) 98 // merge chunk results 99 ); 100 }), 101 // ------------------------------------------------------------- 102 // Transform Firestore docs â your interface 103 // ------------------------------------------------------------- 104 map(collectionSnapshots2 => collectionSnapshots2.map(docItem => { 105 const data = docItem.data(); 106 return __spreadProps(__spreadValues({}, data), { 107 totalWorkHours: this.safe2(data.totalWorkHours), 108 id: docItem.id, 109 exists: docItem.exists() 110 }); 111 }).sort(this.sortByEmployeeIdAndDateAsc)), catchError(error => { 112 console.error("Failed to retrieve work time records.", error); 113 return this.handleFirestoreError(error, "Ophalen tijdregistraties niet gelukt"); 114 })); 115 } 116 // Every pending WorkTimeRecord visible to the current session, no date filter â used by the 117 // pending-work-time dashboard widget so the tile can split the queue into 118 // "⤠7 days old" vs "overdue". Manager scope chunks `session.viewEmployeeIds` at 30 to 119 // respect Firestore's `in` cap; OWNER / ADMIN see the whole org. 120 getPendingWorkTimeRecordsForCurrentUser() { 121 return this.authService.getCurrentSession$().pipe(take(1), switchMap(session => { 122 const colRef = collection(this.firestore, "organizations", session.orgId, "workTimeRecords"); 123 const baseQuery = query(colRef, where("approvalStatus", "==", "pending")); 124 if (session.role === "MANAGER") { 125 const allowedIds = session.viewEmployeeIds ?? []; 126 if (!allowedIds.length) return of([]); 127 const chunks = this.chunkArray(allowedIds, 30); 128 return forkJoin(chunks.map(chunk => from(getDocs(query(baseQuery, where("employeeId", "in", chunk)))).pipe(map(snap => snap.docs)))).pipe(map(arrays => arrays.flat())); 129 } 130 return from(getDocs(baseQuery)).pipe(map(snap => snap.docs)); 131 }), map(docs => docs.map(d => { 132 const data = d.data(); 133 return __spreadProps(__spreadValues({}, data), { 134 totalWorkHours: this.safe2(data.totalWorkHours), 135 id: d.id, 136 exists: d.exists() 137 }); 138 })), catchError(err => { 139 console.error("Failed to retrieve pending work time records.", err); 140 return this.handleFirestoreError(err, "Ophalen tijdregistraties niet gelukt"); 141 })); 142 } 143 // Pending WorkTimeRecords for a specific set of employees, no date filter â used to scope the 144 // pending-work-time widget to a single team's members regardless of the viewer's role. Chunks 145 // the ids at 30 to respect Firestore's `in` cap. 146 getPendingWorkTimeRecordsForEmployees(employeeIds) { 147 if (!employeeIds.length) return of([]); 148 return this.authService.getCurrentSession$().pipe(take(1), switchMap(session => { 149 const colRef = collection(this.firestore, "organizations", session.orgId, "workTimeRecords"); 150 const baseQuery = query(colRef, where("approvalStatus", "==", "pending")); 151 const chunks = this.chunkArray(employeeIds, 30); 152 return forkJoin(chunks.map(chunk => from(getDocs(query(baseQuery, where("employeeId", "in", chunk)))).pipe(map(snap => snap.docs)))).pipe(map(arrays => arrays.flat())); 153 }), map(docs => docs.map(d => { 154 const data = d.data(); 155 return __spreadProps(__spreadValues({}, data), { 156 totalWorkHours: this.safe2(data.totalWorkHours), 157 id: d.id, 158 exists: d.exists() 159 }); 160 })), catchError(err => { 161 console.error("Failed to retrieve pending work time records.", err); 162 return this.handleFirestoreError(err, "Ophalen tijdregistraties niet gelukt"); 163 })); 164 } 165 getPendingWorkTimeRecordsByFormattedDateForEmployee(startDate, employeeId) { 166 const formattedDate = DateTime.fromJSDate(startDate).toFormat("ddMMyyyy"); 167 return this.authService.getCurrentSession$().pipe(take(1), switchMap(session => { 168 const collectionRef = collection(this.firestore, "organizations", session.orgId, "workTimeRecords"); 169 let baseQuery = query(collectionRef, where("dateFormat", "==", formattedDate), where("employeeId", "==", employeeId), limit(1)); 170 return getDocs(baseQuery); 171 }), map(collectionSnapshots2 => { 172 if (!collectionSnapshots2.empty) { 173 const docSnapshot = collectionSnapshots2.docs[0]; 174 return __spreadProps(__spreadValues({}, docSnapshot.data()), { 175 id: docSnapshot.id, 176 exists: docSnapshot.exists() 177 }); 178 } 179 return null; 180 }), catchError(error => { 181 console.error("Failed to retrieve work time insights for employee.", error); 182 return this.handleFirestoreError(error, "Ophalen tijdregistraties niet gelukt"); 183 })); 184 } 185 getDailyWorkTimeRecordsByEmployeeId(employeeId, date) { 186 return this.authService.getCurrentSession$().pipe(take(1), switchMap(({ 187 orgId 188 }) => { 189 const collectionRef = collection(this.firestore, "organizations", orgId, "workTimeRecords"); 190 const dailyRecordQuery = query(collectionRef, where("dateFormat", "==", date), where("employeeId", "==", employeeId), limit(1) 191 // limit to one document since we expect only one daily record per employee 192 ); 193 return getDocs(dailyRecordQuery); 194 }), map(snapshots => { 195 if (snapshots.empty) { 196 return null; 197 } 198 const docItem = snapshots.docs[0]; 199 const data = docItem.data(); 200 return __spreadProps(__spreadValues({}, data), { 201 totalWorkHours: this.safe2(data.totalWorkHours), 202 id: docItem.id, 203 exists: docItem.exists() 204 }); 205 }), catchError(error => { 206 console.error("Failed to retrieve work time record.", error); 207 return this.handleFirestoreError(error, "Ophalen tijdregistraties niet gelukt"); 208 })); 209 } 210 // Recent work-time records for a set of employee ids (e.g. every active member of a team),
211 // filtered at the DB level on the `dateFormat` string field (`ddMMyyyy`) via `in`, which 212 // avoids the broad client-side filtering anti-pattern and hits the (employeeId, dateFormat) 213 // composite index used by single-employee queries. 214 // Firestore caps `in` at 30 values and disjunctive normal form at 30 â combining two `in` 215 // clauses would multiply disjunctions past the limit, so we fan out per employee and only 216 // chunk the date list. For typical windows (<= 30 days) that's one query per employee. 217 getRecentTeamWorkTimeRecords(employeeIds) { 218 if (!employeeIds.length) return of([]); 219 const dayWindow = 7; 220 const today = DateTime.now().startOf("day"); 221 const dateFormats = []; 222 for (let i = 0; i <= dayWindow; i++) { 223 dateFormats.push(today.minus({ 224 days: i 225 }).toFormat("ddMMyyyy")); 226 } 227 const dateChunks = this.chunkArray(dateFormats, 30); 228 return this.authService.getCurrentSession$().pipe(take(1), switchMap(({ 229 orgId 230 }) => { 231 const collectionRef = collection(this.firestore, "organizations", orgId, "workTimeRecords"); 232 const requests = employeeIds.flatMap(employeeId => dateChunks.map(chunk => from(getDocs(query(collectionRef, where("employeeId", "==", employeeId), where("dateFormat", "in", chunk)))))); 233 return forkJoin(requests); 234 }), map(snapshots => { 235 const records = []; 236 for (const snap of snapshots) { 237 for (const docItem of snap.docs) { 238 const data = docItem.data(); 239 records.push(__spreadProps(__spreadValues({}, data), { 240 totalWorkHours: this.safe2(data.totalWorkHours), 241 id: docItem.id, 242 exists: docItem.exists() 243 })); 244 } 245 } 246 return records.sort(this.sortByEmployeeIdAndDateDesc); 247 }), catchError(error => { 248 console.error("Failed to retrieve team work time records.", error); 249 return this.handleFirestoreError(error, "Ophalen tijdregistraties niet gelukt"); 250 })); 251 } 252 getWorkTimeRecordsByEmployeeId(employeeId, startDateInput, endDateInput) { 253 const today = DateTime.now(); 254 const startDate = startDateInput || today.minus({ 255 days: 5 256 }).startOf("day").toJSDate(); 257 const endDate = endDateInput || today.endOf("day").toJSDate(); 258 return this.authService.getCurrentSession$().pipe(take(1), switchMap(({ 259 orgId 260 }) => { 261 const collectionRef = collection(this.firestore, "organizations", orgId, "workTimeRecords"); 262 const baseQuery = query(collectionRef, where("date", ">=", Timestamp.fromDate(startDate)), where("date", "<=", Timestamp.fromDate(endDate)), where("employeeId", "==", employeeId)); 263 return collectionSnapshots(baseQuery); 264 }), map(collectionSnapshots2 => collectionSnapshots2.map(docItem => { 265 const data = docItem.data(); 266 return __spreadProps(__spreadValues({}, data), { 267 totalWorkHours: this.safe2(data.totalWorkHours), 268 id: docItem.id, 269 exists: docItem.exists() 270 }); 271 }).sort(this.sortByEmployeeIdAndDateDesc)), catchError(error => { 272 console.error("Failed to retrieve work time insights.", error); 273 return this.handleFirestoreError(error, "Ophalen tijdregistraties niet gelukt"); 274 })); 275 } 276 getWorkTimeRecordsPaginated(pageSize = 10, firstDoc, lastDoc, sortDirection = "desc", employeeId, startDateInput, endDateInput, approvalStatus) { 277 return this.authService.getCurrentSession$().pipe(take(1), switchMap(session => { 278 const collectionRef = collection(this.firestore, "organizations", session.orgId, "workTimeRecords"); 279 const queryConstraints = []; 280 if (employeeId) { 281 queryConstraints.push(where("employeeId", "==", employeeId)); 282 } else if (session?.role === "MANAGER") { 283 const viewEmployeeIds = session.viewEmployeeIds ?? []; 284 if (viewEmployeeIds.length === 0) { 285 return of({ 286 records: [], 287 firstVisibleDoc: null, 288 lastVisibleDoc: null 289 }); 290 } 291 queryConstraints.push(where("employeeId", "in", viewEmployeeIds)); 292 } 293 if (startDateInput) { 294 const startDate = Timestamp.fromDate(DateTime.fromJSDate(startDateInput).startOf("day").toJSDate()); 295 queryConstraints.push(where("date", ">=", startDate)); 296 } 297 if (endDateInput) { 298 const endDate = Timestamp.fromDate(DateTime.fromJSDate(endDateInput).endOf("day").toJSDate()); 299 queryConstraints.push(where("date", "<=", endDate)); 300 } 301 if (approvalStatus && approvalStatus !== "all") { 302 queryConstraints.push(where("approvalStatus", "==", approvalStatus)); 303 } 304 queryConstraints.push(orderBy("date", sortDirection)); 305 queryConstraints.push(limit(pageSize)); 306 if (firstDoc) { 307 queryConstraints.push(endAt(firstDoc)); 308 } else if (lastDoc) { 309 queryConstraints.push(startAfter(lastDoc)); 310 } 311 const paginatedQuery = query(collectionRef, ...queryConstraints); 312 return from(getDocs(paginatedQuery)).pipe(map(snapshot => { 313 const records = snapshot.docs.map(doc2 => __spreadProps(__spreadValues({}, doc2.data()), { 314 id: doc2.id, 315 exists: doc2.exists() 316 })); 317 const firstVisibleDoc = snapshot.docs.length > 0 ? snapshot.docs[0] : null; 318 const lastVisibleDoc = snapshot.docs.length > 0 ? snapshot.docs[snapshot.docs.length - 1] : null; 319 return { 320 records, 321 firstVisibleDoc, 322 lastVisibleDoc 323 }; 324 })); 325 })); 326 } 327 getFilteredWorkTimeRecordsCount(employeeId, startDateInput, endDateInput, approvalStatus) { 328 return this.authService.getCurrentSession$().pipe(take(1), switchMap(session => { 329 const collectionRef = collection(this.firestore, "organizations", session.orgId, "workTimeRecords"); 330 const queryConstraints = []; 331 if (employeeId) { 332 queryConstraints.push(where("employeeId", "==", employeeId)); 333 } else if (session?.role === "MANAGER") { 334 const viewEmployeeIds = session.viewEmployeeIds ?? []; 335 if (viewEmployeeIds.length === 0) { 336 return of(0); 337 } 338 queryConstraints.push(where("employeeId", "in", viewEmployeeIds)); 339 } 340 if (startDateInput) { 341 const startDate = Timestamp.fromDate(DateTime.fromJSDate(startDateInput).startOf("day").toJSDate()); 342 queryConstraints.push(where("date", ">=", startDate)); 343 } 344 if (endDateInput) { 345 const endDate = Timestamp.fromDate(DateTime.fromJSDate(endDateInput).endOf("day").toJSDate()); 346 queryConstraints.push(where("date", "<=", endDate)); 347 } 348 if (approvalStatus && approvalStatus !== "all") { 349 queryConstraints.push(where("approvalStatus", "==", approvalStatus)); 350 } 351 const countQuery = query(collectionRef, ...queryConstraints); 352 return from(getCountFromServer(countQuery)).pipe(map(snapshot => snapshot.data().count)); 353 })); 354 } 355 /** 356 * Replaces manual time on an existing pending WorkTimeRecord through the 357 * server-authoritative Office command boundary. The persisted record is read 358 * back afterwards so callers continue to receive hydrated Firestore 359 * Timestamp values. 360 */ 361 updateManualTimeOnWorkTimeRecord(workTimeRecordId, update) { 362 return this.authService.getCurrentSession$().pipe(take(1), switchMap(session => this.executeOfficeWorkTimeCommand({ 363 operation: "REPLACE_MANUAL", 364 recordId: workTimeRecordId,
365 intervals: (update.manualTimeRegistration ?? []).map(entry => ({ 366 startTime: entry.startTime.toDate().toISOString(), 367 endTime: entry.endTime.toDate().toISOString() 368 })) 369 }).pipe(switchMap(() => this.getWorkTimeRecordByIdForOrg$(session.orgId, workTimeRecordId))))); 370 } 371 createWorkTimeRecord(date, employeeId) { 372 const url = environment.apiConfig.createOfficeWorkTimeRecord; 373 const payloadDate = DateTime.fromJSDate(date).toFormat("ddMMyyyy"); 374 const body = { 375 date: payloadDate, 376 employeeId, 377 language: environment.language, 378 enableDebug: !environment.production 379 }; 380 return this.http.post(url, body).pipe(catchError(err => this.handleHttpError(err))); 381 } 382 /** Ask the server to recalculate exactly one day; it owns the timezone boundary. */ 383 recalcDayWorkHoursIfNeeded$(employeeId, day) { 384 const requestedDay = day.startOf("day"); 385 const date = requestedDay.toFormat("ddMMyyyy"); 386 const body = { 387 firstDay: date, 388 lastDay: date, 389 employeeId, 390 updateStats: true, 391 language: environment.language, 392 debug: !environment.production 393 }; 394 return this.http.post(environment.apiConfig.recalcWorkTimeRecordPeriod, body).pipe(catchError(err => this.handleHttpError(err))); 395 } 396 /** Ask the server to recalculate the week; it owns the timezone and lifecycle boundary. */ 397 recalcWeekWorkHoursIfNeeded$(employeeId, weekAnchor) { 398 const anchor = weekAnchor.startOf("day"); 399 const weekStart = anchor.set({ 400 weekday: 1 401 }).startOf("day"); 402 const weekEnd = anchor.set({ 403 weekday: 7 404 }).endOf("day"); 405 const url = environment.apiConfig.recalcWorkTimeRecordPeriod; 406 const body = { 407 firstDay: weekStart.toFormat("ddMMyyyy"), 408 lastDay: weekEnd.toFormat("ddMMyyyy"), 409 employeeId, 410 updateStats: true, 411 language: environment.language, 412 debug: !environment.production 413 }; 414 return this.http.post(url, body).pipe(catchError(err => this.handleHttpError(err))); 415 } 416 processSelectedWorkTimeRecords(approvedWorkTimeRecords, rejectedWorkTimeRecords) { 417 const records = [...approvedWorkTimeRecords.map(record => __spreadValues({ 418 recordId: record.id, 419 decision: "approved" 420 }, Array.isArray(record.workHours) ? { 421 workHours: this.normalizeReviewWorkHours(record.workHours) 422 } : {})), ...rejectedWorkTimeRecords.map(record => ({ 423 recordId: record.id, 424 decision: "rejected" 425 }))]; 426 const chunks = this.chunkArray(records, MAX_OFFICE_WORK_TIME_REVIEW_RECORDS); 427 return from(chunks).pipe(concatMap(chunk => this.executeOfficeWorkTimeCommand({ 428 operation: "REVIEW", 429 records: chunk 430 })), toArray(), map(() => void 0)); 431 } 432 normalizeReviewWorkHours(workHours) { 433 const byType = /* @__PURE__ */new Map(); 434 for (const workHour of workHours) { 435 byType.set(workHour.workHourTypeId, Number(((byType.get(workHour.workHourTypeId) ?? 0) + workHour.workHours).toFixed(2))); 436 } 437 return [...byType.entries()].map(([workHourTypeId, hours]) => ({ 438 workHourTypeId, 439 workHours: hours 440 })); 441 } 442 /** 443 * CLOCK IN 444 * ------------------------------------------------- 445 * Delegates the current-day clock mutation to the server command boundary. 446 */ 447 clockInPendingWorkTimeRecord(record) { 448 return this.executeOfficeWorkTimeCommand({ 449 operation: "CLOCK_IN", 450 recordId: record.id 451 }).pipe(map(() => void 0)); 452 } 453 /** 454 * CLOCK OUT 455 * ------------------------------------------------- 456 * Delegates the current-day clock mutation to the server command boundary. 457 */ 458 clockOutPendingWorkTimeRecord(recordId) { 459 return this.executeOfficeWorkTimeCommand({ 460 operation: "CLOCK_OUT", 461 recordId 462 }).pipe(map(() => void 0)); 463 } 464 executeOfficeWorkTimeCommand(command) { 465 return this.http.post(environment.apiConfig.manageOfficeWorkTimeRecords, __spreadProps(__spreadValues({}, command), { 466 language: environment.language 467 })).pipe(catchError(err => this.handleHttpError(err))); 468 } 469 getWorkTimeRecordByIdForOrg$(orgId, workTimeRecordId) { 470 const recordRef = doc(this.firestore, "organizations", orgId, "workTimeRecords", workTimeRecordId); 471 return from(getDoc(recordRef)).pipe(map(snapshot => { 472 if (!snapshot.exists()) { 473 const error = new Error("WorkTimeRecord does not exist"); 474 error.code = "not-found"; 475 throw error; 476 } 477 return __spreadProps(__spreadValues({}, snapshot.data()), { 478 id: snapshot.id, 479 exists: true 480 }); 481 }), catchError(error => this.handleFirestoreError(error, "Bijwerken mislukt"))); 482 } 483 safe2(n) {
484 const v = typeof n === "number" && isFinite(n) ? n : 0; 485 return Math.round(v * 100) / 100; 486 } 487 chunkArray(array, chunkSize) { 488 const chunks = []; 489 for (let i = 0; i < array.length; i += chunkSize) { 490 chunks.push(array.slice(i, i + chunkSize)); 491 } 492 return chunks; 493 } 494 sortByEmployeeIdAndDateAsc(a, b) { 495 if (a.employeeId < b.employeeId) return -1; 496 if (a.employeeId > b.employeeId) return 1; 497 return a.date.toMillis() - b.date.toMillis(); 498 } 499 sortByEmployeeIdAndDateDesc(a, b) { 500 if (a.employeeId < b.employeeId) return -1; 501 if (a.employeeId > b.employeeId) return 1; 502 return b.date.toMillis() - a.date.toMillis(); 503 } 504 handleFirestoreError(error, userMessage) { 505 let friendlyMessage = userMessage; 506 if (error.code === "permission-denied") { 507 friendlyMessage = "Je heeft geen rechten om deze actie uit te voeren"; 508 } else if (error.code === "unavailable") { 509 friendlyMessage = "Firestore service is momenteel niet beschikbaar. Probeer het later opnieuw."; 510 } else if (error.code === "not-found") { 511 friendlyMessage = "Opgevraagd document is niet gevonden in Firestore"; 512 } 513 return throwError(() => new Error(friendlyMessage)); 514 } 515 handleHttpError(err) { 516 if (err?.error) { 517 return throwError(() => err.error); 518 } 519 if (err?.message) { 520 return throwError(() => err.message); 521 } 522 return throwError(() => err); 523 } 524 static { 525 this.ɵfac = function WorkTimeRecordsService_Factory(__ngFactoryType__) { 526 return new (__ngFactoryType__ || _WorkTimeRecordsService)(ɵɵinject(Firestore), ɵɵinject(HttpClient), ɵɵinject(AuthenticationService)); 527 }; 528 } 529 static { 530 this.ɵprov = /* @__PURE__ */ɵɵdefineInjectable({ 531 token: _WorkTimeRecordsService, 532 factory: _WorkTimeRecordsService.ɵfac, 533 providedIn: "root" 534 }); 535 } 536}; 537(() => { 538 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(WorkTimeRecordsService, [{ 539 type: Injectable, 540 args: [{ 541 providedIn: "root" 542 }] 543 }], () => [{ 544 type: Firestore 545 }, { 546 type: HttpClient 547 }, { 548 type: AuthenticationService 549 }], null); 550})(); 551export { MAX_OFFICE_MANUAL_WORK_INTERVALS, WorkTimeRecordsService }; 552/**i18n:55a58011b6fcf12b70aba021cbe233ce2fe179902ce3502a5c6547ccaba0ed7f*/ 553//# sourceMappingURL=chunk-EWJOAG46.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.