Compare commits
2 Commits
6b0b8906a9
...
2d8747c971
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d8747c971 | |||
| 38322a64cf |
@@ -36,6 +36,7 @@ type Booking struct {
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
CounterId int `json:"counter_id"`
|
||||
BookingType BookingType `json:"anwesenheit_typ"`
|
||||
Valid bool `json:"valid"`
|
||||
}
|
||||
|
||||
type IDatabase interface {
|
||||
@@ -252,12 +253,13 @@ func (b *Booking) Update(nb Booking) {
|
||||
func checkLastBooking(b Booking) bool {
|
||||
var check_in_out int
|
||||
slog.Info("Checking with timestamp:", "timestamp", b.Timestamp.String())
|
||||
stmt, err := DB.Prepare((`SELECT check_in_out FROM "anwesenheit" WHERE "card_uid" = $1 AND "timestamp"::DATE <= $2::DATE ORDER BY "timestamp" DESC LIMIT 1;`))
|
||||
stmt, err := DB.Prepare((`SELECT check_in_out FROM "anwesenheit" WHERE "card_uid" = $1 AND "timestamp" <= $2 ORDER BY "timestamp" DESC LIMIT 1;`))
|
||||
if err != nil {
|
||||
log.Fatalf("Error preparing query: %v", err)
|
||||
return false
|
||||
}
|
||||
err = stmt.QueryRow(b.CardUID, b.Timestamp).Scan(&check_in_out)
|
||||
slog.Info("Checking last bookings check_in_out", "Check", check_in_out)
|
||||
if err == sql.ErrNoRows {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -46,11 +46,10 @@ func (d *WorkDay) GetWorktimeAbsence() Absence {
|
||||
|
||||
// Gets the time as is in the db (with corrected pause times)
|
||||
func (d *WorkDay) GetWorktime(u User, base WorktimeBase, includeKurzarbeit bool) time.Duration {
|
||||
if includeKurzarbeit && d.IsKurzArbeit() && len(d.Bookings) > 0 {
|
||||
if includeKurzarbeit && d.IsKurzArbeit() { //&& len(d.Bookings) > 0
|
||||
return d.kurzArbeitAbsence.GetWorktime(u, base, true)
|
||||
}
|
||||
work, pause := calcWorkPause(d.Bookings)
|
||||
work, pause = correctWorkPause(work, pause)
|
||||
work, _ := correctWorkPause(getWorkPause(d))
|
||||
if (d.worktimeAbsece != Absence{}) {
|
||||
work += d.worktimeAbsece.GetWorktime(u, base, false)
|
||||
}
|
||||
@@ -59,7 +58,7 @@ func (d *WorkDay) GetWorktime(u User, base WorktimeBase, includeKurzarbeit bool)
|
||||
|
||||
// Gets the corrected pause times based on db entries
|
||||
func (d *WorkDay) GetPausetime(u User, base WorktimeBase, includeKurzarbeit bool) time.Duration {
|
||||
work, pause := calcWorkPause(d.Bookings)
|
||||
work, pause := getWorkPause(d)
|
||||
work, pause = correctWorkPause(work, pause)
|
||||
return pause.Round(time.Minute)
|
||||
}
|
||||
@@ -81,6 +80,15 @@ func (d *WorkDay) GetTimes(u User, base WorktimeBase, includeKurzarbeit bool) (w
|
||||
return d.GetWorktime(u, base, includeKurzarbeit), d.GetPausetime(u, base, includeKurzarbeit), d.GetOvertime(u, base, includeKurzarbeit)
|
||||
}
|
||||
|
||||
func getWorkPause(d *WorkDay) (work, pause time.Duration) {
|
||||
//if today calc, else take from db
|
||||
if helper.IsSameDate(d.Date(), time.Now()) {
|
||||
return calcWorkPause(d.Bookings)
|
||||
} else {
|
||||
return d.workTime, d.pauseTime
|
||||
}
|
||||
}
|
||||
|
||||
func calcWorkPause(bookings []Booking) (work, pause time.Duration) {
|
||||
var lastBooking Booking
|
||||
for _, b := range bookings {
|
||||
@@ -178,11 +186,16 @@ func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay {
|
||||
var workSec, pauseSec float64
|
||||
|
||||
qStr, err := DB.Prepare(`
|
||||
WITH all_days AS (
|
||||
SELECT generate_series($2::DATE, $3::DATE - INTERVAL '1 day', INTERVAL '1 day')::DATE AS work_date),
|
||||
normalized_bookings AS (
|
||||
SELECT *
|
||||
FROM (
|
||||
WITH
|
||||
all_days AS (
|
||||
SELECT
|
||||
generate_series(
|
||||
$2 ::DATE,
|
||||
$3 ::DATE - INTERVAL '1 day',
|
||||
INTERVAL '1 day'
|
||||
)::DATE AS work_date
|
||||
),
|
||||
all_bookings AS (
|
||||
SELECT
|
||||
a.card_uid,
|
||||
a.timestamp,
|
||||
@@ -192,82 +205,128 @@ func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay {
|
||||
a.anwesenheit_typ,
|
||||
sat.anwesenheit_name AS anwesenheit_typ_name,
|
||||
LAG(a.check_in_out) OVER (
|
||||
PARTITION BY a.card_uid, a.timestamp::DATE
|
||||
ORDER BY a.timestamp
|
||||
) AS prev_check
|
||||
FROM anwesenheit a
|
||||
LEFT JOIN s_anwesenheit_typen sat
|
||||
ON a.anwesenheit_typ = sat.anwesenheit_id
|
||||
WHERE a.card_uid = $1
|
||||
AND a.timestamp::DATE >= $2
|
||||
AND a.timestamp::DATE <= $3
|
||||
) t
|
||||
WHERE prev_check IS NULL OR prev_check <> check_in_out
|
||||
),
|
||||
ordered_bookings AS (
|
||||
SELECT
|
||||
*,
|
||||
LAG(timestamp) OVER (
|
||||
PARTITION BY card_uid, work_date
|
||||
ORDER BY timestamp
|
||||
PARTITION BY
|
||||
a.card_uid,
|
||||
a.timestamp::DATE
|
||||
ORDER BY
|
||||
a.timestamp
|
||||
) AS prev_check,
|
||||
LAG(a.timestamp) OVER (
|
||||
PARTITION BY
|
||||
a.card_uid,
|
||||
a.timestamp::DATE
|
||||
ORDER BY
|
||||
a.timestamp
|
||||
) AS prev_timestamp
|
||||
FROM normalized_bookings
|
||||
FROM
|
||||
anwesenheit a
|
||||
LEFT JOIN s_anwesenheit_typen sat ON a.anwesenheit_typ = sat.anwesenheit_id
|
||||
WHERE
|
||||
a.card_uid = $1
|
||||
AND a.timestamp::DATE >= $2::DATE
|
||||
AND a.timestamp::DATE <= $3::DATE
|
||||
),
|
||||
normalized_bookings AS (
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
all_bookings
|
||||
WHERE
|
||||
prev_check IS NULL
|
||||
OR prev_check <> check_in_out
|
||||
)
|
||||
SELECT
|
||||
d.work_date,
|
||||
COALESCE(MIN(b.timestamp), NOW()) AS time_from,
|
||||
COALESCE(MAX(b.timestamp), NOW()) AS time_to,
|
||||
COALESCE(
|
||||
EXTRACT(EPOCH FROM SUM(
|
||||
EXTRACT(
|
||||
EPOCH
|
||||
FROM
|
||||
SUM(
|
||||
CASE
|
||||
WHEN b.prev_check IN (1, 3) AND b.check_in_out IN (2, 4, 254)
|
||||
THEN b.timestamp - b.prev_timestamp
|
||||
WHEN b.prev_check IN (1, 3)
|
||||
AND b.check_in_out IN (2, 4, 254) THEN b.timestamp - b.prev_timestamp
|
||||
ELSE INTERVAL '0'
|
||||
END
|
||||
)), 0
|
||||
) AS total_work_seconds,
|
||||
COALESCE(
|
||||
EXTRACT(EPOCH FROM SUM(
|
||||
CASE
|
||||
WHEN b.prev_check IN (2, 4, 254) AND b.check_in_out IN (1, 3)
|
||||
THEN b.timestamp - b.prev_timestamp
|
||||
ELSE INTERVAL '0'
|
||||
END
|
||||
)), 0
|
||||
) AS total_pause_seconds,
|
||||
COALESCE(jsonb_agg(jsonb_build_object(
|
||||
'check_in_out', b.check_in_out,
|
||||
'timestamp', b.timestamp,
|
||||
'counter_id', b.counter_id,
|
||||
'anwesenheit_typ', b.anwesenheit_typ,
|
||||
'anwesenheit_typ', jsonb_build_object(
|
||||
'anwesenheit_id', b.anwesenheit_typ,
|
||||
'anwesenheit_name', b.anwesenheit_typ_name
|
||||
)
|
||||
) ORDER BY b.timestamp), '[]'::jsonb) AS bookings
|
||||
FROM all_days d
|
||||
LEFT JOIN ordered_bookings b ON d.work_date = b.work_date
|
||||
GROUP BY d.work_date
|
||||
ORDER BY d.work_date ASC;`)
|
||||
) AS total_work_seconds,
|
||||
EXTRACT(
|
||||
EPOCH
|
||||
FROM
|
||||
SUM(
|
||||
CASE
|
||||
WHEN b.prev_check IN (2, 4, 254)
|
||||
AND b.check_in_out IN (1, 3) THEN b.timestamp - b.prev_timestamp
|
||||
ELSE INTERVAL '0'
|
||||
END
|
||||
)
|
||||
) AS total_pause_seconds,
|
||||
jsonb_agg(
|
||||
jsonb_build_object(
|
||||
'check_in_out',
|
||||
b.check_in_out,
|
||||
'valid',
|
||||
coalesce(b.check_in_out != b.prev_check, true),
|
||||
'timestamp',
|
||||
b.timestamp,
|
||||
'counter_id',
|
||||
b.counter_id,
|
||||
'anwesenheit_typ',
|
||||
jsonb_build_object(
|
||||
'anwesenheit_id',
|
||||
b.anwesenheit_typ,
|
||||
'anwesenheit_name',
|
||||
b.anwesenheit_typ_name
|
||||
)
|
||||
)
|
||||
ORDER BY
|
||||
b.timestamp
|
||||
) FILTER (
|
||||
WHERE
|
||||
b.card_uid IS NOT NULL
|
||||
) AS bookings
|
||||
FROM
|
||||
all_days d
|
||||
LEFT JOIN all_bookings b ON b.work_date = d.work_date
|
||||
GROUP BY
|
||||
d.work_date;
|
||||
`)
|
||||
|
||||
// qStr, err := DB.Prepare(`
|
||||
// WITH all_days AS (
|
||||
// SELECT generate_series($2::DATE, $3::DATE - INTERVAL '1 day', INTERVAL '1 day')::DATE AS work_date),
|
||||
// ordered_bookings AS (
|
||||
// normalized_bookings AS (
|
||||
// SELECT *
|
||||
// FROM (
|
||||
// SELECT
|
||||
// a.timestamp::DATE AS work_date,
|
||||
// a.card_uid,
|
||||
// a.timestamp,
|
||||
// a.timestamp::DATE AS work_date,
|
||||
// a.check_in_out,
|
||||
// a.counter_id,
|
||||
// a.anwesenheit_typ,
|
||||
// sat.anwesenheit_name AS anwesenheit_typ_name,
|
||||
// LAG(a.timestamp) OVER (PARTITION BY a.card_uid, a.timestamp::DATE ORDER BY a.timestamp) AS prev_timestamp,
|
||||
// LAG(a.check_in_out) OVER (PARTITION BY a.card_uid, a.timestamp::DATE ORDER BY a.timestamp) AS prev_check
|
||||
// LAG(a.check_in_out) OVER (
|
||||
// PARTITION BY a.card_uid, a.timestamp::DATE
|
||||
// ORDER BY a.timestamp
|
||||
// ) AS prev_check
|
||||
// FROM anwesenheit a
|
||||
// LEFT JOIN s_anwesenheit_typen sat ON a.anwesenheit_typ = sat.anwesenheit_id
|
||||
// LEFT JOIN s_anwesenheit_typen sat
|
||||
// ON a.anwesenheit_typ = sat.anwesenheit_id
|
||||
// WHERE a.card_uid = $1
|
||||
// AND a.timestamp::DATE >= $2
|
||||
// AND a.timestamp::DATE <= $3
|
||||
// ) t
|
||||
// WHERE prev_check IS NULL OR prev_check <> check_in_out
|
||||
// ),
|
||||
// ordered_bookings AS (
|
||||
// SELECT
|
||||
// *,
|
||||
// LAG(timestamp) OVER (
|
||||
// PARTITION BY card_uid, work_date
|
||||
// ORDER BY timestamp
|
||||
// ) AS prev_timestamp
|
||||
// FROM normalized_bookings
|
||||
// )
|
||||
// SELECT
|
||||
// d.work_date,
|
||||
@@ -322,26 +381,29 @@ func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay {
|
||||
var workDay WorkDay
|
||||
var bookings []byte
|
||||
if err := rows.Scan(&workDay.Day, &workDay.TimeFrom, &workDay.TimeTo, &workSec, &pauseSec, &bookings); err != nil {
|
||||
log.Println("Error scanning row!", err)
|
||||
slog.Error("Error scanning row!", "Error", err)
|
||||
return workDays
|
||||
}
|
||||
workDay.workTime = time.Duration(workSec * float64(time.Second))
|
||||
workDay.pauseTime = time.Duration(pauseSec * float64(time.Second))
|
||||
if bookings != nil {
|
||||
err = json.Unmarshal(bookings, &workDay.Bookings)
|
||||
if err != nil {
|
||||
log.Println("Error parsing bookings JSON!", err)
|
||||
slog.Error("Error parsing bookings JSON!", "Error", err, "Json", bookings)
|
||||
return nil
|
||||
}
|
||||
// better empty day handling
|
||||
if len(workDay.Bookings) == 1 && workDay.Bookings[0].CounterId == 0 {
|
||||
workDay.Bookings = []Booking{}
|
||||
}
|
||||
|
||||
// better empty day handling
|
||||
// if len(workDay.Bookings) == 1 && workDay.Bookings[0].CounterId == 0 {
|
||||
// workDay.Bookings = []Booking{}
|
||||
// }
|
||||
if len(workDay.Bookings) >= 1 || !helper.IsWeekend(workDay.Date()) {
|
||||
workDays = append(workDays, workDay)
|
||||
}
|
||||
}
|
||||
if err = rows.Err(); err != nil {
|
||||
log.Println("Error in workday rows!", err)
|
||||
slog.Error("Error in workday rows!", "Error", err)
|
||||
return workDays
|
||||
}
|
||||
return workDays
|
||||
|
||||
@@ -205,9 +205,15 @@
|
||||
.top-0 {
|
||||
top: calc(var(--spacing) * 0);
|
||||
}
|
||||
.top-1 {
|
||||
top: calc(var(--spacing) * 1);
|
||||
}
|
||||
.top-1\/2 {
|
||||
top: calc(1/2 * 100%);
|
||||
}
|
||||
.top-2 {
|
||||
top: calc(var(--spacing) * 2);
|
||||
}
|
||||
.top-2\.5 {
|
||||
top: calc(var(--spacing) * 2.5);
|
||||
}
|
||||
@@ -217,9 +223,15 @@
|
||||
.right-1 {
|
||||
right: calc(var(--spacing) * 1);
|
||||
}
|
||||
.right-2 {
|
||||
right: calc(var(--spacing) * 2);
|
||||
}
|
||||
.right-2\.5 {
|
||||
right: calc(var(--spacing) * 2.5);
|
||||
}
|
||||
.left-1 {
|
||||
left: calc(var(--spacing) * 1);
|
||||
}
|
||||
.left-1\/2 {
|
||||
left: calc(1/2 * 100%);
|
||||
}
|
||||
@@ -350,6 +362,9 @@
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
.contents {
|
||||
display: contents;
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
@@ -383,6 +398,9 @@
|
||||
.h-2 {
|
||||
height: calc(var(--spacing) * 2);
|
||||
}
|
||||
.h-3 {
|
||||
height: calc(var(--spacing) * 3);
|
||||
}
|
||||
.h-3\.5 {
|
||||
height: calc(var(--spacing) * 3.5);
|
||||
}
|
||||
@@ -407,6 +425,9 @@
|
||||
.w-2 {
|
||||
width: calc(var(--spacing) * 2);
|
||||
}
|
||||
.w-3 {
|
||||
width: calc(var(--spacing) * 3);
|
||||
}
|
||||
.w-3\.5 {
|
||||
width: calc(var(--spacing) * 3.5);
|
||||
}
|
||||
@@ -416,6 +437,9 @@
|
||||
.w-5 {
|
||||
width: calc(var(--spacing) * 5);
|
||||
}
|
||||
.w-9 {
|
||||
width: calc(var(--spacing) * 9);
|
||||
}
|
||||
.w-9\/10 {
|
||||
width: calc(9/10 * 100%);
|
||||
}
|
||||
@@ -428,6 +452,9 @@
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
.flex-shrink {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
.flex-shrink-0 {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -443,10 +470,21 @@
|
||||
.basis-\[content\] {
|
||||
flex-basis: content;
|
||||
}
|
||||
.border-collapse {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.-translate-x-1 {
|
||||
--tw-translate-x: calc(var(--spacing) * -1);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.-translate-x-1\/2 {
|
||||
--tw-translate-x: calc(calc(1/2 * 100%) * -1);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.-translate-y-1 {
|
||||
--tw-translate-y: calc(var(--spacing) * -1);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.-translate-y-1\/2 {
|
||||
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
@@ -457,33 +495,21 @@
|
||||
.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;
|
||||
}
|
||||
.auto-rows-min {
|
||||
grid-auto-rows: min-content;
|
||||
}
|
||||
.grid-cols-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
.grid-cols-5 {
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
}
|
||||
.grid-cols-\[3fr_2fr_2fr_2fr_3fr_3fr_3fr\] {
|
||||
grid-template-columns: 3fr 2fr 2fr 2fr 3fr 3fr 3fr;
|
||||
}
|
||||
.grid-cols-subgrid {
|
||||
grid-template-columns: subgrid;
|
||||
}
|
||||
.grid-rows-6 {
|
||||
grid-template-rows: repeat(6, minmax(0, 1fr));
|
||||
}
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -534,11 +560,6 @@
|
||||
border-bottom-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
|
||||
}
|
||||
}
|
||||
.divide-neutral-300 {
|
||||
:where(& > :not(:last-child)) {
|
||||
border-color: var(--color-neutral-300);
|
||||
}
|
||||
}
|
||||
.justify-self-end {
|
||||
justify-self: flex-end;
|
||||
}
|
||||
@@ -565,18 +586,10 @@
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 0px;
|
||||
}
|
||||
.border-r-0 {
|
||||
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;
|
||||
}
|
||||
.border-dashed {
|
||||
--tw-border-style: dashed;
|
||||
border-style: dashed;
|
||||
@@ -587,9 +600,6 @@
|
||||
.border-neutral-500 {
|
||||
border-color: var(--color-neutral-500);
|
||||
}
|
||||
.border-neutral-600 {
|
||||
border-color: var(--color-neutral-600);
|
||||
}
|
||||
.border-slate-800 {
|
||||
border-color: var(--color-slate-800);
|
||||
}
|
||||
@@ -614,15 +624,15 @@
|
||||
.bg-red-600 {
|
||||
background-color: var(--color-red-600);
|
||||
}
|
||||
.mask-repeat {
|
||||
mask-repeat: repeat;
|
||||
}
|
||||
.p-1 {
|
||||
padding: calc(var(--spacing) * 1);
|
||||
}
|
||||
.p-2 {
|
||||
padding: calc(var(--spacing) * 2);
|
||||
}
|
||||
.p-8 {
|
||||
padding: calc(var(--spacing) * 8);
|
||||
}
|
||||
.px-3 {
|
||||
padding-inline: calc(var(--spacing) * 3);
|
||||
}
|
||||
@@ -635,10 +645,6 @@
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
.text-2xl {
|
||||
font-size: var(--text-2xl);
|
||||
line-height: var(--tw-leading, var(--text-2xl--line-height));
|
||||
}
|
||||
.text-sm {
|
||||
font-size: var(--text-sm);
|
||||
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||
@@ -654,15 +660,15 @@
|
||||
.whitespace-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.\!text-red-500 {
|
||||
color: var(--color-red-500) !important;
|
||||
}
|
||||
.text-accent {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
.text-black {
|
||||
color: var(--color-black);
|
||||
}
|
||||
.text-neutral-300 {
|
||||
color: var(--color-neutral-300);
|
||||
}
|
||||
.text-neutral-500 {
|
||||
color: var(--color-neutral-500);
|
||||
}
|
||||
@@ -690,9 +696,16 @@
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
.opacity-0 {
|
||||
opacity: 0%;
|
||||
}
|
||||
.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,);
|
||||
}
|
||||
@@ -719,18 +732,6 @@
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.\*\:text-center {
|
||||
:is(& > *) {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.\*\:not-print\:p-2 {
|
||||
:is(& > *) {
|
||||
@media not print {
|
||||
padding: calc(var(--spacing) * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
.group-hover\:text-black {
|
||||
&:is(:where(.group):hover *) {
|
||||
@media (hover: hover) {
|
||||
@@ -1138,6 +1139,11 @@
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
}
|
||||
@property --tw-outline-style {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
initial-value: solid;
|
||||
}
|
||||
@property --tw-blur {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
@@ -1210,6 +1216,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;
|
||||
|
||||
@@ -170,10 +170,12 @@ templ workDayWeekComponent(workDay *models.WorkDay) {
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
<span class="icon-[material-symbols-light--schedule-outline] flex-shrink-0"></span>
|
||||
switch {
|
||||
case !workDay.TimeFrom.Equal(workDay.TimeTo):
|
||||
case !workDay.IsEmpty():
|
||||
<span>{ workDay.TimeFrom.Format("15:04") }</span>
|
||||
<span>-</span>
|
||||
<span>{ workDay.TimeTo.Format("15:04") }</span>
|
||||
case workDay.IsKurzArbeit():
|
||||
<span>Kurzarbeit</span>
|
||||
default:
|
||||
<p>Keine Anwesenheit</p>
|
||||
}
|
||||
|
||||
@@ -77,10 +77,13 @@ templ newBookingComponent(d models.IWorkDay) {
|
||||
|
||||
templ bookingComponent(booking models.Booking) {
|
||||
<div>
|
||||
<p class="text-neutral-500 edit-box">
|
||||
<p class={ "text-neutral-500 edit-box", templ.KV("text-red-500", !booking.Valid) }>
|
||||
<span class="text-black 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 px-3 py-2 cursor-pointer"/>
|
||||
{ booking.GetBookingType() }
|
||||
if !booking.Valid {
|
||||
fehlerhafte Buchung, wird nicht zur Berechnung verwendet!
|
||||
}
|
||||
</p>
|
||||
if booking.IsSubmittedAndChecked() {
|
||||
<p>submitted</p>
|
||||
@@ -89,10 +92,10 @@ templ bookingComponent(booking models.Booking) {
|
||||
}
|
||||
|
||||
templ workdayComponent(workDay *models.WorkDay) {
|
||||
if len(workDay.Bookings) < 1 {
|
||||
if workDay.IsEmpty() && !workDay.IsKurzArbeit() {
|
||||
<p class="text group-[.edit]:hidden">Keine Buchung gefunden. Bitte Arbeitsstunden oder Grund der Abwesenheit eingeben!</p>
|
||||
} else {
|
||||
if workDay.IsKurzArbeit() && len(workDay.Bookings) > 0 {
|
||||
if workDay.IsKurzArbeit() {
|
||||
@absenceComponent(workDay.GetKurzArbeit(), true)
|
||||
}
|
||||
for _, booking := range workDay.Bookings {
|
||||
|
||||
Reference in New Issue
Block a user