mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 14:29:34 +00:00
343 lines
8.9 KiB
Vue
343 lines
8.9 KiB
Vue
<template>
|
|
<div class="calendar-wrapper">
|
|
<Vue-cal
|
|
:hide-view-selector="true"
|
|
:hide-title-bar="true"
|
|
:disable-views="['years', 'year', 'month', 'day']"
|
|
:time-from="calConfig.startHour * 60"
|
|
:time-to="calConfig.endHour * 60"
|
|
:selected-date="calConfig.date"
|
|
:onEventClick="taskClicked"
|
|
:editable-events="vueCalConfig.editing"
|
|
:events="calData.tasks"
|
|
:unscheduledTime="calData.unscheduled_times"
|
|
:overlaps-per-time-step="false"
|
|
:showTimeInCells="false"
|
|
:time-cell-height="70"
|
|
:min-cell-width="300"
|
|
@ready="onReady()"
|
|
@view-change="weekChanged"
|
|
@event-drop="eventMoved"
|
|
@event-focus="eventFocused"
|
|
>
|
|
<template v-slot:weekday-heading="{ heading }">
|
|
<div class="w-100 h-100 d-flex flex-column">
|
|
<span class="d-flex align-center">
|
|
<img v-if="getHeadingDate(heading.date) == 'Dnes'" :src="require('./_img/home-icon.svg')" class="mr-2">
|
|
<p>{{ getHeadingDate(heading.date) }}</p>
|
|
</span>
|
|
|
|
<div v-if="heading.unscheduledTime && heading.initials" class="unscheduled-time d-flex align-center text-left">
|
|
<div class="unscheduled-time-initials d-flex align-center justify-center me-4">
|
|
<p>{{heading.initials}}</p>
|
|
</div>
|
|
<div>
|
|
<p class="mb-0 mt-0 unscheduled-time-name">{{heading.name}}</p>
|
|
<h1 class="mb-0 mt-0">{{heading.unscheduledTime}} h</h1>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template v-slot:time-cell="{ hours, minutes }">
|
|
<span class="d-flex align-center justify-center">
|
|
<p>{{hours}}:{{String(minutes).padStart(2, '0')}}</p>
|
|
<div class="time-column-line"></div>
|
|
</span>
|
|
</template>
|
|
|
|
<template v-slot:event="{ event }">
|
|
<div class="event-content-wrapper w-100 h-100 d-flex flex-column justify-space-between">
|
|
<div>
|
|
<small v-if="(event.project_code && (event.end.getTime() - event.start.getTime() >= 7200000) && !event.is_blocker)" class="project-code">{{ event.project_code }}</small>
|
|
<h3>{{ event.title }}</h3>
|
|
<div v-if="(event.end.getTime() - event.start.getTime() >= 7200000) || focusedEventId == event.task_id" class="d-flex align-center event-details">
|
|
<div class="event-initials d-flex justify-center align-center">
|
|
<small>{{ getUserInitials(event) }}</small>
|
|
</div>
|
|
<small>{{ event.start.toLocaleDateString('sk-SK') }}</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="event-footer d-flex" v-if="(event.end.getTime() - event.start.getTime() >= 3600000) || focusedEventId == event.task_id">
|
|
<v-btn rounded class="event-footer-button me-2" @click="this.showCompleteModal = {task: event}"><img :src="require('./_img/checkmark.svg')" alt=""></v-btn>
|
|
<v-btn rounded class="event-footer-button me-2" @click="editTask(event.id)" :style="{opacity: 0.3}"><img :src="require('./_img/pencil.svg')" alt=""></v-btn>
|
|
<v-btn rounded class="event-footer-button me-2" @click="this.showDeleteModal = {task: event}"><img :src="require('./_img/bin.svg')" alt=""></v-btn>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Vue-cal>
|
|
|
|
<Z-complete-task-modal v-if="showCompleteModal" :visible="showCompleteModal ? true : false" :task="showCompleteModal.task" @close="showCompleteModal = null" />
|
|
<Z-delete-task-modal v-if="showDeleteModal" :visible="showDeleteModal ? true : false" :task="showDeleteModal.task" @close="showDeleteModal = null" />
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import ZCompleteTaskModal from '@/plugins/tm@modal/task/z-complete-task-modal.vue'
|
|
import ZDeleteTaskModal from '@/plugins/tm@modal/task/z-delete-task-modal.vue'
|
|
|
|
export default {
|
|
components: {
|
|
ZCompleteTaskModal,
|
|
ZDeleteTaskModal
|
|
},
|
|
|
|
props: {
|
|
calData: {
|
|
type: Object,
|
|
required: true,
|
|
default() {
|
|
return {}
|
|
}
|
|
},
|
|
calConfig: {
|
|
type: Object,
|
|
required: true,
|
|
default() {
|
|
return {startHour: 8, endHour: 16, date: new Date()}
|
|
}
|
|
}
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
vueCalConfig: {
|
|
editing: {
|
|
title: false,
|
|
drag: true,
|
|
resize: false,
|
|
delete: false,
|
|
create: false
|
|
}
|
|
},
|
|
focusedEventId: null,
|
|
showCompleteModal: null,
|
|
showDeleteModal: null
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
weekChanged() {
|
|
const scrollContainer = document.getElementsByClassName('vuecal__scrollable-body')[0]
|
|
scrollContainer.scrollLeft = 0
|
|
|
|
this.$nextTick(() => {
|
|
this.scrollToYesterday()
|
|
})
|
|
},
|
|
|
|
async eventMoved(e) {
|
|
this.focusedEventId = e.event.id
|
|
this.$emit('eventMoved', e)
|
|
},
|
|
|
|
onReady() {
|
|
this.scrollToYesterday()
|
|
this.correctTimecolumnMargin()
|
|
},
|
|
|
|
scrollToYesterday() {
|
|
if (!document.getElementsByClassName('yesterday-cell').length || !document.getElementsByClassName('today-cell').length) return
|
|
|
|
const scrollContainer = document.getElementsByClassName('vuecal__scrollable-body')[0]
|
|
const yesterdayCell = document.getElementsByClassName('yesterday-cell')[0]
|
|
scrollContainer.scrollLeft = yesterdayCell.offsetLeft - scrollContainer.offsetLeft - 20
|
|
},
|
|
|
|
correctTimecolumnMargin() {
|
|
const heightOfDayHeader = document.getElementsByClassName('vuecal__heading')[0].clientHeight
|
|
document.getElementsByClassName('vuecal__time-column')[0].style.marginTop = `${heightOfDayHeader}px`
|
|
},
|
|
|
|
getHeadingDate(value) {
|
|
const date = new Date(value)
|
|
|
|
const today = new Date()
|
|
const yesterday = new Date((new Date()).setDate(today.getDate() - 1))
|
|
const tomorrow = new Date((new Date()).setDate(today.getDate() + 1))
|
|
|
|
if (today.toLocaleDateString('sk-SK') === date.toLocaleDateString('sk-SK')) return "Dnes"
|
|
if (yesterday.toLocaleDateString('sk-SK') === date.toLocaleDateString('sk-SK')) return "Včera"
|
|
if (tomorrow.toLocaleDateString('sk-SK') === date.toLocaleDateString('sk-SK')) return "Zajtra"
|
|
|
|
return date.toLocaleDateString('sk-SK')
|
|
},
|
|
|
|
getUserInitials(event) {
|
|
return event.name.charAt(0).toUpperCase() + event.surname.charAt(0).toUpperCase()
|
|
},
|
|
|
|
taskClicked(task) {
|
|
if (task.end.getTime() - task.start.getTime() <= 3600000) {
|
|
console.log("task", task)
|
|
}
|
|
},
|
|
|
|
editTask(id) {
|
|
console.log('edit', id)
|
|
},
|
|
|
|
eventFocused(event) {
|
|
this.focusedEventId = event.task_id
|
|
console.log(`Focused: ${event.task_id}`)
|
|
},
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="sass" scoped>
|
|
.vuecal
|
|
box-shadow: none !important
|
|
|
|
.calendar-wrapper
|
|
width: 100%
|
|
padding-top: 50px
|
|
|
|
&:deep()
|
|
.vuecal__cells
|
|
-ms-overflow-style: none
|
|
scrollbar-width: none
|
|
&::-webkit-scrollbar
|
|
display: none
|
|
|
|
.vuecal__body
|
|
-ms-overflow-style: none
|
|
scrollbar-width: none
|
|
&::-webkit-scrollbar
|
|
display: none
|
|
|
|
.vuecal__now-line
|
|
display: none !important
|
|
|
|
.weekday-label
|
|
justify-content: start !important
|
|
font-size: 24px
|
|
font-weight: 700
|
|
|
|
.vuecal__weekdays-headings,
|
|
.vuecal__cell:before
|
|
border: none
|
|
|
|
.vuecal__heading
|
|
height: fit-content
|
|
min-height: 100%
|
|
padding-right: 20px
|
|
|
|
.unscheduled-time
|
|
background: rgba(0, 0, 0, 0.04)
|
|
border-radius: 24px
|
|
padding: 10px 15px
|
|
margin-top: 10px
|
|
|
|
.unscheduled-time-name
|
|
font-weight: 400
|
|
font-size: 15px
|
|
|
|
.unscheduled-time-initials
|
|
width: 50px
|
|
height: 50px
|
|
background: #6200EE
|
|
border-radius: 50%
|
|
|
|
p
|
|
font-weight: 400
|
|
font-size: 20px
|
|
color: white
|
|
|
|
|
|
.vuecal__cells.week-view
|
|
border-left: 1px solid rgba(0, 0, 0, .1)
|
|
padding-left: 20px
|
|
|
|
.vuecal__time-column
|
|
width: 150px
|
|
box-shadow: none !important
|
|
|
|
.time-column-line
|
|
width: 40px
|
|
height: 0
|
|
border: 1px solid rgba(33, 33, 33, 0.08)
|
|
margin-left: 10px
|
|
|
|
@media (max-width: 450px)
|
|
.vuecal__time-column
|
|
width: 70px
|
|
|
|
.time-column-line
|
|
width: 10px
|
|
|
|
.vuecal__flex
|
|
flex-wrap: nowrap !important
|
|
|
|
.vuecal__cell
|
|
padding: 10px 20px 10px 0px
|
|
|
|
.vuecal:not(.vuecal--day-view) .vuecal__cell--selected:not(.vuecal__cell--today) ,
|
|
.vuecal__cell--current:not(.vuecal__cell--today),
|
|
.vuecal__cell--today
|
|
background-color: white
|
|
|
|
.vuecal__event
|
|
border-radius: 16px
|
|
padding: 20px 10px
|
|
text-align: left
|
|
background: rgba(248, 248, 248, 1)
|
|
|
|
.project-code
|
|
margin: 0 0 20px
|
|
display: block
|
|
|
|
h3
|
|
font-weight: 400
|
|
color: Black
|
|
margin: 0 0 10px
|
|
|
|
small
|
|
color: black
|
|
|
|
.event-initials
|
|
height: 30px
|
|
width: 30px
|
|
border: 1px solid black
|
|
border-radius: 50%
|
|
padding: 5px
|
|
margin-right: 7px
|
|
|
|
small
|
|
font-size: 11px
|
|
|
|
.event-footer
|
|
padding-top: 15px
|
|
border-top: 1px solid rgba(33, 33, 33, 0.08)
|
|
|
|
.event-footer-button
|
|
box-shadow: none !important
|
|
padding: 9px !important
|
|
min-height: fit-content
|
|
height: fit-content
|
|
min-width: fit-content
|
|
width: fit-content
|
|
|
|
img
|
|
width: 18px
|
|
|
|
// &:hover,
|
|
&:focus
|
|
z-index: 100 !important
|
|
min-height: 200px !important
|
|
|
|
&.event-blocker
|
|
background: #B00020 !important
|
|
|
|
h3,
|
|
.event-details *
|
|
color: white !important
|
|
|
|
.event-details .event-initials
|
|
border: 1px solid white
|
|
|
|
.event-footer
|
|
border-top: 1px solid rgba(255, 255, 255, 0.19)
|
|
</style>
|