diff --git a/app/src/plugins/tm@modal/task/_components/_components/a-task-timeblocks.vue b/app/src/plugins/tm@modal/task/_components/_components/a-task-timeblocks.vue index d149935..e22174b 100644 --- a/app/src/plugins/tm@modal/task/_components/_components/a-task-timeblocks.vue +++ b/app/src/plugins/tm@modal/task/_components/_components/a-task-timeblocks.vue @@ -652,7 +652,7 @@ export default { this._update(subtask); }, - async toggleTimeblockIsFinished(originalTimeblock, index) { + async toggleTimeblockIsFinished(originalTimeblock, _index) { // Only works for published subtasks with saved timeblocks if (!originalTimeblock.id) { return; diff --git a/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock.vue b/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock.vue index 7022124..706a9be 100644 --- a/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock.vue +++ b/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock.vue @@ -1,5 +1,8 @@ @@ -487,4 +495,9 @@ watch( border-radius: 8px margin-bottom: 8px overflow: hidden + +.timeblock--finished + opacity: 0.4 + pointer-events: none + cursor: not-allowed diff --git a/app/src/plugins/tm@modal/task/_components/employees/types.ts b/app/src/plugins/tm@modal/task/_components/employees/types.ts index 000ba8a..e2ba483 100644 --- a/app/src/plugins/tm@modal/task/_components/employees/types.ts +++ b/app/src/plugins/tm@modal/task/_components/employees/types.ts @@ -11,6 +11,7 @@ export interface TimeblockData { starts_at_time: string | null; ends_at_time: string | null; employee_id?: number | null; + is_finished?: number; } export interface EmployeeFullData { diff --git a/app/src/plugins/tm@modal/task/z-task-modal.vue b/app/src/plugins/tm@modal/task/z-task-modal.vue index 1d691a8..89dda3b 100644 --- a/app/src/plugins/tm@modal/task/z-task-modal.vue +++ b/app/src/plugins/tm@modal/task/z-task-modal.vue @@ -480,35 +480,32 @@ export default { data._deadline_time = splittedDeadline[1]; // Convert BE format timeblocks to internal format - const convertedTimeblocks = []; - if (data.timeblocks && data.timeblocks.length > 0) { - data.timeblocks.forEach((timeblock) => { - // If already in internal format, keep as is - if (timeblock.date) { - convertedTimeblocks.push({ - ...timeblock, - employee_id: data.employee_id, // Add employee_id - }); - return; - } + if (data.is_draft && Array.isArray(data.employees)) { + // Handle draft subtasks with employees array + const allDraftTimeblocks = []; - // Convert from BE format to internal format - if (timeblock.start && timeblock.end) { - const startMoment = moment(timeblock.start, 'YYYY-MM-DD HH:mm:ss'); - const endMoment = moment(timeblock.end, 'YYYY-MM-DD HH:mm:ss'); - convertedTimeblocks.push({ - id: timeblock.id || null, - date: startMoment.toDate(), - starts_at_time: startMoment.format('HH:mm'), - ends_at_time: endMoment.format('HH:mm'), - is_finished: timeblock.is_finished || 0, - employee_id: data.employee_id, // Add employee_id - }); - } + data.employees = data.employees.map((emp) => { + const convertedTimeblocks = (emp.timeblocks || []) + .map((tb) => this._convertTimeblockToInternal(tb, emp.id)) + .filter(Boolean); + + // Add to flat array for edit mode + allDraftTimeblocks.push(...convertedTimeblocks); + + return { + ...emp, + timeblocks: convertedTimeblocks, + }; }); + + // Update flat timeblocks array for edit mode + this.timeblocks = allDraftTimeblocks; + } else { + // Handle published subtasks with root-level timeblocks + this.timeblocks = (data.timeblocks || []) + .map((tb) => this._convertTimeblockToInternal(tb, data.employee_id)) + .filter(Boolean); } - // Store in component's timeblocks array - this.timeblocks = convertedTimeblocks; this.subtask = this._enrichTask(data); @@ -522,6 +519,38 @@ export default { }, methods: { + /** + * Convert a timeblock from backend format to internal format + * @param {Object} timeblock - Timeblock in BE format (start/end) or internal format (date/times) + * @param {Number} employeeId - Employee ID to associate with the timeblock + * @returns {Object} Timeblock in internal format + */ + _convertTimeblockToInternal(timeblock, employeeId) { + // If already in internal format, return as is + if (timeblock.date) { + return { + ...timeblock, + employee_id: employeeId, + }; + } + + // Convert from BE format to internal format + if (timeblock.start && timeblock.end) { + const startMoment = moment(timeblock.start, 'YYYY-MM-DD HH:mm:ss'); + const endMoment = moment(timeblock.end, 'YYYY-MM-DD HH:mm:ss'); + return { + id: timeblock.id || null, + date: startMoment.toDate(), + starts_at_time: startMoment.format('HH:mm'), + ends_at_time: endMoment.format('HH:mm'), + is_finished: timeblock.is_finished || 0, + employee_id: employeeId, + }; + } + + return null; + }, + customFilterWithEmployeeFilter(item, input, itemObject) { const shouldShowItem = this.customFilter(item, input); @@ -749,84 +778,41 @@ export default { ); // Convert BE format timeblocks to internal format - const convertedTimeblocks = []; - if (data.timeblocks && data.timeblocks.length > 0) { - data.timeblocks.forEach((timeblock) => { - // If already in internal format, keep as is - if (timeblock.date) { - convertedTimeblocks.push({ - ...timeblock, - employee_id: data.employee_id, // Add employee_id for edit mode - }); - return; - } - - // Convert from BE format to internal format - if (timeblock.start && timeblock.end) { - const startMoment = moment( - timeblock.start, - 'YYYY-MM-DD HH:mm:ss', - ); - const endMoment = moment(timeblock.end, 'YYYY-MM-DD HH:mm:ss'); - convertedTimeblocks.push({ - id: timeblock.id || null, - date: startMoment.toDate(), - starts_at_time: startMoment.format('HH:mm'), - ends_at_time: endMoment.format('HH:mm'), - is_finished: timeblock.is_finished || 0, - employee_id: data.employee_id, // Add employee_id for edit mode - }); - } - }); - } - // Store timeblocks in the component's timeblocks array - this.timeblocks = convertedTimeblocks; - - // If draft with employees data, parse timeblocks for each employee if ( data.is_draft && data.employees && Array.isArray(data.employees) ) { + // Handle draft subtasks with employees array const draftTimeblocks = []; - data.employees.forEach((employee) => { - if (employee.timeblocks && Array.isArray(employee.timeblocks)) { - employee.timeblocks.forEach((timeblock) => { - // Convert BE format to internal format - if (timeblock.start && timeblock.end) { - const startMoment = moment( - timeblock.start, - 'YYYY-MM-DD HH:mm:ss', - ); - const endMoment = moment( - timeblock.end, - 'YYYY-MM-DD HH:mm:ss', - ); - draftTimeblocks.push({ - id: timeblock.id || null, - date: startMoment.toDate(), - starts_at_time: startMoment.format('HH:mm'), - ends_at_time: endMoment.format('HH:mm'), - is_finished: timeblock.is_finished || 0, - employee_id: employee.id, // Associate with employee - }); - } - }); - } + data.employees = data.employees.map((employee) => { + const convertedTimeblocks = (employee.timeblocks || []) + .map((tb) => this._convertTimeblockToInternal(tb, employee.id)) + .filter(Boolean); + + draftTimeblocks.push(...convertedTimeblocks); + + return { + ...employee, + timeblocks: convertedTimeblocks, + }; }); - // Use draft timeblocks if they exist - if (draftTimeblocks.length > 0) { - this.timeblocks = draftTimeblocks; - } + this.timeblocks = draftTimeblocks; // Ensure employees array has proper structure for editing - // Check if last employee is not empty, then add empty slot const lastEmployee = data.employees[data.employees.length - 1]; if (lastEmployee && (lastEmployee.id || lastEmployee.duration)) { data.employees.push({}); } + } else { + // Handle published subtasks with root-level timeblocks + this.timeblocks = (data.timeblocks || []) + .map((tb) => + this._convertTimeblockToInternal(tb, data.employee_id), + ) + .filter(Boolean); } // Ensure at least one timeblock exists for edit mode (non-draft single employee)