PageSourceSearch

https://office.workvine.nl/chunk-EWJOAG46.js

js workvine.nl collected 2026-10-09 01:41:10 UTC 25,433 bytes, 553 lines download raw bytes

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.