Refactored Schedule.vue contain more than one month. Started working on selecting cells.
This commit is contained in:
@@ -8,15 +8,15 @@ AddEmployeeModal(
|
|||||||
@emitResult="addEmployee($event)"
|
@emitResult="addEmployee($event)"
|
||||||
)
|
)
|
||||||
|
|
||||||
//- TODO: #3 Close Modal after successful input
|
|
||||||
<!-- Schedule Table -->
|
<!-- Schedule Table -->
|
||||||
table(class='table table-bordered table-sm' v-for="(row, rIndex) in scheduleData" :key="rIndex")
|
.pt-5(v-for="(month, mIndex) in scheduleData" :key="mIndex")
|
||||||
|
table(class='table table-bordered table-sm' v-for="(row, rIndex) in month" :key="rIndex")
|
||||||
thead
|
thead
|
||||||
tr
|
tr
|
||||||
td.fw-bold(style="width: 150px") {{ format(startDate, "MMMM", {locale: de}) }}
|
td.fw-bold(style="width: 150px") {{ format(startDates[mIndex], "MMMM", {locale: de}) }}
|
||||||
td(v-for="(day, index) in weekdays" :key="index" :class="{'text-body text-opacity-50 bg-secondary bg-opacity-10' : row.dates[index] === null}") {{ day }}
|
td(v-for="(day, index) in weekdays" :key="index" :class="{'text-body text-opacity-50 bg-secondary bg-opacity-10' : row.dates[index] === null}") {{ day }}
|
||||||
tr
|
tr
|
||||||
td.fw-bold {{ format(startDate, "y") }}
|
td.fw-bold {{ format(startDates[mIndex], "y") }}
|
||||||
td(v-for="(date, dIndex) in row.dates" :key="dIndex" :class="{'bg-secondary bg-opacity-10' : row.dates[dIndex] === null}")
|
td(v-for="(date, dIndex) in row.dates" :key="dIndex" :class="{'bg-secondary bg-opacity-10' : row.dates[dIndex] === null}")
|
||||||
template(v-if="date !== null") {{ format(date, "dd.MM.")}}
|
template(v-if="date !== null") {{ format(date, "dd.MM.")}}
|
||||||
tbody
|
tbody
|
||||||
@@ -26,15 +26,20 @@ table(class='table table-bordered table-sm' v-for="(row, rIndex) in scheduleData
|
|||||||
.col.text-start.ps-3 {{employee.handle}}
|
.col.text-start.ps-3 {{employee.handle}}
|
||||||
.col.text-end
|
.col.text-end
|
||||||
button.btn(
|
button.btn(
|
||||||
@click="removeEmployee(rIndex, employee)"
|
@click="removeEmployee(mIndex, rIndex, employee)"
|
||||||
)
|
)
|
||||||
i.bi-x-lg
|
i.bi-x-lg
|
||||||
td(v-for="(date, dIndex) in row.dates" :key="dIndex" :class="{'bg-secondary bg-opacity-10' : row.dates[dIndex] === null}")
|
td(
|
||||||
|
v-for="(date, dIndex) in row.dates"
|
||||||
|
:key="dIndex"
|
||||||
|
:class="{'bg-secondary bg-opacity-10' : row.dates[dIndex] === null, 'selected' : isSelected({mIndex, rIndex, eIndex, dIndex})}"
|
||||||
|
@click="select({mIndex, rIndex, eIndex, dIndex}, $event)"
|
||||||
|
)
|
||||||
tr()
|
tr()
|
||||||
td.text-end
|
td.text-end
|
||||||
button(
|
button(
|
||||||
class="btn"
|
class="btn"
|
||||||
@click="addEmployeeRow = rIndex"
|
@click="addEmployeeRow = rIndex; addEmployeeMonth = mIndex"
|
||||||
data-bs-toggle="modal"
|
data-bs-toggle="modal"
|
||||||
:data-bs-target="'#'+modalId"
|
:data-bs-target="'#'+modalId"
|
||||||
)
|
)
|
||||||
@@ -47,46 +52,103 @@ table(class='table table-bordered table-sm' v-for="(row, rIndex) in scheduleData
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { toRef, watch, computed, ref, h, render } from 'vue'
|
import { toRef, watch, computed, ref, h, render } from 'vue'
|
||||||
import type { Ref } from 'vue'
|
import type { Ref, ComputedRef } from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useEmployees } from '/src/stores/employees.js'
|
import { useEmployees } from '/src/stores/employees.js'
|
||||||
import { addMonths, subDays, addDays, format, getISODay, isValid, eachDayOfInterval } from 'date-fns'
|
import { addMonths, eachMonthOfInterval, subDays, addDays, format, getISODay, getYear, getMonth, isValid, eachDayOfInterval, getDaysInMonth } from 'date-fns'
|
||||||
import { de } from 'date-fns/locale'
|
import { de } from 'date-fns/locale'
|
||||||
import AddEmployeeModal from './AddEmployeeModal.vue'
|
import AddEmployeeModal from './AddEmployeeModal.vue'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Props / Refs
|
* Props
|
||||||
*/
|
*/
|
||||||
const props = defineProps<{
|
const props = defineProps({
|
||||||
startDate: Date,
|
startDate : {
|
||||||
initialOffset: number
|
type: Date,
|
||||||
}>()
|
required: true,
|
||||||
|
},
|
||||||
const endDate = computed(():Date => subDays(addMonths(props.startDate, 1), 1))
|
numberOfMonths : {
|
||||||
const offset = computed(() => getISODay(props.startDate) - 1 + props.initialOffset)
|
type: Number,
|
||||||
|
default: 3,
|
||||||
const addEmployeeRow = ref()
|
required: false,
|
||||||
const startDate = toRef(props, 'startDate')
|
validator(value) {
|
||||||
|
return value > 0
|
||||||
const scheduleData : Ref<ScheduleData> = ref(getScheduleData())
|
}
|
||||||
|
},
|
||||||
/*
|
})
|
||||||
|
/**
|
||||||
|
* End Props
|
||||||
|
*
|
||||||
* Local variables
|
* Local variables
|
||||||
*/
|
*/
|
||||||
const modalId : string = "addEmployeeModal"
|
const modalId : string = "addEmployeeModal"
|
||||||
const weekdays : string[] = getDoubleWeekdays()
|
const weekdays : string[] = getDoubleWeekdays()
|
||||||
const store = useEmployees()
|
const store = useEmployees()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End Local Variables
|
||||||
|
*
|
||||||
|
* Computed
|
||||||
|
*/
|
||||||
|
const startDates : ComputedRef<Date[]> = computed(() => {
|
||||||
|
let numberOfMonths : number;
|
||||||
|
|
||||||
|
if(typeof(props.numberOfMonths) === "string") {
|
||||||
|
numberOfMonths = parseInt(props.numberOfMonths)
|
||||||
|
}
|
||||||
|
else numberOfMonths = props.numberOfMonths
|
||||||
|
|
||||||
|
return eachMonthOfInterval({
|
||||||
|
start: new Date(getYear(props.startDate), getMonth(props.startDate)),
|
||||||
|
end: new Date(getYear(props.startDate), getMonth(props.startDate) + numberOfMonths - 1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const offsets : ComputedRef<number[]> = computed(() => {
|
||||||
|
let arr : number[] = []
|
||||||
|
let offset : number;
|
||||||
|
arr.push(getISODay(startDates.value[0]) - 1)
|
||||||
|
|
||||||
|
for ( let i = 1; i < startDates.value.length; i++ ){
|
||||||
|
offset = getDaysInMonth(startDates.value[i-1]) + arr[arr.length - 1]
|
||||||
|
|
||||||
|
if( offset >= 35 && offset <= 42) {
|
||||||
|
arr.push(getISODay(startDates.value[i])-1+7)
|
||||||
|
}
|
||||||
|
else arr.push(getISODay(startDates.value[i])-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End Computed
|
||||||
|
*
|
||||||
|
* Refs
|
||||||
|
*/
|
||||||
|
const addEmployeeRow : Ref<number> = ref(-1)
|
||||||
|
const addEmployeeMonth : Ref<number> = ref(-1)
|
||||||
|
const scheduleData : Ref<ScheduleData> = ref(getScheduleData())
|
||||||
const { employees } = storeToRefs(store)
|
const { employees } = storeToRefs(store)
|
||||||
|
|
||||||
|
const selected : Ref<Coordinates[]> = ref([])
|
||||||
|
/**
|
||||||
|
* End Refs
|
||||||
|
*
|
||||||
|
* Functions
|
||||||
|
*/
|
||||||
function getScheduleData() : ScheduleData {
|
function getScheduleData() : ScheduleData {
|
||||||
let arr : ScheduleData = []
|
let arr : ScheduleData = []
|
||||||
|
let month : ScheduleMonth = []
|
||||||
let row : ScheduleRow = {dates: [], employees: []}
|
let row : ScheduleRow = {dates: [], employees: []}
|
||||||
|
let end : Date;
|
||||||
|
|
||||||
let start = startDate.value
|
|
||||||
let end = endDate.value
|
|
||||||
let i
|
let i
|
||||||
|
|
||||||
for (i = 0; i < offset.value ; i++) {
|
startDates.value.forEach((start, mIndex) => {
|
||||||
|
end = subDays(addMonths(start, 1), 1)
|
||||||
|
|
||||||
|
for (i = 0; i < offsets.value[mIndex] ; i++) {
|
||||||
row.dates.push(null)
|
row.dates.push(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,11 +162,14 @@ table(class='table table-bordered table-sm' v-for="(row, rIndex) in scheduleData
|
|||||||
row.dates.push(null)
|
row.dates.push(null)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
arr.push(row)
|
month.push(row)
|
||||||
row = {dates: [], employees: []}
|
row = {dates: [], employees: []}
|
||||||
i = 0
|
i = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arr.push(month)
|
||||||
|
month = []
|
||||||
|
})
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,20 +178,44 @@ table(class='table table-bordered table-sm' v-for="(row, rIndex) in scheduleData
|
|||||||
return arr.concat(arr)
|
return arr.concat(arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeEmployee(rIndex: number, emp : Employee) : void {
|
|
||||||
let i = scheduleData.value[rIndex].employees.indexOf(emp)
|
|
||||||
if(i > -1){
|
|
||||||
scheduleData.value[rIndex].employees.splice(i, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addEmployee(param : Employee){
|
function addEmployee(param : Employee){
|
||||||
if (addEmployeeRow.value !== undefined && param !== null) {
|
if (addEmployeeMonth.value > -1 && addEmployeeMonth.value > -1) {
|
||||||
scheduleData.value[addEmployeeRow.value].employees.push(param)
|
scheduleData.value[addEmployeeMonth.value][addEmployeeRow.value].employees.push(param)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(startDate, () => {
|
function isSelected(c : Coordinates) : boolean {
|
||||||
|
return selected.value.some(el => {
|
||||||
|
return el.mIndex === c.mIndex && el.rIndex === c.rIndex && el.eIndex === c.rIndex && el.dIndex === c.dIndex
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event Listeners
|
||||||
|
*/
|
||||||
|
function removeEmployee(mIndex : number, rIndex: number, emp : Employee) : void {
|
||||||
|
let i = scheduleData.value[mIndex][rIndex].employees.indexOf(emp)
|
||||||
|
if(i > -1){
|
||||||
|
scheduleData.value[mIndex][rIndex].employees.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function select(coord : Coordinates, e : MouseEvent) {
|
||||||
|
|
||||||
|
if(e.ctrlKey){
|
||||||
|
selected.value.push(coord)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selected.value = []
|
||||||
|
selected.value.push(coord)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watchers
|
||||||
|
*/
|
||||||
|
watch(startDates, () => {
|
||||||
scheduleData.value = getScheduleData()
|
scheduleData.value = getScheduleData()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -151,4 +240,8 @@ table(class='table table-bordered table-sm' v-for="(row, rIndex) in scheduleData
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
border: 2px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
13
src/types/schedule-data.d.ts
vendored
13
src/types/schedule-data.d.ts
vendored
@@ -1,5 +1,5 @@
|
|||||||
type ScheduleData = [
|
type ScheduleData = [
|
||||||
...ScheduleRow[]
|
...ScheduleMonth[]
|
||||||
]
|
]
|
||||||
|
|
||||||
type Employee = {
|
type Employee = {
|
||||||
@@ -13,3 +13,14 @@ type ScheduleRow = {
|
|||||||
dates : (Date | null)[],
|
dates : (Date | null)[],
|
||||||
employees : Employee[]
|
employees : Employee[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ScheduleMonth = [
|
||||||
|
...ScheduleRow[]
|
||||||
|
]
|
||||||
|
|
||||||
|
type Coordinates = {
|
||||||
|
mIndex : number,
|
||||||
|
rIndex : number,
|
||||||
|
eIndex : number,
|
||||||
|
dIndex : number
|
||||||
|
}
|
||||||
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
MonthPicker(:selectedMonth="selectedMonth" :selectedYear="selectedYear" @getMonth="selectedMonth = $event" @getYear="selectedYear = $event")
|
MonthPicker(:selectedMonth="selectedMonth" :selectedYear="selectedYear" @getMonth="selectedMonth = $event" @getYear="selectedYear = $event")
|
||||||
|
|
||||||
div(class="mt-5" v-for="(month, index) in months" :key="index")
|
Schedule( :startDate="new Date(selectedYear, selectedMonth)")
|
||||||
Schedule( :startDate="months[index]" :initialOffset="iOffsets[index]")
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -15,24 +14,4 @@ div(class="mt-5" v-for="(month, index) in months" :key="index")
|
|||||||
|
|
||||||
const selectedMonth = ref(getMonth(new Date()))
|
const selectedMonth = ref(getMonth(new Date()))
|
||||||
const selectedYear = ref(getYear(new Date()))
|
const selectedYear = ref(getYear(new Date()))
|
||||||
|
|
||||||
const months = computed(() => {
|
|
||||||
return eachMonthOfInterval({
|
|
||||||
start: new Date(selectedYear.value, selectedMonth.value),
|
|
||||||
end : new Date(selectedYear.value, selectedMonth.value + 2)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const iOffsets = computed(() => {
|
|
||||||
let arr : number[] = []
|
|
||||||
arr.push(0)
|
|
||||||
|
|
||||||
months.value.forEach(month => {
|
|
||||||
if ( getDaysInMonth(month) + getISODay(month) - 1 + arr[arr.length - 1] > 34) {
|
|
||||||
arr.push(7)
|
|
||||||
}
|
|
||||||
else arr.push(0)
|
|
||||||
})
|
|
||||||
return arr
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user