[timeblocks]

This commit is contained in:
JakubPapso committed 2024-02-06 19:20:09 +01:00
1 parent cb44878dcb
commit 6a89b7bc47
5 files changed
+218 -17

No files matched your search

@@ -7,6 +7,12 @@ export default {
},
methods: {
setFocusEvent() {
document.querySelectorAll('.v-autocomplete input').forEach(input => {
input.addEventListener('focus', this.onInputFocus)
})
},
onDateFocus($event) {
if ($event == undefined) {
this.preventInputFocus = true
@@ -98,7 +98,10 @@ export default {
this.starts_at_time = null
this.ends_at_time = null
this.$nextTick(() => this.v$.$reset())
this.$nextTick(() => {
this.setFocusEvent()
this.v$.$reset()
})
try {
if (blocker?.id) {
@@ -260,6 +260,7 @@ export default {
this.visible = true
this.mastertask = null
this.$nextTick(() => {
this.setFocusEvent()
this.v$.$reset()
})
@@ -0,0 +1,103 @@
<template>
<div class="timeblock w-100">
<div v-if="deletable && editable" class="x-button">
<button @click="$emit('removeTimeblock')" class="x-button">x</button>
</div>
<Datepicker :model-value="timeblock.date" @focus="$emit('onDateFocus')" @update:model-value="updateDate" 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" />
<div class="splitted-time-inputs">
<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" bg-color="white" label="Začiatok" />
<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" bg-color="white" label="Koniec" />
</div>
</div>
</template>
<script>
import useVuelidate from '@vuelidate/core'
import { requiredIf } from '@vuelidate/validators'
import Datepicker from '@vuepic/vue-datepicker'
export default {
components: {
Datepicker
},
props: {
timeblock: {
type: Object,
required: true
},
deletable: {
type: Boolean,
default: false
},
editable: {
type: Boolean,
default: false
}
},
data() {
return {
v$: useVuelidate(),
}
},
validations() {
return {
timeblock: {
starts_at_time: { required: requiredIf(this.timeblock.date) },
ends_at_time: { required: requiredIf(this.timeblock.date) }
}
}
},
methods: {
onFocus() {
console.log('focus')
},
updateDate(date) {
const timeblock = { ...this.timeblock }
if (date) timeblock.date = date
this.$emit('updateTimeblock', timeblock)
},
updateStartTime(event) {
const timeblock = { ...this.timeblock }
timeblock.starts_at_time = event.target.value
this.$emit('updateTimeblock', timeblock)
},
updateEndTime(event) {
const timeblock = { ...this.timeblock }
timeblock.ends_at_time = event.target.value
this.$emit('updateTimeblock', timeblock)
},
}
}
</script>
<style lang="sass" scoped>
.timeblock
position: relative
border-top: 1px solid #e0e0e0
padding: 20px 0 5px 0
.splitted-time-inputs
display: flex !important
flex-direction: row !important
gap: 15px
margin-bottom: -11px
.x-button
display: flex
justify-content: flex-end
align-items: center
position: relative
bottom: 5px
button
margin-right: 5px
.error input
border: 1px solid red !important
</style>e
+104 -16
View File
@@ -16,7 +16,7 @@
<div class="splitted-inputs">
<!-- TODO: Bialko validacie -->
<Datepicker v-model="subtask.deadline" :auto-apply="true" @focus="onDateFocus" :min-date="new Date()" class="modal-input left" format="dd.MM.yyyy" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Deadline" :class="{ error: v$.subtask.deadline.$errors?.length }" :validations="v$.subtask.deadline" />
<Datepicker v-model="subtask.deadline" @focus="onDateFocus" :auto-apply="true" :min-date="new Date()" class="modal-input left" format="dd.MM.yyyy" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Deadline" :class="{ error: v$.subtask.deadline.$errors?.length }" :validations="v$.subtask.deadline" />
<v-text-field class="modal-input right" variant="solo" v-model="subtask._deadline_time" label="Čas" append-inner-icon="mdi-clock-outline" type="time" @focus="onInputFocus" :class="{ error: v$.subtask._deadline_time.$errors.length }" :hint="v$.subtask._deadline_time.$errors ? errorUtils.parseErrors(v$.subtask._deadline_time.$errors) : null" />
</div>
@@ -62,11 +62,28 @@
<!-- <div class="w-100">
<Datepicker v-model="subtask.date" :class="{ error: v$.subtask.date.$errors.length }" format="dd.MM.yyyy" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Dátum" :auto-apply="true" :enable-time-picker="false" @focus="onDateFocus" class="mb-5 modal-input" />
<div class="splitted-time-inputs">
<v-text-field v-model="subtask.starts_at_time" :class="{ error: v$.subtask.starts_at_time.$errors.length }" type="time" variant="solo" bg-color="white" label="Začiatok" />
<v-text-field v-model="subtask.ends_at_time" :class="{ error: v$.subtask.ends_at_time.$errors.length }" type="time" variant="solo" bg-color="white" label="Koniec" />
<v-text-field :class="{ error: v$.subtask.starts_at_time.$errors.length }" type="time" variant="solo" bg-color="white" label="Začiatok" />
<v-text-field :class="{ error: v$.subtask.ends_at_time.$errors.length }" type="time" variant="solo" bg-color="white" label="Koniec" />
</div>
</div> -->
<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)" @onDateFocus="onDateFocus" :timeblock="timeblock" :deletable="index > 0" editable :ref="`timetable-${index}`" />
<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="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>
</div>
<div class="w-100 modal-input">
<QuillEditor ref="description" v-model="subtask.description" placeholder="Popis" theme="snow" class="rich-text-editor" @input="subtask.description = $event.srcElement.innerHTML" />
</div>
@@ -123,7 +140,7 @@ import Datepicker from '@vuepic/vue-datepicker'
import ZFilesUpload from '@/plugins/tm@_components/z-files-upload.vue'
import ATaskTimeblocks from '@/plugins/tm@modal/task/_components/_components/a-task-timeblocks.vue'
import useVuelidate from '@vuelidate/core'
import { required, requiredIf } from '@vuelidate/validators'
import { required, requiredIf, optional } from '@vuelidate/validators'
import errorUtils from '@/plugins/lib@auth/_utils/error.utils'
import { QuillEditor } from '@vueup/vue-quill'
import VuetifyFixFocusMixin from '@/plugins/tm@modal/_mixins/vuetify-fix-focus'
@@ -135,15 +152,19 @@ import '@vueup/vue-quill/dist/vue-quill.snow.css'
import AutocompleteMixin from '@/plugins/tm@_mixins/autocomplete.mixin'
import ZTaskReadonlyInfo from './_components/z-task-readonly-info.vue'
import ATimeblock from './_components/a-timeblock.vue'
import { mapGetters } from 'vuex'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
import axios from 'axios'
export default {
emits: ['close', 'refresh'],
mixins: [VuetifyFixFocusMixin, SelectsMixin, AutocompleteMixin, modalMixin],
components: {
ZTaskReadonlyInfo,
ATimeblock,
ZFilesUpload,
Datepicker,
// ATaskTimeblocks,
@@ -160,9 +181,13 @@ export default {
errorUtils,
v$: useVuelidate(),
employeeValidations: [],
preventInputFocus: false,
showDatePicker: false,
selectedNewDate: []
selectedNewDate: [],
timeblocks: [{
date: null,
starts_at_time: null,
ends_at_time: null
}]
}
},
@@ -176,9 +201,6 @@ export default {
master_task_id: { required },
deadline: { required },
_deadline_time: { required },
// starts_at_time: { requiredIf: requiredIf(this.subtask.date) },
// ends_at_time: { requiredIf: requiredIf(this.subtask.starts_at_time) }
// description: { required }
}
}
},
@@ -210,11 +232,28 @@ export default {
},
methods: {
updateTimeblock(val, index) {
this.timeblocks[index] = val
},
removeTimeblock(index) {
this.timeblocks.splice(index, 1)
},
async showModal({ subtask, editMode = false, mastertask = {} }) {
console.log(subtask)
this.isSaving = false
this.subtask = null
this.visible = true
this.$nextTick(() => this.v$.$reset())
this.timeblocks = [{
date: null,
starts_at_time: null,
ends_at_time: null
}]
this.$nextTick(() => {
this.v$.$reset()
this.setFocusEvent()
})
try {
if (subtask?.id) {
@@ -263,9 +302,10 @@ export default {
async save() {
const employeesValid = await this._validateEmployees()
const timeblocksValid = this.subtask?.id ? true : await this._validateTimeblocks()
if (!(await this.v$.$validate())) return
if (!employeesValid) return
if (!employeesValid || !timeblocksValid) return
this.subtask.description = this.$refs['description'].getHTML()
this._mergeDeadlineTimeDate()
@@ -286,7 +326,13 @@ export default {
this.$store.commit('tm/update_subtask', subtask)
this.$events.emit('on-subtask-edited', this.subtask)
} else {
const { subtasks } = await this.$axios.post_auth(`v1/mastertasks/${this.subtask.master_task_id}/subtasks`, this.subtask)
this.subtask.employees.forEach(employee => {
if (employee.id)
employee.timeblocks = this.timeblocks.filter(timeblock => timeblock.date).map(timeblock => { return { start: `${moment(timeblock.date).format('YYYY-MM-DD')} ${timeblock.starts_at_time}:00`, end: `${moment(timeblock.date).format('YYYY-MM-DD')} ${timeblock.ends_at_time}:00`, id: null } })
})
const subtaskCopy = JSON.parse(JSON.stringify(this.subtask))
delete subtaskCopy._master_task
const { subtasks } = await this.$axios.post_auth(`v1/mastertasks/${this.subtask.master_task_id}/subtasks`, subtaskCopy)
this.subtask.id = subtasks[0].id
subtasks.forEach((subtask) => {
@@ -364,6 +410,15 @@ export default {
})
},
async _validateTimeblocks() {
let invalid = false
for(let i = 0; i < this.timeblocks.length; i++) {
const ref = this.$refs[`timetable-${i}`]
invalid = await ref[0].v$.$validate() || invalid
}
return invalid
},
_enrichTask(subtask) {
return {
...subtask,
@@ -470,8 +525,41 @@ export default {
.files
margin-top: 104px !important
// .splitted-time-inputs
// display: flex !important
// flex-direction: row !important
// gap: 15px
.timeblocks
display: flex
flex-direction: column
align-items: center
border-bottom: 1px solid #e0e0e0
.end-button
width: 100%
display: flex
justify-content: flex-end
align-items: center
border-top: 1px solid #e0e0e0
height: 70px
button
background: #7f39fb !important
border-radius: 4px !important
color: #fff !important
height: 50px
width: 203px
.splitted-time-inputs
display: flex !important
flex-direction: row !important
gap: 15px
margin-bottom: -11px
.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
</style>