mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 06:20:21 +00:00
feature(task-modal): added ability to edit timeblocks both on create and edit
This commit is contained in:
1 parent
80d0e57351
commit
056b27b016
2 files changed
+133
-85
No files matched your search
@@ -27,7 +27,6 @@
|
||||
<v-text-field
|
||||
:value="timeblock.starts_at_time"
|
||||
@input="updateStartTime"
|
||||
@focus="onInputFocus"
|
||||
:class="{ error: v$?.timeblock.starts_at_time.$errors.length }"
|
||||
type="time"
|
||||
variant="solo"
|
||||
@@ -37,7 +36,6 @@
|
||||
<v-text-field
|
||||
:value="timeblock.ends_at_time"
|
||||
@input="updateEndTime"
|
||||
@focus="onInputFocus"
|
||||
:class="{ error: v$?.timeblock.ends_at_time.$errors.length }"
|
||||
type="time"
|
||||
variant="solo"
|
||||
@@ -109,20 +107,20 @@ export default {
|
||||
async openDatepicker(ref) {
|
||||
this.$refs[ref].openMenu();
|
||||
},
|
||||
|
||||
updateDate(date) {
|
||||
const timeblock = { ...this.timeblock };
|
||||
if (date) timeblock.date = date;
|
||||
this.$emit('updateTimeblock', timeblock);
|
||||
const updated = { ...this.timeblock, date };
|
||||
this.$emit('updateTimeblock', updated);
|
||||
},
|
||||
|
||||
updateStartTime(event) {
|
||||
const timeblock = { ...this.timeblock };
|
||||
timeblock.starts_at_time = event.target.value;
|
||||
this.$emit('updateTimeblock', timeblock);
|
||||
const updated = { ...this.timeblock, starts_at_time: event.target.value };
|
||||
this.$emit('updateTimeblock', updated);
|
||||
},
|
||||
|
||||
updateEndTime(event) {
|
||||
const timeblock = { ...this.timeblock };
|
||||
timeblock.ends_at_time = event.target.value;
|
||||
this.$emit('updateTimeblock', timeblock);
|
||||
const updated = { ...this.timeblock, ends_at_time: event.target.value };
|
||||
this.$emit('updateTimeblock', updated);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -158,4 +156,3 @@ export default {
|
||||
width: 100% !important
|
||||
pointer-events: none
|
||||
</style>
|
||||
e
|
||||
@@ -234,70 +234,22 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="!subtask.id">
|
||||
<div class="timeblocks w-100">
|
||||
<A-timeblock
|
||||
v-for="(timeblock, index) in timeblocks"
|
||||
:key="index"
|
||||
@updateTimeblock="(val) => updateTimeblock(val, index)"
|
||||
@removeTimeblock="removeTimeblock(index)"
|
||||
:timeblock="timeblock"
|
||||
:deletable="index > 0"
|
||||
editable
|
||||
:ref="`timetable-${index}`"
|
||||
:prevent-input-focus="preventInputFocus"
|
||||
:on-input-focus="onInputFocus"
|
||||
:on-date-open="onDateOpen"
|
||||
/>
|
||||
<div class="end-button w-100">
|
||||
<button
|
||||
@click="
|
||||
timeblocks.push({
|
||||
date: null,
|
||||
starts_at_time: null,
|
||||
ends_at_time: null,
|
||||
})
|
||||
"
|
||||
>
|
||||
Pridať časový blok
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div
|
||||
v-else
|
||||
v-for="(timeblock, index) in subtask.timeblocks"
|
||||
:key="index"
|
||||
class="timeblock w-100"
|
||||
>
|
||||
<Datepicker
|
||||
:model-value="timeblock.start.substring(0, 10)"
|
||||
format="dd.MM.yyyy"
|
||||
locale="sk"
|
||||
select-text="Vybrať"
|
||||
cancel-text="Zrušiť"
|
||||
placeholder="Dátum"
|
||||
:auto-apply="true"
|
||||
:enable-time-picker="false"
|
||||
readonly
|
||||
class="mb-5 modal-input"
|
||||
<div class="timeblocks w-100">
|
||||
<A-timeblock
|
||||
v-for="(timeblock, index) in editableTimeblocks"
|
||||
:key="index"
|
||||
@updateTimeblock="(val) => updateTimeblock(val, index)"
|
||||
@removeTimeblock="removeTimeblock(index)"
|
||||
:timeblock="timeblock"
|
||||
:deletable="index > 0"
|
||||
:editable="true"
|
||||
:ref="`timetable-${index}`"
|
||||
:prevent-input-focus="preventInputFocus"
|
||||
:on-input-focus="onInputFocus"
|
||||
:on-date-open="onDateOpen"
|
||||
/>
|
||||
<div class="splitted-time-inputs w-100">
|
||||
<v-text-field
|
||||
:value="timeblock.start.substring(11, 16)"
|
||||
type="time"
|
||||
variant="solo"
|
||||
bg-color="white"
|
||||
label="Začiatok"
|
||||
/>
|
||||
<v-text-field
|
||||
:value="timeblock.end.substring(11, 16)"
|
||||
type="time"
|
||||
variant="solo"
|
||||
bg-color="white"
|
||||
label="Koniec"
|
||||
/>
|
||||
<div class="end-button w-100">
|
||||
<button @click="addTimeblock">Pridať časový blok</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -459,6 +411,27 @@ export default {
|
||||
_fullName: `${mastertask.name} [${mastertask.project_code}]`,
|
||||
}));
|
||||
},
|
||||
|
||||
// Unified timeblocks for both create and update modes
|
||||
editableTimeblocks: {
|
||||
get() {
|
||||
if (this.subtask?.id) {
|
||||
// Update mode: use subtask.timeblocks (from BE)
|
||||
return this.subtask.timeblocks || [];
|
||||
}
|
||||
// Create mode: use this.timeblocks (local state)
|
||||
return this.timeblocks;
|
||||
},
|
||||
set(value) {
|
||||
if (this.subtask?.id) {
|
||||
// Update mode: update subtask.timeblocks (Vue 3 reactivity)
|
||||
this.subtask.timeblocks = value;
|
||||
} else {
|
||||
// Create mode: update this.timeblocks
|
||||
this.timeblocks = value;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
validations() {
|
||||
@@ -520,11 +493,42 @@ export default {
|
||||
},
|
||||
|
||||
updateTimeblock(val, index) {
|
||||
this.timeblocks[index] = val;
|
||||
if (this.subtask?.id) {
|
||||
// Update mode: direct assignment (Vue 3 reactivity)
|
||||
this.subtask.timeblocks[index] = val;
|
||||
} else {
|
||||
// Create mode: direct assignment
|
||||
this.timeblocks[index] = val;
|
||||
}
|
||||
},
|
||||
|
||||
addTimeblock() {
|
||||
const newTimeblock = {
|
||||
date: null,
|
||||
starts_at_time: null,
|
||||
ends_at_time: null,
|
||||
};
|
||||
|
||||
if (this.subtask?.id) {
|
||||
// Update mode
|
||||
if (!this.subtask.timeblocks) {
|
||||
this.subtask.timeblocks = [];
|
||||
}
|
||||
this.subtask.timeblocks.push(newTimeblock);
|
||||
} else {
|
||||
// Create mode
|
||||
this.timeblocks.push(newTimeblock);
|
||||
}
|
||||
},
|
||||
|
||||
removeTimeblock(index) {
|
||||
this.timeblocks.splice(index, 1);
|
||||
if (this.subtask?.id) {
|
||||
// Update mode
|
||||
this.subtask.timeblocks.splice(index, 1);
|
||||
} else {
|
||||
// Create mode
|
||||
this.timeblocks.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
async showModal({ subtask, editMode = false, mastertask = {} }) {
|
||||
@@ -549,6 +553,35 @@ export default {
|
||||
`v1/subtasks/${subtask.id}`,
|
||||
);
|
||||
|
||||
// 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);
|
||||
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,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
data.timeblocks = convertedTimeblocks;
|
||||
|
||||
if (!data.deadline) {
|
||||
this.editMode = editMode || !data.id;
|
||||
return (this.subtask = this._enrichTask(data));
|
||||
@@ -624,9 +657,7 @@ export default {
|
||||
|
||||
async validateAllFields() {
|
||||
const employeesValid = await this._validateEmployees();
|
||||
const timeblocksValid = this.subtask?.id
|
||||
? true
|
||||
: await this._validateTimeblocks();
|
||||
const timeblocksValid = await this._validateTimeblocks();
|
||||
|
||||
if (!(await this.v$.$validate())) return;
|
||||
if (!employeesValid || !timeblocksValid) return;
|
||||
@@ -661,9 +692,22 @@ export default {
|
||||
return timesheet;
|
||||
});
|
||||
|
||||
// Convert timeblocks from internal format to BE format for update
|
||||
const timeblocks = (this.subtask.timeblocks || [])
|
||||
.filter((timeblock) => timeblock.date) // Only send timeblocks with dates
|
||||
.map((timeblock) => {
|
||||
const dateStr = moment(timeblock.date).format('YYYY-MM-DD');
|
||||
return {
|
||||
id: timeblock.id || null,
|
||||
start: `${dateStr} ${timeblock.starts_at_time}:00`,
|
||||
end: `${dateStr} ${timeblock.ends_at_time}:00`,
|
||||
is_finished: timeblock.is_finished || 0,
|
||||
};
|
||||
});
|
||||
|
||||
const { subtask } = await this.$axios.patch_auth_form(
|
||||
`v1/subtasks/${this.subtask.id}`,
|
||||
{ ...this.subtask, timesheets },
|
||||
{ ...this.subtask, timesheets, timeblocks },
|
||||
);
|
||||
localStorage.removeItem('subtaskData');
|
||||
|
||||
@@ -809,12 +853,19 @@ export default {
|
||||
},
|
||||
|
||||
async _validateTimeblocks() {
|
||||
let invalid = false;
|
||||
for (let i = 0; i < this.timeblocks.length; i++) {
|
||||
let valid = true;
|
||||
const timeblocks = this.editableTimeblocks;
|
||||
|
||||
for (let i = 0; i < timeblocks.length; i++) {
|
||||
const ref = this.$refs[`timetable-${i}`];
|
||||
invalid = (await ref[0].v$.$validate()) || invalid;
|
||||
if (ref && ref[0]) {
|
||||
const isValid = await ref[0].v$.$validate();
|
||||
if (!isValid) {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return invalid;
|
||||
return valid;
|
||||
},
|
||||
|
||||
_enrichTask(subtask) {
|
||||
|
||||
Reference in new issue
Block a user