222 lines
10 KiB
Plaintext
222 lines
10 KiB
Plaintext
package templates
|
|
|
|
import (
|
|
"arbeitszeitmessung/helper"
|
|
"arbeitszeitmessung/models"
|
|
"fmt"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
templ inputForm() {
|
|
{{
|
|
urlParams := ctx.Value("urlParams").(url.Values)
|
|
user := ctx.Value("user").(models.User)
|
|
}}
|
|
<div class="grid-sub divide-x-1 bg-neutral-300 max-md:flex max-md:flex-col">
|
|
<div class="grid-cell md:col-span-1 max-md:grid grid-cols-2">
|
|
<p class="font-bold uppercase">{ user.Vorname + " " + user.Name }</p>
|
|
<div class="justify-self-end">
|
|
<p class="text-sm">Überstunden</p>
|
|
<p class="text-accent">{ user.Overtime }</p>
|
|
</div>
|
|
</div>
|
|
<form id="timeRangeForm" method="GET" class="grid-cell flex flex-row md:col-span-3 gap-2 ">
|
|
@lineComponent()
|
|
<div class="flex flex-col gap-2 justify-between grow-1">
|
|
<input type="date" value={ urlParams.Get("time_from") } name="time_from" class="w-full bg-neutral-100 placeholder:text-neutral-400 text-neutral-700 text-sm border border-neutral-0 rounded-md px-3 py-2 transition duration-300 ease focus:outline-none focus:border-neutral-400 hover:border-neutral-300" placeholder="Zeitraum von..."/>
|
|
<input type="date" value={ urlParams.Get("time_to") } name="time_to" class="w-full bg-neutral-100 placeholder:text-neutral-400 text-neutral-700 text-sm border border-neutral-0 rounded-md px-3 py-2 transition duration-300 ease focus:outline-none focus:border-neutral-400 hover:border-neutral-300" placeholder="Zeitraum bis..."/>
|
|
</div>
|
|
</form>
|
|
<div class="grid-cell content-end">
|
|
<button type="submit" form="timeRangeForm" class="btn bg-neutral-100 hover:bg-neutral-700 color-neutral-700">
|
|
<p class="">Anzeigen</p>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
templ defaultDayComponent(day models.IWorkDay) {
|
|
if day.IsWorkDay() {
|
|
{{
|
|
workDay, _ := day.(*models.WorkDay)
|
|
}}
|
|
@workDayComponent(*workDay, false)
|
|
} else {
|
|
{{
|
|
absentDay, _ := day.(*models.Absence)
|
|
}}
|
|
<div class={ "grid-sub divide-x-1 hover:bg-neutral-200 transition-colors" }>
|
|
<div class="grid-cell md:col-span-1 flex flex-row gap-2">
|
|
@timeGaugeComponent(100, false)
|
|
<p><span class="font-bold uppercase hidden md:inline">{ day.Date().Format("Mon") }:</span> { day.Date().Format("02.01.2006") }</p>
|
|
</div>
|
|
<div class="grid-cell flex flex-row md:col-span-3 gap-2 w-full">
|
|
@lineComponent()
|
|
<div class="flex flex-col gap-2 group w-full justify-center">
|
|
<p>{ absentDay.AbwesenheitTyp.Name } <span class="text-neutral-700">bis { absentDay.DateTo.Format("02.01.2006") }</span></p>
|
|
</div>
|
|
</div>
|
|
<div class="grid-cell">
|
|
@changeButtonComponent("time-" + absentDay.Date().Format("2006-01-02"))
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
|
|
templ workDayComponent(workDay models.WorkDay, submitted bool) {
|
|
{{
|
|
// work, pause := workDay.GetWorkTimeString()
|
|
user := ctx.Value("user").(models.User)
|
|
work, pause, overtime := workDay.GetAllWorkTimesReal(user)
|
|
// overtime := helper.FormatDuration(workDay.CalcOvertime(user))
|
|
justify := ""
|
|
if len(workDay.Bookings) <= 1 {
|
|
justify = "justify-content: center"
|
|
}
|
|
}}
|
|
<div class={ "grid-sub divide-x-1 hover:bg-neutral-200 transition-colors", templ.KV("bg-neutral-100", submitted) }>
|
|
<div class="grid-cell md:col-span-1 flex flex-row gap-2">
|
|
@timeGaugeComponent(workDay.GetDayProgress(user), workDay.Day.Equal(time.Now().Truncate(24*time.Hour)))
|
|
<div>
|
|
<p class=""><span class="font-bold uppercase hidden md:inline">{ workDay.Day.Format("Mon") }:</span> { workDay.Day.Format("02.01.2006") }</p>
|
|
if (workDay.RequiresAction()) {
|
|
<p class="text-red-600">Bitte anpassen</p>
|
|
} else {
|
|
if work > 0 {
|
|
<p class=" text-sm mt-1">Arbeitszeit:</p>
|
|
<p class="text-accent flex flex-row items-center"><span class="icon-[material-symbols-light--nest-clock-farsight-analog-outline]"></span>{ helper.FormatDuration(work) }</p>
|
|
}
|
|
if pause > 0 {
|
|
<p class="text-neutral-500 flex flex-row items-center"><span class="icon-[material-symbols-light--motion-photos-paused-outline]"></span>{ helper.FormatDuration(pause) }</p>
|
|
}
|
|
if overtime > 0 {
|
|
<p class="text-neutral-500 flex flex-row items-center"><span class="icon-[material-symbols-light--more-time]"></span>{ helper.FormatDuration(overtime) }</p>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="all-booking-component flex flex-row md:col-span-3 gap-2 w-full grid-cell">
|
|
@lineComponent()
|
|
<form id={ "time-" + workDay.Day.Format("2006-01-02") } class="flex flex-col gap-2 group w-full justify-between" style={ justify } method="post">
|
|
if len(workDay.Bookings) < 1 {
|
|
<p class="text group-[.edit]:hidden">Keine Buchung gefunden. Bitte Arbeitsstunden oder Grund der Abwesenheit eingeben!</p>
|
|
@absenceComponent(workDay)
|
|
@newBookingComponent(workDay)
|
|
} else {
|
|
@absenceComponent(workDay)
|
|
for _, booking := range workDay.Bookings {
|
|
@bookingComponent(booking)
|
|
}
|
|
if workDay.IsKurzArbeit() {
|
|
<p>Kurzarbeit</p>
|
|
}
|
|
@newBookingComponent(workDay)
|
|
}
|
|
<input type="hidden" name="action" value="change"/> <!-- default action value for ändern button -->
|
|
</form>
|
|
</div>
|
|
<div class="grid-cell">
|
|
@changeButtonComponent("time-" + workDay.Day.Format("2006-01-02"))
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
templ changeButtonComponent(id string) {
|
|
<button class="btn w-auto group" type="submit" onclick={ templ.JSFuncCall("editDay", templ.JSExpression("this"), templ.JSExpression("event"), id) }>
|
|
<p class="hidden md:block group-[.edit]:hidden">Ändern</p>
|
|
<p class="hidden group-[.edit]:md:block">Absenden</p>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-4 h-4 md:hidden">
|
|
<path class="group-[.edit]:hidden md:hidden" d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325"></path>
|
|
<path class="hidden group-[.edit]:block md:hidden" d="M12.736 3.97a.733.733 0 0 1 j1.047 0c.286.289.29.756.01 1.05L7.88 12.01a.733.733 0 0 1-1.065.02L3.217 8.384a.757.757 0 0 1 0-1.06.733.733 0 0 1 1.047 0l3.052 3.093 5.4-6.425z"></path>
|
|
</svg>
|
|
</button>
|
|
}
|
|
|
|
templ timeGaugeComponent(progress int8, today bool) {
|
|
{{
|
|
var bgColor string
|
|
switch {
|
|
case (0 > progress):
|
|
bgColor = "bg-red-600"
|
|
break
|
|
case (progress > 0 && progress < 95):
|
|
bgColor = "bg-orange-500"
|
|
break
|
|
case (95 <= progress && progress <= 105):
|
|
bgColor = "bg-accent"
|
|
break
|
|
case (progress > 105):
|
|
bgColor = "bg-purple-600"
|
|
break
|
|
default:
|
|
bgColor = "bg-neutral-400"
|
|
break
|
|
}
|
|
}}
|
|
if today {
|
|
<div class="flex-start flex w-2 h-full overflow-hidden rounded-full bg-neutral-300 print:hidden">
|
|
<div class={ "flex w-full items-center justify-center overflow-hidden rounded-full", bgColor } style={ fmt.Sprintf("height: %d%%", int(progress)) }></div>
|
|
</div>
|
|
} else {
|
|
<div class={ "w-2 h-full bg-accent rounded-md flex-shrink-0", bgColor }></div>
|
|
}
|
|
}
|
|
|
|
templ lineComponent() {
|
|
<div class="flex flex-col w-2 py-2 items-center text-accent print:hidden">
|
|
<svg class="size-2" viewBox="0 0 24 24" fill="currentColor">
|
|
<polygon points="12,2 22,12 12,22 2,12"></polygon>
|
|
</svg>
|
|
<div class="w-[2px] bg-accent flex-grow -my-1"></div>
|
|
<svg class="size-2" viewBox="0 0 24 24" fill="currentColor">
|
|
<polygon points="12,2 22,12 12,22 2,12"></polygon>
|
|
</svg>
|
|
</div>
|
|
}
|
|
|
|
templ absenceComponent(d models.WorkDay) {
|
|
<div class="no-booking-component hidden group-[.edit]:flex flex-col gap-2 align-center">
|
|
<select name="absence" onchange={ templ.JSFuncCall("editAbwesenheit", templ.JSExpression("this"), templ.JSExpression("event")) } class="grow cursor-pointer rounded-md text-neutral-800 p-2 md:px-4 border text-center text-sm transition-colors border-neutral-900" disabled>
|
|
<option value="0">Abwesenheit?</option>
|
|
for _, absence := range models.GetAbsenceTypesCached() {
|
|
<option value={ strconv.Itoa(int(absence.Id)) }>{ absence.Name }</option>
|
|
}
|
|
</select>
|
|
</div>
|
|
}
|
|
|
|
templ newBookingComponent(d models.WorkDay) {
|
|
<div class="new-booking-component hidden group-[.edit]:flex flex-row gap-2 items-center">
|
|
<button name="action" value="add" type="submit" class="hover:text-accent cursor-pointer icon-[material-symbols-light--add-circle-outline]"></button>
|
|
<input name="timestamp" type="time" value={ time.Now().Format("15:04") } class="text-neutral-700 group-[.edit]:inline hidden bg-neutral-100 text-sm border border-neutral-200 rounded-md px-3 py-2 transition duration-300 ease focus:outline-none focus:border-neutral-400 hover:border-neutral-300"/>
|
|
<input name="date" type="hidden" value={ d.Day.Format("2006-01-02") }/>
|
|
<select name="check_in_out">
|
|
<option value="0" disabled>Kommen/Gehen</option>
|
|
<option value="3" selected?={ len(d.Bookings) > 0 && d.Bookings[len(d.Bookings)-1].CheckInOut%2 == 0 }>Kommen</option>
|
|
<option value="4" selected?={ len(d.Bookings) > 0 && d.Bookings[len(d.Bookings)-1].CheckInOut%2 == 1 }>Gehen</option>
|
|
</select>
|
|
</div>
|
|
}
|
|
|
|
templ bookingComponent(booking models.Booking) {
|
|
<div>
|
|
<p class="text-neutral-500">
|
|
<span class="text-neutral-700 group-[.edit]:hidden inline">{ booking.Timestamp.Format("15:04") }</span>
|
|
<input disabled name={ "booking_" + strconv.Itoa(booking.CounterId) } type="time" value={ booking.Timestamp.Format("15:04") } class="text-neutral-700 group-[.edit]:inline hidden bg-neutral-100 text-sm border border-neutral-200 rounded-md px-3 py-2 transition duration-300 ease focus:outline-none focus:border-neutral-400 hover:border-neutral-300"/>
|
|
{ booking.GetBookingType() }
|
|
</p>
|
|
</div>
|
|
}
|
|
|
|
templ LegendComponent() {
|
|
<div class="flex flex-row gap-4 md:mx-[10%] print:hidden">
|
|
<div class="flex flex-row items-center gap-2"><div class="rounded-full size-4 bg-red-600"></div><span>Fehler</span></div>
|
|
<div class="flex flex-row items-center gap-2"><div class="rounded-full size-4 bg-orange-500"></div><span>Arbeitszeit unter regulär</span></div>
|
|
<div class="flex flex-row items-center gap-2"><div class="rounded-full size-4 bg-accent"></div><span>Arbeitszeit vollständig</span></div>
|
|
<div class="flex flex-row items-center gap-2"><div class="rounded-full size-4 bg-purple-600"></div><span>Überstunden</span></div>
|
|
<div class="flex flex-row items-center gap-2"><div class="rounded-full size-4 bg-neutral-400"></div><span>Keine Buchungen</span></div>
|
|
</div>
|
|
}
|