Refactored Schedule.vue contain more than one month. Started working on selecting cells.

This commit is contained in:
Sockenklaus
2021-10-11 00:00:44 +02:00
parent 0e64a815ea
commit 9d8b3c27a2
3 changed files with 184 additions and 101 deletions

View File

@@ -8,38 +8,43 @@ AddEmployeeModal(
@emitResult="addEmployee($event)"
)
//- TODO: #3 Close Modal after successful input
<!-- Schedule Table -->
table(class='table table-bordered table-sm' v-for="(row, rIndex) in scheduleData" :key="rIndex")
thead
tr
td.fw-bold(style="width: 150px") {{ format(startDate, "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 }}
tr
td.fw-bold {{ format(startDate, "y") }}
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.")}}
tbody
tr(v-for="(employee, eIndex) in row.employees" :key="eIndex")
td
.row.justify-content-between.align-items-center.employee-wrapper
.col.text-start.ps-3 {{employee.handle}}
.col.text-end
button.btn(
@click="removeEmployee(rIndex, employee)"
.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
tr
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 }}
tr
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}")
template(v-if="date !== null") {{ format(date, "dd.MM.")}}
tbody
tr(v-for="(employee, eIndex) in row.employees" :key="eIndex")
td
.row.justify-content-between.align-items-center.employee-wrapper
.col.text-start.ps-3 {{employee.handle}}
.col.text-end
button.btn(
@click="removeEmployee(mIndex, rIndex, employee)"
)
i.bi-x-lg
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)"
) &nbsp;
tr()
td.text-end
button(
class="btn"
@click="addEmployeeRow = rIndex; addEmployeeMonth = mIndex"
data-bs-toggle="modal"
:data-bs-target="'#'+modalId"
)
i.bi-x-lg
td(v-for="(date, dIndex) in row.dates" :key="dIndex" :class="{'bg-secondary bg-opacity-10' : row.dates[dIndex] === null}") &nbsp;
tr()
td.text-end
button(
class="btn"
@click="addEmployeeRow = rIndex"
data-bs-toggle="modal"
:data-bs-target="'#'+modalId"
)
i.bi.bi-plus-lg
td(v-for="(date, dIndex) in row.dates" :key="dIndex" :class="{'bg-secondary bg-opacity-10' : row.dates[dIndex] === null}") &nbsp;
i.bi.bi-plus-lg
td(v-for="(date, dIndex) in row.dates" :key="dIndex" :class="{'bg-secondary bg-opacity-10' : row.dates[dIndex] === null}") &nbsp;
</template>
@@ -47,64 +52,124 @@ table(class='table table-bordered table-sm' v-for="(row, rIndex) in scheduleData
<script setup lang="ts">
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 { 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 AddEmployeeModal from './AddEmployeeModal.vue'
/*
* Props / Refs
*/
const props = defineProps<{
startDate: Date,
initialOffset: number
}>()
const endDate = computed(():Date => subDays(addMonths(props.startDate, 1), 1))
const offset = computed(() => getISODay(props.startDate) - 1 + props.initialOffset)
const addEmployeeRow = ref()
const startDate = toRef(props, 'startDate')
const scheduleData : Ref<ScheduleData> = ref(getScheduleData())
/*
* Local variables
* Props
*/
const props = defineProps({
startDate : {
type: Date,
required: true,
},
numberOfMonths : {
type: Number,
default: 3,
required: false,
validator(value) {
return value > 0
}
},
})
/**
* End Props
*
* Local variables
*/
const modalId : string = "addEmployeeModal"
const weekdays : string[] = getDoubleWeekdays()
const store = useEmployees()
const { employees } = storeToRefs(store)
/**
* 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 selected : Ref<Coordinates[]> = ref([])
/**
* End Refs
*
* Functions
*/
function getScheduleData() : ScheduleData {
let arr : ScheduleData = []
let month : ScheduleMonth = []
let row : ScheduleRow = {dates: [], employees: []}
let end : Date;
let start = startDate.value
let end = endDate.value
let i
for (i = 0; i < offset.value ; i++) {
row.dates.push(null)
}
while (start <= end){
while (i < 14 && start <= end){
row.dates.push(start)
start = addDays(start, 1)
i++
}
while (i < 14) {
startDates.value.forEach((start, mIndex) => {
end = subDays(addMonths(start, 1), 1)
for (i = 0; i < offsets.value[mIndex] ; i++) {
row.dates.push(null)
i++
}
arr.push(row)
row = {dates: [], employees: []}
i = 0
}
while (start <= end){
while (i < 14 && start <= end){
row.dates.push(start)
start = addDays(start, 1)
i++
}
while (i < 14) {
row.dates.push(null)
i++
}
month.push(row)
row = {dates: [], employees: []}
i = 0
}
arr.push(month)
month = []
})
return arr
}
@@ -113,20 +178,44 @@ table(class='table table-bordered table-sm' v-for="(row, rIndex) in scheduleData
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){
if (addEmployeeRow.value !== undefined && param !== null) {
scheduleData.value[addEmployeeRow.value].employees.push(param)
if (addEmployeeMonth.value > -1 && addEmployeeMonth.value > -1) {
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()
})
@@ -151,4 +240,8 @@ table(class='table table-bordered table-sm' v-for="(row, rIndex) in scheduleData
opacity: 1;
}
.selected {
border: 2px solid black;
}
</style>

View File

@@ -1,5 +1,5 @@
type ScheduleData = [
...ScheduleRow[]
...ScheduleMonth[]
]
type Employee = {
@@ -12,4 +12,15 @@ type Employee = {
type ScheduleRow = {
dates : (Date | null)[],
employees : Employee[]
}
type ScheduleMonth = [
...ScheduleRow[]
]
type Coordinates = {
mIndex : number,
rIndex : number,
eIndex : number,
dIndex : number
}

View File

@@ -2,8 +2,7 @@
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="months[index]" :initialOffset="iOffsets[index]")
Schedule( :startDate="new Date(selectedYear, selectedMonth)")
</template>
@@ -15,24 +14,4 @@ div(class="mt-5" v-for="(month, index) in months" :key="index")
const selectedMonth = ref(getMonth(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>