feat(z-task-modal): enhance timeblock conversion logic and improve draft handling for employee-specific timeblocks

This commit is contained in:
Matej Glasnák committed 2026-01-08 02:28:03 +01:00
1 parent 81aaa293dd
commit 7a5f354912
4 files changed
+106 -106

No files matched your search

@@ -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;
@@ -1,5 +1,8 @@
<template>
<div class="timeblock">
<div
class="timeblock"
:class="{ 'timeblock--finished': modelValue.is_finished }"
>
<a-employee-timeblock-header
:model-value="modelValue"
:min-date="minDate"
@@ -25,22 +28,27 @@
/>
<!-- Timeline Visualization -->
<a-employee-timeblock-timeline
<div
v-if="modelValue.date && employee"
ref="timelineRef"
:is-loading="isLoading"
:employee="employee"
:scheduled-blocks="scheduledBlocks"
:other-timeblocks="otherTimeblocksForSameDate"
:current-timeblock-range="currentTimeblockRange"
:collision="collision"
:collision-segments="collisionSegments"
:timeblock-duration="timeblockDuration"
:start-hour="START_HOUR"
:end-hour="END_HOUR"
:hour-width="hourWidth"
@timeblock-updated="handleTimeblockUpdated"
/>
:class="{ 'timeline-wrapper--finished': modelValue.is_finished }"
class="timeline-wrapper"
>
<a-employee-timeblock-timeline
ref="timelineRef"
:is-loading="isLoading"
:employee="employee"
:scheduled-blocks="scheduledBlocks"
:other-timeblocks="otherTimeblocksForSameDate"
:current-timeblock-range="currentTimeblockRange"
:collision="collision"
:collision-segments="collisionSegments"
:timeblock-duration="timeblockDuration"
:start-hour="START_HOUR"
:end-hour="END_HOUR"
:hour-width="hourWidth"
@timeblock-updated="handleTimeblockUpdated"
/>
</div>
</div>
</template>
@@ -487,4 +495,9 @@ watch(
border-radius: 8px
margin-bottom: 8px
overflow: hidden
.timeblock--finished
opacity: 0.4
pointer-events: none
cursor: not-allowed
</style>
@@ -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 {
+75 -89
View File
@@ -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)