diff --git a/Backend/endpoints/time.go b/Backend/endpoints/time.go index 0be3f67..b92d3b5 100644 --- a/Backend/endpoints/time.go +++ b/Backend/endpoints/time.go @@ -5,6 +5,7 @@ import ( "arbeitszeitmessung/models" "arbeitszeitmessung/templates" "context" + "database/sql" "encoding/json" "log" "net/http" @@ -30,6 +31,22 @@ func TimeHandler(w http.ResponseWriter, r *http.Request) { } } +func AbsencHandler(w http.ResponseWriter, r *http.Request) { + helper.RequiresLogin(Session, w, r) + helper.SetCors(w) + switch r.Method { + case http.MethodPost: + err := updateAbsence(r) + if err != nil { + http.Error(w, "Internal error", http.StatusInternalServerError) + return + } + http.Redirect(w, r, "/time", 301) + default: + http.Error(w, "Method not allowed!", http.StatusMethodNotAllowed) + } +} + func parseTimestamp(r *http.Request, getKey string, fallback string) (time.Time, error) { getTimestamp := r.URL.Query().Get(getKey) if getTimestamp == "" { @@ -165,6 +182,84 @@ func updateBooking(w http.ResponseWriter, r *http.Request) { getBookings(w, r) } +func updateAbsence(r *http.Request) error { + r.ParseForm() + var loc *time.Location + loc, err := time.LoadLocation(helper.GetEnv("TZ", "Europe/Berlin")) + if err != nil { + log.Println("Error loading location", err) + loc = time.Local + } + + dateFrom, err := time.ParseInLocation("2006-01-02", r.FormValue("date_from"), loc) + if err != nil { + log.Println("Error parsing date_from input for absence", err) + return err + } + + dateTo, err := time.ParseInLocation("2006-01-02", r.FormValue("date_to"), loc) + if err != nil { + log.Println("Error parsing date_to input for absence", err) + return err + } + + absenceTypeId, err := strconv.Atoi(r.FormValue("aw_type")) + if err != nil { + log.Println("Error parsing aw_type", err) + return err + } + + absenceId, err := strconv.Atoi(r.FormValue("aw_id")) + if err != nil && r.FormValue("aw_id") == "" { + absenceId = 0 + } else if err != nil { + log.Println("Error parsing aw_id", err) + return err + } + + absenceType, err := models.GetAbsenceTypeById(int8(absenceTypeId)) + if err != nil { + log.Println("No matching absence type found!") + return err + } + + newAbsence := models.Absence{DateFrom: dateFrom, DateTo: dateTo, AbwesenheitTyp: absenceType} + + absence, err := models.GetAbsenceById(absenceId) + if err == sql.ErrNoRows { + err = nil + log.Println("Absence not found creating new!") + + user, err := models.GetUserFromSession(Session, r.Context()) + if err != nil { + log.Println("No user found!", err) + return err + } + newAbsence.CardUID = user.CardUID + newAbsence.Insert() + } + if err != nil { + log.Println("Cannot get Absence for id: ", absenceId, err) + return err + } + if r.FormValue("action") == "delete" { + log.Println("Deleting Absence!", "Not implemented") + // TODO + //absence.Delete() + return nil + } + + if absence.Update(newAbsence) { + err = absence.Save() + if err != nil { + log.Println("Error saving updated absence!", err) + return err + } + } + return nil + +} + func createAbsence(absenceType int, user models.User, loc *time.Location, r *http.Request) { absenceDate, err := time.ParseInLocation("2006-01-02", r.FormValue("date"), loc) if err != nil { diff --git a/Backend/main.go b/Backend/main.go index 98a5e22..35395e2 100644 --- a/Backend/main.go +++ b/Backend/main.go @@ -43,6 +43,7 @@ func main() { // handles the different http routes server.HandleFunc("/time/new", endpoints.TimeCreateHandler) + server.Handle("/absence", ParamsMiddleware(endpoints.AbsencHandler)) server.Handle("/time", ParamsMiddleware(endpoints.TimeHandler)) server.HandleFunc("/logout", endpoints.LogoutHandler) server.HandleFunc("/user/{action}", endpoints.UserHandler) diff --git a/Backend/models/absence.go b/Backend/models/absence.go index b0fb959..7d9e913 100644 --- a/Backend/models/absence.go +++ b/Backend/models/absence.go @@ -109,6 +109,23 @@ func (a *Absence) Insert() error { return nil } +func (a *Absence) Save() error { + qStr, err := DB.Prepare(` + UPDATE abwesenheit SET card_uid = $2, abwesenheit_typ = $3, datum_from = $4, datum_to = $5 WHERE counter_id = $1; + `) + if err != nil { + log.Println("Error preparing sql Statement (Absence Save)", err) + return err + } + defer qStr.Close() + _, err = qStr.Query(a.CounterId, a.CardUID, a.AbwesenheitTyp.Id, a.DateFrom, a.DateTo) + if err != nil { + log.Println("Error executing update statement", err) + return err + } + return nil +} + func GetAbsenceById(counterId int) (Absence, error) { var absence Absence = Absence{CounterId: counterId} qStr, err := DB.Prepare("SELECT card_uid, abwesenheit_typ, datum_from, datum_to FROM abwesenheit WHERE counter_id = $1;") @@ -179,6 +196,27 @@ func GetAbsencesByCardUID(card_uid string, tsFrom time.Time, tsTo time.Time) ([] return absences, nil } +func (a *Absence) Update(na Absence) bool { + change := false + if a.CardUID != na.CardUID && na.CardUID != "" { + a.CardUID = na.CardUID + change = true + } + if a.AbwesenheitTyp != na.AbwesenheitTyp && na.AbwesenheitTyp.Id != 0 { + a.AbwesenheitTyp = na.AbwesenheitTyp + change = true + } + if !a.DateFrom.Equal(na.DateFrom) && !na.DateFrom.IsZero() { + a.DateFrom = na.DateFrom + change = true + } + if !a.DateTo.Equal(na.DateTo) && !na.DateTo.IsZero() { + a.DateTo = na.DateTo + change = true + } + return change +} + func GetAbsenceTypes() (map[int8]AbsenceType, error) { var types = make(map[int8]AbsenceType) qStr, err := DB.Prepare("SELECT abwesenheit_id, abwesenheit_name, arbeitszeit_equivalent FROM s_abwesenheit_typen;") diff --git a/Backend/models/workDay.go b/Backend/models/workDay.go index 51025b9..5a99af4 100644 --- a/Backend/models/workDay.go +++ b/Backend/models/workDay.go @@ -24,15 +24,16 @@ type IWorkDay interface { } type WorkDay struct { - Day time.Time `json:"day"` - Bookings []Booking `json:"bookings"` - workTime time.Duration - pauseTime time.Duration - realWorkTime time.Duration - realPauseTime time.Duration - TimeFrom time.Time - TimeTo time.Time - kurzArbeit bool + Day time.Time `json:"day"` + Bookings []Booking `json:"bookings"` + workTime time.Duration + pauseTime time.Duration + realWorkTime time.Duration + realPauseTime time.Duration + TimeFrom time.Time + TimeTo time.Time + kurzArbeit bool + kurzArbeitAbsence Absence } func GetDays(user User, tsFrom, tsTo time.Time, orderedForward bool) []IWorkDay { @@ -53,6 +54,7 @@ func GetDays(user User, tsFrom, tsTo time.Time, orderedForward bool) []IWorkDay if day.AbwesenheitTyp.WorkTime == 1 { if workDay, ok := allDays[day.Date().Format("2006-01-02")].(*WorkDay); ok { workDay.kurzArbeit = true + workDay.kurzArbeitAbsence = day } } else { allDays[day.Date().Format("2006-01-02")] = &day @@ -85,6 +87,10 @@ func (d *WorkDay) TimeWorkVirtual(u User) time.Duration { return d.workTime } +func (d *WorkDay) GetKurzArbeit() Absence { + return d.kurzArbeitAbsence +} + func (d *WorkDay) TimeWorkReal(u User) time.Duration { d.realWorkTime, d.realPauseTime = 0, 0 var lastBooking Booking diff --git a/Backend/src/main.css b/Backend/src/main.css index 85ae31e..9afdfb3 100644 --- a/Backend/src/main.css +++ b/Backend/src/main.css @@ -1,120 +1,127 @@ @import "tailwindcss"; @source "../templates/*.templ"; @plugin "@iconify/tailwind4" { - scale: 1.25; + scale: 1.25; } @theme { - --color-accent-50: #e7fdea; - --color-accent-100: #cbfbd1; - --color-accent-200: #9cf7a8; - --color-accent-300: #68f37a; - --color-accent-400: #33ef4d; - --color-accent-500: #11db2d; - --color-accent-600: #0eaf23; - --color-accent-700: #0a851b; - --color-accent-800: #075a12; - --color-accent-900: #032b09; - --color-accent-950: #021805; - --color-accent: #0eaf23; - --color-text-50: #f7f8f7; - --color-text-100: #f2f3f2; - --color-text-200: #e2e4e2; - --color-text-300: #d2d6d2; - --color-text-400: #c2c7c2; - --color-text-500: #afb6af; - --color-text-600: #97a097; - --color-text-700: #7d877d; - --color-text-800: #5a625a; - --color-text-900: #161816; - --color-text-950: #000000; + --color-accent-50: #e7fdea; + --color-accent-100: #cbfbd1; + --color-accent-200: #9cf7a8; + --color-accent-300: #68f37a; + --color-accent-400: #33ef4d; + --color-accent-500: #11db2d; + --color-accent-600: #0eaf23; + --color-accent-700: #0a851b; + --color-accent-800: #075a12; + --color-accent-900: #032b09; + --color-accent-950: #021805; + --color-accent: #0eaf23; + --color-text-50: #f7f8f7; + --color-text-100: #f2f3f2; + --color-text-200: #e2e4e2; + --color-text-300: #d2d6d2; + --color-text-400: #c2c7c2; + --color-text-500: #afb6af; + --color-text-600: #97a097; + --color-text-700: #7d877d; + --color-text-800: #5a625a; + --color-text-900: #161816; + --color-text-950: #000000; } @layer base { - body { - -webkit-print-color-adjust: exact !important; - print-color-adjust: exact !important; - } + body { + -webkit-print-color-adjust: exact !important; + print-color-adjust: exact !important; + background-color: white; + } } @layer components { - .grid-main { - display: grid; - grid-template-columns: 2fr auto 1fr; - align-items: stretch; - } - - .grid-sub { - display: grid; - grid-template-columns: subgrid; - grid-column: 1 / -1; - border-color: var(--color-neutral-400); - transition: background-color 0.2s ease-in-out; - } - - .grid-sub.responsive { - display: flex; - flex-direction: column; - } - - .grid-sub:hover { - background-color: var(--color-neutral-200); - } - - .grid-cell { - padding: calc(var(--spacing) * 2); - border-color: var(--color-neutral-400); - } - - .btn { - width: 100%; - cursor: pointer; - border-radius: var(--radius-md); - color: var(--color-neutral-800); - font-size: var(--text-sm); - text-align: center; - padding: calc(var(--spacing) * 2); - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-neutral-800); - transition-property: - color, background-color, border-color, outline-color, - text-decoration-color, fill, stroke, --tw-gradient-from, - --tw-gradient-via, --tw-gradient-to; - transition-timing-function: var( - --tw-ease, - var(--default-transition-timing-function) - ); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - } - - .btn:hover { - color: var(--color-white); - background-color: var(--color-neutral-700); - } - - .btn:disabled { - opacity: 50%; - pointer-events: none; - } - - .btn:active, - .btn:focus { - background-color: var(--color-neutral-700); - } - - @media (width >=48rem) { .grid-main { - grid-template-columns: repeat(5, 1fr); - margin: 0 10%; + display: grid; + grid-template-columns: 4fr 6fr 1fr; + align-items: stretch; + } + + .grid-sub { + display: grid; + grid-template-columns: subgrid; + grid-column: 1 / -1; + border-color: var(--color-neutral-400); + transition: background-color 0.2s ease-in-out; } .grid-sub.responsive { - display: grid; + display: flex; + flex-direction: column; + } + + .grid-sub:hover { + background-color: var(--color-neutral-200); + } + + .grid-cell { + padding: calc(var(--spacing) * 2); + border-color: var(--color-neutral-400); } .btn { - padding-inline: calc(var(--spacing) * 4); + width: 100%; + cursor: pointer; + border-radius: var(--radius-md); + color: var(--color-neutral-800); + font-size: var(--text-sm); + text-align: center; + padding: calc(var(--spacing) * 2); + border-style: var(--tw-border-style); + border-width: 1px; + border-color: var(--color-neutral-800); + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + + input.btn, + select.btn { + transition-duration: 300ms; + } + + .btn:hover { + color: var(--color-white); + background-color: var(--color-neutral-700); + } + + .btn:disabled { + opacity: 50%; + pointer-events: none; + } + + input.btn, + select.btn { + text-align: left; + } + + input.btn:hover, + select.btn:hover { + border-color: var(--color-neutral-300); + background-color: var(--color-neutral-100); + color: var(--color-neutral-800); + } + + @media (width >=48rem) { + .grid-main { + grid-template-columns: repeat(5, 1fr); + margin: 0 10%; + } + + .grid-sub.responsive { + display: grid; + } + + .btn { + padding-inline: calc(var(--spacing) * 4); + } } - } } diff --git a/Backend/static/css/styles.css b/Backend/static/css/styles.css index 143d6f3..1e919bf 100644 --- a/Backend/static/css/styles.css +++ b/Backend/static/css/styles.css @@ -9,8 +9,10 @@ "Courier New", monospace; --color-red-500: oklch(63.7% 0.237 25.331); --color-red-600: oklch(57.7% 0.245 27.325); + --color-red-700: oklch(50.5% 0.213 27.518); --color-orange-500: oklch(70.5% 0.213 47.604); --color-purple-600: oklch(55.8% 0.288 302.321); + --color-slate-700: oklch(37.2% 0.044 257.287); --color-neutral-100: oklch(97% 0 0); --color-neutral-200: oklch(92.2% 0 0); --color-neutral-300: oklch(87% 0 0); @@ -190,9 +192,24 @@ .\@container { container-type: inline-size; } + .absolute { + position: absolute; + } .relative { position: relative; } + .top-2 { + top: calc(var(--spacing) * 2); + } + .top-2\.5 { + top: calc(var(--spacing) * 2.5); + } + .right-2 { + right: calc(var(--spacing) * 2); + } + .right-2\.5 { + right: calc(var(--spacing) * 2.5); + } .col-span-2 { grid-column: span 2 / span 2; } @@ -211,9 +228,15 @@ .mt-1 { margin-top: calc(var(--spacing) * 1); } + .mb-1 { + margin-bottom: calc(var(--spacing) * 1); + } .mb-2 { margin-bottom: calc(var(--spacing) * 2); } + .ml-1 { + margin-left: calc(var(--spacing) * 1); + } .icon-\[material-symbols-light--add-circle-outline\] { display: inline-block; width: 1.25em; @@ -253,6 +276,19 @@ mask-size: 100% 100%; --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='black' d='M12.003 21q-1.866 0-3.51-.708q-1.643-.709-2.859-1.924t-1.925-2.856T3 12.003t.709-3.51Q4.417 6.85 5.63 5.634t2.857-1.925T11.997 3t3.51.709q1.643.708 2.859 1.922t1.925 2.857t.709 3.509t-.708 3.51t-1.924 2.859t-2.856 1.925t-3.509.709M12 20q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4T6.325 6.325T4 12t2.325 5.675T12 20m0-8'/%3E%3C/svg%3E"); } + .icon-\[material-symbols-light--delete-outline\] { + display: inline-block; + width: 1.25em; + height: 1.25em; + background-color: currentColor; + -webkit-mask-image: var(--svg); + mask-image: var(--svg); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 100% 100%; + mask-size: 100% 100%; + --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='black' d='M7.616 20q-.672 0-1.144-.472T6 18.385V6H5V5h4v-.77h6V5h4v1h-1v12.385q0 .69-.462 1.153T16.384 20zM17 6H7v12.385q0 .269.173.442t.443.173h8.769q.23 0 .423-.192t.192-.424zM9.808 17h1V8h-1zm3.384 0h1V8h-1zM7 6v13z'/%3E%3C/svg%3E"); + } .icon-\[material-symbols-light--more-time\] { display: inline-block; width: 1.25em; @@ -292,6 +328,22 @@ mask-size: 100% 100%; --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='black' d='M14.935 16.223L11.5 12.789V7.923h1v4.464l3.123 3.123zM11.5 6V4h1v2zm6.5 6.5v-1h2v1zM11.5 20v-2h1v2zM4 12.5v-1h2v1zm8.003 8.5q-1.867 0-3.51-.708q-1.643-.709-2.859-1.924t-1.925-2.856T3 12.003t.709-3.51Q4.417 6.85 5.63 5.634t2.857-1.925T11.997 3t3.51.709q1.643.708 2.859 1.922t1.925 2.857t.709 3.509t-.708 3.51t-1.924 2.859t-2.856 1.925t-3.509.709M12 20q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4T6.325 6.325T4 12t2.325 5.675T12 20m0-8'/%3E%3C/svg%3E"); } + .icon-\[material-symbols-light--schedule-outline\] { + display: inline-block; + width: 1.25em; + height: 1.25em; + background-color: currentColor; + -webkit-mask-image: var(--svg); + mask-image: var(--svg); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 100% 100%; + mask-size: 100% 100%; + --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='black' d='m15.646 16.354l.708-.708l-3.854-3.854V7h-1v5.208zM12.003 21q-1.866 0-3.51-.708q-1.643-.709-2.859-1.924t-1.925-2.856T3 12.003t.709-3.51Q4.417 6.85 5.63 5.634t2.857-1.925T11.997 3t3.51.709q1.643.708 2.859 1.922t1.925 2.857t.709 3.509t-.708 3.51t-1.924 2.859t-2.856 1.925t-3.509.709M12 20q3.325 0 5.663-2.337T20 12t-2.337-5.663T12 4T6.337 6.338T4 12t2.338 5.663T12 20'/%3E%3C/svg%3E"); + } + .block { + display: block; + } .flex { display: flex; } @@ -315,12 +367,27 @@ width: calc(var(--spacing) * 4); height: calc(var(--spacing) * 4); } + .size-5 { + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + } + .size-6 { + width: calc(var(--spacing) * 6); + height: calc(var(--spacing) * 6); + } + .size-7 { + width: calc(var(--spacing) * 7); + height: calc(var(--spacing) * 7); + } .h-2 { height: calc(var(--spacing) * 2); } .h-4 { height: calc(var(--spacing) * 4); } + .h-5 { + height: calc(var(--spacing) * 5); + } .h-8 { height: calc(var(--spacing) * 8); } @@ -336,6 +403,12 @@ .w-4 { width: calc(var(--spacing) * 4); } + .w-5 { + width: calc(var(--spacing) * 5); + } + .w-9 { + width: calc(var(--spacing) * 9); + } .w-9\/10 { width: calc(9/10 * 100%); } @@ -348,9 +421,15 @@ .w-full { width: 100%; } + .flex-shrink { + flex-shrink: 1; + } .flex-shrink-0 { flex-shrink: 0; } + .shrink { + flex-shrink: 1; + } .flex-grow { flex-grow: 1; } @@ -360,9 +439,27 @@ .grow-1 { flex-grow: 1; } + .basis-\[content\] { + flex-basis: content; + } + .basis-auto { + flex-basis: auto; + } + .border-collapse { + border-collapse: collapse; + } .cursor-pointer { cursor: pointer; } + .resize { + resize: both; + } + .scroll-m-2 { + scroll-margin: calc(var(--spacing) * 2); + } + .appearance-none { + appearance: none; + } .break-after-page { break-after: page; } @@ -399,6 +496,9 @@ .items-center { align-items: center; } + .items-end { + align-items: flex-end; + } .justify-around { justify-content: space-around; } @@ -459,6 +559,10 @@ border-right-style: var(--tw-border-style); border-right-width: 0px; } + .border-r-1 { + border-right-style: var(--tw-border-style); + border-right-width: 1px; + } .border-b-0 { border-bottom-style: var(--tw-border-style); border-bottom-width: 0px; @@ -496,6 +600,9 @@ .bg-red-600 { background-color: var(--color-red-600); } + .mask-repeat { + mask-repeat: repeat; + } .p-1 { padding: calc(var(--spacing) * 1); } @@ -557,9 +664,19 @@ .text-red-600 { color: var(--color-red-600); } + .text-slate-700 { + color: var(--color-slate-700); + } .uppercase { text-transform: uppercase; } + .underline { + text-decoration-line: underline; + } + .outline { + outline-style: var(--tw-outline-style); + outline-width: 1px; + } .filter { filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } @@ -656,10 +773,17 @@ } } } - .hover\:bg-red-600 { + .hover\:bg-red-500 { &:hover { @media (hover: hover) { - background-color: var(--color-red-600); + background-color: var(--color-red-500); + } + } + } + .hover\:bg-red-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-red-700); } } } @@ -708,11 +832,6 @@ opacity: 50%; } } - .max-md\:flex { - @media (width < 48rem) { - display: flex; - } - } .max-md\:grid { @media (width < 48rem) { display: grid; @@ -723,11 +842,6 @@ display: none; } } - .max-md\:flex-col { - @media (width < 48rem) { - flex-direction: column; - } - } .max-md\:divide-y-1 { @media (width < 48rem) { :where(& > :not(:last-child)) { @@ -853,12 +967,13 @@ body { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; + background-color: white; } } @layer components { .grid-main { display: grid; - grid-template-columns: 2fr auto 1fr; + grid-template-columns: 4fr 6fr 1fr; align-items: stretch; } .grid-sub { @@ -891,9 +1006,12 @@ border-width: 1px; border-color: var(--color-neutral-800); transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to; - transition-timing-function: var( --tw-ease, var(--default-transition-timing-function) ); + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-duration: var(--tw-duration, var(--default-transition-duration)); } + input.btn, select.btn { + transition-duration: 300ms; + } .btn:hover { color: var(--color-white); background-color: var(--color-neutral-700); @@ -902,8 +1020,13 @@ opacity: 50%; pointer-events: none; } - .btn:active, .btn:focus { - background-color: var(--color-neutral-700); + input.btn, select.btn { + text-align: left; + } + input.btn:hover, select.btn:hover { + border-color: var(--color-neutral-300); + background-color: var(--color-neutral-100); + color: var(--color-neutral-800); } @media (width >=48rem) { .grid-main { @@ -937,6 +1060,11 @@ syntax: "*"; inherits: false; } +@property --tw-outline-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} @property --tw-blur { syntax: "*"; inherits: false; @@ -1001,6 +1129,7 @@ --tw-border-style: solid; --tw-divide-y-reverse: 0; --tw-font-weight: initial; + --tw-outline-style: solid; --tw-blur: initial; --tw-brightness: initial; --tw-contrast: initial; diff --git a/Backend/static/script.js b/Backend/static/script.js index 520ec52..e5f27bd 100644 --- a/Backend/static/script.js +++ b/Backend/static/script.js @@ -12,6 +12,30 @@ function editDay(element, event, formId) { } } +function editAbsence(element, event, absenceId) { + var form = document.getElementById("absence_form"); + console.log(absenceId); + + if (absenceId != 0) { + const fieldsToSync = ["date_from", "date_to", "aw_type", "aw_id"]; + + var dataForm = document.getElementById(absenceId); + + fieldsToSync.forEach((name) => { + const src = dataForm.querySelector(`[name=${name}]`); + const target = form.querySelector(`[name=${name}]`); + if (!src || !target) return; + target.value = src.value; + }); + } else { + var dataForm = element.closest(".grid-sub").querySelector(".all-booking-component > form"); + form.querySelector("[name=date_from]").value = dataForm.id.replace("time-", ""); + form.querySelector("[name=date_to]").value = dataForm.id.replace("time-", ""); + } + form.classList.remove("hidden"); + form.scrollIntoView({ behavior: "smooth", block: "start", inline: "nearest" }); +} + function editAbwesenheit(element, event) { var newBookingComponent = element.closest(".grid-sub").querySelector(".new-booking-component"); if (element.value == 0) { diff --git a/Backend/templates/headerComponent_templ.go b/Backend/templates/headerComponent_templ.go index 8e59160..aeef6ec 100644 --- a/Backend/templates/headerComponent_templ.go +++ b/Backend/templates/headerComponent_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.943 +// templ: version: v0.3.924 package templates //lint:file-ignore SA4006 This context is only used if a nested component is present. diff --git a/Backend/templates/pages.templ b/Backend/templates/pages.templ index 2b938bf..8ca8aff 100644 --- a/Backend/templates/pages.templ +++ b/Backend/templates/pages.templ @@ -1,9 +1,6 @@ package templates -import ( - "arbeitszeitmessung/models" - "time" -) +import "arbeitszeitmessung/models" templ Base() { @@ -15,25 +12,6 @@ templ Base() { } -templ TimePage(workDays []models.WorkDay, lastSub time.Time) { - {{ - allDays := ctx.Value("days").([]models.IWorkDay) - }} - @Base() - @headerComponent() -
- @inputForm() - for _, day := range allDays { - @defaultDayComponent(day) - // @dayComponent(day, day.Day.Before(lastSub)) - if (day.Date().Weekday() == time.Monday) { -
- } - } -
- @LegendComponent() -} - templ LoginPage(success bool, errorMsg string) { @Base()
diff --git a/Backend/templates/pages_templ.go b/Backend/templates/pages_templ.go index 0dbe185..3a54c9b 100644 --- a/Backend/templates/pages_templ.go +++ b/Backend/templates/pages_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.943 +// templ: version: v0.3.924 package templates //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -8,10 +8,7 @@ package templates import "github.com/a-h/templ" import templruntime "github.com/a-h/templ/runtime" -import ( - "arbeitszeitmessung/models" - "time" -) +import "arbeitszeitmessung/models" func Base() templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { @@ -42,7 +39,7 @@ func Base() templ.Component { }) } -func TimePage(workDays []models.WorkDay, lastSub time.Time) templ.Component { +func LoginPage(success bool, errorMsg string) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -63,101 +60,34 @@ func TimePage(workDays []models.WorkDay, lastSub time.Time) templ.Component { templ_7745c5c3_Var2 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - - allDays := ctx.Value("days").([]models.IWorkDay) templ_7745c5c3_Err = Base().Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = headerComponent().Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = inputForm().Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - for _, day := range allDays { - templ_7745c5c3_Err = defaultDayComponent(day).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if day.Date().Weekday() == time.Monday { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = LegendComponent().Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -func LoginPage(success bool, errorMsg string) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var3 := templ.GetChildren(ctx) - if templ_7745c5c3_Var3 == nil { - templ_7745c5c3_Var3 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = Base().Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "

Benutzer Anmelden

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

Benutzer Anmelden

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if !success { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

Login fehlgeschlagen, bitte erneut versuchen!

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

Login fehlgeschlagen, bitte erneut versuchen!

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var4 string - templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(errorMsg) + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(errorMsg) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pages.templ`, Line: 46, Col: 46} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/pages.templ`, Line: 24, Col: 46} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -181,9 +111,9 @@ func UserPage(status int) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var5 := templ.GetChildren(ctx) - if templ_7745c5c3_Var5 == nil { - templ_7745c5c3_Var5 = templ.NopComponent + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent } ctx = templ.ClearChildren(ctx) templ_7745c5c3_Err = Base().Render(ctx, templ_7745c5c3_Buffer) @@ -194,28 +124,28 @@ func UserPage(status int) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

Passwort ändern

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "

Passwort ändern

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } switch { case status == 401: - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "

Aktuelles Passwort nicht korrekt!

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

Aktuelles Passwort nicht korrekt!

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } case status >= 400: - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

Passwortwechsel fehlgeschlagen, bitte erneut versuchen!

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "

Passwortwechsel fehlgeschlagen, bitte erneut versuchen!

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } case status == 202: - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "

Passwortänderung erfolgreich

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "

Passwortänderung erfolgreich

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "

Nutzer abmelden

Nutzer von Weboberfläche abmelden.

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

Nutzer abmelden

Nutzer von Weboberfläche abmelden.

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -239,18 +169,18 @@ func statusCheckMark(status models.WeekStatus, target models.WeekStatus) templ.C }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var6 := templ.GetChildren(ctx) - if templ_7745c5c3_Var6 == nil { - templ_7745c5c3_Var6 = templ.NopComponent + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent } ctx = templ.ClearChildren(ctx) if status >= target { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -260,6 +190,63 @@ func statusCheckMark(status models.WeekStatus, target models.WeekStatus) templ.C } func TeamPage(weeks []models.WorkWeek, userWeek models.WorkWeek) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = Base().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = headerComponent().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "

Eigene Abrechnung

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = workWeekComponent(userWeek, false).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if len(weeks) > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "

Abrechnung Mitarbeiter

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + for _, week := range weeks { + templ_7745c5c3_Err = workWeekComponent(week, true).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func TeamPresencePage(teamPresence map[bool][]models.User) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -288,64 +275,7 @@ func TeamPage(weeks []models.WorkWeek, userWeek models.WorkWeek) templ.Component if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "

Eigene Abrechnung

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = workWeekComponent(userWeek, false).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if len(weeks) > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "

Abrechnung Mitarbeiter

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - for _, week := range weeks { - templ_7745c5c3_Err = workWeekComponent(week, true).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -func TeamPresencePage(teamPresence map[bool][]models.User) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var8 := templ.GetChildren(ctx) - if templ_7745c5c3_Var8 == nil { - templ_7745c5c3_Var8 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = Base().Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = headerComponent().Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "

Anwesend

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "

Anwesend

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -355,7 +285,7 @@ func TeamPresencePage(teamPresence map[bool][]models.User) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "

Nicht Anwesend

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "

Nicht Anwesend

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -365,7 +295,7 @@ func TeamPresencePage(teamPresence map[bool][]models.User) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -389,12 +319,12 @@ func LogoutButton() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var9 := templ.GetChildren(ctx) - if templ_7745c5c3_Var9 == nil { - templ_7745c5c3_Var9 = templ.NopComponent + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/Backend/templates/pdf_templ.go b/Backend/templates/pdf_templ.go index 57c5998..d9c5e51 100644 --- a/Backend/templates/pdf_templ.go +++ b/Backend/templates/pdf_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.943 +// templ: version: v0.3.924 package templates //lint:file-ignore SA4006 This context is only used if a nested component is present. diff --git a/Backend/templates/teamComponents.templ b/Backend/templates/teamComponents.templ index 33be818..e5738b9 100644 --- a/Backend/templates/teamComponents.templ +++ b/Backend/templates/teamComponents.templ @@ -44,7 +44,7 @@ templ defaultWeekDayComponent(u models.User, day models.IWorkDay) { { helper.FormatDuration(pause) }
- + switch { case !workDay.TimeFrom.Equal(workDay.TimeTo): { workDay.TimeFrom.Format("15:04") } diff --git a/Backend/templates/teamComponents_templ.go b/Backend/templates/teamComponents_templ.go index 1660f58..ec539f2 100644 --- a/Backend/templates/teamComponents_templ.go +++ b/Backend/templates/teamComponents_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.3.943 +// templ: version: v0.3.924 package templates //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -207,7 +207,7 @@ func defaultWeekDayComponent(u models.User, day models.IWorkDay) templ.Component if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/Backend/templates/timeComponents.templ b/Backend/templates/timeComponents.templ index a258fb3..f50e3a3 100644 --- a/Backend/templates/timeComponents.templ +++ b/Backend/templates/timeComponents.templ @@ -1,130 +1,89 @@ 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) - }} -
-
-

{ user.Vorname + " " + user.Name }

-
-

Überstunden

-

{ user.Overtime }

-
-
-
- @lineComponent() -
- - -
-
-
- -
+templ lineComponent() { +
+ + + +
+ + +
} -templ defaultDayComponent(day models.IWorkDay) { - if day.IsWorkDay() { - {{ - workDay, _ := day.(*models.WorkDay) - }} - @workDayComponent(*workDay, false) - } else { - {{ - absentDay, _ := day.(*models.Absence) - }} -
-
- @timeGaugeComponent(100, false) -

{ day.Date().Format("02.01.2006") }

-
-
- @lineComponent() -
-

{ absentDay.AbwesenheitTyp.Name } bis { absentDay.DateTo.Format("02.01.2006") }

-
-
-
- @changeButtonComponent("time-" + absentDay.Date().Format("2006-01-02")) -
-
- } -} - -templ workDayComponent(workDay models.WorkDay, submitted bool) { +// 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" +// } +// }} +//
+//
+// @timeGaugeComponent(workDay.GetDayProgress(user), workDay.Day.Equal(time.Now().Truncate(24*time.Hour))) +//
+//

{ workDay.Day.Format("02.01.2006") }

+// if (workDay.RequiresAction()) { +//

Bitte anpassen

+// } else { +// if work > 0 { +//

Arbeitszeit:

+//

{ helper.FormatDuration(work) }

+// } +// if pause > 0 { +// } +//

{ helper.FormatDuration(pause) }

+// if overtime > 0 { +//

{ helper.FormatDuration(overtime) }

+// } +// } +//
+//
+//
+// @lineComponent() +//
+// if len(workDay.Bookings) < 1 { +//

Keine Buchung gefunden. Bitte Arbeitsstunden oder Grund der Abwesenheit eingeben!

+// @absenceComponent(workDay) +// @newBookingComponent(workDay) +// } else { +// @absenceComponent(workDay) +// for _, booking := range workDay.Bookings { +// @bookingComponent(booking) +// } +// if workDay.IsKurzArbeit() { +//

Kurzarbeit

+// } +// @newBookingComponent(workDay) +// } +// +//
+//
+//
+// @changeButtonComponent("time-" + workDay.Day.Format("2006-01-02")) +//
+//
+// } +templ changeButtonComponent(id string, workDay 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" + functionName := "editDay" + if !workDay { + functionName = "editAbsence" } }} -
-
- @timeGaugeComponent(workDay.GetDayProgress(user), workDay.Day.Equal(time.Now().Truncate(24*time.Hour))) -
-

{ workDay.Day.Format("02.01.2006") }

- if (workDay.RequiresAction()) { -

Bitte anpassen

- } else { - if work > 0 { -

Arbeitszeit:

-

{ helper.FormatDuration(work) }

- } - if pause > 0 { -

{ helper.FormatDuration(pause) }

- } - if overtime > 0 { -

{ helper.FormatDuration(overtime) }

- } - } -
-
-
- @lineComponent() -
- if len(workDay.Bookings) < 1 { -

Keine Buchung gefunden. Bitte Arbeitsstunden oder Grund der Abwesenheit eingeben!

- @absenceComponent(workDay) - @newBookingComponent(workDay) - } else { - @absenceComponent(workDay) - for _, booking := range workDay.Bookings { - @bookingComponent(booking) - } - if workDay.IsKurzArbeit() { -

Kurzarbeit

- } - @newBookingComponent(workDay) - } - -
-
-
- @changeButtonComponent("time-" + workDay.Day.Format("2006-01-02")) -
-
-} - -templ changeButtonComponent(id string) { -
} -templ newBookingComponent(d models.WorkDay) { +templ newBookingComponent(d *models.WorkDay) { ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - var templ_7745c5c3_Var29 = []any{"w-2 h-full bg-accent rounded-md flex-shrink-0", bgColor} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var29...) + var templ_7745c5c3_Var8 = []any{"w-2 h-full bg-accent rounded-md flex-shrink-0", bgColor} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\">
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -652,7 +256,7 @@ func timeGaugeComponent(progress int8, today bool) templ.Component { }) } -func lineComponent() templ.Component { +func newAbsenceComponent() templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -668,12 +272,29 @@ func lineComponent() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var31 := templ.GetChildren(ctx) - if templ_7745c5c3_Var31 == nil { - templ_7745c5c3_Var31 = templ.NopComponent + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -681,7 +302,7 @@ func lineComponent() templ.Component { }) } -func absenceComponent(d models.WorkDay) templ.Component { +func newBookingComponent(d *models.WorkDay) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -697,140 +318,58 @@ func absenceComponent(d models.WorkDay) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var32 := templ.GetChildren(ctx) - if templ_7745c5c3_Var32 == nil { - templ_7745c5c3_Var32 = templ.NopComponent + templ_7745c5c3_Var12 := templ.GetChildren(ctx) + if templ_7745c5c3_Var12 == nil { + templ_7745c5c3_Var12 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -854,64 +393,64 @@ func bookingComponent(booking models.Booking) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var39 := templ.GetChildren(ctx) - if templ_7745c5c3_Var39 == nil { - templ_7745c5c3_Var39 = templ.NopComponent + templ_7745c5c3_Var15 := templ.GetChildren(ctx) + if templ_7745c5c3_Var15 == nil { + templ_7745c5c3_Var15 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var40 string - templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(booking.Timestamp.Format("15:04")) + var templ_7745c5c3_Var16 string + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(booking.Timestamp.Format("15:04")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timeComponents.templ`, Line: 206, Col: 97} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timeComponents.templ`, Line: 150, Col: 97} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\" 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\"> ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var43 string - templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(booking.GetBookingType()) + var templ_7745c5c3_Var19 string + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(booking.GetBookingType()) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timeComponents.templ`, Line: 208, Col: 29} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timeComponents.templ`, Line: 152, Col: 29} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -935,12 +474,12 @@ func LegendComponent() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var44 := templ.GetChildren(ctx) - if templ_7745c5c3_Var44 == nil { - templ_7745c5c3_Var44 = templ.NopComponent + templ_7745c5c3_Var20 := templ.GetChildren(ctx) + if templ_7745c5c3_Var20 == nil { + templ_7745c5c3_Var20 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "
Fehler
Arbeitszeit unter regulär
Arbeitszeit vollständig
Überstunden
Keine Buchungen
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
Fehler
Arbeitszeit unter regulär
Arbeitszeit vollständig
Überstunden
Keine Buchungen
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/Backend/templates/timePage.templ b/Backend/templates/timePage.templ new file mode 100644 index 0000000..6f86c77 --- /dev/null +++ b/Backend/templates/timePage.templ @@ -0,0 +1,169 @@ +package templates + +import ( + "arbeitszeitmessung/helper" + "arbeitszeitmessung/models" + "net/url" + "strconv" + "time" +) + +templ TimePage(workDays []models.WorkDay, lastSub time.Time) { + {{ + allDays := ctx.Value("days").([]models.IWorkDay) + }} + @Base() + @headerComponent() +
+ @inputForm() + for _, day := range allDays { + @defaultDayComponent(day) + if (day.Date().Weekday() == time.Monday) { +
+ } + } +
+ @LegendComponent() +} + +templ inputForm() { + {{ + urlParams := ctx.Value("urlParams").(url.Values) + user := ctx.Value("user").(models.User) + }} +
+
+

{ user.Vorname + " " + user.Name }

+
+

Überstunden

+

{ user.Overtime }

+
+
+
+ @lineComponent() +
+ + +
+
+
+ +
+
+ +} + +templ defaultDayComponent(day models.IWorkDay) { + {{ + user := ctx.Value("user").(models.User) + justify := "justify-center" + if day.IsWorkDay() && len(day.(*models.WorkDay).Bookings) > 1 { + justify = "justify-between" + } + }} +
+
+ @timeGaugeComponent(day.GetDayProgress(user), day.Date().Equal(time.Now().Truncate(24*time.Hour))) +
+

+ { day.Date().Format( + +"02.01.2006") } +

+ if day.IsWorkDay() { + {{ + workDay, _ := day.(*models.WorkDay) + work, pause, overtime := workDay.GetAllWorkTimesVirtual(user) + }} + if day.RequiresAction() { +

Bitte anpassen

+ } else { + if work > 0 { +

Arbeitszeit:

+

{ helper.FormatDuration(work) }

+ } + if pause > 0 { + } +

{ helper.FormatDuration(pause) }

+ if overtime != 0 { +

+ + { helper.FormatDuration(overtime) } +

+ } + } + } +
+
+
+ @lineComponent() +
+ @newAbsenceComponent() + if day.IsWorkDay() { + {{ + workDay, _ := day.(*models.WorkDay) + }} + if len(workDay.Bookings) < 1 { +

Keine Buchung gefunden. Bitte Arbeitsstunden oder Grund der Abwesenheit eingeben!

+ } + for _, booking := range workDay.Bookings { + @bookingComponent(booking) + } + @newBookingComponent(workDay) + if workDay.IsKurzArbeit() { + @absentInput(workDay.GetKurzArbeit()) +

Kurzarbeit

+ } + } else { + {{ + absentDay, _ := day.(*models.Absence) + }} + @absentInput(*absentDay) +

{ absentDay.AbwesenheitTyp.Name } bis { absentDay.DateTo.Format("02.01.2006") }

+ } +
+
+
+ @changeButtonComponent("time-"+day.Date().Format("2006-01-02"), day.IsWorkDay()) +
+
+} + +templ absentInput(a models.Absence) { + + + + +} diff --git a/Backend/templates/timePage_templ.go b/Backend/templates/timePage_templ.go new file mode 100644 index 0000000..36c7b99 --- /dev/null +++ b/Backend/templates/timePage_templ.go @@ -0,0 +1,591 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.924 +package templates + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "arbeitszeitmessung/helper" + "arbeitszeitmessung/models" + "net/url" + "strconv" + "time" +) + +func TimePage(workDays []models.WorkDay, lastSub time.Time) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + + allDays := ctx.Value("days").([]models.IWorkDay) + templ_7745c5c3_Err = Base().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = headerComponent().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = inputForm().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, day := range allDays { + templ_7745c5c3_Err = defaultDayComponent(day).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if day.Date().Weekday() == time.Monday { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = LegendComponent().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func inputForm() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + + urlParams := ctx.Value("urlParams").(url.Values) + user := ctx.Value("user").(models.User) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(user.Vorname + " " + user.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 36, Col: 66} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "

Überstunden

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(user.Overtime) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 39, Col: 42} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = lineComponent().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "

Abwesenheit

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func defaultDayComponent(day models.IWorkDay) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var9 := templ.GetChildren(ctx) + if templ_7745c5c3_Var9 == nil { + templ_7745c5c3_Var9 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + + user := ctx.Value("user").(models.User) + justify := "justify-center" + if day.IsWorkDay() && len(day.(*models.WorkDay).Bookings) > 1 { + justify = "justify-between" + } + var templ_7745c5c3_Var10 = []any{"grid-sub divide-x-1 hover:bg-neutral-200 transition-colors"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = timeGaugeComponent(day.GetDayProgress(user), day.Date().Equal(time.Now().Truncate(24*time.Hour))).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var13 string + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(day.Date().Format( + + "02.01.2006")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 103, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if day.IsWorkDay() { + + workDay, _ := day.(*models.WorkDay) + work, pause, overtime := workDay.GetAllWorkTimesVirtual(user) + if day.RequiresAction() { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "

Bitte anpassen

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + if work > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "

Arbeitszeit:

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var14 string + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(work)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 115, Col: 155} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if pause > 0 { + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var15 string + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(pause)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 119, Col: 172} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if overtime != 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var16 string + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(helper.FormatDuration(overtime)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 123, Col: 41} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = lineComponent().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var17 = []any{"flex flex-col gap-2 group w-full ", justify} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var17...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = newAbsenceComponent().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if day.IsWorkDay() { + + workDay, _ := day.(*models.WorkDay) + if len(workDay.Bookings) < 1 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "

Keine Buchung gefunden. Bitte Arbeitsstunden oder Grund der Abwesenheit eingeben!

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + for _, booking := range workDay.Bookings { + templ_7745c5c3_Err = bookingComponent(booking).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = newBookingComponent(workDay).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if workDay.IsKurzArbeit() { + templ_7745c5c3_Err = absentInput(workDay.GetKurzArbeit()).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "

Kurzarbeit

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + } else { + + absentDay, _ := day.(*models.Absence) + templ_7745c5c3_Err = absentInput(*absentDay).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var20 string + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(absentDay.AbwesenheitTyp.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 154, Col: 39} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, " bis ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var21 string + templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(absentDay.DateTo.Format("02.01.2006")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/timePage.templ`, Line: 154, Col: 116} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = changeButtonComponent("time-"+day.Date().Format("2006-01-02"), day.IsWorkDay()).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func absentInput(a models.Absence) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var22 := templ.GetChildren(ctx) + if templ_7745c5c3_Var22 == nil { + templ_7745c5c3_Var22 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/db.sql b/db.sql index 4ba7830..cdc1beb 100644 --- a/db.sql +++ b/db.sql @@ -203,7 +203,7 @@ WITH params AS ( 14::int AS start_days_ago, -- how many days back to start 0::int AS end_days_ahead, -- how many days forward (0 = today) 0::float AS pause_probability, - 0.2::float AS absence_probability + 0.0::float AS absence_probability ), days AS ( SELECT gs::date AS work_date, p.card_uid, p.geraet_id, p.pause_probability, p.absence_probability diff --git a/migrations/20250904114004_intervals.up.sql b/migrations/20250904114004_intervals.up.sql index 272ceb8..b3c6baf 100644 --- a/migrations/20250904114004_intervals.up.sql +++ b/migrations/20250904114004_intervals.up.sql @@ -1,13 +1,19 @@ ALTER TABLE wochen_report - ALTER COLUMN ueberstunden TYPE interval - USING - make_interval( - hours => floor(ueberstunden)::int, - mins => round((ueberstunden - floor(ueberstunden)) * 60)::int - ), - ALTER COLUMN arbeitszeit TYPE interval - USING - make_interval( - hours => floor(arbeitszeit)::int, - mins => round((arbeitszeit - floor(arbeitszeit)) * 60)::int - ); + ADD COLUMN ueberstunden_interval interval, + ADD COLUMN arbeitszeit_interval interval; + +UPDATE wochen_report +SET + ueberstunden_interval = CASE WHEN ueberstunden IS NULL THEN NULL ELSE (ueberstunden::double precision * INTERVAL '1 hour') END, + arbeitszeit_interval = CASE WHEN arbeitszeit IS NULL THEN NULL ELSE (arbeitszeit::double precision * INTERVAL '1 hour') END; + +-- when happy, drop old columns and rename new ones +ALTER TABLE wochen_report + DROP COLUMN ueberstunden, + DROP COLUMN arbeitszeit; + +ALTER TABLE wochen_report + RENAME COLUMN ueberstunden_interval TO ueberstunden; + +ALTER TABLE wochen_report + RENAME COLUMN arbeitszeit_interval TO arbeitszeit; diff --git a/migrations/20250916093608.down.sql b/migrations/20250916093608_kurzarbeit.down.sql similarity index 100% rename from migrations/20250916093608.down.sql rename to migrations/20250916093608_kurzarbeit.down.sql diff --git a/migrations/20250916093608.up.sql b/migrations/20250916093608_kurzarbeit.up.sql similarity index 100% rename from migrations/20250916093608.up.sql rename to migrations/20250916093608_kurzarbeit.up.sql diff --git a/migrations/atlas.sum b/migrations/atlas.sum index d57ff83..4950d34 100644 --- a/migrations/atlas.sum +++ b/migrations/atlas.sum @@ -1,7 +1,15 @@ -h1:31y/DB0ca2cm603nNckNvVCwm+XuMaVsoGUB+JvrOKs= -20250901201159_initial.up.sql h1:Mb1RlVdFvcxqU9HrSK6oNeURqFa3O4KzB3rDa+6+3gc= -20250901201250_control_tables.up.sql h1:a5LATgR/CRiC4GsqxkJ94TyJOxeTcW74eCnodIy+c1E= -20250901201710_triggers_extension.up.sql h1:z9b6Hk9btE2Ns4mU7B16HjvYBP6EEwHAXVlvPpkn978= -20250903221313_overtime.up.sql h1:t/B435ShW5ZEnzC81jRABWVZ5gNm7tPZPnOO6/ZY6ow= -20250903233030_non_null_contraints.up.sql h1:e7d+6ZdpEjPh2cc65N3S06oD2e6diMuG7+klhgYsym8= -20250904114004_intervals.up.sql h1:Sz8FIVvvcCIS3aIuSjyzFYLs32fjMcMMHk62shj6Qpw= +h1:3AxgD8mnu/F+JGtJu9FZvA9Ro0UUtGPgyjskKtfTYUQ= +20250901201159_initial.down.sql h1:cmF5CvNGqEfcmbRgiqaqDWERdNNRaMzarbNLJ/Y35o4= +20250901201159_initial.up.sql h1:Yrak/+wfQ4Tu/dVR/cUZ/75DlAcv4G/OJXDqpgSw47U= +20250901201250_control_tables.down.sql h1:f/KmhO9pOI45J8ZRjFonvD3CypB+rOoGOPN2WMFHvOw= +20250901201250_control_tables.up.sql h1:of5E07p0N1aen9CdQNEOrO7ffbKZC6kp4oK5KPzU9+g= +20250901201710_triggers_extension.down.sql h1:a9va3FSfHBWzODJSJO+ywNa2hiZwjG/vmvYGb3L1lnM= +20250901201710_triggers_extension.up.sql h1:nUBPd2eDssi/TwMVF/nOJkIM5rUM0iINdg1K9pZRZN0= +20250903221313_overtime.down.sql h1:X+jJESqcZ6ZTd2H563z6kRaXb4dn4sA02D3ck2795v8= +20250903221313_overtime.up.sql h1:C3DSiNVpe9v0Un1DEQ0lsy5yToR8iqcggv91GSr6tRE= +20250903233030_non_null_contraints.down.sql h1:42TZzPsji2Ze50k6sLwgIuNo4Trk3m3ni/aIfQJ97dE= +20250903233030_non_null_contraints.up.sql h1:k6zR5YNSAP4fo5QEc58KZ0LxvEz1nl0X/AAcZ+TG3I4= +20250904114004_intervals.down.sql h1:SquJAPinzFIRN6fJjLLIRsz59Tyr4RwGiGuOFI/N1SQ= +20250904114004_intervals.up.sql h1:AFqncTGOiEZVBbhWFqN2zlQ7DyhybB5wJr6a36Atk1E= +20250916093608_kurzarbeit.down.sql h1:ljM1a1pQCxOQiXRaXU04GC4V9yy2y20x5eUNQ/zyx+o= +20250916093608_kurzarbeit.up.sql h1:pTiw0VfGaf26mhJg4wf98Fqwn1kShJ+PiN2PiM4q1kk=