mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 14:29:34 +00:00
feat(z-task-modal): enhance timeblock conversion logic and improve draft handling for employee-specific timeblocks
This commit is contained in:
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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user