refactor(task-modals): updated timeblocks to new local dat format

This commit is contained in:
Matej Glasnák committed 2025-10-14 18:42:07 +02:00
1 parent eaf83bf0cc
commit 0035251080
8 files changed
+1059 -597

No files matched your search

@@ -1,154 +1,226 @@
<template>
<v-table>
<thead>
<tr>
<th @click="getSelectedTimeblockDeadline" class="text-left">Kód projektu</th>
<th class="text-left">Názov</th>
<th class="text-left">Deadline</th>
<th class="text-left">Najbližší neuzavretý</th>
<th class="text-left">Naplánované</th>
<th class="text-left">Zostávajúce</th>
<th class="text-left">Akcia</th>
</tr>
</thead>
<v-table>
<thead>
<tr>
<th @click="getSelectedTimeblockDeadline" class="text-left">
Kód projektu
</th>
<th class="text-left">Názov</th>
<th class="text-left">Deadline</th>
<th class="text-left">Najbližší neuzavretý</th>
<th class="text-left">Naplánované</th>
<th class="text-left">Zostávajúce</th>
<th class="text-left">Akcia</th>
</tr>
</thead>
<tbody>
<tr class="cursor-pointer" v-for="subtask in subtasks" :key="subtask.id" @click.stop="editTask(subtask, false)">
<td>{{ subtask.project_code }}</td>
<td>{{ subtask.title ?? subtask.master_task }}</td>
<td v-if="subtask.deadline">{{ getDeadline(subtask) }}</td>
<v-tooltip text="Deadline z Mastertasku" location="end">
<template v-slot:activator="{ props }">
<td v-if="!subtask.deadline" v-bind="props">{{ getDeadline(subtask) }}*</td>
</template>
</v-tooltip>
<td>{{ displayTimeblock(subtask) }}</td>
<td>{{ subtask.duration }} h</td>
<td>{{ (subtask.duration - subtask.spent_time).toFixed(2) }} h</td>
<tbody>
<tr
class="cursor-pointer"
v-for="subtask in subtasks"
:key="subtask.id"
@click.stop="editTask(subtask, false)"
>
<td>{{ subtask.project_code }}</td>
<td>{{ subtask.title ?? subtask.master_task }}</td>
<td v-if="subtask.deadline">{{ getDeadline(subtask) }}</td>
<v-tooltip text="Deadline z Mastertasku" location="end">
<template v-slot:activator="{ props }">
<td v-if="!subtask.deadline" v-bind="props">
{{ getDeadline(subtask) }}*
</td>
</template>
</v-tooltip>
<td>{{ displayTimeblock(subtask) }}</td>
<td>{{ subtask.duration }} h</td>
<td>{{ (subtask.duration - subtask.spent_time).toFixed(2) }} h</td>
<td class="task-action">
<div class="d-flex justify-start align-center">
<img class="pencil-icon mr-3" :class="{'disabled': loadingSubtask[subtask.id]}" :src="checkmarkDouble" @click.stop="handleCompleteTask(subtask)">
<td class="task-action">
<div class="d-flex justify-start align-center">
<img
class="pencil-icon mr-3"
:class="{ disabled: loadingSubtask[subtask.id] }"
:src="checkmarkDouble"
@click.stop="handleCompleteTask(subtask)"
/>
<template v-if="subtask.type == 'office365'">
<img class="pencil-icon" :src="eye" @click.stop="editTask(subtask, false)">
<img class="office-icon" :src="office365" />
</template>
<template v-if="subtask.type == 'office365'">
<img
class="pencil-icon"
:src="eye"
@click.stop="editTask(subtask, false)"
/>
<img class="office-icon" :src="office365" />
</template>
<template v-else>
<img class="pencil-icon" :src="eye" @click.stop="editTask(subtask, false)">
<img class="trash-icon" :src="bin" @click.stop="deleteTask(subtask)" />
</template>
</div>
</td>
</tr>
</tbody>
</v-table>
<template v-else>
<img
class="pencil-icon"
:src="eye"
@click.stop="editTask(subtask, false)"
/>
<img
class="trash-icon"
:src="bin"
@click.stop="deleteTask(subtask)"
/>
</template>
</div>
</td>
</tr>
</tbody>
</v-table>
</template>
<script>
import { bin, eye, office365, checkmarkDouble } from '@/plugins/app/_img'
import { bin, eye, office365, checkmarkDouble } from '@/plugins/app/_img';
import { mapGetters } from 'vuex'
import moment from 'moment'
import { mapGetters } from 'vuex';
import moment from 'moment';
export default {
props: {
subtasks: {
type: Array,
required: true
}
},
props: {
subtasks: {
type: Array,
required: true,
},
},
data() {
return {
eye,
bin,
office365,
checkmarkDouble,
loadingSubtask: {}
}
},
data() {
return {
eye,
bin,
office365,
checkmarkDouble,
loadingSubtask: {},
};
},
computed: {
...mapGetters('tm', ['mastertasks'])
},
computed: {
...mapGetters('tm', ['mastertasks']),
},
methods: {
editTask(subtask, editMode = false) {
this.$events.emit('show-subtask-modal', {subtask, editMode})
},
methods: {
editTask(subtask, editMode = false) {
this.$events.emit('show-subtask-modal', { subtask, editMode });
},
async handleCompleteTask(subtask) {
const areAllTimeBlocksFinished = subtask.timeblocks.every(tb => tb.is_finished)
async handleCompleteTask(subtask) {
const areAllTimeBlocksFinished = subtask.timeblocks.every(
(tb) => tb.is_finished,
);
if (!areAllTimeBlocksFinished) {
this.$events.emit('show-unable-to-complete-task-modal', { subtask })
} else {
await this._finishSubtask(subtask)
}
},
if (!areAllTimeBlocksFinished) {
this.$events.emit('show-unable-to-complete-task-modal', { subtask });
} else {
await this._finishSubtask(subtask);
}
},
deleteTask(subtask) {
if (subtask.type == 'office365')
return this.$events.emit('show-unable-to-edit-office-task-modal', { mode: 'delete' })
deleteTask(subtask) {
if (subtask.type == 'office365')
return this.$events.emit('show-unable-to-edit-office-task-modal', {
mode: 'delete',
});
this.$events.emit('show-delete-task-modal', {subtask})
},
this.$events.emit('show-delete-task-modal', { subtask });
},
getDeadline(subtask) {
if (subtask?.deadline)
return moment(subtask.deadline).format('DD.MM.yyyy')
getDeadline(subtask) {
if (subtask?.deadline)
return moment(subtask.deadline).format('DD.MM.yyyy');
return moment(subtask.master_task_deadline).format('DD.MM.yyyy')
},
return moment(subtask.master_task_deadline).format('DD.MM.yyyy');
},
getSelectedTimeblockDeadline(timeblocks) {
const currentDate = moment()
getSelectedTimeblockDeadline(timeblocks) {
const currentDate = moment();
const unfinishedTimeblocks = timeblocks.filter(tb => tb.is_finished === 0)
if (unfinishedTimeblocks.length > 0) return moment(unfinishedTimeblocks[0].end).format('DD.MM.yyyy, HH:mm')
const unfinishedTimeblocks = timeblocks.filter(
(tb) => tb.is_finished === 0,
);
if (unfinishedTimeblocks.length > 0)
return moment(unfinishedTimeblocks[0].end).format('DD.MM.yyyy, HH:mm');
const upcomingTimeblocks = timeblocks
.filter(tb => moment(tb.end).isAfter(currentDate))
.sort((a, b) => moment(a.end).diff(moment(b.end)))
const upcomingTimeblocks = timeblocks
.filter((tb) => moment(tb.end).isAfter(currentDate))
.sort((a, b) => moment(a.end).diff(moment(b.end)));
if (upcomingTimeblocks.length > 0 && upcomingTimeblocks.is_finished === 0) return moment(upcomingTimeblocks[0].end).format('DD.MM.yyyy, HH:mm')
if (upcomingTimeblocks.length > 0 && upcomingTimeblocks.is_finished === 0)
return moment(upcomingTimeblocks[0].end).format('DD.MM.yyyy, HH:mm');
return ''
},
return '';
},
displayTimeblock(subtask) {
const timeblockDeadline = this.getSelectedTimeblockDeadline(subtask.timeblocks)
displayTimeblock(subtask) {
const timeblockDeadline = this.getSelectedTimeblockDeadline(
subtask.timeblocks,
);
return timeblockDeadline !== '' ? timeblockDeadline : 'Žiadny termín'
},
return timeblockDeadline !== '' ? timeblockDeadline : 'Žiadny termín';
},
async _finishSubtask(subtask) {
const tempSubtask = {...subtask, is_finished: 1, timesheets: subtask?.timesheets.map((timesheet) => {
delete timesheet.employee_name
return timesheet
}) || []}
async _finishSubtask(subtask) {
const timesheets =
subtask?.timesheets.map((timesheet) => {
delete timesheet.employee_name;
return timesheet;
}) || [];
try {
this.loadingSubtask[subtask.id] = true
await this.$axios.put_auth(`v1/subtasks/${tempSubtask.id}`, tempSubtask)
// Convert timeblocks from internal format to BE format
const timeblocks = (subtask.timeblocks || [])
.filter((timeblock) => {
// Filter timeblocks that have either old format (date) or new format (start)
return timeblock.date || timeblock.start;
})
.map((timeblock) => {
// If already in BE format (has start field), return as is
if (timeblock.start && !timeblock.date) {
return {
id: timeblock.id || null,
start: timeblock.start,
end: timeblock.end,
is_finished: timeblock.is_finished || 0,
};
}
this.$store.dispatch('tm/removeOngoingSubtask', subtask.id)
this.$events.emit('on-subtask-edited', subtask)
} catch (error) {
this.$toast.error(error.message || error)
// Convert from internal format to BE format
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,
};
});
if (process.env.NODE_ENV === 'development')
console.log('[a-ongoing-table.vue] Error: ', error)
} finally {
this.loadingSubtask[subtask.id] = false
}
}
}
}
const tempSubtask = {
...subtask,
is_finished: 1,
timesheets,
timeblocks,
};
try {
this.loadingSubtask[subtask.id] = true;
await this.$axios.put_auth(
`v1/subtasks/${tempSubtask.id}`,
tempSubtask,
);
this.$store.dispatch('tm/removeOngoingSubtask', subtask.id);
this.$events.emit('on-subtask-edited', subtask);
} catch (error) {
this.$toast.error(error.message || error);
if (process.env.NODE_ENV === 'development')
console.log('[a-ongoing-table.vue] Error: ', error);
} finally {
this.loadingSubtask[subtask.id] = false;
}
},
},
};
</script>
<style lang="sass" scoped>