bugs + CR's

This commit is contained in:
romankko2 committed 2023-10-12 17:28:05 +02:00
1 parent 9974d8b9e4
commit bb7b59cc0e
15 files changed
+257 -19

No files matched your search

+8 -1
View File
@@ -10,6 +10,7 @@
<Z-task-modal ref="z-task-modal" @on-subtask-edited="onTaskEdited" />
<Z-delete-task-modal ref="z-delete-task-modal" @on-subtask-deleted="onTaskDeleted" />
<Z-delete-timeBlock-modal ref="z-delete-timeblock-modal" @on-subtask-edited="onTaskEdited" />
<Z-delete-blocker-modal ref="z-delete-blocker-modal" @on-blocker-deleted="onBlockerDeleted" />
<Z-delete-master-task-modal ref="z-delete-master-task-modal" @on-mastertask-deleted="onMasterTaskDeleted" />
<Z-complete-task-modal ref="z-complete-task-modal" @on-subtask-edited="onTaskEdited" />
@@ -26,6 +27,7 @@
import ZDeleteTeamModal from '@/plugins/tm@modal/team/z-delete-team-modal.vue'
import ZTeamModal from '@/plugins/tm@modal/team/z-team-modal.vue'
import ZDeleteTaskModal from '@/plugins/tm@modal/task/z-delete-task-modal.vue'
import ZDeleteTimeBlockModal from '@/plugins/tm@modal/task/z-delete-timeblock-modal.vue'
import ZTaskModal from '@/plugins/tm@modal/task/z-task-modal.vue'
import ZDeleteBlockerModal from '@/plugins/tm@modal/blocker/z-delete-blocker-modal.vue'
import ZCompleteTaskModal from '@/plugins/tm@modal/task/z-complete-task-modal.vue'
@@ -51,7 +53,8 @@ export default {
ZDeleteMasterTaskModal,
ZDeleteTeamMemberModal,
ZShowMenuModal,
ZCompleteMasterTaskModal
ZCompleteMasterTaskModal,
ZDeleteTimeBlockModal
},
mounted() {
@@ -71,6 +74,10 @@ export default {
this.$refs['z-delete-task-modal'].showModal({subtask})
})
this.$events.on('show-delete-timeblock-modal', ({subtask}) => {
this.$refs['z-delete-timeblock-modal'].showModal({subtask})
})
this.$events.on('show-delete-blocker-modal', ({blocker}) => {
this.$refs['z-delete-blocker-modal'].showModal({blocker})
})
@@ -104,12 +104,30 @@
<v-btn rounded class="event-footer-button me-2" :class="{'completed': event.subtask?.is_finished}" @click.stop="completeTask(event)"><img :src="require('@/plugins/app/_img/icons/checkmark-double.svg')" alt=""></v-btn>
<v-btn rounded class="event-footer-button me-2" :class="{'completed': event._timeblock_is_finished}" @click.stop="toggleTimeblockIsFinished(event)"><img :src="require('@/plugins/app/_img/icons/checkmark.svg')" alt=""></v-btn>
<v-btn rounded class="event-footer-button me-2" @click.stop="editTask(event)"><img :src="require('@/plugins/app/_img/icons/eye.svg')" alt=""></v-btn>
<v-btn rounded class="event-footer-button me-2" @click.stop="deleteTask(event)"><img :src="require('@/plugins/app/_img/icons/bin.svg')" alt=""></v-btn>
<v-btn rounded class="event-footer-button me-2" @click.stop="deleteTimeBlockInTask(event)"><img :src="require('@/plugins/app/_img/icons/bin.svg')" alt=""></v-btn>
</template>
</div>
</div>
</template>
</Vue-cal>
<!-- <v-dialog v-model="visible" max-width="750" persistent>
<v-card>
<div class="d-flex justify-space-between align-center">
<h1 class="text-red">Ste si istý, že chcete pridať timeblock po deadline ?</h1>
<v-icon
@click.stop="visible = false"
icon="mdi-close"
size="large"
class="mb-15"
></v-icon>
</div>
<v-card-actions class="mt-10 d-flex justify-start align-center mobile-view">
<v-btn class="button primary half" variant="flat">ÁNO</v-btn>
<v-btn class="button primary half outline" @click.stop="visible = false">ZRUŠIŤ</v-btn>
</v-card-actions>
</v-card>
</v-dialog> -->
</div>
</template>
@@ -157,7 +175,8 @@ export default {
},
focusedEventId: null,
timeCellHeight: 100,
tmUtils
tmUtils,
visible: false
}
},
@@ -173,6 +192,14 @@ export default {
return moment(masterTask).format('DD.MM.yyyy') ? moment(masterTask.deadline).format('DD.MM.yyyy') : ''
},
isAfterDeadline(event) {
const deadline = this.getDeadline(event.subtask)
if (deadline) {
return this.tmUtils.isAfter(event.date, moment(deadline, 'DD.MM.yyyy'))
}
return false
},
weekChanged() {
const scrollContainer = this.$el.getElementsByClassName('vuecal__scrollable-body')[0]
scrollContainer.scrollLeft = 0
@@ -199,6 +226,7 @@ export default {
return timesheet
})
}
try {
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${editedSubtask.id}`, editedSubtask)
this.$events.emit('on-subtask-edited', subtask)
@@ -208,6 +236,24 @@ export default {
} catch (error) {
this.$toast.error(error.message || error)
}
const isAfterDeadline = this.isAfterDeadline(event)
if(isAfterDeadline) this.$toast.error('Timeblock, ktorý ste presunuli je po deadline !')
// if (isAfterDeadline) {
// this.visible = true
// } else {
// try {
// const { subtask } = await this.$axios.put_auth(`v1/subtasks/${editedSubtask.id}`, editedSubtask)
// this.$events.emit('on-subtask-edited', subtask)
// if (subtask.employee_id == this.$store.getters['auth/user'].id)
// this.$events.emit('show-task-add-time-modal', { subtask })
// } catch (error) {
// this.$toast.error(error.message || error)
// }
// }
} else if(this.$route.name == 'Dashboard - Teams') {
const editedSubtask = {
...event.subtask,
@@ -317,8 +363,8 @@ export default {
this.$events.emit('show-subtask-modal', {subtask})
},
deleteTask({ subtask }) {
this.$events.emit('show-delete-task-modal', {subtask})
deleteTimeBlockInTask({ subtask }) {
this.$events.emit('show-delete-timeblock-modal', {subtask})
},
editBlocker({ blocker }) {
@@ -58,6 +58,7 @@ export default {
},
}
</script>
<style lang="sass" scoped>
#calendar
&:deep(.fc-media-screen)
@@ -112,4 +113,4 @@ export default {
right: 4px
&:deep(.fc-daygrid-day-frame)
min-height: 100px
</style>
</style>
@@ -58,6 +58,12 @@ export default {
mounted() {
const monthIndex = new Date().getMonth()
this.filter.month = monthIndex < 9 ? `0${monthIndex + 1}` : `${monthIndex + 1}`
const savedTeamMT = localStorage.getItem('savedTeamMT')
const savedCreatedBy = localStorage.getItem('savedCreatedBy')
const savedEmployee = localStorage.getItem('savedEmployee')
if(savedTeamMT) this.filter.teamId = JSON.parse(savedTeamMT)
if(savedCreatedBy) this.filter.createdById = JSON.parse(savedCreatedBy)
if(savedEmployee) this.filter.employeeId = JSON.parse(savedEmployee)
},
computed: {
@@ -88,6 +94,9 @@ export default {
filter: {
handler() {
this.$emit('filterChanged', this.filter)
localStorage.setItem('savedTeamMT', this.filter.teamId)
localStorage.setItem('savedCreatedBy', this.filter.createdById)
localStorage.setItem('savedEmployee', this.filter.employeeId)
},
deep: true
}
@@ -59,6 +59,19 @@ export default {
// };
// });
return this.mastertasks.map(event => {
// const currentDate = new Date()
// const eventDeadline = new Date(event.deadline)
// const isEventOnCurrentDate =
// eventDeadline.getFullYear() === currentDate.getFullYear() &&
// eventDeadline.getMonth() === currentDate.getMonth() &&
// eventDeadline.getDate() === currentDate.getDate()
// console.log("isEventOnCurrentDate:", isEventOnCurrentDate)
// console.log("eventDeadline:", eventDeadline)
// const backgroundColor = isEventOnCurrentDate ? 'red' : event.color
// console.log("backgroundColor:", backgroundColor)
return {
id: event.id,
title: `${event.project_code} - ${event.name}`,
@@ -2,7 +2,8 @@
<v-row class="px-10 py-8 subheader">
<v-autocomplete
:custom-filter="customFilter"
:match-any="true" v-model="selectedTeam"
:match-any="true"
v-model="selectedTeam"
class="subheader-input"
:items="teams"
item-title="name"
@@ -68,8 +69,9 @@ export default {
},
mounted() {
// TODO automaticky preselect
this.selectedTeam = this.teams[1].id
const savedTeam = localStorage.getItem('selectedTeam')
if(savedTeam) this.selectedTeam = JSON.parse(savedTeam)
else this.selectedTeam = this.teams[0]?.id
this.$nextTick(() => this._updateFilters())
},
@@ -98,6 +100,8 @@ export default {
if (!this.filter.start || !this.filter.end || !this.filter.team) return
this.$emit('filter-changed', this.filter)
localStorage.setItem('selectedTeam', this.filter.team.id)
}
},
@@ -57,7 +57,7 @@ export default {
id: index + 1,
name: employee.name,
employee_id: employee.id,
// date: this.filter.start,
date: this.filter.start,
fullname: `${employee.name} ${employee.surname}`,
initials: employee.name.charAt(0).toUpperCase() + employee.surname.charAt(0).toUpperCase(),
unscheduledTime: unscheduledTime > 0 ? (unscheduledTime / 60).toFixed(1) : 0,
@@ -17,7 +17,7 @@
:items="[...enrichedEmployees]" item-title="_fullName" item-value="id" variant="solo"
class="modal-input" v-model="blocker.employee_id" />
<!-- <Z-autocomplete label="Vyhľadať zamestnanca" :value="blocker?.employee ? `${blocker?.employee?.name} ${blocker?.employee?.surname}` : ''" :options="enrichedEmployees.map(employee => ({key: employee.id, value: employee._fullName}))" :clear-on-submit="false" :class="{ error: v$.blocker.employee.$errors.length }" class="modal-input" @option-selected="onEmployeeSelected" /> -->
<Datepicker class="modal-input mb-5" v-model="datepicker" format="dd.MM.yyyy" locale="sk"
<Datepicker class="modal-input mb-5" v-model="datepicker" :auto-apply="true" format="dd.MM.yyyy" locale="sk"
:class="{ error: v$.datepicker.$errors?.length }" :validations="v$.datepicker" select-text="Vybrať"
cancel-text="Zrušiť" placeholder="Dátum" :enable-time-picker="false" ref="datepicker" />
@@ -50,7 +50,7 @@
<!-- <Z-autocomplete label="Vyhľadať zamestnanca" :options="employeesOptions" class="modal-input" @option-selected="onEmployeeSelected" /> -->
<v-btn class="w-100 mb-5 button secondary" :class="{error: v$.mastertask.project_id.$errors.length}" @click="showAddEmployeeInput = true"> <v-icon class="mx-1" icon="mdi-plus" />Pridať zamestnanca </v-btn>
<v-btn :disabled="mastertask.id" class="w-100 mb-5 button secondary" :class="{error: v$.mastertask.project_id.$errors.length}" @click="showAddEmployeeInput = true"> <v-icon class="mx-1" icon="mdi-plus" />Pridať zamestnanca </v-btn>
<div class="w-100 modal-input" :class="{ error: v$.mastertask.description.$errors.length }">
<QuillEditor ref="description" v-model="mastertask.description" placeholder="Popis" theme="snow" class="rich-text-editor" @keyup="onQuillEditorInput" />
@@ -33,7 +33,7 @@
</div>
<v-card-actions class="mt-10 d-flex flex-column modal-content">
<Datepicker v-model="form.date" format="dd.MM.yyyy" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Dátum" :enable-time-picker="false" class="mb-5 modal-input" :class="{error: v$.form.date.$errors.length}" />
<Datepicker v-model="form.date" format="dd.MM.yyyy" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Dátum" :auto-apply="true" :enable-time-picker="false" class="mb-5 modal-input" :class="{error: v$.form.date.$errors.length}" />
<v-text-field v-model="form.starts_at_time" type="time" variant="solo" bg-color="white" :hint="v$.form.starts_at_time.$errors ? errorUtils.parseErrors(v$.form.starts_at_time.$errors) : null" :class="{ error: v$.form.starts_at_time.$errors.length }" class="mb-1 modal-input" label="Začiatok" />
<v-text-field v-model="form.ends_at_time" type="time" variant="solo" bg-color="white" :hint="v$.form.ends_at_time.$errors ? errorUtils.parseErrors(v$.form.ends_at_time.$errors) : null" :class="{ error: v$.form.ends_at_time.$errors.length }" class="modal-input" label="Koniec" />
</v-card-actions>
@@ -41,6 +41,24 @@
<v-btn @click="submit()" class="button primary mt-5">Potvrdiť</v-btn>
</v-card>
</v-dialog>
<v-dialog v-model="visible" max-width="750" persistent>
<v-card>
<div class="d-flex justify-space-between align-center">
<h1 class="text-red">Ste si istý, že chcete pridať timeblock po deadline <br> <b class="text-black">z mastertasku {{ subtask?.project_code }} ?</b></h1>
<v-icon
@click.stop="visible = false"
icon="mdi-close"
size="large"
class="mb-15"
></v-icon>
</div>
<v-card-actions class="mt-10 d-flex justify-start align-center mobile-view">
<v-btn class="button primary half" variant="flat" @click.stop="confirmSubmit()">ÁNO</v-btn>
<v-btn class="button primary half outline" @click.stop="visible = false">ZRUŠIŤ</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
@@ -52,6 +70,8 @@ import { required } from '@vuelidate/validators'
import Datepicker from '@vuepic/vue-datepicker'
import moment from 'moment'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
import { mapGetters } from 'vuex'
export default {
mixins: [ modalMixin ],
@@ -79,6 +99,7 @@ export default {
errorUtils,
tmUtils,
showModal: false,
visible: false,
form: {
date: null,
starts_at_time: '09:00',
@@ -97,6 +118,10 @@ export default {
}
},
computed: {
...mapGetters('tm', ['mastertasks'])
},
methods: {
async submit() {
if (!await this.v$.$validate())
@@ -121,12 +146,46 @@ export default {
if(subtask.deadline) subtask.deadline = tmUtils.formatDateTimeForBackend(subtask.deadline)
const isAfterDeadline = this.isAfterDeadline()
if (isAfterDeadline) {
this.visible = true
} else {
if (!subtask.id) {
this.$emit('update-unfinished-subtask', subtask)
} else {
this._update(subtask)
}
}
},
async confirmSubmit() {
const subtask = JSON.parse(JSON.stringify(this.subtask))
const splittedStartsAtTime = this.form.starts_at_time.split(':')
const splittedEndsAtTime = this.form.ends_at_time.split(':')
const start = moment(this.form.date).hours(parseInt(splittedStartsAtTime[0])).minutes(parseInt(splittedStartsAtTime[1])).toISOString()
const end = moment(this.form.date).hours(parseInt(splittedEndsAtTime[0])).minutes(parseInt(splittedEndsAtTime[1])).toISOString()
if (!subtask?.timeblocks) { subtask.timeblocks = [] }
if (!subtask?.timesheets) { subtask.timesheets = [] }
if (!subtask?.is_finished) { subtask.is_finished = 0 }
subtask.timeblocks.push({
end: tmUtils.formatDateTimeForBackend(end),
id: null,
is_finished: 0,
start: tmUtils.formatDateTimeForBackend(start)
})
if(subtask.deadline) subtask.deadline = tmUtils.formatDateTimeForBackend(subtask.deadline)
if (!subtask.id) {
this.$emit('update-unfinished-subtask', subtask)
this.closeModal()
return
}
this.visible = false
this._update(subtask)
},
@@ -185,6 +244,21 @@ export default {
}
},
isAfterDeadline() {
const deadline = this.getDeadline(this.subtask)
if (deadline) {
return this.tmUtils.isAfter(this.form.date, moment(deadline, 'DD.MM.yyyy'))
}
return false
},
getDeadline(subtask) {
if(subtask.deadline) return moment(subtask.deadline).format('DD.MM.yyyy')
else if(!this.mastertasks) return ''
const masterTask = this.mastertasks.find((mt) => mt.id === subtask.master_task_id)
return moment(masterTask).format('DD.MM.yyyy') ? moment(masterTask.deadline).format('DD.MM.yyyy') : ''
},
closeModal() {
this.form = {
date: null,
@@ -53,8 +53,8 @@ export default {
await this.$axios.delete_auth(`v1/subtasks/${this.subtask.id}`)
this.$store.commit('tm/delete_subtask', this.subtask)
this.$emit('on-subtask-deleted', this.subtask)
this.closeModal()
this.$emit('on-subtask-deleted', this.subtask)
} catch (error) {
this.$toast.error(error)
} finally {
@@ -0,0 +1,83 @@
<template>
<v-dialog v-model="visible" max-width="500" persistent>
<v-card>
<div class="d-flex justify-space-between align-center">
<h4 class="mt-3">Vyberte časový úsek, ktorý chcete odstrániť</h4>
<v-icon
@click.stop="closeModal()"
icon="mdi-close"
size="large"
></v-icon>
</div>
<div v-for="(timeblock, index) in subtask.timeblocks" :key="timeblock.id" class="d-flex align-center justify-center mb-3 mt-3">
<p class="task-badge rounded-pill" :class="{'strike-through': timeblock.is_finished}">{{ tmUtils.formatDateTime(timeblock.start) }} - {{ tmUtils.formatDateTime(timeblock.end) }}</p>
<v-icon @click.stop="subtask.id ? deleteTimeblock(timeblock) : deleteTimeblockWithoutId(index)" class="close-icon circle-border cursor-pointer ml-3 text-red" icon="mdi-close" size="medium" />
</div>
</v-card>
</v-dialog>
</template>
<script>
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
import tmUtils from '@/plugins/tm@_utils/tm.utils'
export default {
mixins: [ modalMixin ],
emits: ['on-subtask-edited'],
data() {
return {
visible: false,
subtask: null,
isDeleting: false,
tmUtils
}
},
methods: {
async showModal({ subtask }) {
this.subtask = subtask
this.visible = true
},
closeModal() {
this.visible = false
},
async deleteTimeblock({ id }) {
const subtask = JSON.parse(JSON.stringify(this.subtask))
subtask.timeblocks = subtask.timeblocks.filter(timeblock => timeblock.id != id)
if(subtask.deadline) subtask.deadline = tmUtils.formatDateTimeForBackend(subtask.deadline)
this._update(subtask)
},
deleteTimeblockWithoutId(i) {
this.$emit('delete-timeblock')
},
async _update(data) {
try {
const timesheets = data.timesheets.map((timesheet) => {
delete timesheet.employee_name
return timesheet
})
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${data.id}`, {...data, timesheets})
this.closeModal()
this.$events.emit('on-subtask-edited', subtask)
} catch (error) {
this.$toast.error(error.message || error)
}
},
}
}
</script>
<style lang="sass" scoped>
.close-icon:hover
background: red
color: #fff !important
</style>
@@ -211,7 +211,10 @@ export default {
if (subtask?.id) {
const data = await this.$axios.get_auth_data(`v1/subtasks/${subtask.id}`)
if (!data.deadline) return (this.subtask = this._enrichTask(data))
if (!data.deadline) {
this.editMode = editMode || !data.id
return (this.subtask = this._enrichTask(data))
}
const splittedDeadline = data.deadline.split(' ')
data.deadline = moment(splittedDeadline[0])
@@ -231,9 +234,9 @@ export default {
this.subtask.project_code = subtask.project_code
}
}
this.editMode = editMode || !this.subtask.id
} catch (error) {
console.error('ERROR', error)
this.$toast.error(error)
}
},
+1 -2
View File
@@ -81,14 +81,13 @@ export class I18n {
(response) => {
return response
},
// fixnut aby logger nezaznamenaval chybu ak padne requet kvoli loggeru
(error) => {
if(error.response) {
axios.post('https://logger.wezeo.dev/cms/api/data/new', {
data: JSON.stringify(error)
})
}
return Promise.reject(error)
return Promise.reject(error.response)
}
)
}
@@ -71,7 +71,6 @@ export default {
async delete_auth(url: string, config?: any) {
config = this._config(config)
return axios.delete(url, config)
.then(response => response.data)
.catch(error => Promise.reject(toastUtils.parseAndTranslate(error)))