// get Roster Data ROSTER getActiveRosterData = async (year_week) => { if (year_week === DATE_YEAR_WEEK) { return ROSTER } else if (year_week === DATE_YEAR_WEEK_TABLE_FROM) { return ROSTER_TABLE_FROM } else if (year_week === DATE_YEAR_WEEK_TABLE_TO) { return ROSTER_TABLE_TO } else { return getDataRosterToRoster(year_week) } } getDataRosterToRoster = async (year_week) => { let roster = ROSTERS.find(ro => ro.year_week === year_week)?.roster pushR = (r) => { ROSTERS.push({year_week: year_week, roster: [...r]}) } if (typeof roster !== "undefined") { return roster } else if (ROSTERS_YEARWEEK.indexOf(year_week) === -1) { return createDataA(year_week).then(() => { return dbGet_roster_active(year_week).then(r => {pushR(r); return r}) }) } else { return dbGet_roster_active(year_week).then(r => {pushR(r); return r}) } } getRosterBefore = async (d) => { let yws = ROSTERS_YEARWEEK let r_id = yws.indexOf(DATE_YEAR_WEEK)+d if (r_id && r_id < yws.length) {return await getDataRosterToRoster(yws[r_id]) } } // create new Roster createDataA = async (year_week) => { if (!year_week) {year_week = DATE_YEAR_WEEK} createR = (changes) => { return dbSet_roster(year_week, TIME_STEP, [DAYBREAK_1, DAYBREAK_2]).then(() => { if (year_week < DATE_YEAR_WEEK_OLDEST) { changes.forEach(c => dbSet_roster_change_where_yearweek_and_day(year_week, c.day_id, c.start, c.end, c.amount)) } return dbGet_rosters_yearweek().then((yws) => { ROSTERS_YEARWEEK = yws if (year_week === DATE_YEAR_WEEK) { DATE_YEAR_WEEK_NEWEST = ROSTERS_YEARWEEK[0] DATE_YEAR_WEEK_OLDEST = ROSTERS_YEARWEEK[ROSTERS_YEARWEEK.length-1] } return yws }) }) } if (year_week < DATE_YEAR_WEEK_OLDEST) { return dbGet_roster_changes_where_yearweek(DATE_YEAR_WEEK_OLDEST).then((changes) => { return createR(changes) }) } else { return createR() } } // get Active Roster getActiveRoster = async (reload) => { showLoading("getActiveRoster") EDITABLE_ROWS_TOP = await dbGet_roster_editable_rows_top(DATE_YEAR_WEEK) EDITABLE_ROWS_BOTTOM = await dbGet_roster_editable_rows_bottom(DATE_YEAR_WEEK) EDITABLE_CELLS_RIGHT = await dbGet_roster_editable_cells_right(DATE_YEAR_WEEK) ROSTER_PERSON_INFOS = await dbGet_roster_info_where_yearweek(DATE_YEAR_WEEK) let yws = await dbGet_rosters_yearweek() let roster_data if (yws.indexOf(DATE_YEAR_WEEK) > -1) { roster_data = await dbGet_roster_where_yearweek(DATE_YEAR_WEEK) } else { roster_data = await dbGet_roster_where_yearweek(yws[0]) } DAYBREAK_1 = roster_data.break_60 DAYBREAK_2 = roster_data.break_90 TIME_STEP = roster_data.time_step callback_1 = () => { return getSettings().then(() => { if ((EDITABLE_ROW) || (EDITABLE_ROWS_TOP.length > 0)) { setEditableRowTrue() } else {document.querySelector("#Roster-week-add-editable-row button.row-top").classList.remove("active")} if ((EDITABLE_ROW_BOTTOM) ||(EDITABLE_ROWS_BOTTOM.length > 0)) { setEditableRowBottomTrue() } else {document.querySelector("#Roster-week-add-editable-row button.row-bottom").classList.remove("active")} if ((EDITABLE_CELLS_RIGHT.length > 0) || EDITABLE_CELL) { EDITABLE_CELL = true; document.querySelector("#Roster-week-add-editable-cell button").classList.add("active") } else if (DISPLAY_EDITABLE_CELL.v) { setEditableCellTrue() } else {document.querySelector("#Roster-week-add-editable-cell button").classList.remove("active")} renderPerson() let person_list_buttons = document.querySelectorAll("#Person-list-buttons button") for (let i=0; i 0) person_list_buttons[0].classList.add("active") loadRosterTableWeek() return loadRosterTable().then(() => { hideLoading("getActiveRoster") setZoomLevel(SETTINGS.zoom_web) return }) }) } callback_0 = () => { if (ROSTERS_YEARWEEK.indexOf(DATE_YEAR_WEEK) === -1) { return createDataA().then(() => {return callback_1()}) } else { return callback_1() } } return callback_0() } getActiveRosterWeek = async (reload) => { showLoading("getActiveRoster") EDITABLE_ROWS_TOP = await dbGet_roster_editable_rows_top(DATE_YEAR_WEEK) EDITABLE_ROWS_BOTTOM = await dbGet_roster_editable_rows_bottom(DATE_YEAR_WEEK) EDITABLE_CELLS_RIGHT = await dbGet_roster_editable_cells_right(DATE_YEAR_WEEK) ROSTER_PERSON_INFOS = await dbGet_roster_info_where_yearweek(DATE_YEAR_WEEK) let yws = await dbGet_rosters_yearweek() let roster_data if (yws.indexOf(DATE_YEAR_WEEK) > -1) { roster_data = await dbGet_roster_where_yearweek(DATE_YEAR_WEEK) } else { roster_data = await dbGet_roster_where_yearweek(yws[0]) } DAYBREAK_1 = roster_data.break_60 DAYBREAK_2 = roster_data.break_90 TIME_STEP = roster_data.time_step NOWEEKEDIT = true callback_1 = () => { return getSettings().then(() => { if ((DISPLAY_EDITABLE_ROW.v) || (EDITABLE_ROWS_TOP.length > 0)) { EDITABLE_ROW = true } else {EDITABLE_ROW = false } if ((DISPLAY_EDITABLE_ROW_BOTTOM.v) ||(EDITABLE_ROWS_BOTTOM.length > 0)) { EDITABLE_ROW_BOTTOM = true } else {EDITABLE_ROW_BOTTOM = false} if (EDITABLE_CELLS_RIGHT.length > 0) { EDITABLE_CELL = true } else if (DISPLAY_EDITABLE_CELL.v) { EDITABLE_CELL = true } else {EDITABLE_CELL = false} loadRosterTableWeek() hideLoading("getActiveRoster") }) } callback_0 = () => { if (ROSTERS_YEARWEEK.indexOf(DATE_YEAR_WEEK) === -1) { hideLoading("getActiveRoster") return } else { return callback_1() } } return callback_0() } // Roster Amount per day changeTimeAmount = async (el, day_id, direction, ael) => { let roster = ROSTER[day_id] let blocks_multiple = document.getElementById(`Table-times-thead-tr-${day_id}`).querySelectorAll(".th-amount-container.active") let block_this_active = document.getElementById(`Table-times-thead-tr-${day_id}`).getElementsByClassName("th-amount-container")[ael] if (!block_this_active.classList.contains("active")) { if (blocks_multiple.length > 0) { for (i=0; i< blocks_multiple.length; i++) { blocks_multiple[i].classList.remove("active") } blocks_multiple = [] } } if (blocks_multiple.length > 0) { for (i=0; i< blocks_multiple.length; i++) { let block = blocks_multiple[i] let block_time = block.parentNode.parentNode let time = parseFloat(block_time.getAttribute("time")) let t_id = roster.d.map(a => {return a.t}).indexOf(time) let amount = roster.d[t_id].a let newAmount = amount if (direction === "up") { if (amount < PERSONS.length) newAmount = amount+1 } else { if (amount > 0) newAmount = amount-1 } ROSTER[day_id].d[t_id].a = newAmount block_time.getElementsByClassName("time-amount-max")[0].innerHTML = newAmount } setTimeAmountTh(day_id) let change_times = structuredClone(ROSTER[day_id].d) change_times.forEach(data => {data.time = data.t; data.amount = data.a; delete data.t; delete data.a}) setDataAC(DATE_YEAR_WEEK, day_id, change_times) return } let amount = roster.d[ael].a let newAmount = amount if (direction === "up") { if (amount < PERSONS.length) newAmount = amount+1 } else { if (amount > 0) newAmount = amount-1 } if (amount === newAmount) return ROSTER[day_id].d[ael].a = newAmount let change_times = structuredClone(ROSTER[day_id].d) change_times.forEach(data => {data.time = data.t; data.amount = data.a; delete data.t; delete data.a}) setDataAC(DATE_YEAR_WEEK, day_id, change_times) document.getElementById("Roster-"+day_id).getElementsByClassName("time-amount-max")[ael].innerHTML = newAmount setTimeAmountTh(day_id) } getPersonAmountForDay = (day_id) => { let amount_day = [] ROSTER[day_id].d.forEach(time => amount_day.push({ time: time.t, is: getPersonAmountForDayTime(day_id, time.t).length, max: time.a }) ) return amount_day } getPersonAmountForDayTime = (day_id, time) => { let shifts = PERSONS.map(p => p.shifts).flat(1).filter(s => s.day_id === day_id) let shifts_in_time = [] shifts.forEach(shift => { if (shift.start <= time && shift.end >= time) shifts_in_time.push(shift) }) return shifts_in_time } setTimeAmountTh = async (day_id) => { for (let id=0; id= colors_red_orange_green.length) color = colors_red_orange_green[colors_red_orange_green.length-1] if (amount > ROSTER[day_id].d[id].a) color = "#458caf" else if (amount === ROSTER[day_id].d[id].a) color = "#61a64d" let block_th = document.getElementById("Table-times-thead-tr-"+day_id).querySelector('[time="'+el.t+'"]') block_th.setAttribute("style", `background-color: ${color}; border-color: ${color}87;`) block_th.getElementsByClassName("time-amount-is")[0].innerHTML = amount+"/" } } setTimeAmount = async (person_id) => { let person = PERSONS.find(p => p.id === person_id) for (let day_id=0; day_id {res(getPersonHoursWithFreedays(person_id))}) hours_total = await hours_total hours_total = parseFloat(hours_total.toFixed(2)) for (var i = 0; i < blocks_name.length; i++) { blocks_name[i].getElementsByClassName("hours-given")[0].innerHTML = hours_a+"/"+hours_total } document.querySelector(`#Tr-${person_id}-day-${day_id} .hours-today`).innerHTML = hours-person.mpa[day_id] document.querySelector(`#Tr-${person_id}-day-${day_id} .break-today`).innerHTML = breaks let block_overtime = document.querySelector(`#Tr-${person_id}-day-${day_id} .td-overtime`) let overtime = person.overtime if (overtime === 0) {block_overtime.classList.add("green"); block_overtime.classList.remove("orange", "red")} else if (overtime > 0) {overtime = `+${overtime}`; block_overtime.classList.add("red"); block_overtime.classList.remove("green", "orange")} else if (overtime < 0) {block_overtime.classList.add("orange"); block_overtime.classList.remove("green", "red")} block_overtime.innerHTML = overtime document.querySelector(`#Person-table-tr-${person_id} .td-overtime`).innerHTML = overtime setTimeAmountTh(day_id) } } getBlockTimeTd = (person_id, day_id, time) => { let block_table_row = document.getElementById(`Tr-${person_id}-day-${day_id}`) if (!block_table_row) return let block_td = block_table_row.querySelector('[time="'+time+'"]') return block_td } removePersonFromShiftDay = async (person_id, day_id, year_week, noreload) => { if (!year_week) { year_week = DATE_YEAR_WEEK} if (day_id >= DAYS.length) return if (ROSTERS_YEARWEEK.indexOf(year_week) === -1) return let shifts = [] let year_week_set = false return dbRemove_shift_where_person_and_year_week_and_day(person_id, year_week, day_id).then(() => { if (year_week !== DATE_YEAR_WEEK) return if (!noreload) { return setActivePerson(person_id).then((person) => { return reloadPersonDayData(person_id, day_id, year_week) }) } return }) } // get auto shift getBestShiftStarts = async (person_id, day_id) => { let amount_sortet = getPersonAmountForDay(day_id).sort((a, b) => {return (b.max-b.is)-(a.max-a.is) }) let average = new Promise((res, rej) => {res(getPersonAverageHours(person_id, day_id))}) average = await average let best = [] let max_diff = amount_sortet.map(da => (da.max-da.is))[0] getMax = (max, is) => { let re = max-is if (re < 0) {re = (re*max_diff/100)*max_diff} else {re = (re*max_diff/100) } return re } ROSTER[day_id].d.forEach(d => { max_diff = amount_sortet.map(da => (da.max-da.is))[0] let rank = amount_sortet.filter(da => { return da.time >= d.t && da.time < d.t+average}).map(da => ((getMax(da.max, da.is)*100)/da.max)).reduce((a, b) => a + b, 0) best.push({time: d.t, rank: rank}) }) return best.sort((a,b) => b.rank-a.rank) } getAutoTimeStart = async (person_id, day_id) => { let average = await getPersonAverageHours(person_id, day_id) let start = await getBestShiftStarts(person_id, day_id) start = start[0].time if (start+average > ROSTER[day_id].d[ROSTER[day_id].d.length-1].t) {start = ROSTER[day_id].d[ROSTER[day_id].d.length-1].t-average} if (start < ROSTER[day_id].d[0].t) {start = ROSTER[day_id].d[0].t} return start } /* autoAddShifts = async (rerun) => { showLoading("autoAddShifts") let person_without = new Promise((res, rej) => {res(getPersonWithoutShifts())}) person_without = await person_without if (person_without.length === 0) return while (person_without.length > 0) { let max_id = person_without.map(p => p[2] === person_without[0][2]).indexOf(false)-1 if (!max_id >= 0) {max_id = 0} let person_without_id = Math.floor(Math.random() * max_id) let person = person_without[person_without_id] let person_id = person[0] let days = person[1] for (let di=0; di {res(getAutoTimeStart(person_id, day_id))}) as = await as addNewShiftToRoster(person_id, day_id, as, undefined, undefined, true) } person_without.splice(person_without_id, 1) } getActiveRoster().then(() => hideLoading("autoAddShifts")) } */ addExtrashiftToRoster = (person_id, day_id, time_start, start, end) => { let prev_duration let average getD = async () => { prev_duration = await getPersonDayHoursAndBreaks(person_id, day_id) prev_duration = prev_duration [0] average = new Promise((res, rej) => {res(getPersonAverageHours(person_id, day_id))}) average = await average } setD = () => { let duration = average-prev_duration-TIME_STEP if (duration < 0) {duration = 2} let time_end = time_start+duration if (time_start < start) { if (time_end > start-(TIME_STEP*2)) {time_end = start-(TIME_STEP*2)} } if (time_start > end) { if (time_end > ROSTER[day_id].d[ROSTER[day_id].d.length-1].t) {time_end = ROSTER[day_id].d[ROSTER[day_id].d.length-1].t} } if (time_end < time_start) { time_end = time_start} addShift(DATE_YEAR_WEEK, day_id, person_id, time_start, time_end) } getD().then(() => setD()) } addShiftToNextRoster = (person_id, day_id, time_start, time_end, should_delete) => { let next_yw = getDateToRosterDate(new Date(getDateOfISOWeek(DATE_YEAR_WEEK).getTime() + 7 * 24 * 60 * 60 * 1000))[0] ROSTERS_YEARWEEK.indexOf(next_yw === -1) && createDataA(next_yw) should_delete && dbRemove_shift_where_person_and_year_week_and_day(person_id, next_yw, day_id).then(() => { dbAdd_shift(next_yw, day_id, person_id, time_start, time_end) }) } getShiftEnd = async (person_id, day_id, time_start, year_week) => { if (typeof year_week === "undefined") {year_week = DATE_YEAR_WEEK} let roster = await getActiveRosterData(year_week) let person_average_hours = await getPersonAverageHours(person_id, day_id, year_week) if (person_average_hours > 6) person_average_hours = person_average_hours+DAYBREAK_1 if (person_average_hours > 9) person_average_hours = person_average_hours+DAYBREAK_2 let time_end = time_start+person_average_hours-TIME_STEP if (time_start === roster[day_id].d[0].t && roster[day_id].d[1].t-roster[day_id].d[0].t !== TIME_STEP) { time_end = time_end-TIME_STEPS[TIME_STEPS.indexOf(TIME_STEP)-1] } if (time_end > roster[day_id].d[roster[day_id].d.length-1].t+TIME_STEP) time_end = roster[day_id].d[roster[day_id].d.length-1].t+TIME_STEP return time_end } setShift = async (year_week, day_id, person_id, shift_id) => { showLoading(`setShift-${shift_id}`) if (year_week === DATE_YEAR_WEEK) { setActivePerson(person_id, year_week).then((persons) => { reloadPersonDayData(person_id, day_id) hideLoading(`setShift-${shift_id}`) }) } if (document.getElementById("Roster-week-table-to")) { setActivePerson(person_id, year_week).then((persons) => { reloadPersonDayData(person_id, day_id, year_week, "Roster-week-table-to").then(() => { hideLoading(`setShift-${shift_id}`) }) }) } } addShift = async (year_week, day_id, person_id, start, end, noreload) => { return dbAdd_shift(year_week, day_id, person_id, start, end).then(shift => { if ((year_week === DATE_YEAR_WEEK) || (year_week === DATE_YEAR_WEEK_TABLE_TO)) { if (!noreload) { return setShift(year_week, day_id, person_id, shift.id) } } return shift.shift_id }) } updateShift = async (shift, start, end, noreload) => { dbSet_shift_where_id(shift.id, start, end).then(() => { if (!noreload) { setShift(shift.yearweek, shift.day_id, shift.person_id, shift.id) } }) } addNewShiftToRoster = async (person_id, day_id, time_start, time_end, year_week, noreload) => { let person = await getActivePersonById(person_id) let year_week_set = false if (typeof year_week === "undefined") {year_week = DATE_YEAR_WEEK; year_week_set = true} let cif = await checkIfPersonDayIsFree(person_id, day_id, year_week) if (cif !== false) return let roster = await getActiveRosterData(year_week) if (typeof time_end === "undefined") { time_end = await getShiftEnd(person_id, day_id, time_start, year_week) } add = () => { ROSTERS_YEARWEEK.indexOf(year_week) === -1 && createDataA(year_week) return removePersonFromShiftDay(person.id, day_id, year_week, true).then(() => { return addShift(year_week, day_id, person_id, time_start, time_end, noreload) }) } return add() } splitShift = (person_id, day_id, shift_id, time, start, end) => { dbRemove_shift_where_id(shift_id).then(() => { addShift(DATE_YEAR_WEEK, day_id, person_id, start, time) addShift(DATE_YEAR_WEEK, day_id, person_id, time+TIME_STEP, end) }) } modifyShift = (year_week, day_id, shift_id, person_id, time, direction) => { showLoading("modifyShift") getActivePersonById(person_id, year_week).then(person => { let shifts = person.shifts.filter(s => s.day_id === day_id) let shift = shifts.find(s => s.id === shift_id) let shift_b = shifts.find(s => s.start !== shift.start) if (time < ROSTER[day_id].d[0].t) {time = ROSTER[day_id].d[0].t} else if (time > ROSTER[day_id].d[ROSTER[day_id].d.length-1].t) {time = ROSTER[day_id].d[ROSTER[day_id].d.length-1].t} if (direction !== 1 && time > shift.end) { addNewShiftToRoster(person_id, day_id, time, undefined, year_week) return } if ((typeof shift_b !== "undefined" && time-TIME_STEP === shift_b.end) || (typeof shift_b !== "undefined" && time+TIME_STEP === shift_b.start)) { let start let end let new_shift if (time-TIME_STEP === shift_b.end) { start = shift_b.start end = shift.end } else if (time+TIME_STEP === shift_b.start) { start = shift.start end = shift_b.end } addNewShiftToRoster(person_id, day_id, start, end, year_week) } else if (direction === 1) { updateShift(shift, shift.start, time+TIME_STEP) } else { updateShift(shift, time, shift.end) } hideLoading("modifyShift") }) } timeHasShift = (time, shifts) => { let has_shift = false shifts.forEach(shift => { if (shift.start <= time && shift.end > time) has_shift = true }) return has_shift } createBlockExtraShift = (person, day_id, time, start, end) => { let person_id = person.id let block_add = document.createElement("button") block_add.innerHTML = "+" block_add.classList.add("roster-add-extra-shift") block_add.setAttribute("title", `${person.name}\nExtra Schicht hinzufügen\n${timeToHHMM(time)}`) block_add.setAttribute("onClick", `addExtrashiftToRoster(${person_id}, ${day_id}, ${time}, ${start}, ${end})`) return block_add } // load editable Roster addRosterButtonInnerShiftExtendShort = (person_id, day_id, shift_id, time) => { getActivePersonById(person_id).then(person => { let shift = person.shifts.find(s => s.id === shift_id) let start = shift.start let end = shift.end if (end-start <= TIME_STEP) return let block_td = getBlockTimeTd(person_id, day_id, time) let block_td_container = block_td.getElementsByClassName("container")[0] let block_container = document.createElement("div") let block_button_shorten = document.createElement("button") let block_button_extend = document.createElement("button") let block_container_remove = block_td_container.getElementsByClassName("shiftmodify-buttons-container-inner")[0] let block_extend_remove = block_td_container.getElementsByClassName("roster-extend-shift")[0] if (typeof block_container_remove !== "undefined") block_container_remove.remove() if (typeof block_extend_remove !== "undefined") block_extend_remove.remove() block_container.classList.add("shiftmodify-buttons-container-inner") if (time !== start) { block_button_extend.classList.add("chevron-right") block_button_extend.setAttribute("onclick", `modifyShift("${DATE_YEAR_WEEK}", ${day_id}, ${shift_id}, ${person_id}, ${time}, 0)`) block_button_extend.setAttribute("title", `${person.name}\nSchichtstart verschieben\n${timeToHHMM(time)}`) block_container.appendChild(block_button_extend) } if (time !== end) { block_button_shorten.classList.add("chevron-left") block_button_shorten.setAttribute("onclick", `modifyShift("${DATE_YEAR_WEEK}", ${day_id}, ${shift_id}, ${person_id}, ${time}, 1)`) block_button_shorten.setAttribute("title", `${person.name}\nSchichtende verschieben\n${timeToHHMM(time+TIME_STEP)}`) block_container.appendChild(block_button_shorten) } block_td_container.appendChild(block_container) if (time === start) { block_button_shorten.setAttribute("style", "width: 100%;") } else if (time === end) { block_button_extend.setAttribute("style", "width: 100%;") } }) } addRosterButtonExtendShift = (person, day_id, shift_id, time, direction) => { let person_id = person.id let block_td = getBlockTimeTd(person_id, day_id, time) let block_container = block_td.getElementsByClassName("container")[0] let block_container_mod = block_container.getElementsByClassName("shiftmodify-buttons-container")[0] if (typeof block_container_mod === "undefined") return let block_button = document.createElement("button") let chevron = "chevron-left" let click = `modifyShift("${DATE_YEAR_WEEK}", ${day_id}, ${shift_id}, ${person_id}, ${time}, 0)` let title_text = `${person.name}\nSchichtstart verschieben\n${timeToHHMM(time)}` if (direction === 1) { chevron = "chevron-right" click = `modifyShift("${DATE_YEAR_WEEK}", ${day_id}, ${shift_id}, ${person_id}, ${time}, 1)` title_text = `${person.name}\nSchichtende verschieben\n${timeToHHMM(time+TIME_STEP)}` } block_button.classList.add("roster-extend-shift", chevron) block_button.setAttribute("title", title_text) block_button.setAttribute("onClick", click) block_container_mod.appendChild(block_button) } addRosterButtonSplitShift = (person, day_id, shift_id, time, start, end) => { let person_id = person.id let block_td = getBlockTimeTd(person_id, day_id, time) let block_td_container = block_td.getElementsByClassName("container")[0] let block_remove_button = block_td.getElementsByClassName("container")[0].getElementsByClassName("shift-split")[0] if (block_remove_button) block_td_container.removeChild(block_remove_button) let block_button = document.createElement("button") block_button.classList.add("shift-split", "button-x", "shiftmodify-button-header") block_button.setAttribute("title", `${person.name}\nSchicht teilen\n${timeToHHMM(time)}`) block_button.setAttribute("onClick", `splitShift(${person_id}, ${day_id}, ${shift_id}, ${time}, ${start}, ${end})`) block_td_container.appendChild(block_button) } loadEditablePersonDayShift = (person_id, day_id, noWReload) => { showLoading("loadEditablePersonDayShift") let person = PERSONS.find(p => p.id === person_id) let shifts = person.shifts.filter(s => s.day_id === day_id) shifts.sort((a, b) => a.start-b.start) let shift = shifts[0] if (shift) { // remove extra shift buttons let block_tr = document.getElementById(`Tr-${person_id}-day-${day_id}`) let remove_splits = block_tr.querySelectorAll(".shift-split") let remove_adds = block_tr.querySelectorAll(".roster-add-extra-shift") let remove_extend = block_tr.querySelectorAll(".roster-extend-shift") let removes_mod_inner = block_tr.querySelectorAll(".shiftmodify-buttons-container-inner") let removes = [...remove_splits, ...remove_adds, ...removes_mod_inner, ...remove_extend ] for (i=0; i { let time = data.t let block_td = getBlockTimeTd(person_id, day_id, time) let block_container = block_td.querySelector(".container") block_td.classList.remove("assigned") let has_shift = timeHasShift(time, shifts) if (has_shift) { is_during = true is_before = false if (is_after) {is_after = false; shift = shifts[1]} block_td.classList.add("assigned") } else if (is_during) { is_during = false is_after = true } if (has_shift) { block_td.classList.add("assigned") addRosterButtonInnerShiftExtendShort(person_id, day_id, shift.id, time) if (shifts.length === 1 && time !== shift.start && time !== shift.end-TIME_STEP) addRosterButtonSplitShift(person, day_id, shifts[0].id, time, shifts[0].start, shifts[0].end) } else if (is_before) { if (time !== shift.start-TIME_STEP && shifts.length === 1) block_container.appendChild(createBlockExtraShift(person, day_id, time, shift.start, shift.end)) addRosterButtonExtendShift(person, day_id, shift.id, time) } else if (is_after) { if (time !== shift.end && shifts.length === 1) block_container.appendChild(createBlockExtraShift(person, day_id, time, shift.start, shift.end)) addRosterButtonExtendShift(person, day_id, shift.id, time, 1) } }) } checkIfPersonDayIsFree(person_id, day_id).then(check_if_free => { let h_mpa = check_if_free ? 0 : person.mpa[day_id] if (h_mpa === 0) {h_mpa = ""} let block_mpa = document.querySelector(`#Tr-${person_id}-day-${day_id} .hours-mpa`) if (block_mpa) { block_mpa.innerHTML = `
${h_mpa}
`} }) hideLoading("loadEditablePersonDayShift") } loadEditableDataIntoRosterTable = (el, day_id) => { showLoading("loadEditableDataIntoRosterTable") window.onmousemove = (e) => eventListenerEditRosterDay(e, day_id) el.classList.add("d-none") let block = document.querySelector(`#Roster-${day_id}`) if (block.classList.contains("editable")) { hideLoading("loadEditableDataIntoRosterTable") return } block.classList.add("editable") PERSONS.forEach(person => { loadEditablePersonDayShift(person.id, day_id) }) hideLoading("loadEditableDataIntoRosterTable") } getShiftTimeText = (shift, day_id, table_id) => { if (typeof table_id === "undefined") {table_id = "Roster-week-table"} let shift_start = shift.start let shift_end = shift.end let text_start = timeToHHMM(shift_start) if (text_start.length === 4) {text_start = " "+text_start} let text_end = timeToHHMM(shift_end) if (text_end.length === 4) {text_end = " "+text_end} if (EDITABLE_TABLES.indexOf(table_id) > -1) { return `

-

` } else { return `

${text_start}

-

${text_end}

` } } // reload Person data reloadPersonData = (person_id, year_week, table_id) => { showLoading(`reloadPersonData${person_id}`) DAYS.forEach((day, day_id) => { reloadPersonDayData(person_id, day_id, year_week, table_id).then(() => { hideLoading(`reloadPersonData${person_id}`) }) }) } reloadPersonDayData = async (person_id, day_id, year_week, table_id) => { showLoading(`reloadPersonDayData-${person_id}-${day_id}`) if (!year_week) {year_week = DATE_YEAR_WEEK} if (!table_id) {table_id = "Roster-week-table"} getActivePersonById(person_id, year_week).then(person => { // set week if (year_week === DATE_YEAR_WEEK && table_id !== "Roster-week-table") { renderRosterTableWeekPersonDay(person, day_id, year_week, document.querySelector(`#Roster-week-table .Roster-week-td-name-${person_id}-day-${day_id}`), table_id) } renderRosterTableWeekPersonDay(person, day_id, year_week, document.querySelector(`#${table_id} .Roster-week-td-name-${person_id}-day-${day_id}`), table_id).then(() => { // set week hours and breaks let block_name = document.querySelector(`#${table_id} .Roster-week-tr-${person_id} .Roster-week-td-name`) if (!block_name) {hideLoading(`reloadPersonDayData-${person_id}-${day_id}`); return} let block_td_hours = block_name.querySelector(".hours") let block_td_breaks = block_name.querySelector(".breaks") getPersonHoursAndBreaks(person_id, year_week).then(hours_breaks_all => { let breaks_all = hours_breaks_all[1] getPersonHoursWithFreedays(person_id, year_week).then(hours_total => { hours_total = parseFloat(hours_total.toFixed(2)) block_td_hours.innerHTML = hours_breaks_all[0]+"/"+hours_total block_td_breaks.innerHTML = hours_breaks_all[1] }) }) }) if (year_week === DATE_YEAR_WEEK) { // set Person Table row renderPersonTableRow(person_id) // set roster createBlockRosterTablePersonRow(person, ROSTER[day_id], day_id, document.querySelector(`#Tr-${person_id}-day-${day_id}`)).then(() => { // set roster hours and breaks setTimeAmount(person_id) loadEditablePersonDayShift(person_id, day_id, true) hideLoading(`reloadPersonDayData-${person_id}-${day_id}`) }) } else { hideLoading(`reloadPersonDayData-${person_id}-${day_id}`) } }) } loadTableWeekPersonData = async (person_id, year_week, table_id) => { showLoading(`loadTableWeekPersonData-${person_id}`) if (typeof year_week === "undefined") { year_week = DATE_YEAR_WEEK} if (typeof table_id === "undefined") { table_id = "Roster-week-table"} let person = await getActivePersonById(person_id, year_week) let block_table = document.querySelector(`#${table_id}`) if (EDITABLE_TABLES.indexOf(table_id) > -1) block_table.classList.add("Roster-week-editable") for (let day_id=0; day_id { if (day_id === DAYS.length-1) hideLoading(`loadTableWeekPersonData-${person_id}`) }) } } rosterWeekDisplayOvertime = (el) => { if (DISPLAY_OVERTIME) { el.classList.remove("active") dbSet_settings_overtime_default(false) DISPLAY_OVERTIME = false } else { el.classList.add("active") dbSet_settings_overtime_default(true) DISPLAY_OVERTIME = true } loadRosterTableWeek() } rosterWeekAddEditableRow = (el) => { if (EDITABLE_ROW) { el.classList.remove("active") EDITABLE_ROW = false dbRemove_roster_editable_rows_top(DATE_YEAR_WEEK) EDITABLE_ROWS_TOP = [] } else { el.classList.add("active") EDITABLE_ROW = true EDITABLE_ROWS_TOP = [] //for (let i=0; i<6; i++) {EDITABLE_ROWS_TOP.push({id: i.toString(), yearweek: DATE_YEAR_WEEK, text: ''})} } loadRosterTableWeek() } rosterWeekAddEditableRowBottom = (el) => { if (EDITABLE_ROW_BOTTOM) { el.classList.remove("active") EDITABLE_ROW_BOTTOM = false dbRemove_roster_editable_rows_bottom(DATE_YEAR_WEEK) EDITABLE_ROWS_BOTTOM = [] } else { el.classList.add("active") EDITABLE_ROW_BOTTOM = true EDITABLE_ROWS_BOTTOM = [] //for (let i=0; i<6; i++) {EDITABLE_ROWS_BOTTOM.push({id: i.toString(), yearweek: DATE_YEAR_WEEK, text: ''})} } loadRosterTableWeek() } rosterWeekAddEditableCell = (el) => { if (EDITABLE_CELL) { el.classList.remove("active") EDITABLE_CELL = false dbRemove_roster_editable_cells_right(DATE_YEAR_WEEK) EDITABLE_CELLS_RIGHT = [] loadRosterTableWeek() } else { setEditableCellTrue() dbGet_roster_editable_cells_right(DATE_YEAR_WEEK).then(ec => { EDITABLE_CELLS_RIGHT = ec loadRosterTableWeek() }) /*EDITABLE_CELLS_RIGHT = [] EDITABLE_CELLS_RIGHT.push({id: "i", yearweek: DATE_YEAR_WEEK, text: ""}) PERSONS.forEach(person => { EDITABLE_CELLS_RIGHT.push({id: person.id, yearweek: DATE_YEAR_WEEK, text: ""}) })*/ } } setEditableCell = (cell, id, text) => { id = id.toString() if (cell === "row_top") dbSet_roster_editable_rows_top_where_key(DATE_YEAR_WEEK, id, text) else if (cell === "row_bottom") dbSet_roster_editable_rows_bottom_where_key(DATE_YEAR_WEEK, id, text) else if (cell === "cell_right") dbSet_roster_editable_cells_right_where_key(DATE_YEAR_WEEK, id, text) } renderRosterTableWeekPersonDay = async (person, day_id, year_week, block_td, table_id) => { if (!block_td) {return} block_td.innerHTML = "" block_td.classList.remove("v-bottom", "free", "v-bottom") let shifts = person.shifts.filter(s => s.day_id === day_id) let person_id = person.id // set info let info_set = false setInfo = async (person_id, day_id, block_td) => { if (info_set) return block_info = document.createElement("div") block_info.classList.add("info") let info if (year_week === DATE_YEAR_WEEK) { info = ROSTER_PERSON_INFOS.find(i => i.day_id === day_id && i.id === person_id.toString())?.text } else if (year_week === DATE_YEAR_WEEK_TABLE_FROM) { info = ROSTER_PERSON_INFOS_TABLE_FROM.find(i => i.day_id === day_id && i.id === person_id.toString())?.text } else if (year_week === DATE_YEAR_WEEK_TABLE_TO) { info = ROSTER_PERSON_INFOS_TABLE_TO.find(i => i.day_id === day_id && i.id === person_id.toString())?.text } else { info = await dbGet_roster_info_where_yearweek_and_day_and_person(year_week, day_id, person_id) } if (typeof info !== "undefined") { let block_info_text = document.createElement("div") block_info_text.innerHTML = info block_info.appendChild(block_info_text) block_td.appendChild(block_info) } else { block_td.classList.remove("v-bottom") } info_set = true } // set free let ch_free = await checkIfPersonDayIsFree(person_id, day_id, year_week) if (ch_free) { block_td.classList.add("free") let block_free = document.createElement("div") block_free.classList.add("free") let block_time = document.createElement("p") block_time.classList.add("time") block_time.innerHTML = ch_free block_free.appendChild(block_time) block_td.appendChild(block_free) if (ch_free === dbGet_settings_label_cut(2)) { let block_duration = document.createElement("p") block_duration.classList.add("duration") //let duration = await getPersonDayHoursAndBreaks(person_id, day_id, year_week)[0] block_td.appendChild(block_duration) } setInfo(person_id, day_id, block_td) return } else { block_td.classList.remove("free") } // set empty shift if (shifts.length === 0) { block_td.classList.add("no-shift") block_td.classList.add("v-bottom") setInfo(person_id, day_id, block_td) return } // set shift let block_td_container = document.createElement("div") block_td.appendChild(block_td_container) let block_time_container = document.createElement("div") if (EDITABLE_TABLES.indexOf(table_id) > -1) { getAutoTimeStart(person_id, day_id).then(auto_start => { if (shifts.length === 0) block_time_container.setAttribute("onClick", `addNewShiftToRoster(${person_id}, ${day_id}, ${auto_start}, undefined, "${year_week}")`) }) } block_time_container.classList.add("time") block_td_container.classList.add("container") shifts.sort((a, b) => { return a.start - b.start; }); let title_shift_text = person.name shifts.forEach((shift, shift_id) => { let block_time = document.createElement("div") let shift_text = getShiftTimeText(shift, day_id, table_id) block_time.innerHTML = shift_text block_time_container.appendChild(block_time) }) block_td_container.appendChild(block_time_container) // set hours getPersonDayHoursAndBreaks(person_id, day_id, year_week).then(hours_breaks => { let duration = hours_breaks[0].toString() duration = duration-person.mpa[day_id] if (Math.floor(hours_breaks[0]).toString().length === 1) {duration = " "+duration} let block_duration = document.createElement("p") block_duration.classList.add("duration") block_duration.setAttribute("title", "Stunden") block_duration.innerHTML = parseFloat(duration) === 0 ? "" : duration block_td_container.appendChild(block_duration) // set break let block_break = document.createElement("p") let break_day = hours_breaks[1] block_break.classList.add("break") block_break.setAttribute("title", "Pause") if (break_day < 10) {break_day = ` ${break_day} `} block_break.innerHTML = parseFloat(duration) === 0 ? "" : break_day block_td_container.appendChild(block_break) }) // set mpa let block_mpa = document.createElement("div") let block_mpa_title = document.createElement("div") let block_mpa_value = document.createElement("div") if (person.mpa[day_id] > 0) { if (EDITABLE_TABLES.indexOf(table_id) > -1) { block_mpa_value = document.createElement("input") block_mpa_value.setAttribute("value", person.mpa[day_id]) block_mpa_value.setAttribute("title", `${getRenames("m").a} ändern.`) block_mpa_value.setAttribute("type", `number`) block_mpa_value.setAttribute("step", `0.25`) block_mpa_value.setAttribute("onchange", `addMpaToday(${person_id}, ${day_id}, this.value)`) } else { block_mpa_value.innerHTML = person.mpa[day_id] } block_mpa_title.innerHTML = getRenames("m").a } else { if (EDITABLE_TABLES.indexOf(table_id) > -1) { block_mpa.setAttribute("onClick", `showLoading("addMpaToday"); window.setTimeout(() => {addMpaToday(${person_id}, ${day_id}, 1); hideLoading("addMpaToday")},50)`) block_mpa.setAttribute("title", `${getRenames("m").a} mit 1h für diesen Tag hinzufügen.`) } } block_mpa.classList.add("mpa") block_mpa.appendChild(block_mpa_title) block_mpa.appendChild(block_mpa_value) block_td_container.appendChild(block_mpa) // set shift label let label_sl = person.sl[day_id] if (label_sl !== false) { block_td_container.style = 'grid-template-areas: "time time time time" "break mpa label duration";' let block_sl = document.createElement("div") block_sl.classList.add("label") block_sl.innerHTML = dbGet_shift_label_cut(label_sl) block_td_container.appendChild(block_sl) } setInfo(person_id, day_id, block_td) } createBlockRosterTableWeek = async (year_week, table_id) => { if (typeof table_id === "undefined") { table_id = "Roster-week-table" } if (typeof year_week === "undefined") { year_week = DATE_YEAR_WEEK } let date = getDateOfISOWeek(year_week) let block_table = document.createElement("table") block_table.setAttribute("id", table_id) if (EDITABLE_TABLES.indexOf(table_id) > -1) block_table.classList.add("Roster-week-editable") let block_thead = document.createElement("thead") let block_thead_row = document.createElement("tr") let block_th = document.createElement("th") block_th.classList.add("Roster-week-th-name") let block_th_name = document.createElement("p") block_th_name.innerHTML = "Name" block_th.appendChild(block_th_name) block_thead_row.appendChild(block_th) let roster = await getActiveRosterData(year_week) roster.forEach((roster, day_id) => { let day_date = new Date(date) day_date.setDate(day_date.getDate() - (day_date.getDay() + 6) % 7 + day_id) let block_th = document.createElement("th") let block_th_day = document.createElement("p") let block_th_day_date = document.createElement("p") block_th.classList.add("Roster-week-th") block_th.setAttribute("day_id", day_id) block_th_day.innerHTML = roster.n block_th_day_date.innerHTML = day_date.toLocaleDateString('de', {day: '2-digit', month: '2-digit', year: '2-digit'}) block_th.appendChild(block_th_day) block_th.appendChild(block_th_day_date) block_thead_row.appendChild(block_th) }) if (EDITABLE_CELL) { let block_th_cell = document.createElement("th") block_th_cell.classList.add("td-editable-cell", `Roster-week-td-editable-cell-i`) if (!NOWEEKEDIT) block_th_cell.setAttribute("contenteditable", "true") block_th_cell.addEventListener('focusout', (e) => setEditableCell("cell_right", "i", e.target.innerHTML)) if (EDITABLE_ROW) block_th_cell.setAttribute("rowspan", "2") block_th_cell.innerHTML = EDITABLE_CELLS_RIGHT.find(c => c.id === "i")?.text || "" block_thead_row.appendChild(block_th_cell) } block_thead.appendChild(block_thead_row) let block_tbody = document.createElement("tbody") addEmptyRow = () => { let block_tbody_row = document.createElement("tr") block_tbody_row.classList.add("tr-empty") let block_td = document.createElement("td") if (EDITABLE_CELL) { block_td.setAttribute("colspan", DAYS.length+2) } else { block_td.setAttribute("colspan", DAYS.length+1) } block_tbody_row.appendChild(block_td) block_tbody.appendChild(block_tbody_row) } if (table_id === "Roster-week-table" && EDITABLE_ROW) { let block_thead_row_1 = document.createElement("tr") block_thead_row_1.classList.add("tr-editable") for (let i=0; i<6; i++) { let block_th_er = document.createElement("th") block_th_er.setAttribute("id", `Roster-week-th-editable-${i}`) if (!NOWEEKEDIT) block_th_er.setAttribute("contenteditable", `true`) block_th_er.addEventListener('focusout', (e) => setEditableCell("row_top", i, e.target.innerHTML)) block_th_er.innerHTML = EDITABLE_ROWS_TOP.find(c => c.id === i.toString())?.text || "" block_thead_row_1.appendChild(block_th_er) } block_thead.appendChild(block_thead_row_1) addEmptyRow() } block_table.appendChild(block_thead) let sort_d = false if ((SETTINGS.sort_week.indexOf("d-d") > -1) || (SETTINGS.sort_week.indexOf("d-u") > -1)) {sort_d = true} let person_week if (year_week === DATE_YEAR_WEEK) { person_week = PERSONS_WEEK } else if (year_week === DATE_YEAR_WEEK_TABLE_FROM) { person_week = PERSONS_TABLE_FROM } else if (year_week === DATE_YEAR_WEEK_TABLE_TO) { person_week = PERSONS_TABLE_TO } else { person_week = await getSortedPersonRosterWeek(1, year_week) } let sort_d_c = person_week[0].department if (typeof sort_d_c === "undefined") return for (let pw=0; pw {res(getPersonHoursWithFreedays(person_id, year_week))}) hours_total = await hours_total hours_total = parseFloat(hours_total.toFixed(2)) block_td_hours.innerHTML = hours_breaks_all[0]+"/"+hours_total block_td_breaks.innerHTML = hours_breaks_all[1] // set overtime if (DISPLAY_OVERTIME) { block_td_overtime.innerHTML = person.overtime } for (let day_id=0; day_id setEditableCell("cell_right", person_id, e.target.innerHTML)) block_td_cell.innerHTML = EDITABLE_CELLS_RIGHT.find(c => c.id === person_id.toString())?.text || "" block_tbody_row.appendChild(block_td_cell) } block_tbody.appendChild(block_tbody_row) } if (EDITABLE_ROW_BOTTOM) { addEmptyRow() let block_tr_editable = document.createElement("tr") block_tr_editable.classList.add("tr-editable") for (let i=0; i<6; i++) { let block_td_ediatable = document.createElement("td") block_td_ediatable.setAttribute("id", `Roster-week-td-bottom-editable-${i}`) if (!NOWEEKEDIT) block_td_ediatable.setAttribute("contenteditable", `true`) block_td_ediatable.addEventListener('focusout', (e) => setEditableCell("row_bottom", i, e.target.innerHTML)) block_td_ediatable.innerHTML = EDITABLE_ROWS_BOTTOM.find(c => c.id === i.toString())?.text || "" block_tr_editable.appendChild(block_td_ediatable) } block_tbody.appendChild(block_tr_editable) } block_table.appendChild(block_tbody) return block_table } loadRosterTableWeekData = async (year_week, table_id) => { if (PERSONS.length === 0) return showLoading("loadRosterTableWeekData") if (typeof year_week === "undefined") { year_week = DATE_YEAR_WEEK } if (typeof table_id === "undefined") { table_id = "Roster-week-table" } let person_all if (year_week === DATE_YEAR_WEEK) { person_all = PERSONS } else if (year_week === DATE_YEAR_WEEK_TABLE_TO) { person_all = PERSONS_TABLE_TO } else if (year_week === DATE_YEAR_WEEK_TABLE_FROM) { person_all = PERSONS_TABLE_FROM } else { person_all = dbGet_persons_active_where_yearweek(year_week) } for (let i=0; i { if (i === person_all.length-1) { hideLoading("loadRosterTableWeekData") } }) } DAYS.forEach((day, day_id) => { let day_date = new Date(getIsoStringFromDay(day_id, year_week)) document.querySelectorAll(`#${table_id} .Roster-week-th`)[day_id].querySelectorAll("p")[1].innerHTML = day_date.toLocaleDateString('de', {day: '2-digit', month: '2-digit', year: '2-digit'}) }) } loadRosterTableWeek = () => { if (PERSONS.length === 0) return let block_roster_container = document.getElementById("Roster-week-container") let block_header = document.createElement("h2") let block_print = document.createElement("button") block_roster_container.innerHTML = "" block_header.innerHTML = "Woche "+DATE_WEEK block_print.innerHTML = "Drucken" block_print.classList.add("button-print") block_print.setAttribute("onClick", `printTable("Roster-week-container", ${DATE_YEAR_WEEK})`) block_roster_container.appendChild(block_header) block_roster_container.appendChild(block_print) createB = async () => { let create_block = new Promise((res, rej) => {res(createBlockRosterTableWeek())}) create_block = await create_block block_roster_container.appendChild(create_block ) } createB().then(() => { let block_week_info = document.createElement("div") block_week_info.setAttribute("id", "Roster-week-info") block_week_info.innerHTML = "" let info = ROSTER_PERSON_INFOS.find(i => i.day_id === 999 && i.id === "all")?.text if (typeof info !== "undefined") { let block_week_info_text = document.createElement("div") block_week_info_text.innerHTML = info block_week_info.appendChild(block_week_info_text) document.querySelector("#Roster-week-week-info").classList.add("active") document.getElementById("Set-week-info-container").querySelector("textarea").value = info document.getElementById("Set-week-info-container").classList.remove("d-none") } block_roster_container.appendChild(block_week_info) }) } eventListenerEditRosterDay = (event, day_id) => { let block_container = document.getElementById(`Roster-${day_id}`) if (!block_container.contains(event.target)) { let button = block_container.querySelector(".button-edit-table") button.classList.remove("d-none") window.onmousemove = null } } createDaysOption = (day_id) => { let blocks = [] DAYS.forEach((day, d_id) => { if (day_id === d_id) return let block = document.createElement("option") block.value = d_id block.innerHTML = day blocks.push(block) }) return blocks } copyRosterDay = async (day_id, from_id) => { showLoading("copyRosterDay") setS = async (shifts, did, yw) => { let noreload = shifts.length === 1 ? false : true if (yw !== DATE_YEAR_WEEK) {noreload = true} if (shifts.length === 0) return return addNewShiftToRoster(shifts[0].person_id, did, shifts[0].start, shifts[0].end, yw, noreload).then(() => { if (shifts.length > 1) { return addShift(yw, did, shifts[1].person_id, shifts[1].start, shifts[1].end) } return }) } asyncMain = () => { let new_roster_data let year_week let year_week_to = DATE_YEAR_WEEK if (day_id === "all") { year_week = DATE_YEAR_WEEK from_id = parseFloat(from_id) setAs = async() => { for (let p = 0; p s.day_id === from_id) for (let d_id=0; d_id { if (cf === false) { setS(shifts, d_id, year_week_to).then(() => { if (p === PERSONS.length-1) { hideLoading("copyRosterDay")} }) } else if (p === PERSONS.length-1) { hideLoading("copyRosterDay")} }) } } } setAs() } else { if (from_id === "week_before") { year_week = DATE_YEAR_WEEK_BEFORE from_id = day_id day_id = parseFloat(day_id) } else if (from_id === "week_before_week") { year_week = DATE_YEAR_WEEK_BEFORE from_id = day_id day_id = parseFloat(day_id) } else if (day_id === "next"){ year_week = DATE_YEAR_WEEK year_week_to = DATE_YEAR_WEEK_AFTER from_id = parseFloat(from_id) day_id = from_id } else { year_week = DATE_YEAR_WEEK from_id = parseFloat(from_id) day_id = parseFloat(day_id) } loopP = (persons_yw) => { for (let p=0; p s.day_id === from_id) checkIfPersonDayIsFree(persons_yw[p].id, day_id, year_week_to).then(cf => { if (cf === false) { setS(shifts, day_id, year_week_to).then(() => { if (p === persons_yw.length-1) { hideLoading("copyRosterDay")} }) } else if (p === persons_yw.length-1) { hideLoading("copyRosterDay")} }) } } if (ROSTERS_YEARWEEK.indexOf(year_week_to) === -1) { createDataA(year_week_to).then(() => { loopP(PERSONS) }) } else if (DATE_YEAR_WEEK === year_week) { loopP(PERSONS) } else { dbGet_persons_active_where_yearweek(year_week).then(persons_yw => loopP(persons_yw)) } } } asyncMain() } removeDayShifts = (day_id) => { showLoading("removeDayShifts") checkElementInView("main") dbRemove_shift_where_year_week_and_day(DATE_YEAR_WEEK, day_id).then(() => { setPerson().then(() => { getActiveRoster().then(() => { if (INVIEW.length > 0) document.querySelector(INVIEW)?.scrollIntoView() hideLoading("removeDayShifts") }) }) }) } requestRemoveDayShifts = (day_id) => { document.body.classList.add("noscroll") document.getElementById("Popup").classList.add("active", "request-remove") let block = document.getElementById("Popup-container") block.style.width = "300px" let block_text = document.createElement("p") block_text.innerHTML = "Sicher dass du alle Schichten für "+DAYS[day_id]+" löschen möchtest?" block.appendChild(block_text) let block_button_cancel = document.createElement("button") block_button_cancel.setAttribute("onClick", "closePopup()") block_button_cancel.innerHTML = "abbrechen" block.appendChild(block_button_cancel) let block_button_remove = document.createElement("button") block_button_remove.setAttribute("onClick", "removeDayShifts("+day_id+");closePopup()") block_button_remove.innerHTML = "löschen" block.appendChild(block_button_remove) document.getElementById("Popup").onclick = (e) => eventListenerClosePopup(e) } scrollTimeIntoView = (day_id, time) => { document.getElementById("Table-times-thead-tr-"+day_id).querySelector(`[time="${time}"]`).scrollIntoView({behavior: "smooth", inline: "center", block: "nearest"}) } addRosterPersonDayInfo = (person_id, day_id, text) => { while (text.slice(-1) === "\n") {text = text.substring(0, text.length-1)} let info = ROSTER_PERSON_INFOS.find(i => i.day_id === day_id && i.id === person_id.toString()) if (typeof info !== "undefined") {info.text = text} else ROSTER_PERSON_INFOS.push({id: person_id.toString(), yearweek: DATE_YEAR_WEEK, day_id: day_id, text: text}) dbSet_roster_info_where_yearweek_and_day_and_person(DATE_YEAR_WEEK, day_id, person_id, text) } removeRosterPersonDayInfo = (person_id, day_id) => { ROSTER_PERSON_INFOS = ROSTER_PERSON_INFOS.filter(i => `${i.id}-${i.day_id}` !== `${person_id}-${day_id}`) dbRemove_roster_info_where_yearweek_and_day_and_person(DATE_YEAR_WEEK, day_id, person_id) } closePersonDayInfoInput = (person_id, day_id, block) => { let block_text = block.querySelector("textarea") let text = block_text.value if (text.length === 0) { removeRosterPersonDayInfo(person_id, day_id) block.querySelector("button").classList.remove("set") } else if (text.length > 0) { block.querySelector("button").classList.add("set") addRosterPersonDayInfo(person_id, day_id, text) } block.removeChild(block_text) document.getElementById(`Td-name-${person_id}-day-${day_id}`).classList.remove("active") document.body.onclick = null reloadPersonDayData(person_id, day_id) } eventListenerClosePersonDayInfoInput = (evt, person_id, day_id, block) => { let targetEl = evt.target let clickEl = block do { if (targetEl == clickEl) return targetEl = targetEl.parentNode; } while (targetEl); closePersonDayInfoInput(person_id, day_id, block) } openPersonDayInfoInput = (person_id, day_id, el) => { let block = el.parentNode let block_input = document.createElement("textarea") document.getElementById(`Td-name-${person_id}-day-${day_id}`).classList.add("active") let info = ROSTER_PERSON_INFOS.find(i => i.day_id === day_id && i.id === person_id.toString())?.text if (typeof info !== "undefined") block_input.value = info block.appendChild(block_input) window.setTimeout(() => { document.body.onclick = (e) => eventListenerClosePersonDayInfoInput(e, person_id, day_id, block) }, 100) } createBlockRosterTablePersonRow = async (person, roster, day_id, block_tbody_row) => { document.querySelector(`#Roster-${day_id}`).classList.remove("editable") let year_week = DATE_YEAR_WEEK let person_id = person.id let shifts_all = person.shifts let shifts = shifts_all.filter(s => s.day_id === day_id) block_tbody_row.innerHTML = "" // create table name let block_name_td = document.createElement("td") let block_td_name_hours_container = document.createElement("div") block_td_name_hours_container.classList.add("td-name-hours-container") let block_name_td_container = document.createElement("div") let d_color = DEPARTMENT_COLORS[DEPARTMENTS.map(d => d.id).indexOf(person.department)] block_name_td.style.background = `linear-gradient(to right, black 1px, ${d_color} 1px, ${d_color} calc(100% - 1px), black 1px)` block_name_td_container.classList.add("td-name-container") block_name_td.setAttribute("id", "Td-name-"+person_id+"-day-"+day_id) block_name_td.classList.add(`name-${person_id}`, "td-name", "td-name-hours", "td-sticky") let block_name_hours = document.createElement("div") block_name_hours.classList.add("hours-amount") let block_name_td_container_hours = document.createElement("div") block_name_td_container_hours.classList.add("hours-container") let block_name_td_name = document.createElement("div") block_name_td_name.classList.add("name") block_name_td_name.innerHTML = person.name block_name_td_container.appendChild(block_name_td_name) let block_name_td_overtime = document.createElement("div") block_name_td_overtime.classList.add("td-overtime") let overtime = person.overtime let overtime_t = getOvertimeTitleText(overtime, person.name) if (overtime === 0) {block_name_td_overtime.classList.add("green"); block_name_td_overtime.classList.remove("orange", "red")} else if (overtime > 0) {overtime = `+${overtime}`; block_name_td_overtime.classList.add("red"); block_name_td_overtime.classList.remove("green", "orange")} else if (overtime < 0) {block_name_td_overtime.classList.add("orange"); block_name_td_overtime.classList.remove("green", "red")} block_name_td_overtime.innerHTML = overtime block_name_td_overtime.setAttribute("title", overtime_t) block_name_td_container.appendChild(block_name_td_overtime) let hours_breaks = await getPersonDayHoursAndBreaks(person_id, day_id, year_week) let hours = hours_breaks[0] let breaks = hours_breaks[1] let hours_total = await getPersonHoursWithFreedays(person_id) hours_total = parseFloat(hours_total.toFixed(2)) let hours_breaks_all = await getPersonHoursAndBreaks(person_id, year_week) let hours_a = hours_breaks_all[0] let breaks_a = hours_breaks_all[1] let block_name_hours_vs_given = document.createElement("div") block_name_hours_vs_given.setAttribute("title", "Stunden vergeben/Stunden max") block_name_hours_vs_given.classList.add("hours-given") block_name_hours_vs_given.innerHTML = hours_a+"/"+hours_total block_name_hours.appendChild(block_name_hours_vs_given) block_name_td_container_hours.appendChild(block_name_hours) block_name_td_container.appendChild(block_name_td_container_hours) block_td_name_hours_container.appendChild(block_name_td_container) block_name_td.appendChild(block_td_name_hours_container) // create table name hours // top let block_td_top_bottom = document.createElement("div") block_td_top_bottom.classList.add("td-top-bottom") let block_td_top = document.createElement("div") block_td_top.classList.add("td-top") let block_name_mpa = document.createElement("div") block_name_mpa.setAttribute("title", getRenames("m").a) block_name_mpa.classList.add("hours-mpa") let mpa = person.mpa[day_id] let check_if_free = await checkIfPersonDayIsFree(person_id, day_id) if (check_if_free) {mpa = 0} let check_betterment = check_if_free === getRenames("b").a ? true : false let block_name_mpa_value = document.createElement("div") block_name_mpa_value.innerHTML = mpa === 0 ? "" : person.mpa[day_id] block_name_mpa.style.zIndex = mpa === 0 ? "-1" : "0" block_name_mpa.appendChild(block_name_mpa_value) block_td_top.appendChild(block_name_mpa) let block_name_td_info = document.createElement("div") block_name_td_info.classList.add("td-info") let block_name_td_info_button = document.createElement("button") let info = ROSTER_PERSON_INFOS.find(i => i.day_id === day_id && i.id === person_id.toString())?.text info && info.length > 0 && block_name_td_info_button.classList.add("set") block_name_td_info_button.classList.add("button-info") block_name_td_info_button.setAttribute("onClick", `openPersonDayInfoInput(${person_id}, ${day_id}, this)`) block_name_td_info_button.setAttribute("title", "Informationen zu der Schicht hinzufügen") block_name_td_info_button.innerHTML = "i" block_name_td_info.appendChild(block_name_td_info_button) block_td_top.appendChild(block_name_td_info) let block_name_td_menu = document.createElement("div") let block_name_td_button = document.createElement("button") block_name_td_button.classList.add("button-menu", "hamburger") block_name_td_button.innerHTML = "" block_name_td_button.setAttribute("onClick", "openRosterPersonMenu("+person_id+", "+day_id+")") block_name_td_menu.classList.add("menu", "menu-"+person_id+"-day-"+day_id) block_td_top.appendChild(block_name_td_button) if (check_if_free) { block_name_td_button.setAttribute("disabled", "true") } block_td_top.appendChild(block_name_td_menu) block_td_top_bottom.appendChild(block_td_top) // bottom let block_td_bottom = document.createElement("div") block_td_bottom.classList.add("td-bottom") let block_name_break = document.createElement("div") block_name_break.setAttribute("title", "Pause heute") block_name_break.classList.add("break-today") block_name_break.innerHTML = breaks block_td_bottom.appendChild(block_name_break) let block_name_hours_today = document.createElement("div") block_name_hours_today.setAttribute("title", "Schichtstunden heute ohne MPA") block_name_hours_today.classList.add("hours-today") block_name_hours_today.innerHTML = check_betterment ? hours : hours-person.mpa[day_id] block_td_bottom.appendChild(block_name_hours_today) block_td_top_bottom .appendChild(block_td_bottom) block_td_name_hours_container.appendChild(block_td_top_bottom) // create table time block_tbody_row.setAttribute("onmouseover", `this.classList.add("hover");`) block_tbody_row.setAttribute("onmouseout", `this.classList.remove("hover");`) block_tbody_row.setAttribute("id", `Tr-${person_id}-day-${day_id}`) block_tbody_row.classList.add("tr-name-"+person_id) block_tbody_row.appendChild(block_name_td) // create table td callback_r = (name) => { let block_td_after = document.createElement("td") block_td_after.classList.add("td-name-after") block_td_after.innerHTML = name return block_td_after } let label = person.sl[day_id] roster.d.forEach((data, time_id) => { let time = data.t let block_times_td = document.createElement("td") let block_times_container = document.createElement("div") block_times_container.classList.add("container") let block_times_content block_times_td.setAttribute("person", person.name) block_times_td.setAttribute("time", time) block_times_td.classList.add("td-day-time") if (check_if_free === false) { block_times_content = document.createElement("div") block_times_content.classList.add("shiftmodify-buttons-container") let block_times_button_shift = document.createElement("button") block_times_button_shift.classList.add("roster-add-shift") if (label !== false) { block_times_button_shift.innerHTML = dbGet_shift_label_cut(label) } else { block_times_button_shift.innerHTML = "" } block_times_button_shift.setAttribute("title", `${person.name}\nNeue Schicht\n${timeToHHMM(time)}`) block_times_button_shift.setAttribute("onClick", "addNewShiftToRoster("+person_id+", "+day_id+", "+time+")") block_times_content.appendChild(block_times_button_shift) block_times_container.appendChild(block_times_content) } else { block_times_td.classList.add("free") block_times_content = document.createElement("p") block_times_content.innerHTML = check_if_free block_times_container.innerHTML = "" block_times_container.appendChild(block_times_content) } block_times_td.appendChild(block_times_container) block_tbody_row.appendChild(block_times_td) if (time_id === roster.d.length-1) block_tbody_row.appendChild(callback_r(person.name)) if (shifts.find(s => s.start <= time && s.end >time)) { block_times_td.classList.add("assigned") } }) } renderRosterSort = () => { let block_roster_container = document.getElementById("Roster-days-container") let block = document.createElement("div") let block_remove = document.querySelector("#Sort-roster-by") block.setAttribute("id", "Sort-roster-by") block.classList.add("settings-box") let block_box = document.createElement("div") block_box.classList.add("sort-box") let block_name = document.createElement("button") block_name.setAttribute("id", "Sort-roster-by-name") block_name.classList.add("sort-roster-by", "sort") block_name.setAttribute("name", "n") block_name.setAttribute("onClick", "sortRosterBy('days', this)") block_name.innerHTML = "Name" let block_dep = document.createElement("button") block_dep.setAttribute("id", "Sort-roster-by-department") block_dep.classList.add("sort-roster-by", "sort") block_dep.setAttribute("name", "d") block_dep.setAttribute("onClick", "sortRosterBy('days', this)") block_dep.innerHTML = "Bereich" let block_hou = document.createElement("button") block_hou.setAttribute("id", "Sort-roster-by-hours") block_hou.classList.add("sort-roster-by", "sort") block_hou.setAttribute("name", "h") block_hou.setAttribute("onClick", "sortRosterBy('days', this)") block_hou.innerHTML = "Stunden" if (block_remove) block_roster_container.removeChild(block_remove) block_box.appendChild(block_name) block_box.appendChild(block_dep) block_box.appendChild(block_hou) block.appendChild(block_box) block_roster_container.appendChild(block) setRosterSortButtons(0) } loadRosterTable = async () => { let block_roster_container = document.getElementById("Roster-days-container") block_roster_container.innerHTML = "" renderRosterSort() let day = structuredClone(DATE) day.setDate(day.getDate() - 1) for (let day_id=0; day_id block_button_copy_from.appendChild(block)) block_container_copy_from_to.appendChild(block_button_copy_from) let block_button_copy_to = document.createElement("select") block_button_copy_to.classList.add("select-copy-to", "select-copy") block_button_copy_to.setAttribute("title", "Den gesamten Plan dieses Tages, auf einen Anderen Tag übertragen.\nDies löscht alle vorhandenen Schichten des zieltages.") block_button_copy_to.setAttribute("onchange", "copyRosterDay(this.value, "+day_id+")") block_button_copy_to.innerHTML = '' createDaysOption(day_id).forEach(block => block_button_copy_to.appendChild(block)) let block_copy_to_all = document.createElement("option") block_copy_to_all.setAttribute("value", "all") block_copy_to_all.innerHTML = "Alle" block_button_copy_to.appendChild(block_copy_to_all) block_container_copy_from_to.appendChild(block_button_copy_to) block_container_roster_head.appendChild(block_container_copy_from_to) let block_table_container = document.createElement("div") block_table_container.setAttribute("id", "Table-"+day_id+"-container") block_table_container.classList.add("tables-container") let block_button_edit_table = document.createElement("button") block_button_edit_table.setAttribute("onClick", `loadEditableDataIntoRosterTable(this, ${day_id})`) block_button_edit_table.classList.add("button-edit-table") let block_button_edit_table_text = document.createElement("div") block_button_edit_table_text.innerHTML = "Bearbeiten" block_button_edit_table.appendChild(block_button_edit_table_text) block_table_container.appendChild(block_button_edit_table) let block_table = document.createElement("table") block_table.classList.add("table-times") let block_thead = document.createElement("thead") let block_tbody = document.createElement("tbody") let block_thead_row = document.createElement("tr") block_thead_row.setAttribute("id", "Table-times-thead-tr-"+day_id) let block_time_scroll = document.createElement("div") block_time_scroll.classList.add("time-scroll-container") block_container_roster_head.appendChild(block_time_scroll) block_container_roster.appendChild(block_container_roster_head) let block_button_remove = document.createElement("button") block_button_remove.innerHTML = "löschen" block_button_remove.classList.add("button-remove-day-shifts", "button-remove") block_button_remove.setAttribute("onClick", "requestRemoveDayShifts("+day_id+")") block_container_roster_head.appendChild(block_button_remove) let block_th_name = document.createElement("th") let block_th_name_day = document.createElement("div") block_th_name_day.innerHTML = DAYS[day_id] block_th_name.appendChild(block_th_name_day) block_thead_row.appendChild(block_th_name) block_thead.appendChild(block_thead_row) block_table.appendChild(block_thead) block_table.appendChild(block_tbody) block_table_container.appendChild(block_table) block_container_roster.appendChild(block_table_container) block_roster_container.appendChild(block_container_roster) for (let time_id=0; time_id= colors_red_orange_green.length) color = colors_red_orange_green[colors_red_orange_green.length-1] if (amount > time.a) color = "#458caf" else if (amount === time.a) color = "#61a64d" block_th.setAttribute("style", `background-color: ${color}; border-color: ${color}87;`) block_th_amount_is.innerHTML = amount+"/" } let time_last = timeToHHMM(ROSTER[day_id].d[ROSTER[day_id].d.length-1].t+TIME_STEP) let block_th = document.createElement("th") block_th.setAttribute("colspan", "2") let block_th_p = document.createElement("p") block_th_p.innerHTML = time_last block_th_p.classList.add("time") block_th.classList.add("th-day-time") block_th.appendChild(block_th_p) block_thead_row.appendChild(block_th) let log_date = performance.now() for (let pr=0; pr { showLoading("toggleTableWeekEditeable") let year_week = DATE_YEAR_WEEK let table_id = EDITABLE_TABLES.indexOf(table_name) if (table_id > -1) { EDITABLE_TABLES.splice(table_id, 1) } else { EDITABLE_TABLES.push(table_name) } if (document.querySelector("#Popup .item-table-to .select-roster")) { year_week = document.querySelector("#Popup .item-table-to .select-roster").value } loadRosterTableWeekData(year_week, table_name).then(() => { hideLoading("toggleTableWeekEditeable") }) }