From efbbd70b9eb83919415713dd2fb31121b316900a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Glasn=C3=A1k?= Date: Wed, 4 Feb 2026 11:21:02 +0100 Subject: [PATCH] build(test): --- app/dist/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/dist/js/index.js b/app/dist/js/index.js index b04c75d..dc5ad1b 100644 --- a/app/dist/js/index.js +++ b/app/dist/js/index.js @@ -543,7 +543,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var cor /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_es_array_push_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.array.push.js */ \"./node_modules/core-js/modules/es.array.push.js\");\n/* harmony import */ var core_js_modules_es_array_push_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_array_push_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_es_json_stringify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/es.json.stringify.js */ \"./node_modules/core-js/modules/es.json.stringify.js\");\n/* harmony import */ var core_js_modules_es_json_stringify_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_json_stringify_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! core-js/modules/esnext.iterator.constructor.js */ \"./node_modules/core-js/modules/esnext.iterator.constructor.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! core-js/modules/esnext.iterator.filter.js */ \"./node_modules/core-js/modules/esnext.iterator.filter.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var core_js_modules_esnext_iterator_find_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! core-js/modules/esnext.iterator.find.js */ \"./node_modules/core-js/modules/esnext.iterator.find.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_find_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_find_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var core_js_modules_esnext_iterator_for_each_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! core-js/modules/esnext.iterator.for-each.js */ \"./node_modules/core-js/modules/esnext.iterator.for-each.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_for_each_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_for_each_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! core-js/modules/esnext.iterator.map.js */ \"./node_modules/core-js/modules/esnext.iterator.map.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var core_js_modules_esnext_iterator_some_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! core-js/modules/esnext.iterator.some.js */ \"./node_modules/core-js/modules/esnext.iterator.some.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_some_js__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_some_js__WEBPACK_IMPORTED_MODULE_7__);\n/* harmony import */ var _plugins_tm_components_z_datepicker_vue__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @/plugins/tm@_components/z-datepicker.vue */ \"./src/plugins/tm@_components/z-datepicker.vue\");\n/* harmony import */ var _plugins_tm_components_z_files_upload_vue__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @/plugins/tm@_components/z-files-upload.vue */ \"./src/plugins/tm@_components/z-files-upload.vue\");\n/* harmony import */ var _vuelidate_core__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @vuelidate/core */ \"./node_modules/@vuelidate/core/dist/index.esm.js\");\n/* harmony import */ var _vuelidate_validators__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @vuelidate/validators */ \"./node_modules/@vuelidate/validators/dist/index.esm.js\");\n/* harmony import */ var _plugins_lib_auth_utils_error_utils__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @/plugins/lib@auth/_utils/error.utils */ \"./src/plugins/lib@auth/_utils/error.utils.ts\");\n/* harmony import */ var _vueup_vue_quill__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @vueup/vue-quill */ \"./node_modules/@vueup/vue-quill/dist/vue-quill.esm-bundler.js\");\n/* harmony import */ var _master_task_mixins_selects_mixin__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../master-task/_mixins/selects.mixin */ \"./src/plugins/tm@modal/master-task/_mixins/selects.mixin.ts\");\n/* harmony import */ var _plugins_tm_utils_tm_utils__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @/plugins/tm@_utils/tm.utils */ \"./src/plugins/tm@_utils/tm.utils.ts\");\n/* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! moment */ \"./node_modules/moment/moment.js\");\n/* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_16___default = /*#__PURE__*/__webpack_require__.n(moment__WEBPACK_IMPORTED_MODULE_16__);\n/* harmony import */ var _vueup_vue_quill_dist_vue_quill_snow_css__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @vueup/vue-quill/dist/vue-quill.snow.css */ \"./node_modules/@vueup/vue-quill/dist/vue-quill.snow.css\");\n/* harmony import */ var _vueup_vue_quill_dist_vue_quill_snow_css__WEBPACK_IMPORTED_MODULE_17___default = /*#__PURE__*/__webpack_require__.n(_vueup_vue_quill_dist_vue_quill_snow_css__WEBPACK_IMPORTED_MODULE_17__);\n/* harmony import */ var _plugins_tm_mixins_autocomplete_mixin__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @/plugins/tm@_mixins/autocomplete.mixin */ \"./src/plugins/tm@_mixins/autocomplete.mixin.ts\");\n/* harmony import */ var _components_z_task_readonly_info_vue__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./_components/z-task-readonly-info.vue */ \"./src/plugins/tm@modal/task/_components/z-task-readonly-info.vue\");\n/* harmony import */ var _components_employees_a_employee_vue__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./_components/employees/a-employee.vue */ \"./src/plugins/tm@modal/task/_components/employees/a-employee.vue\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.esm-bundler.js\");\n/* harmony import */ var _plugins_tm_modal_mixins_modal_mixin__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @/plugins/tm@modal/_mixins/modal.mixin */ \"./src/plugins/tm@modal/_mixins/modal.mixin.ts\");\n/* harmony import */ var _plugins_tm_modal_components_a_resize_handle_vue__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @/plugins/tm@modal/_components/a-resize-handle.vue */ \"./src/plugins/tm@modal/_components/a-resize-handle.vue\");\n/* harmony import */ var _plugins_tm_modal_components_a_reset_size_button_vue__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @/plugins/tm@modal/_components/a-reset-size-button.vue */ \"./src/plugins/tm@modal/_components/a-reset-size-button.vue\");\n/* harmony import */ var _plugins_tm_modal_components_a_close_button_vue__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @/plugins/tm@modal/_components/a-close-button.vue */ \"./src/plugins/tm@modal/_components/a-close-button.vue\");\n/* harmony import */ var _z_remove_employee_modal_vue__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ./z-remove-employee-modal.vue */ \"./src/plugins/tm@modal/task/z-remove-employee-modal.vue\");\n/* harmony import */ var _z_remove_timeblock_modal_vue__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ./z-remove-timeblock-modal.vue */ \"./src/plugins/tm@modal/task/z-remove-timeblock-modal.vue\");\n/* provided dependency */ var console = __webpack_require__(/*! ./node_modules/console-browserify/index.js */ \"./node_modules/console-browserify/index.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n components: {\n ZTaskReadonlyInfo: _components_z_task_readonly_info_vue__WEBPACK_IMPORTED_MODULE_19__[\"default\"],\n AEmployee: _components_employees_a_employee_vue__WEBPACK_IMPORTED_MODULE_20__[\"default\"],\n ZFilesUpload: _plugins_tm_components_z_files_upload_vue__WEBPACK_IMPORTED_MODULE_9__[\"default\"],\n ZDatepicker: _plugins_tm_components_z_datepicker_vue__WEBPACK_IMPORTED_MODULE_8__[\"default\"],\n // ATaskTimeblocks,\n QuillEditor: _vueup_vue_quill__WEBPACK_IMPORTED_MODULE_13__.QuillEditor,\n AResizeHandle: _plugins_tm_modal_components_a_resize_handle_vue__WEBPACK_IMPORTED_MODULE_23__[\"default\"],\n AResetSizeButton: _plugins_tm_modal_components_a_reset_size_button_vue__WEBPACK_IMPORTED_MODULE_24__[\"default\"],\n ACloseButton: _plugins_tm_modal_components_a_close_button_vue__WEBPACK_IMPORTED_MODULE_25__[\"default\"],\n ZRemoveEmployeeModal: _z_remove_employee_modal_vue__WEBPACK_IMPORTED_MODULE_26__[\"default\"],\n ZRemoveTimeblockModal: _z_remove_timeblock_modal_vue__WEBPACK_IMPORTED_MODULE_27__[\"default\"]\n },\n mixins: [_master_task_mixins_selects_mixin__WEBPACK_IMPORTED_MODULE_14__[\"default\"], _plugins_tm_mixins_autocomplete_mixin__WEBPACK_IMPORTED_MODULE_18__[\"default\"], _plugins_tm_modal_mixins_modal_mixin__WEBPACK_IMPORTED_MODULE_22__[\"default\"]],\n emits: ['close', 'refresh'],\n data() {\n return {\n tmUtils: _plugins_tm_utils_tm_utils__WEBPACK_IMPORTED_MODULE_15__[\"default\"],\n editMode: false,\n visible: false,\n subtask: null,\n isSaving: false,\n errorUtils: _plugins_lib_auth_utils_error_utils__WEBPACK_IMPORTED_MODULE_12__[\"default\"],\n v$: (0,_vuelidate_core__WEBPACK_IMPORTED_MODULE_10__[\"default\"])(),\n showDatePicker: false,\n selectedNewDate: [],\n timeblocks: [],\n deletedTimeblockIds: [],\n // Track IDs of saved timeblocks that have been deleted\n wasFormValidationTriggered: false,\n modalName: 'z-task-modal',\n modalSize: 'large',\n employeeRefs: [],\n pendingRemoveEmployeeId: undefined,\n pendingRemoveEmployeeIndex: undefined,\n timeblockClientIdCounter: 0 // Counter for generating unique client-side IDs\n };\n },\n computed: {\n ...(0,vuex__WEBPACK_IMPORTED_MODULE_21__.mapGetters)('tm', ['mastertasks', 'enrichedEmployees']),\n enrichedMastertasks() {\n return this.mastertasks.map(mastertask => ({\n ...mastertask,\n _fullName: `${mastertask.name} [${mastertask.project_code}]`\n }));\n },\n editModeEmployee: {\n get() {\n return {\n id: this.subtask?.employee_id || null,\n duration: this.subtask?.duration || null\n };\n },\n set(value) {\n if (this.subtask) {\n this.subtask.employee_id = value.id;\n this.subtask.duration = value.duration;\n }\n }\n },\n isDraftWithMultipleEmployees() {\n return this.subtask?.is_draft && Array.isArray(this.subtask?.employees) && this.subtask.employees.length > 0;\n }\n },\n validations() {\n return {\n subtask: {\n master_task_id: {\n required: _vuelidate_validators__WEBPACK_IMPORTED_MODULE_11__.required\n },\n deadline: {\n required: _vuelidate_validators__WEBPACK_IMPORTED_MODULE_11__.required\n },\n _deadline_time: {\n required: _vuelidate_validators__WEBPACK_IMPORTED_MODULE_11__.required\n }\n }\n };\n },\n watch: {\n 'subtask.employee_id'(value, oldValue) {\n if (!value || !oldValue) return;\n\n // In edit mode: reassign timeblocks to new employee\n if (this.subtask.id) {\n this.timeblocks = this.timeblocks.map(tb => {\n if (tb.employee_id == oldValue) {\n return {\n ...tb,\n employee_id: value\n };\n }\n return tb;\n });\n } else {\n // In create mode: remove old employee's timeblocks\n this.timeblocks = this.timeblocks.filter(tb => tb.employee_id != oldValue);\n }\n this.subtask._employee = this.enrichedEmployees.find(employee => employee.id == this.subtask.employee_id);\n },\n 'subtask.employees': {\n handler() {\n if (!this.subtask?.employees) return;\n const lastEmployee = this.subtask.employees[this.subtask.employees.length - 1];\n if (lastEmployee?.id || lastEmployee?.duration) this.subtask.employees.push({});\n },\n deep: true\n },\n 'subtask.master_task_id'(value) {\n if (!value) return;\n this.subtask._master_task = this.mastertasks.find(mastertask => mastertask.id == this.subtask.master_task_id);\n this.subtask.project_code = this.subtask._master_task?.project_code || null;\n },\n editMode() {\n this.$nextTick(() => {\n this.$refs['description']?.setHTML(this.subtask.description || '');\n });\n },\n subtask: {\n handler(val) {\n if (this.editMode && !this.subtask?.id) {\n const employees = val?.employees?.filter(employee => employee?.id || employee?.duration) || [{}];\n const subtaskData = {\n ...val,\n employees: employees && employees.length > 0 ? employees : [{}]\n };\n localStorage.setItem('subtaskData', JSON.stringify(subtaskData));\n }\n },\n deep: true\n },\n timeblocks: {\n handler(val) {\n if (this.editMode && !this.subtask?.id) {\n // Save timeblocks to localStorage for new tasks\n localStorage.setItem('subtaskTimeblocks', JSON.stringify(val));\n }\n },\n deep: true\n }\n },\n mounted() {\n // Handle remove timeblock modal\n this.$events.on('show-remove-timeblock-modal', ({\n onConfirm\n }) => {\n this.$refs.removeTimeblockModal.showModal({\n onConfirm\n });\n });\n this.$events.on('add-timeblock', timeblock => {\n if (!this.subtask) return;\n if (!this.subtask.timeblocks) {\n this.subtask.timeblocks = [];\n }\n if (!this.subtask.timesheets) {\n this.subtask.timesheets = [];\n }\n if (!this.subtask.is_finished) {\n this.subtask.is_finished = 0;\n }\n this.subtask.timeblocks.push(timeblock);\n });\n this.$events.on('on-subtask-edited', subtask => {\n if (subtask?.id !== this.subtask?.id) return;\n const data = JSON.parse(JSON.stringify(subtask));\n const splittedDeadline = data.deadline?.split(' ') || [];\n data.deadline = splittedDeadline[0];\n data._deadline_time = splittedDeadline[1];\n\n // Convert BE format timeblocks to internal format\n if (data.is_draft && Array.isArray(data.employees)) {\n // Handle draft subtasks with employees array\n const allDraftTimeblocks = [];\n data.employees = data.employees.map(emp => {\n const convertedTimeblocks = (emp.timeblocks || []).map(tb => this._convertTimeblockToInternal(tb, emp.id)).filter(Boolean);\n\n // Add to flat array for edit mode\n allDraftTimeblocks.push(...convertedTimeblocks);\n return {\n ...emp,\n timeblocks: convertedTimeblocks\n };\n });\n\n // Update flat timeblocks array for edit mode\n this.timeblocks = allDraftTimeblocks;\n } else {\n // Handle published subtasks with root-level timeblocks\n this.timeblocks = (data.timeblocks || []).map(tb => this._convertTimeblockToInternal(tb, data.employee_id)).filter(Boolean);\n }\n this.subtask = this._enrichTask(data);\n\n // TODO: Remove? riesil som neodstranovanie jedineho zanamu v trvani a odpracovanom case\n this.$forceUpdate();\n });\n this.$events.on('on-subtask-deleted', subtask => {\n if (subtask?.id == this.subtask?.id) this.closeModal();\n });\n },\n methods: {\n /**\n * Convert a timeblock from backend format to internal format\n * @param {Object} timeblock - Timeblock in BE format (start/end) or internal format (date/times)\n * @param {Number} employeeId - Employee ID to associate with the timeblock\n * @returns {Object} Timeblock in internal format\n */\n _convertTimeblockToInternal(timeblock, employeeId) {\n // If already in internal format, ensure it has a client ID\n if (timeblock.date) {\n return {\n ...timeblock,\n _clientId: timeblock._clientId || `client-${++this.timeblockClientIdCounter}`,\n employee_id: employeeId\n };\n }\n\n // Convert from BE format to internal format\n if (timeblock.start && timeblock.end) {\n const startMoment = moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.start, 'YYYY-MM-DD HH:mm:ss');\n const endMoment = moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.end, 'YYYY-MM-DD HH:mm:ss');\n return {\n id: timeblock.id || null,\n _clientId: timeblock._clientId || `client-${++this.timeblockClientIdCounter}`,\n date: startMoment.toDate(),\n starts_at_time: startMoment.format('HH:mm'),\n ends_at_time: endMoment.format('HH:mm'),\n is_finished: timeblock.is_finished || 0,\n employee_id: employeeId\n };\n }\n return null;\n },\n customFilterWithEmployeeFilter(item, input, itemObject) {\n const shouldShowItem = this.customFilter(item, input);\n if (!shouldShowItem) return false;\n if (!itemObject?.value) return false;\n const employeeId = itemObject.value;\n if (!this.subtask.id) {\n // New subtask with multiple employees support\n // Hide employees that are already selected in any slot\n // The v-autocomplete will still display the currently selected employee\n const isAlreadySelected = Array.isArray(this.subtask.employees) && this.subtask.employees.some(emp => emp.id && Number(emp.id) === employeeId);\n return shouldShowItem && !isAlreadySelected;\n } else if (this.subtask.is_draft) {\n // Edit draft subtask with multiple employees support\n // Hide employees that are already selected in any slot\n const isAlreadySelected = Array.isArray(this.subtask.employees) && this.subtask.employees.some(emp => emp.id && Number(emp.id) === employeeId);\n return shouldShowItem && !isAlreadySelected;\n } else {\n // Saved standard subtask, allow \"re-select\" for better UX\n return shouldShowItem;\n }\n },\n toggleEditMode() {\n if (this.subtask.type == 'office365') return this.$events.emit('show-unable-to-edit-office-task-modal', {\n mode: 'edit'\n });\n this.editMode = !this.editMode;\n },\n // Set refs for employee components in create mode\n setEmployeeRef(el, index) {\n if (el) {\n this.employeeRefs[index] = el;\n }\n },\n openDatepicker(ref) {\n this.$refs[ref].openMenu();\n },\n // Helper: Get employee by ID\n getEmployeeById(employeeId) {\n return this.enrichedEmployees.find(emp => emp.id === employeeId);\n },\n // Helper: Get employee full name\n getEmployeeFullName(employeeId) {\n const employee = this.getEmployeeById(employeeId);\n return employee ? `${employee.name} ${employee.surname}` : '';\n },\n // Helper: Get enriched employee data by ID\n getEnrichedEmployee(employeeId) {\n return this.enrichedEmployees.find(emp => emp.id === employeeId) || {};\n },\n // Helper: Get valid employees (with id and duration) in create mode\n getValidEmployees() {\n if (!this.subtask?.employees) return [];\n return this.subtask.employees.filter(emp => emp.id && emp.duration);\n },\n // Helper: Get timeblocks for specific employee\n getEmployeeTimeblocks(employeeId) {\n if (!this.timeblocks || !employeeId) return [];\n return this.timeblocks.filter(tb => tb.employee_id && Number(tb.employee_id) === Number(employeeId));\n },\n updateEmployeeTimeblocks(updatedTimeblocks, employeeId) {\n // Track deleted timeblocks (saved timeblocks that are no longer in the updated list)\n const updatedIds = new Set(updatedTimeblocks.filter(tb => tb.id).map(tb => tb.id));\n const deletedIds = this.timeblocks.filter(tb => tb.employee_id == employeeId && tb.id && !updatedIds.has(tb.id)).map(tb => tb.id).filter(id => !this.deletedTimeblockIds.includes(id));\n this.deletedTimeblockIds.push(...deletedIds);\n\n // Replace timeblocks for this employee\n const otherEmployeeTimeblocks = this.timeblocks.filter(tb => tb.employee_id != employeeId);\n const updatedWithEmployeeId = updatedTimeblocks.map(tb => ({\n ...tb,\n employee_id: employeeId\n }));\n this.timeblocks = [...otherEmployeeTimeblocks, ...updatedWithEmployeeId];\n },\n updateTimeblock(val, index, employeeId) {\n const employeeTimeblocks = this.getEmployeeTimeblocks(employeeId);\n const timeblock = employeeTimeblocks[index];\n if (!timeblock) return;\n\n // Find the actual index in the full timeblocks array\n const actualIndex = this.timeblocks.indexOf(timeblock);\n if (actualIndex !== -1) {\n this.timeblocks[actualIndex] = {\n ...val,\n employee_id: employeeId\n };\n }\n },\n addTimeblock(employeeId, afterIndex = -1) {\n const newTimeblock = {\n _clientId: `client-${++this.timeblockClientIdCounter}`,\n // Unique client-side ID\n date: new Date(),\n // Preset to current day\n starts_at_time: null,\n ends_at_time: null,\n employee_id: employeeId\n };\n\n // Get timeblocks for this employee\n const employeeTimeblocks = this.timeblocks.filter(tb => tb.employee_id == employeeId);\n if (afterIndex === -1 || afterIndex >= employeeTimeblocks.length - 1) {\n // Add at the end\n this.timeblocks.push(newTimeblock);\n } else {\n // Find the position in the full timeblocks array\n const timeblockToInsertAfter = employeeTimeblocks[afterIndex];\n const insertPosition = this.timeblocks.indexOf(timeblockToInsertAfter) + 1;\n this.timeblocks.splice(insertPosition, 0, newTimeblock);\n }\n },\n removeTimeblock(index, employeeId) {\n const employeeTimeblocks = this.getEmployeeTimeblocks(employeeId);\n const timeblock = employeeTimeblocks[index];\n if (!timeblock) return;\n\n // Find the actual index in the full timeblocks array\n const actualIndex = this.timeblocks.indexOf(timeblock);\n if (actualIndex !== -1) {\n this.timeblocks.splice(actualIndex, 1);\n }\n },\n // Handle remove employee - also removes their timeblocks\n handleRemoveEmployee() {\n this.pendingRemoveEmployeeId = this.subtask.employee_id;\n this.$refs.removeEmployeeModal.showModal();\n },\n removeEmployeeAtIndex(index) {\n this.pendingRemoveEmployeeIndex = index;\n this.$refs.removeEmployeeModal.showModal();\n },\n confirmRemoveEmployee() {\n // Handle edit mode (single employee removal)\n if (this.pendingRemoveEmployeeId !== undefined) {\n if (this.subtask.employee_id) {\n // Remove all timeblocks for this employee\n this.timeblocks = this.timeblocks.filter(tb => tb.employee_id != this.subtask.employee_id);\n }\n\n // Clear employee data in edit mode\n this.subtask.employee_id = null;\n this.subtask.duration = null;\n this.pendingRemoveEmployeeId = undefined;\n }\n // Handle create mode (multiple employees removal)\n else if (this.pendingRemoveEmployeeIndex !== undefined && Array.isArray(this.subtask.employees)) {\n const employee = this.subtask.employees[this.pendingRemoveEmployeeIndex];\n if (employee?.id) {\n // Remove all timeblocks for this employee\n this.timeblocks = this.timeblocks.filter(tb => tb.employee_id != employee.id);\n }\n\n // Remove employee from array\n this.subtask.employees.splice(this.pendingRemoveEmployeeIndex, 1);\n this.pendingRemoveEmployeeIndex = undefined;\n }\n },\n async showModal({\n subtask,\n editMode = false,\n mastertask = {}\n }) {\n this.isSaving = false;\n this.subtask = null;\n this.wasFormValidationTriggered = false; // Reset validation trigger\n\n // CRITICAL: Prevent v-dialog autofocus BEFORE modal opens\n this.preventInputFocus = true;\n this.visible = true;\n this.timeblocks = [];\n this.deletedTimeblockIds = []; // Reset deleted timeblock IDs\n this.employeeRefs = [];\n this.$nextTick(() => {\n this.v$.$reset();\n\n // Reset after modal is fully rendered and v-dialog autofocus has been blocked\n setTimeout(() => {\n this.preventInputFocus = false;\n }, 300);\n });\n try {\n if (subtask?.id) {\n const data = await this.$axios.get_auth_data(`v1/subtasks/${subtask.id}`);\n\n // Convert BE format timeblocks to internal format\n if (data.is_draft && data.employees && Array.isArray(data.employees)) {\n // Handle draft subtasks with employees array\n const draftTimeblocks = [];\n data.employees = data.employees.map(employee => {\n const convertedTimeblocks = (employee.timeblocks || []).map(tb => this._convertTimeblockToInternal(tb, employee.id)).filter(Boolean);\n draftTimeblocks.push(...convertedTimeblocks);\n return {\n ...employee,\n timeblocks: convertedTimeblocks\n };\n });\n this.timeblocks = draftTimeblocks;\n\n // Ensure employees array has proper structure for editing\n const lastEmployee = data.employees[data.employees.length - 1];\n if (lastEmployee && (lastEmployee.id || lastEmployee.duration)) {\n data.employees.push({});\n }\n } else {\n // Handle published subtasks with root-level timeblocks\n this.timeblocks = (data.timeblocks || []).map(tb => this._convertTimeblockToInternal(tb, data.employee_id)).filter(Boolean);\n }\n\n // Ensure at least one timeblock exists for edit mode (non-draft single employee)\n if (data.employee_id && !data.is_draft && this.timeblocks.length === 0) {\n this.addTimeblock(data.employee_id);\n }\n if (!data.deadline) {\n this.subtask = this._enrichTask(data);\n this.editMode = editMode || !data.id;\n\n // Set Quill editor content after subtask is loaded and editMode is set\n this.$nextTick(() => {\n if (this.$refs['description']) {\n this.$refs['description'].setHTML(this.subtask.description || '');\n }\n });\n return;\n }\n const splittedDeadline = data.deadline.split(' ');\n data.deadline = splittedDeadline[0];\n data._deadline_time = splittedDeadline[1];\n this.subtask = this._enrichTask(data);\n } else {\n const savedSubtask = localStorage.getItem('subtaskData');\n const savedTimeblocks = localStorage.getItem('subtaskTimeblocks');\n try {\n if (savedSubtask) {\n const parsedSubtask = JSON.parse(savedSubtask);\n this.subtask = parsedSubtask;\n // If the parsed result is not an object, reset to default\n if (typeof this.subtask !== 'object' || this.subtask === null) {\n throw new Error('Parsed subtask is not an object');\n }\n\n // Load timeblocks from localStorage if they exist\n if (savedTimeblocks) {\n try {\n let parsedTimeblocks = JSON.parse(savedTimeblocks);\n\n // Filter out timeblocks that are not valid\n parsedTimeblocks = parsedTimeblocks.filter(tb => tb.employee_id && tb.starts_at_time && tb.ends_at_time);\n if (Array.isArray(parsedTimeblocks)) {\n this.timeblocks = parsedTimeblocks.map(tb => ({\n ...tb,\n _clientId: tb._clientId || `client-${++this.timeblockClientIdCounter}`,\n date: tb.date ? new Date(tb.date) : null\n }));\n } else {\n this.timeblocks = [];\n }\n } catch (e) {\n console.error('Error parsing saved timeblocks:', e);\n this.timeblocks = [];\n }\n }\n this.$nextTick(() => {\n this.$refs['description']?.setHTML(this.subtask.description || '');\n });\n } else {\n throw new Error('subtaskData is null or undefined');\n }\n } catch (error) {\n // Initialize with current logged-in employee\n const currentUserId = this.$store.getters['auth/user']?.id;\n const currentEmployee = currentUserId ? this.enrichedEmployees.find(emp => emp.id === currentUserId) : null;\n this.subtask = {\n master_task: mastertask,\n employees: currentEmployee ? [{\n id: currentEmployee.id,\n duration: null\n }] : [{}],\n _deadline_time: '17:00'\n };\n\n // Add a timeblock for the current user if they exist\n if (currentUserId) {\n this.addTimeblock(currentUserId);\n }\n }\n if (subtask?.deadline && subtask._deadline_time && subtask.employee_id) {\n const employee = this.enrichedEmployees.find(employee => employee.id == subtask.employee_id);\n\n // Get current logged-in user\n const currentUserId = this.$store.getters['auth/user']?.id;\n const isCurrentUser = currentUserId === subtask.employee_id;\n\n // If the clicked employee is different from current user, add current user first as empty slot\n if (!isCurrentUser) {\n this.subtask.employees = [{\n id: currentUserId,\n duration: null\n },\n // Empty current user slot\n employee // The clicked employee with data\n ];\n } else {\n // Same user or no current user, just add the clicked employee\n this.subtask.employees = [employee];\n }\n this.subtask.deadline = subtask.deadline;\n this.subtask._deadline_time = subtask._deadline_time;\n setTimeout(() => {\n this.timeblocks = [...(!isCurrentUser ? [{\n _clientId: `client-${++this.timeblockClientIdCounter}`,\n date: new Date(subtask.deadline),\n starts_at_time: subtask._deadline_time,\n ends_at_time: null,\n employee_id: currentUserId\n }] : []), {\n _clientId: `client-${++this.timeblockClientIdCounter}`,\n date: new Date(subtask.deadline),\n starts_at_time: subtask._deadline_time,\n ends_at_time: null,\n employee_id: subtask.employee_id\n }];\n }, 500);\n }\n if (subtask?.master_task_id && subtask?.project_code) {\n this.subtask.master_task_id = subtask.master_task_id;\n this.subtask.project_code = subtask.project_code;\n }\n }\n this.editMode = editMode || !this.subtask.id;\n\n // Set Quill editor content after editMode is set\n // This ensures the description is loaded when opening in edit mode\n if (this.editMode) {\n this.$nextTick(() => {\n if (this.$refs['description']) {\n this.$refs['description'].setHTML(this.subtask?.description || '');\n }\n });\n }\n } catch (error) {\n this.$toast.error(this.$parseError(error));\n }\n },\n deleteTimeblock(i) {\n this.subtask.timeblocks.splice(i, 1);\n },\n closeModal() {\n this.visible = false;\n this.$router.replace({\n name: this.$route.name\n });\n },\n async validate(concept = false) {\n if (concept === false) {\n const employeesValid = await this._validateEmployees();\n const timeblocksValid = await this._validateTimeblocks();\n if (!(await this.v$.$validate())) return;\n if (!employeesValid || !timeblocksValid) return;\n return true;\n } else {\n this.v$.subtask.master_task_id.$touch();\n return this.v$.subtask.master_task_id.$errors.length === 0;\n }\n },\n async save(concept = false) {\n this.v$.$reset();\n this.wasFormValidationTriggered = true;\n if (!(await this.validate(concept))) return;\n this.subtask.description = this.$refs['description'].getHTML();\n this._mergeDeadlineTimeDate();\n try {\n this.isSaving = true;\n\n // Concept tasks may not have a deadline time set\n this.subtask.deadline = this.subtask.deadline ? moment__WEBPACK_IMPORTED_MODULE_16___default()(this.subtask.deadline).format('YYYY-MM-DD HH:mm:SS') : null;\n if (this.subtask?.id) {\n const timesheets = this.subtask.timesheets.map(timesheet => {\n delete timesheet.employee_name;\n return timesheet;\n });\n\n // Convert timeblocks from internal format to BE format for update\n // Filter out completely empty timeblocks AND timeblocks without all required fields\n // Pre draft s multiple employees preskočiť - timeblocks sú v employees array\n const timeblocks = this.subtask.is_draft && this.isDraftWithMultipleEmployees ? [] : this.timeblocks.filter(timeblock => timeblock.date && timeblock.starts_at_time && timeblock.ends_at_time && Number(timeblock.employee_id) === Number(this.subtask.employee_id)) // Only send complete timeblocks for this employee\n .map(timeblock => {\n const dateStr = moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.date).format('YYYY-MM-DD');\n return {\n id: timeblock.id || null,\n start: `${dateStr} ${timeblock.starts_at_time}:00`,\n end: `${dateStr} ${timeblock.ends_at_time}:00`,\n is_finished: timeblock.is_finished || 0\n };\n });\n const payload = {\n ...this.subtask,\n timesheets,\n timeblocks\n };\n\n // For drafts with multiple employees, include employees array\n if (this.subtask.is_draft && this.isDraftWithMultipleEmployees) {\n const validEmployees = this._filterValidEmployees(this.subtask.employees, concept);\n\n // Assign timeblocks to each employee\n validEmployees.forEach(employee => {\n const employeeTimeblocks = this._getEmployeeTimeblocks(employee.id, true);\n employee.timeblocks = employeeTimeblocks.map(tb => ({\n start: `${moment__WEBPACK_IMPORTED_MODULE_16___default()(tb.date).format('YYYY-MM-DD')} ${tb.starts_at_time}:00`,\n end: `${moment__WEBPACK_IMPORTED_MODULE_16___default()(tb.date).format('YYYY-MM-DD')} ${tb.ends_at_time}:00`,\n id: tb.id || null\n }));\n });\n payload.employees = validEmployees;\n }\n if (concept) {\n payload.is_draft = 1;\n } else {\n payload.is_draft = 0;\n }\n const {\n subtask\n } = await this.$axios.patch_auth_form(`v1/subtasks/${this.subtask.id}`, payload);\n localStorage.removeItem('subtaskData');\n localStorage.removeItem('subtaskTimeblocks');\n this.$store.commit('tm/update_subtask', subtask);\n this.$events.emit('on-subtask-edited', this.subtask);\n } else {\n const validEmployees = this._filterValidEmployees(this.subtask.employees, concept);\n\n // Assign timeblocks to each employee based on employee_id\n // Filter out empty/incomplete timeblocks - only send fully filled timeblocks\n validEmployees.forEach(employee => {\n const employeeTimeblocks = this._getEmployeeTimeblocks(employee.id, true);\n employee.timeblocks = employeeTimeblocks.map(timeblock => {\n return {\n start: `${moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.date).format('YYYY-MM-DD')} ${timeblock.starts_at_time}:00`,\n end: `${moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.date).format('YYYY-MM-DD')} ${timeblock.ends_at_time}:00`,\n id: null\n };\n });\n });\n const subtaskCopy = {\n ...this.subtask,\n employees: validEmployees\n };\n if (concept) {\n subtaskCopy.is_draft = true;\n subtaskCopy.employees = subtaskCopy.employees?.length > 0 ? subtaskCopy.employees : [{\n id: this.$store.getters['auth/user']?.id,\n duration: 0\n }];\n }\n delete subtaskCopy._master_task;\n const {\n subtasks\n } = await this.$axios.post_auth(`v1/mastertasks/${this.subtask.master_task_id}/subtasks`, subtaskCopy);\n localStorage.removeItem('subtaskData');\n localStorage.removeItem('subtaskTimeblocks');\n this.subtask.id = subtasks[0].id;\n subtasks.forEach(subtask => {\n this.$store.commit('tm/update_subtask', subtask);\n this.$events.emit('on-subtask-edited', this.subtask);\n });\n this.$events.emit('task-created');\n this.$events.emit('close-both-modals');\n }\n this.closeModal();\n } catch (error) {\n console.log('error', error);\n this.$toast.error(this.$parseError(error));\n } finally {\n this.isSaving = false;\n }\n },\n openDeleteTaskModal(subtask) {\n if (subtask.type == 'office365') return this.$events.emit('show-unable-to-edit-office-task-modal', {\n mode: 'delete'\n });\n this.$events.emit('show-delete-task-modal', {\n subtask\n });\n },\n showCompleteTaskModal() {\n this.$events.emit('show-complete-task-modal', {\n subtask: this.subtask\n });\n if (this.subtask.deadline) this.subtask.deadline = _plugins_tm_utils_tm_utils__WEBPACK_IMPORTED_MODULE_15__[\"default\"].formatDateTimeForBackend(this.subtask.deadline);\n },\n filesUploaded(files) {\n this.subtask.files = files;\n },\n updateSubtask(subtask) {\n this.subtask = subtask;\n },\n _mergeDeadlineTimeDate() {\n // Override for concept tasks which may not have a deadline time set (check for invalid date)\n if (isNaN(new Date(this.subtask.deadline).getTime()) || !this.subtask._deadline_time) {\n this.subtask.deadline = null;\n } else {\n const date = new Date(this.subtask.deadline);\n const timeParts = this.subtask._deadline_time.split(':');\n date.setHours(parseInt(timeParts[0]));\n date.setMinutes(parseInt(timeParts[1]));\n this.subtask.deadline = date;\n }\n },\n _filterValidEmployees(employees, isConcept) {\n // Filter employees based on whether it's a concept/draft or published task\n // For concepts: only require id (duration can be null/0)\n // For published tasks: require both id and duration\n if (!Array.isArray(employees)) return [];\n return employees.filter(employee => {\n if (isConcept) {\n return employee.id; // Only require ID for concepts/drafts\n }\n return employee.id && employee.duration; // Require both for published tasks\n });\n },\n _getEmployeeTimeblocks(employeeId, requireComplete = true) {\n // Get timeblocks for a specific employee with proper type handling\n // Use Number() conversion to avoid type mismatch issues (string vs number)\n const filtered = this.timeblocks.filter(tb => {\n const idsMatch = Number(tb.employee_id) === Number(employeeId);\n if (!requireComplete) {\n return idsMatch;\n }\n\n // For complete timeblocks, also require date and time fields\n return idsMatch && tb.date && tb.starts_at_time && tb.ends_at_time;\n });\n return filtered;\n },\n async _validateEmployees() {\n if (this.subtask.id && !this.subtask.is_draft) {\n // For existing subtasks, at least one employee is required\n const hasEmployee = !!(this.subtask.employee_id && this.subtask.duration);\n return hasEmployee;\n } else {\n let valid = true;\n\n // Validate ALL employee component refs (this will show errors on inputs)\n for (let i = 0; i < this.employeeRefs.length; i++) {\n const employeeRef = this.employeeRefs[i];\n\n // Validate employees that have any data (partial or complete)\n if (employeeRef && typeof employeeRef.validate === 'function') {\n if (!(await employeeRef.validate())) {\n valid = false;\n }\n }\n }\n return valid;\n }\n },\n async _validateTimeblocks() {\n // Date alone is valid. Validation only applies if start OR end time is filled.\n // If start OR end is filled, then ALL fields (date, start, end) are required.\n let valid = true;\n for (const timeblock of this.timeblocks) {\n const hasStart = !!timeblock.starts_at_time;\n const hasEnd = !!timeblock.ends_at_time;\n const hasAnyTime = hasStart || hasEnd;\n\n // If no time data (start/end), timeblock is valid (date alone is OK)\n if (!hasAnyTime) {\n continue;\n }\n\n // If start OR end is filled, ALL fields are required\n const hasDate = !!timeblock.date;\n if (!hasDate || !hasStart || !hasEnd) {\n valid = false;\n break;\n }\n\n // Validate that end time is after start time\n const dateStr = moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.date).format('YYYY-MM-DD');\n const start = moment__WEBPACK_IMPORTED_MODULE_16___default()(`${dateStr} ${timeblock.starts_at_time}`, 'YYYY-MM-DD HH:mm');\n const end = moment__WEBPACK_IMPORTED_MODULE_16___default()(`${dateStr} ${timeblock.ends_at_time}`, 'YYYY-MM-DD HH:mm');\n if (end.isSameOrBefore(start)) {\n valid = false;\n break;\n }\n }\n return valid;\n },\n _enrichTask(subtask) {\n return {\n ...subtask,\n _created_by: this.enrichedEmployees.find(employee => employee.id == subtask.created_by),\n _employee: this.enrichedEmployees.find(employee => employee.id == subtask.employee_id),\n _master_task: this.mastertasks.find(mastertask => mastertask.id == subtask.master_task_id)\n };\n }\n }\n});\n\n//# sourceURL=webpack://jandl/./src/plugins/tm@modal/task/z-task-modal.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use%5B0%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D\n}"); +eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_es_array_push_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.array.push.js */ \"./node_modules/core-js/modules/es.array.push.js\");\n/* harmony import */ var core_js_modules_es_array_push_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_array_push_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_es_json_stringify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/es.json.stringify.js */ \"./node_modules/core-js/modules/es.json.stringify.js\");\n/* harmony import */ var core_js_modules_es_json_stringify_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_json_stringify_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! core-js/modules/esnext.iterator.constructor.js */ \"./node_modules/core-js/modules/esnext.iterator.constructor.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! core-js/modules/esnext.iterator.filter.js */ \"./node_modules/core-js/modules/esnext.iterator.filter.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var core_js_modules_esnext_iterator_find_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! core-js/modules/esnext.iterator.find.js */ \"./node_modules/core-js/modules/esnext.iterator.find.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_find_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_find_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var core_js_modules_esnext_iterator_for_each_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! core-js/modules/esnext.iterator.for-each.js */ \"./node_modules/core-js/modules/esnext.iterator.for-each.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_for_each_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_for_each_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! core-js/modules/esnext.iterator.map.js */ \"./node_modules/core-js/modules/esnext.iterator.map.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var core_js_modules_esnext_iterator_some_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! core-js/modules/esnext.iterator.some.js */ \"./node_modules/core-js/modules/esnext.iterator.some.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_some_js__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_some_js__WEBPACK_IMPORTED_MODULE_7__);\n/* harmony import */ var _plugins_tm_components_z_datepicker_vue__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @/plugins/tm@_components/z-datepicker.vue */ \"./src/plugins/tm@_components/z-datepicker.vue\");\n/* harmony import */ var _plugins_tm_components_z_files_upload_vue__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @/plugins/tm@_components/z-files-upload.vue */ \"./src/plugins/tm@_components/z-files-upload.vue\");\n/* harmony import */ var _vuelidate_core__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @vuelidate/core */ \"./node_modules/@vuelidate/core/dist/index.esm.js\");\n/* harmony import */ var _vuelidate_validators__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @vuelidate/validators */ \"./node_modules/@vuelidate/validators/dist/index.esm.js\");\n/* harmony import */ var _plugins_lib_auth_utils_error_utils__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @/plugins/lib@auth/_utils/error.utils */ \"./src/plugins/lib@auth/_utils/error.utils.ts\");\n/* harmony import */ var _vueup_vue_quill__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @vueup/vue-quill */ \"./node_modules/@vueup/vue-quill/dist/vue-quill.esm-bundler.js\");\n/* harmony import */ var _master_task_mixins_selects_mixin__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../master-task/_mixins/selects.mixin */ \"./src/plugins/tm@modal/master-task/_mixins/selects.mixin.ts\");\n/* harmony import */ var _plugins_tm_utils_tm_utils__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @/plugins/tm@_utils/tm.utils */ \"./src/plugins/tm@_utils/tm.utils.ts\");\n/* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! moment */ \"./node_modules/moment/moment.js\");\n/* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_16___default = /*#__PURE__*/__webpack_require__.n(moment__WEBPACK_IMPORTED_MODULE_16__);\n/* harmony import */ var _vueup_vue_quill_dist_vue_quill_snow_css__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @vueup/vue-quill/dist/vue-quill.snow.css */ \"./node_modules/@vueup/vue-quill/dist/vue-quill.snow.css\");\n/* harmony import */ var _vueup_vue_quill_dist_vue_quill_snow_css__WEBPACK_IMPORTED_MODULE_17___default = /*#__PURE__*/__webpack_require__.n(_vueup_vue_quill_dist_vue_quill_snow_css__WEBPACK_IMPORTED_MODULE_17__);\n/* harmony import */ var _plugins_tm_mixins_autocomplete_mixin__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @/plugins/tm@_mixins/autocomplete.mixin */ \"./src/plugins/tm@_mixins/autocomplete.mixin.ts\");\n/* harmony import */ var _components_z_task_readonly_info_vue__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./_components/z-task-readonly-info.vue */ \"./src/plugins/tm@modal/task/_components/z-task-readonly-info.vue\");\n/* harmony import */ var _components_employees_a_employee_vue__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./_components/employees/a-employee.vue */ \"./src/plugins/tm@modal/task/_components/employees/a-employee.vue\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.esm-bundler.js\");\n/* harmony import */ var _plugins_tm_modal_mixins_modal_mixin__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @/plugins/tm@modal/_mixins/modal.mixin */ \"./src/plugins/tm@modal/_mixins/modal.mixin.ts\");\n/* harmony import */ var _plugins_tm_modal_components_a_resize_handle_vue__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @/plugins/tm@modal/_components/a-resize-handle.vue */ \"./src/plugins/tm@modal/_components/a-resize-handle.vue\");\n/* harmony import */ var _plugins_tm_modal_components_a_reset_size_button_vue__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @/plugins/tm@modal/_components/a-reset-size-button.vue */ \"./src/plugins/tm@modal/_components/a-reset-size-button.vue\");\n/* harmony import */ var _plugins_tm_modal_components_a_close_button_vue__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @/plugins/tm@modal/_components/a-close-button.vue */ \"./src/plugins/tm@modal/_components/a-close-button.vue\");\n/* harmony import */ var _z_remove_employee_modal_vue__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ./z-remove-employee-modal.vue */ \"./src/plugins/tm@modal/task/z-remove-employee-modal.vue\");\n/* harmony import */ var _z_remove_timeblock_modal_vue__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ./z-remove-timeblock-modal.vue */ \"./src/plugins/tm@modal/task/z-remove-timeblock-modal.vue\");\n/* provided dependency */ var console = __webpack_require__(/*! ./node_modules/console-browserify/index.js */ \"./node_modules/console-browserify/index.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n components: {\n ZTaskReadonlyInfo: _components_z_task_readonly_info_vue__WEBPACK_IMPORTED_MODULE_19__[\"default\"],\n AEmployee: _components_employees_a_employee_vue__WEBPACK_IMPORTED_MODULE_20__[\"default\"],\n ZFilesUpload: _plugins_tm_components_z_files_upload_vue__WEBPACK_IMPORTED_MODULE_9__[\"default\"],\n ZDatepicker: _plugins_tm_components_z_datepicker_vue__WEBPACK_IMPORTED_MODULE_8__[\"default\"],\n // ATaskTimeblocks,\n QuillEditor: _vueup_vue_quill__WEBPACK_IMPORTED_MODULE_13__.QuillEditor,\n AResizeHandle: _plugins_tm_modal_components_a_resize_handle_vue__WEBPACK_IMPORTED_MODULE_23__[\"default\"],\n AResetSizeButton: _plugins_tm_modal_components_a_reset_size_button_vue__WEBPACK_IMPORTED_MODULE_24__[\"default\"],\n ACloseButton: _plugins_tm_modal_components_a_close_button_vue__WEBPACK_IMPORTED_MODULE_25__[\"default\"],\n ZRemoveEmployeeModal: _z_remove_employee_modal_vue__WEBPACK_IMPORTED_MODULE_26__[\"default\"],\n ZRemoveTimeblockModal: _z_remove_timeblock_modal_vue__WEBPACK_IMPORTED_MODULE_27__[\"default\"]\n },\n mixins: [_master_task_mixins_selects_mixin__WEBPACK_IMPORTED_MODULE_14__[\"default\"], _plugins_tm_mixins_autocomplete_mixin__WEBPACK_IMPORTED_MODULE_18__[\"default\"], _plugins_tm_modal_mixins_modal_mixin__WEBPACK_IMPORTED_MODULE_22__[\"default\"]],\n emits: ['close', 'refresh'],\n data() {\n return {\n tmUtils: _plugins_tm_utils_tm_utils__WEBPACK_IMPORTED_MODULE_15__[\"default\"],\n editMode: false,\n visible: false,\n subtask: null,\n isSaving: false,\n errorUtils: _plugins_lib_auth_utils_error_utils__WEBPACK_IMPORTED_MODULE_12__[\"default\"],\n v$: (0,_vuelidate_core__WEBPACK_IMPORTED_MODULE_10__[\"default\"])(),\n showDatePicker: false,\n selectedNewDate: [],\n timeblocks: [],\n deletedTimeblockIds: [],\n // Track IDs of saved timeblocks that have been deleted\n wasFormValidationTriggered: false,\n modalName: 'z-task-modal',\n modalSize: 'large',\n employeeRefs: [],\n pendingRemoveEmployeeId: undefined,\n pendingRemoveEmployeeIndex: undefined,\n timeblockClientIdCounter: 0 // Counter for generating unique client-side IDs\n };\n },\n computed: {\n ...(0,vuex__WEBPACK_IMPORTED_MODULE_21__.mapGetters)('tm', ['mastertasks', 'enrichedEmployees']),\n enrichedMastertasks() {\n return this.mastertasks.map(mastertask => ({\n ...mastertask,\n _fullName: `${mastertask.name} [${mastertask.project_code}]`\n }));\n },\n editModeEmployee: {\n get() {\n return {\n id: this.subtask?.employee_id || null,\n duration: this.subtask?.duration || null\n };\n },\n set(value) {\n if (this.subtask) {\n this.subtask.employee_id = value.id;\n this.subtask.duration = value.duration;\n }\n }\n },\n isDraftWithMultipleEmployees() {\n return this.subtask?.is_draft && Array.isArray(this.subtask?.employees) && this.subtask.employees.length > 0;\n }\n },\n validations() {\n return {\n subtask: {\n master_task_id: {\n required: _vuelidate_validators__WEBPACK_IMPORTED_MODULE_11__.required\n },\n deadline: {\n required: _vuelidate_validators__WEBPACK_IMPORTED_MODULE_11__.required\n },\n _deadline_time: {\n required: _vuelidate_validators__WEBPACK_IMPORTED_MODULE_11__.required\n }\n }\n };\n },\n watch: {\n 'subtask.employee_id'(value, oldValue) {\n if (!value || !oldValue) return;\n\n // In edit mode: reassign timeblocks to new employee\n if (this.subtask.id) {\n this.timeblocks = this.timeblocks.map(tb => {\n if (tb.employee_id == oldValue) {\n return {\n ...tb,\n employee_id: value\n };\n }\n return tb;\n });\n } else {\n // In create mode: remove old employee's timeblocks\n this.timeblocks = this.timeblocks.filter(tb => tb.employee_id != oldValue);\n }\n this.subtask._employee = this.enrichedEmployees.find(employee => employee.id == this.subtask.employee_id);\n },\n 'subtask.employees': {\n handler() {\n if (!this.subtask?.employees) return;\n const lastEmployee = this.subtask.employees[this.subtask.employees.length - 1];\n if (lastEmployee?.id || lastEmployee?.duration) this.subtask.employees.push({});\n },\n deep: true\n },\n 'subtask.master_task_id'(value) {\n if (!value) return;\n this.subtask._master_task = this.mastertasks.find(mastertask => mastertask.id == this.subtask.master_task_id);\n this.subtask.project_code = this.subtask._master_task?.project_code || null;\n },\n editMode() {\n this.$nextTick(() => {\n this.$refs['description']?.setHTML(this.subtask.description || '');\n });\n },\n subtask: {\n handler(val) {\n if (this.editMode && !this.subtask?.id) {\n const employees = val?.employees?.filter(employee => employee?.id || employee?.duration) || [{}];\n const subtaskData = {\n ...val,\n employees: employees && employees.length > 0 ? employees : [{}]\n };\n localStorage.setItem('subtaskData', JSON.stringify(subtaskData));\n }\n },\n deep: true\n },\n timeblocks: {\n handler(val) {\n if (this.editMode && !this.subtask?.id) {\n // Save timeblocks to localStorage for new tasks\n localStorage.setItem('subtaskTimeblocks', JSON.stringify(val));\n }\n },\n deep: true\n }\n },\n mounted() {\n // Handle remove timeblock modal\n this.$events.on('show-remove-timeblock-modal', ({\n onConfirm\n }) => {\n this.$refs.removeTimeblockModal.showModal({\n onConfirm\n });\n });\n this.$events.on('add-timeblock', timeblock => {\n if (!this.subtask) return;\n if (!this.subtask.timeblocks) {\n this.subtask.timeblocks = [];\n }\n if (!this.subtask.timesheets) {\n this.subtask.timesheets = [];\n }\n if (!this.subtask.is_finished) {\n this.subtask.is_finished = 0;\n }\n this.subtask.timeblocks.push(timeblock);\n });\n this.$events.on('on-subtask-edited', subtask => {\n if (subtask?.id !== this.subtask?.id) return;\n const data = JSON.parse(JSON.stringify(subtask));\n const splittedDeadline = data.deadline?.split(' ') || [];\n data.deadline = splittedDeadline[0];\n data._deadline_time = splittedDeadline[1];\n\n // Convert BE format timeblocks to internal format\n if (data.is_draft && Array.isArray(data.employees)) {\n // Handle draft subtasks with employees array\n const allDraftTimeblocks = [];\n data.employees = data.employees.map(emp => {\n const convertedTimeblocks = (emp.timeblocks || []).map(tb => this._convertTimeblockToInternal(tb, emp.id)).filter(Boolean);\n\n // Add to flat array for edit mode\n allDraftTimeblocks.push(...convertedTimeblocks);\n return {\n ...emp,\n timeblocks: convertedTimeblocks\n };\n });\n\n // Update flat timeblocks array for edit mode\n this.timeblocks = allDraftTimeblocks;\n } else {\n // Handle published subtasks with root-level timeblocks\n this.timeblocks = (data.timeblocks || []).map(tb => this._convertTimeblockToInternal(tb, data.employee_id)).filter(Boolean);\n }\n this.subtask = this._enrichTask(data);\n\n // TODO: Remove? riesil som neodstranovanie jedineho zanamu v trvani a odpracovanom case\n this.$forceUpdate();\n });\n this.$events.on('on-subtask-deleted', subtask => {\n if (subtask?.id == this.subtask?.id) this.closeModal();\n });\n },\n methods: {\n /**\n * Convert a timeblock from backend format to internal format\n * @param {Object} timeblock - Timeblock in BE format (start/end) or internal format (date/times)\n * @param {Number} employeeId - Employee ID to associate with the timeblock\n * @returns {Object} Timeblock in internal format\n */\n _convertTimeblockToInternal(timeblock, employeeId) {\n // If already in internal format, ensure it has a client ID\n if (timeblock.date) {\n return {\n ...timeblock,\n _clientId: timeblock._clientId || `client-${++this.timeblockClientIdCounter}`,\n employee_id: employeeId\n };\n }\n\n // Convert from BE format to internal format\n if (timeblock.start && timeblock.end) {\n const startMoment = moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.start, 'YYYY-MM-DD HH:mm:ss');\n const endMoment = moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.end, 'YYYY-MM-DD HH:mm:ss');\n return {\n id: timeblock.id || null,\n _clientId: timeblock._clientId || `client-${++this.timeblockClientIdCounter}`,\n date: startMoment.toDate(),\n starts_at_time: startMoment.format('HH:mm'),\n ends_at_time: endMoment.format('HH:mm'),\n is_finished: timeblock.is_finished || 0,\n employee_id: employeeId\n };\n }\n return null;\n },\n customFilterWithEmployeeFilter(item, input, itemObject) {\n const shouldShowItem = this.customFilter(item, input);\n if (!shouldShowItem) return false;\n if (!itemObject?.value) return false;\n const employeeId = itemObject.value;\n if (!this.subtask.id) {\n // New subtask with multiple employees support\n // Hide employees that are already selected in any slot\n // The v-autocomplete will still display the currently selected employee\n const isAlreadySelected = Array.isArray(this.subtask.employees) && this.subtask.employees.some(emp => emp.id && Number(emp.id) === employeeId);\n return shouldShowItem && !isAlreadySelected;\n } else if (this.subtask.is_draft) {\n // Edit draft subtask with multiple employees support\n // Hide employees that are already selected in any slot\n const isAlreadySelected = Array.isArray(this.subtask.employees) && this.subtask.employees.some(emp => emp.id && Number(emp.id) === employeeId);\n return shouldShowItem && !isAlreadySelected;\n } else {\n // Saved standard subtask, allow \"re-select\" for better UX\n return shouldShowItem;\n }\n },\n toggleEditMode() {\n if (this.subtask.type == 'office365') return this.$events.emit('show-unable-to-edit-office-task-modal', {\n mode: 'edit'\n });\n this.editMode = !this.editMode;\n },\n // Set refs for employee components in create mode\n setEmployeeRef(el, index) {\n if (el) {\n this.employeeRefs[index] = el;\n }\n },\n openDatepicker(ref) {\n this.$refs[ref].openMenu();\n },\n // Helper: Get employee by ID\n getEmployeeById(employeeId) {\n return this.enrichedEmployees.find(emp => emp.id === employeeId);\n },\n // Helper: Get employee full name\n getEmployeeFullName(employeeId) {\n const employee = this.getEmployeeById(employeeId);\n return employee ? `${employee.name} ${employee.surname}` : '';\n },\n // Helper: Get enriched employee data by ID\n getEnrichedEmployee(employeeId) {\n return this.enrichedEmployees.find(emp => emp.id === employeeId) || {};\n },\n // Helper: Get valid employees (with id and duration) in create mode\n getValidEmployees() {\n if (!this.subtask?.employees) return [];\n return this.subtask.employees.filter(emp => emp.id && emp.duration);\n },\n // Helper: Get timeblocks for specific employee\n getEmployeeTimeblocks(employeeId) {\n if (!this.timeblocks || !employeeId) return [];\n return this.timeblocks.filter(tb => tb.employee_id && Number(tb.employee_id) === Number(employeeId));\n },\n updateEmployeeTimeblocks(updatedTimeblocks, employeeId) {\n // Track deleted timeblocks (saved timeblocks that are no longer in the updated list)\n const updatedIds = new Set(updatedTimeblocks.filter(tb => tb.id).map(tb => tb.id));\n const deletedIds = this.timeblocks.filter(tb => tb.employee_id == employeeId && tb.id && !updatedIds.has(tb.id)).map(tb => tb.id).filter(id => !this.deletedTimeblockIds.includes(id));\n this.deletedTimeblockIds.push(...deletedIds);\n\n // Replace timeblocks for this employee\n const otherEmployeeTimeblocks = this.timeblocks.filter(tb => tb.employee_id != employeeId);\n const updatedWithEmployeeId = updatedTimeblocks.map(tb => ({\n ...tb,\n employee_id: employeeId\n }));\n this.timeblocks = [...otherEmployeeTimeblocks, ...updatedWithEmployeeId];\n },\n updateTimeblock(val, index, employeeId) {\n const employeeTimeblocks = this.getEmployeeTimeblocks(employeeId);\n const timeblock = employeeTimeblocks[index];\n if (!timeblock) return;\n\n // Find the actual index in the full timeblocks array\n const actualIndex = this.timeblocks.indexOf(timeblock);\n if (actualIndex !== -1) {\n this.timeblocks[actualIndex] = {\n ...val,\n employee_id: employeeId\n };\n }\n },\n addTimeblock(employeeId, afterIndex = -1) {\n const newTimeblock = {\n _clientId: `client-${++this.timeblockClientIdCounter}`,\n // Unique client-side ID\n date: new Date(),\n // Preset to current day\n starts_at_time: null,\n ends_at_time: null,\n employee_id: employeeId\n };\n\n // Get timeblocks for this employee\n const employeeTimeblocks = this.timeblocks.filter(tb => tb.employee_id == employeeId);\n if (afterIndex === -1 || afterIndex >= employeeTimeblocks.length - 1) {\n // Add at the end\n this.timeblocks.push(newTimeblock);\n } else {\n // Find the position in the full timeblocks array\n const timeblockToInsertAfter = employeeTimeblocks[afterIndex];\n const insertPosition = this.timeblocks.indexOf(timeblockToInsertAfter) + 1;\n this.timeblocks.splice(insertPosition, 0, newTimeblock);\n }\n },\n removeTimeblock(index, employeeId) {\n const employeeTimeblocks = this.getEmployeeTimeblocks(employeeId);\n const timeblock = employeeTimeblocks[index];\n if (!timeblock) return;\n\n // Find the actual index in the full timeblocks array\n const actualIndex = this.timeblocks.indexOf(timeblock);\n if (actualIndex !== -1) {\n this.timeblocks.splice(actualIndex, 1);\n }\n },\n // Handle remove employee - also removes their timeblocks\n handleRemoveEmployee() {\n this.pendingRemoveEmployeeId = this.subtask.employee_id;\n this.$refs.removeEmployeeModal.showModal();\n },\n removeEmployeeAtIndex(index) {\n this.pendingRemoveEmployeeIndex = index;\n this.$refs.removeEmployeeModal.showModal();\n },\n confirmRemoveEmployee() {\n // Handle edit mode (single employee removal)\n if (this.pendingRemoveEmployeeId !== undefined) {\n if (this.subtask.employee_id) {\n // Remove all timeblocks for this employee\n this.timeblocks = this.timeblocks.filter(tb => tb.employee_id != this.subtask.employee_id);\n }\n\n // Clear employee data in edit mode\n this.subtask.employee_id = null;\n this.subtask.duration = null;\n this.pendingRemoveEmployeeId = undefined;\n }\n // Handle create mode (multiple employees removal)\n else if (this.pendingRemoveEmployeeIndex !== undefined && Array.isArray(this.subtask.employees)) {\n const employee = this.subtask.employees[this.pendingRemoveEmployeeIndex];\n if (employee?.id) {\n // Remove all timeblocks for this employee\n this.timeblocks = this.timeblocks.filter(tb => tb.employee_id != employee.id);\n }\n\n // Remove employee from array\n this.subtask.employees.splice(this.pendingRemoveEmployeeIndex, 1);\n this.pendingRemoveEmployeeIndex = undefined;\n }\n },\n async showModal({\n subtask,\n editMode = false,\n mastertask = {}\n }) {\n this.isSaving = false;\n this.subtask = null;\n this.wasFormValidationTriggered = false; // Reset validation trigger\n\n // CRITICAL: Prevent v-dialog autofocus BEFORE modal opens\n this.preventInputFocus = true;\n this.visible = true;\n this.timeblocks = [];\n this.deletedTimeblockIds = []; // Reset deleted timeblock IDs\n this.employeeRefs = [];\n this.$nextTick(() => {\n this.v$.$reset();\n\n // Reset after modal is fully rendered and v-dialog autofocus has been blocked\n setTimeout(() => {\n this.preventInputFocus = false;\n }, 300);\n });\n try {\n if (subtask?.id) {\n const data = await this.$axios.get_auth_data(`v1/subtasks/${subtask.id}`);\n\n // Convert BE format timeblocks to internal format\n if (data.is_draft && data.employees && Array.isArray(data.employees)) {\n // Handle draft subtasks with employees array\n const draftTimeblocks = [];\n data.employees = data.employees.map(employee => {\n const convertedTimeblocks = (employee.timeblocks || []).map(tb => this._convertTimeblockToInternal(tb, employee.id)).filter(Boolean);\n draftTimeblocks.push(...convertedTimeblocks);\n return {\n ...employee,\n timeblocks: convertedTimeblocks\n };\n });\n this.timeblocks = draftTimeblocks;\n\n // Ensure employees array has proper structure for editing\n const lastEmployee = data.employees[data.employees.length - 1];\n if (lastEmployee && (lastEmployee.id || lastEmployee.duration)) {\n data.employees.push({});\n }\n } else {\n // Handle published subtasks with root-level timeblocks\n this.timeblocks = (data.timeblocks || []).map(tb => this._convertTimeblockToInternal(tb, data.employee_id)).filter(Boolean);\n }\n\n // Ensure at least one timeblock exists for edit mode (non-draft single employee)\n if (data.employee_id && !data.is_draft && this.timeblocks.length === 0) {\n this.addTimeblock(data.employee_id);\n }\n if (!data.deadline) {\n this.subtask = this._enrichTask(data);\n this.editMode = editMode || !data.id;\n\n // Set Quill editor content after subtask is loaded and editMode is set\n this.$nextTick(() => {\n if (this.$refs['description']) {\n this.$refs['description'].setHTML(this.subtask.description || '');\n }\n });\n return;\n }\n const splittedDeadline = data.deadline.split(' ');\n data.deadline = splittedDeadline[0];\n data._deadline_time = splittedDeadline[1];\n this.subtask = this._enrichTask(data);\n } else {\n const savedSubtask = localStorage.getItem('subtaskData');\n const savedTimeblocks = localStorage.getItem('subtaskTimeblocks');\n try {\n if (savedSubtask) {\n const parsedSubtask = JSON.parse(savedSubtask);\n this.subtask = parsedSubtask;\n // If the parsed result is not an object, reset to default\n if (typeof this.subtask !== 'object' || this.subtask === null) {\n throw new Error('Parsed subtask is not an object');\n }\n\n // Load timeblocks from localStorage if they exist\n if (savedTimeblocks) {\n try {\n let parsedTimeblocks = JSON.parse(savedTimeblocks);\n\n // Filter out timeblocks that are not valid\n parsedTimeblocks = parsedTimeblocks.filter(tb => tb.employee_id && tb.starts_at_time && tb.ends_at_time);\n if (Array.isArray(parsedTimeblocks)) {\n this.timeblocks = parsedTimeblocks.map(tb => ({\n ...tb,\n _clientId: tb._clientId || `client-${++this.timeblockClientIdCounter}`,\n date: tb.date ? new Date(tb.date) : null\n }));\n } else {\n this.timeblocks = [];\n }\n } catch (e) {\n console.error('Error parsing saved timeblocks:', e);\n this.timeblocks = [];\n }\n }\n this.$nextTick(() => {\n this.$refs['description']?.setHTML(this.subtask.description || '');\n });\n } else {\n throw new Error('subtaskData is null or undefined');\n }\n } catch (error) {\n // Initialize with current logged-in employee\n const currentUserId = this.$store.getters['auth/user']?.id;\n const currentEmployee = currentUserId ? this.enrichedEmployees.find(emp => emp.id === currentUserId) : null;\n this.subtask = {\n master_task: mastertask,\n employees: currentEmployee ? [{\n id: currentEmployee.id,\n duration: null\n }] : [{}],\n _deadline_time: '17:00'\n };\n\n // Add a timeblock for the current user if they exist\n if (currentUserId) {\n this.addTimeblock(currentUserId);\n }\n }\n if (subtask?.deadline && subtask._deadline_time && subtask.employee_id) {\n const employee = this.enrichedEmployees.find(employee => employee.id == subtask.employee_id);\n\n // Get current logged-in user\n const currentUserId = this.$store.getters['auth/user']?.id;\n const isCurrentUser = currentUserId === subtask.employee_id;\n\n // If the clicked employee is different from current user, add current user first as empty slot\n if (!isCurrentUser) {\n this.subtask.employees = [{\n id: currentUserId,\n duration: null\n },\n // Empty current user slot\n employee // The clicked employee with data\n ];\n } else {\n // Same user or no current user, just add the clicked employee\n this.subtask.employees = [employee];\n }\n this.subtask.deadline = subtask.deadline;\n this.subtask._deadline_time = subtask._deadline_time;\n setTimeout(() => {\n this.timeblocks = [...(!isCurrentUser ? [{\n _clientId: `client-${++this.timeblockClientIdCounter}`,\n date: new Date(subtask.deadline),\n starts_at_time: subtask._deadline_time,\n ends_at_time: null,\n employee_id: currentUserId\n }] : []), {\n _clientId: `client-${++this.timeblockClientIdCounter}`,\n date: new Date(subtask.deadline),\n starts_at_time: subtask._deadline_time,\n ends_at_time: null,\n employee_id: subtask.employee_id\n }];\n }, 500);\n }\n if (subtask?.master_task_id && subtask?.project_code) {\n this.subtask.master_task_id = subtask.master_task_id;\n this.subtask.project_code = subtask.project_code;\n }\n }\n this.editMode = editMode || !this.subtask.id;\n\n // Set Quill editor content after editMode is set\n // This ensures the description is loaded when opening in edit mode\n if (this.editMode) {\n this.$nextTick(() => {\n if (this.$refs['description']) {\n this.$refs['description'].setHTML(this.subtask?.description || '');\n }\n });\n }\n } catch (error) {\n this.$toast.error(this.$parseError(error));\n }\n },\n deleteTimeblock(i) {\n this.subtask.timeblocks.splice(i, 1);\n },\n closeModal() {\n this.visible = false;\n this.$router.replace({\n name: this.$route.name\n });\n },\n async validate(concept = false) {\n if (concept === false) {\n const employeesValid = await this._validateEmployees();\n const timeblocksValid = await this._validateTimeblocks();\n if (!(await this.v$.$validate())) return;\n if (!employeesValid || !timeblocksValid) return;\n return true;\n } else {\n this.v$.subtask.master_task_id.$touch();\n return this.v$.subtask.master_task_id.$errors.length === 0;\n }\n },\n async save(concept = false) {\n this.v$.$reset();\n this.wasFormValidationTriggered = true;\n if (!(await this.validate(concept))) return;\n this.subtask.description = this.$refs['description'].getHTML();\n this._mergeDeadlineTimeDate();\n try {\n this.isSaving = true;\n\n // Concept tasks may not have a deadline time set\n this.subtask.deadline = this.subtask.deadline ? moment__WEBPACK_IMPORTED_MODULE_16___default()(this.subtask.deadline).format('YYYY-MM-DD HH:mm:SS') : null;\n if (this.subtask?.id) {\n const timesheets = this.subtask.timesheets.map(timesheet => {\n delete timesheet.employee_name;\n return timesheet;\n });\n\n // Filter out existing attachments (from backend) and keep only new File objects\n // Existing attachments have 'path' property, new files are File instances\n const newFiles = (this.subtask.files || []).filter(file => file instanceof File);\n this.subtask.files = newFiles;\n\n // Convert timeblocks from internal format to BE format for update\n // Filter out completely empty timeblocks AND timeblocks without all required fields\n // Pre draft s multiple employees preskočiť - timeblocks sú v employees array\n const timeblocks = this.subtask.is_draft && this.isDraftWithMultipleEmployees ? [] : this.timeblocks.filter(timeblock => timeblock.date && timeblock.starts_at_time && timeblock.ends_at_time && Number(timeblock.employee_id) === Number(this.subtask.employee_id)) // Only send complete timeblocks for this employee\n .map(timeblock => {\n const dateStr = moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.date).format('YYYY-MM-DD');\n return {\n id: timeblock.id || null,\n start: `${dateStr} ${timeblock.starts_at_time}:00`,\n end: `${dateStr} ${timeblock.ends_at_time}:00`,\n is_finished: timeblock.is_finished || 0\n };\n });\n const payload = {\n ...this.subtask,\n timesheets,\n timeblocks\n };\n\n // For drafts with multiple employees, include employees array\n if (this.subtask.is_draft && this.isDraftWithMultipleEmployees) {\n const validEmployees = this._filterValidEmployees(this.subtask.employees, concept);\n\n // Assign timeblocks to each employee\n validEmployees.forEach(employee => {\n const employeeTimeblocks = this._getEmployeeTimeblocks(employee.id, true);\n employee.timeblocks = employeeTimeblocks.map(tb => ({\n start: `${moment__WEBPACK_IMPORTED_MODULE_16___default()(tb.date).format('YYYY-MM-DD')} ${tb.starts_at_time}:00`,\n end: `${moment__WEBPACK_IMPORTED_MODULE_16___default()(tb.date).format('YYYY-MM-DD')} ${tb.ends_at_time}:00`,\n id: tb.id || null\n }));\n });\n payload.employees = validEmployees;\n }\n if (concept) {\n payload.is_draft = 1;\n } else {\n payload.is_draft = 0;\n }\n const {\n subtask\n } = await this.$axios.patch_auth_form(`v1/subtasks/${this.subtask.id}`, payload);\n localStorage.removeItem('subtaskData');\n localStorage.removeItem('subtaskTimeblocks');\n this.$store.commit('tm/update_subtask', subtask);\n this.$events.emit('on-subtask-edited', this.subtask);\n } else {\n const validEmployees = this._filterValidEmployees(this.subtask.employees, concept);\n\n // Assign timeblocks to each employee based on employee_id\n // Filter out empty/incomplete timeblocks - only send fully filled timeblocks\n validEmployees.forEach(employee => {\n const employeeTimeblocks = this._getEmployeeTimeblocks(employee.id, true);\n employee.timeblocks = employeeTimeblocks.map(timeblock => {\n return {\n start: `${moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.date).format('YYYY-MM-DD')} ${timeblock.starts_at_time}:00`,\n end: `${moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.date).format('YYYY-MM-DD')} ${timeblock.ends_at_time}:00`,\n id: null\n };\n });\n });\n const subtaskCopy = {\n ...this.subtask,\n employees: validEmployees\n };\n if (concept) {\n subtaskCopy.is_draft = true;\n subtaskCopy.employees = subtaskCopy.employees?.length > 0 ? subtaskCopy.employees : [{\n id: this.$store.getters['auth/user']?.id,\n duration: 0\n }];\n }\n delete subtaskCopy._master_task;\n const {\n subtasks\n } = await this.$axios.post_auth(`v1/mastertasks/${this.subtask.master_task_id}/subtasks`, subtaskCopy);\n localStorage.removeItem('subtaskData');\n localStorage.removeItem('subtaskTimeblocks');\n this.subtask.id = subtasks[0].id;\n subtasks.forEach(subtask => {\n this.$store.commit('tm/update_subtask', subtask);\n this.$events.emit('on-subtask-edited', this.subtask);\n });\n this.$events.emit('task-created');\n this.$events.emit('close-both-modals');\n }\n this.closeModal();\n } catch (error) {\n console.log('error', error);\n this.$toast.error(this.$parseError(error));\n } finally {\n this.isSaving = false;\n }\n },\n openDeleteTaskModal(subtask) {\n if (subtask.type == 'office365') return this.$events.emit('show-unable-to-edit-office-task-modal', {\n mode: 'delete'\n });\n this.$events.emit('show-delete-task-modal', {\n subtask\n });\n },\n showCompleteTaskModal() {\n this.$events.emit('show-complete-task-modal', {\n subtask: this.subtask\n });\n if (this.subtask.deadline) this.subtask.deadline = _plugins_tm_utils_tm_utils__WEBPACK_IMPORTED_MODULE_15__[\"default\"].formatDateTimeForBackend(this.subtask.deadline);\n },\n filesUploaded(files) {\n this.subtask.files = files;\n },\n updateSubtask(subtask) {\n this.subtask = subtask;\n },\n _mergeDeadlineTimeDate() {\n // Check if deadline date is valid\n const isValidDate = !isNaN(new Date(this.subtask.deadline).getTime());\n if (!isValidDate) {\n this.subtask.deadline = null;\n return;\n }\n const date = new Date(this.subtask.deadline);\n\n // If time is set, use it; otherwise use default time (23:59) for concepts\n if (this.subtask._deadline_time) {\n const timeParts = this.subtask._deadline_time.split(':');\n date.setHours(parseInt(timeParts[0]));\n date.setMinutes(parseInt(timeParts[1]));\n } else {\n // Default time for concepts without time specified\n date.setHours(23);\n date.setMinutes(59);\n }\n this.subtask.deadline = date;\n },\n _filterValidEmployees(employees, isConcept) {\n // Filter employees based on whether it's a concept/draft or published task\n // For concepts: only require id (duration can be null/0)\n // For published tasks: require both id and duration\n if (!Array.isArray(employees)) return [];\n return employees.filter(employee => {\n if (isConcept) {\n return employee.id; // Only require ID for concepts/drafts\n }\n return employee.id && employee.duration; // Require both for published tasks\n });\n },\n _getEmployeeTimeblocks(employeeId, requireComplete = true) {\n // Get timeblocks for a specific employee with proper type handling\n // Use Number() conversion to avoid type mismatch issues (string vs number)\n const filtered = this.timeblocks.filter(tb => {\n const idsMatch = Number(tb.employee_id) === Number(employeeId);\n if (!requireComplete) {\n return idsMatch;\n }\n\n // For complete timeblocks, also require date and time fields\n return idsMatch && tb.date && tb.starts_at_time && tb.ends_at_time;\n });\n return filtered;\n },\n async _validateEmployees() {\n if (this.subtask.id && !this.subtask.is_draft) {\n // For existing subtasks, at least one employee is required\n const hasEmployee = !!(this.subtask.employee_id && this.subtask.duration);\n return hasEmployee;\n } else {\n let valid = true;\n\n // Validate ALL employee component refs (this will show errors on inputs)\n for (let i = 0; i < this.employeeRefs.length; i++) {\n const employeeRef = this.employeeRefs[i];\n\n // Validate employees that have any data (partial or complete)\n if (employeeRef && typeof employeeRef.validate === 'function') {\n if (!(await employeeRef.validate())) {\n valid = false;\n }\n }\n }\n return valid;\n }\n },\n async _validateTimeblocks() {\n // Date alone is valid. Validation only applies if start OR end time is filled.\n // If start OR end is filled, then ALL fields (date, start, end) are required.\n let valid = true;\n for (const timeblock of this.timeblocks) {\n const hasStart = !!timeblock.starts_at_time;\n const hasEnd = !!timeblock.ends_at_time;\n const hasAnyTime = hasStart || hasEnd;\n\n // If no time data (start/end), timeblock is valid (date alone is OK)\n if (!hasAnyTime) {\n continue;\n }\n\n // If start OR end is filled, ALL fields are required\n const hasDate = !!timeblock.date;\n if (!hasDate || !hasStart || !hasEnd) {\n valid = false;\n break;\n }\n\n // Validate that end time is after start time\n const dateStr = moment__WEBPACK_IMPORTED_MODULE_16___default()(timeblock.date).format('YYYY-MM-DD');\n const start = moment__WEBPACK_IMPORTED_MODULE_16___default()(`${dateStr} ${timeblock.starts_at_time}`, 'YYYY-MM-DD HH:mm');\n const end = moment__WEBPACK_IMPORTED_MODULE_16___default()(`${dateStr} ${timeblock.ends_at_time}`, 'YYYY-MM-DD HH:mm');\n if (end.isSameOrBefore(start)) {\n valid = false;\n break;\n }\n }\n return valid;\n },\n _enrichTask(subtask) {\n return {\n ...subtask,\n _created_by: this.enrichedEmployees.find(employee => employee.id == subtask.created_by),\n _employee: this.enrichedEmployees.find(employee => employee.id == subtask.employee_id),\n _master_task: this.mastertasks.find(mastertask => mastertask.id == subtask.master_task_id)\n };\n }\n }\n});\n\n//# sourceURL=webpack://jandl/./src/plugins/tm@modal/task/z-task-modal.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use%5B0%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D\n}"); /***/ }),