mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 14:29:34 +00:00
wip(task-timeline): stage changes
This commit is contained in:
1 parent
69ea8be701
commit
00c4bf4d65
7 files changed
+878
-693
No files matched your search
@@ -54,7 +54,7 @@
|
||||
|
||||
<div class="splitted-inputs">
|
||||
<!-- TODO: Bialko validacie -->
|
||||
<div class="w-100 modal-input">
|
||||
<div class="left">
|
||||
<Z-datepicker
|
||||
ref="datepicker-01"
|
||||
v-model="subtask.deadline"
|
||||
@@ -99,20 +99,25 @@
|
||||
updateEmployeeTimeblocks($event, subtask.employee_id)
|
||||
"
|
||||
@clear-employee="handleRemoveEmployee"
|
||||
@add-timeblock="addTimeblock(subtask.employee_id)"
|
||||
@add-timeblock="
|
||||
(afterIndex) => addTimeblock(subtask.employee_id, afterIndex)
|
||||
"
|
||||
/>
|
||||
|
||||
<!-- Create Mode: Multiple Employees -->
|
||||
<template v-else>
|
||||
<A-employee
|
||||
v-for="(employee, index) in getValidEmployees()"
|
||||
v-for="(employee, index) in subtask.employees"
|
||||
:key="`employee-${employee.id || index}`"
|
||||
:ref="(el) => setEmployeeRef(el, index)"
|
||||
v-model:employee-data="subtask.employees[index]"
|
||||
:timeblocks="getEmployeeTimeblocks(employee.id)"
|
||||
:custom-filter="customFilter"
|
||||
@update:timeblocks="updateEmployeeTimeblocks($event, employee.id)"
|
||||
@clear-employee="() => removeEmployeeAtIndex(index)"
|
||||
@add-timeblock="addTimeblock(employee.id)"
|
||||
@add-timeblock="
|
||||
(afterIndex) => addTimeblock(employee.id, afterIndex)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -296,12 +301,12 @@ export default {
|
||||
isSaving: false,
|
||||
errorUtils,
|
||||
v$: useVuelidate(),
|
||||
employeeValidations: [],
|
||||
showDatePicker: false,
|
||||
selectedNewDate: [],
|
||||
timeblocks: [],
|
||||
wasFormValidationTriggered: false,
|
||||
modalName: 'z-task-modal',
|
||||
employeeRefs: [],
|
||||
};
|
||||
},
|
||||
|
||||
@@ -490,6 +495,13 @@ export default {
|
||||
this.editMode = !this.editMode;
|
||||
},
|
||||
|
||||
// Set refs for employee components in create mode
|
||||
setEmployeeRef(el, index) {
|
||||
if (el) {
|
||||
this.employeeRefs[index] = el;
|
||||
}
|
||||
},
|
||||
|
||||
openDatepicker(ref) {
|
||||
this.$refs[ref].openMenu();
|
||||
},
|
||||
@@ -530,17 +542,6 @@ export default {
|
||||
this.timeblocks = [...otherTimeblocks, ...timeblocksWithEmployeeId];
|
||||
},
|
||||
|
||||
// Clear employee validation
|
||||
clearEmployeeValidation(index) {
|
||||
if (index !== undefined && this.employeeValidations[index]) {
|
||||
this.employeeValidations[index].employee = false;
|
||||
this.employeeValidations[index].duration = false;
|
||||
} else if (index === undefined && this.employeeValidations[0]) {
|
||||
this.employeeValidations[0].employee = false;
|
||||
this.employeeValidations[0].duration = false;
|
||||
}
|
||||
},
|
||||
|
||||
updateTimeblock(val, index, employeeId) {
|
||||
const employeeTimeblocks = this.getEmployeeTimeblocks(employeeId);
|
||||
const timeblock = employeeTimeblocks[index];
|
||||
@@ -555,7 +556,7 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
addTimeblock(employeeId) {
|
||||
addTimeblock(employeeId, afterIndex = -1) {
|
||||
const newTimeblock = {
|
||||
date: new Date(), // Preset to current day
|
||||
starts_at_time: null,
|
||||
@@ -563,7 +564,21 @@ export default {
|
||||
employee_id: employeeId,
|
||||
};
|
||||
|
||||
this.timeblocks.push(newTimeblock);
|
||||
// Get timeblocks for this employee
|
||||
const employeeTimeblocks = this.timeblocks.filter(
|
||||
(tb) => tb.employee_id === employeeId,
|
||||
);
|
||||
|
||||
if (afterIndex === -1 || afterIndex >= employeeTimeblocks.length - 1) {
|
||||
// Add at the end
|
||||
this.timeblocks.push(newTimeblock);
|
||||
} else {
|
||||
// Find the position in the full timeblocks array
|
||||
const timeblockToInsertAfter = employeeTimeblocks[afterIndex];
|
||||
const insertPosition =
|
||||
this.timeblocks.indexOf(timeblockToInsertAfter) + 1;
|
||||
this.timeblocks.splice(insertPosition, 0, newTimeblock);
|
||||
}
|
||||
},
|
||||
|
||||
removeTimeblock(index, employeeId) {
|
||||
@@ -628,6 +643,7 @@ export default {
|
||||
|
||||
this.visible = true;
|
||||
this.timeblocks = [];
|
||||
this.employeeRefs = [];
|
||||
this.$nextTick(() => {
|
||||
this.v$.$reset();
|
||||
|
||||
@@ -922,55 +938,42 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
_validateEmployees() {
|
||||
return new Promise((resolve) => {
|
||||
this.employeeValidations = [];
|
||||
async _validateEmployees() {
|
||||
if (this.subtask.id) {
|
||||
// For existing subtasks, at least one employee is required
|
||||
// Component-level validation will handle the conditional validation
|
||||
const hasEmployee = !!(
|
||||
this.subtask.employee_id && this.subtask.duration
|
||||
);
|
||||
if (!hasEmployee) {
|
||||
this.$toast.error('Je potrebné vybrať zamestnanca a trvanie');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// For new subtasks, require at least one complete employee (id + duration)
|
||||
const validEmployees = this.subtask.employees.filter(
|
||||
(employee) => employee.id && employee.duration,
|
||||
);
|
||||
|
||||
if (this.subtask.id) {
|
||||
// For existing subtasks, require both employee and duration
|
||||
if (!this.subtask.employee_id || !this.subtask.duration) {
|
||||
this.employeeValidations[0] = {
|
||||
employee: !this.subtask.employee_id,
|
||||
duration: !this.subtask.duration,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// For new subtasks, require at least one employee with duration
|
||||
let hasValidEmployee = false;
|
||||
|
||||
this.subtask.employees.forEach((employee, index) => {
|
||||
// Skip validation if both id and duration are empty
|
||||
if (!employee.id && !employee.duration) {
|
||||
// If this is the first employee and no valid employee exists yet, show validation
|
||||
if (index === 0 && !hasValidEmployee) {
|
||||
this.employeeValidations[index] = {
|
||||
employee: true,
|
||||
duration: true,
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate if either id or duration is filled
|
||||
if (employee.id || employee.duration) {
|
||||
this.employeeValidations[index] = {
|
||||
employee: !employee.id,
|
||||
duration: !employee.duration,
|
||||
};
|
||||
|
||||
// If both id and duration are present, mark as valid
|
||||
if (employee.id && employee.duration) {
|
||||
hasValidEmployee = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (validEmployees.length === 0) {
|
||||
this.$toast.error(
|
||||
'Je potrebné pridať aspoň jedného zamestnanca s trvaním',
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
const isError = this.employeeValidations.some(
|
||||
(employee) => employee.duration || employee.employee,
|
||||
);
|
||||
resolve(!isError);
|
||||
});
|
||||
// Validate all employee component refs (includes employee select and timeblocks validation)
|
||||
for (const employeeRef of this.employeeRefs) {
|
||||
if (employeeRef && typeof employeeRef.validate === 'function') {
|
||||
const isValid = await employeeRef.validate();
|
||||
if (!isValid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
async _validateTimeblocks() {
|
||||
@@ -1046,6 +1049,18 @@ export default {
|
||||
.border-bottom
|
||||
border-bottom: 1px solid rgba(0,0,0,.1)
|
||||
|
||||
.splitted-inputs
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
gap: 16px
|
||||
|
||||
.left
|
||||
flex: 1
|
||||
|
||||
.right ::v-deep
|
||||
.v-field__field
|
||||
height: 56px !important
|
||||
|
||||
.done-btn
|
||||
background: #7f39fb !important
|
||||
border-radius: 4px !important
|
||||
@@ -1053,111 +1068,10 @@ export default {
|
||||
height: 50px
|
||||
width: 203px
|
||||
|
||||
.remove-employee
|
||||
position: relative
|
||||
width: 100%
|
||||
|
||||
svg
|
||||
position: absolute
|
||||
right: 5px
|
||||
top: 29px
|
||||
z-index: 5
|
||||
opacity: .5
|
||||
|
||||
&.hide-arrow ::v-deep
|
||||
.mdi-menu-down,
|
||||
.mdi-menu-up
|
||||
display: none
|
||||
|
||||
.employee-wrapper
|
||||
position: relative
|
||||
width: 100%
|
||||
|
||||
svg
|
||||
position: absolute
|
||||
right: 4px
|
||||
top: 28px
|
||||
z-index: 5
|
||||
opacity: .5
|
||||
|
||||
&.hide-arrow ::v-deep
|
||||
.mdi-menu-down,
|
||||
.mdi-menu-up
|
||||
display: none
|
||||
|
||||
@media screen and (max-width: 522px)
|
||||
.files
|
||||
margin-top: 104px !important
|
||||
|
||||
.employees-timeblocks
|
||||
display: flex
|
||||
flex-direction: column
|
||||
width: 100%
|
||||
margin-top: 20px
|
||||
|
||||
.employee-timeblocks-section
|
||||
width: 100%
|
||||
margin-bottom: 30px
|
||||
border: 1px solid #e0e0e0
|
||||
border-radius: 8px
|
||||
padding: 20px
|
||||
background: #fafafa
|
||||
|
||||
.employee-header
|
||||
margin-bottom: 15px
|
||||
padding-bottom: 10px
|
||||
border-bottom: 2px solid #7f39fb
|
||||
|
||||
h3
|
||||
margin: 0
|
||||
color: #7f39fb
|
||||
font-size: 18px
|
||||
font-weight: 600
|
||||
|
||||
.end-button
|
||||
width: 100%
|
||||
display: flex
|
||||
justify-content: flex-end
|
||||
align-items: center
|
||||
margin-top: 20px
|
||||
padding-top: 20px
|
||||
border-top: 1px solid #e0e0e0
|
||||
|
||||
button
|
||||
background: #7f39fb !important
|
||||
border-radius: 4px !important
|
||||
color: #fff !important
|
||||
height: 50px
|
||||
width: 203px
|
||||
border: none
|
||||
cursor: pointer
|
||||
transition: all 0.2s
|
||||
font-size: 14px
|
||||
font-weight: 500
|
||||
|
||||
&:hover
|
||||
background: #6b2dd9 !important
|
||||
|
||||
&:active
|
||||
background: #5a24b8 !important
|
||||
|
||||
.timeblock
|
||||
position: relative
|
||||
border-top: 1px solid #e0e0e0
|
||||
padding: 20px 0 10px 0
|
||||
|
||||
.splitted-time-inputs
|
||||
display: flex !important
|
||||
flex-direction: row !important
|
||||
gap: 15px
|
||||
margin-bottom: -11px
|
||||
|
||||
.datepicker-wrapper
|
||||
width: 70%
|
||||
.datepicker-input
|
||||
width: 100% !important
|
||||
pointer-events: none
|
||||
|
||||
.quill-editor-wrapper
|
||||
:deep(.ql-container)
|
||||
min-height: 200px
|
||||
|
||||
Reference in new issue
Block a user