dev/finalFixes #81
@@ -36,6 +36,7 @@ type Booking struct {
|
|||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
CounterId int `json:"counter_id"`
|
CounterId int `json:"counter_id"`
|
||||||
BookingType BookingType `json:"anwesenheit_typ"`
|
BookingType BookingType `json:"anwesenheit_typ"`
|
||||||
|
Valid bool `json:"valid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IDatabase interface {
|
type IDatabase interface {
|
||||||
@@ -252,12 +253,13 @@ func (b *Booking) Update(nb Booking) {
|
|||||||
func checkLastBooking(b Booking) bool {
|
func checkLastBooking(b Booking) bool {
|
||||||
var check_in_out int
|
var check_in_out int
|
||||||
slog.Info("Checking with timestamp:", "timestamp", b.Timestamp.String())
|
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 {
|
if err != nil {
|
||||||
log.Fatalf("Error preparing query: %v", err)
|
log.Fatalf("Error preparing query: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
err = stmt.QueryRow(b.CardUID, b.Timestamp).Scan(&check_in_out)
|
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 {
|
if err == sql.ErrNoRows {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,11 +186,16 @@ func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay {
|
|||||||
var workSec, pauseSec float64
|
var workSec, pauseSec float64
|
||||||
|
|
||||||
qStr, err := DB.Prepare(`
|
qStr, err := DB.Prepare(`
|
||||||
WITH all_days AS (
|
WITH
|
||||||
SELECT generate_series($2::DATE, $3::DATE - INTERVAL '1 day', INTERVAL '1 day')::DATE AS work_date),
|
all_days AS (
|
||||||
normalized_bookings AS (
|
SELECT
|
||||||
SELECT *
|
generate_series(
|
||||||
FROM (
|
$2 ::DATE,
|
||||||
|
$3 ::DATE - INTERVAL '1 day',
|
||||||
|
INTERVAL '1 day'
|
||||||
|
)::DATE AS work_date
|
||||||
|
),
|
||||||
|
all_bookings AS (
|
||||||
SELECT
|
SELECT
|
||||||
a.card_uid,
|
a.card_uid,
|
||||||
a.timestamp,
|
a.timestamp,
|
||||||
@@ -200,82 +205,128 @@ func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay {
|
|||||||
a.anwesenheit_typ,
|
a.anwesenheit_typ,
|
||||||
sat.anwesenheit_name AS anwesenheit_typ_name,
|
sat.anwesenheit_name AS anwesenheit_typ_name,
|
||||||
LAG(a.check_in_out) OVER (
|
LAG(a.check_in_out) OVER (
|
||||||
PARTITION BY a.card_uid, a.timestamp::DATE
|
PARTITION BY
|
||||||
ORDER BY a.timestamp
|
a.card_uid,
|
||||||
) AS prev_check
|
a.timestamp::DATE
|
||||||
FROM anwesenheit a
|
ORDER BY
|
||||||
LEFT JOIN s_anwesenheit_typen sat
|
a.timestamp
|
||||||
ON a.anwesenheit_typ = sat.anwesenheit_id
|
) AS prev_check,
|
||||||
WHERE a.card_uid = $1
|
LAG(a.timestamp) OVER (
|
||||||
AND a.timestamp::DATE >= $2
|
PARTITION BY
|
||||||
AND a.timestamp::DATE <= $3
|
a.card_uid,
|
||||||
) t
|
a.timestamp::DATE
|
||||||
WHERE prev_check IS NULL OR prev_check <> check_in_out
|
ORDER BY
|
||||||
),
|
a.timestamp
|
||||||
ordered_bookings AS (
|
|
||||||
SELECT
|
|
||||||
*,
|
|
||||||
LAG(timestamp) OVER (
|
|
||||||
PARTITION BY card_uid, work_date
|
|
||||||
ORDER BY timestamp
|
|
||||||
) AS prev_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
|
SELECT
|
||||||
d.work_date,
|
d.work_date,
|
||||||
COALESCE(MIN(b.timestamp), NOW()) AS time_from,
|
COALESCE(MIN(b.timestamp), NOW()) AS time_from,
|
||||||
COALESCE(MAX(b.timestamp), NOW()) AS time_to,
|
COALESCE(MAX(b.timestamp), NOW()) AS time_to,
|
||||||
COALESCE(
|
EXTRACT(
|
||||||
EXTRACT(EPOCH FROM SUM(
|
EPOCH
|
||||||
|
FROM
|
||||||
|
SUM(
|
||||||
CASE
|
CASE
|
||||||
WHEN b.prev_check IN (1, 3) AND b.check_in_out IN (2, 4, 254)
|
WHEN b.prev_check IN (1, 3)
|
||||||
THEN b.timestamp - b.prev_timestamp
|
AND b.check_in_out IN (2, 4, 254) THEN b.timestamp - b.prev_timestamp
|
||||||
ELSE INTERVAL '0'
|
ELSE INTERVAL '0'
|
||||||
END
|
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
|
) AS total_work_seconds,
|
||||||
FROM all_days d
|
EXTRACT(
|
||||||
LEFT JOIN ordered_bookings b ON d.work_date = b.work_date
|
EPOCH
|
||||||
GROUP BY d.work_date
|
FROM
|
||||||
ORDER BY d.work_date ASC;`)
|
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(`
|
// qStr, err := DB.Prepare(`
|
||||||
// WITH all_days AS (
|
// WITH all_days AS (
|
||||||
// SELECT generate_series($2::DATE, $3::DATE - INTERVAL '1 day', INTERVAL '1 day')::DATE AS work_date),
|
// 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
|
// SELECT
|
||||||
// a.timestamp::DATE AS work_date,
|
// a.card_uid,
|
||||||
// a.timestamp,
|
// a.timestamp,
|
||||||
|
// a.timestamp::DATE AS work_date,
|
||||||
// a.check_in_out,
|
// a.check_in_out,
|
||||||
// a.counter_id,
|
// a.counter_id,
|
||||||
// a.anwesenheit_typ,
|
// a.anwesenheit_typ,
|
||||||
// sat.anwesenheit_name AS anwesenheit_typ_name,
|
// 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 (
|
||||||
// LAG(a.check_in_out) OVER (PARTITION BY a.card_uid, a.timestamp::DATE ORDER BY a.timestamp) AS prev_check
|
// PARTITION BY a.card_uid, a.timestamp::DATE
|
||||||
|
// ORDER BY a.timestamp
|
||||||
|
// ) AS prev_check
|
||||||
// FROM anwesenheit a
|
// 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
|
// WHERE a.card_uid = $1
|
||||||
// AND a.timestamp::DATE >= $2
|
// AND a.timestamp::DATE >= $2
|
||||||
// AND a.timestamp::DATE <= $3
|
// 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
|
// SELECT
|
||||||
// d.work_date,
|
// d.work_date,
|
||||||
@@ -330,26 +381,29 @@ func GetWorkDays(user User, tsFrom, tsTo time.Time) []WorkDay {
|
|||||||
var workDay WorkDay
|
var workDay WorkDay
|
||||||
var bookings []byte
|
var bookings []byte
|
||||||
if err := rows.Scan(&workDay.Day, &workDay.TimeFrom, &workDay.TimeTo, &workSec, &pauseSec, &bookings); err != nil {
|
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
|
return workDays
|
||||||
}
|
}
|
||||||
workDay.workTime = time.Duration(workSec * float64(time.Second))
|
workDay.workTime = time.Duration(workSec * float64(time.Second))
|
||||||
workDay.pauseTime = time.Duration(pauseSec * float64(time.Second))
|
workDay.pauseTime = time.Duration(pauseSec * float64(time.Second))
|
||||||
|
if bookings != nil {
|
||||||
err = json.Unmarshal(bookings, &workDay.Bookings)
|
err = json.Unmarshal(bookings, &workDay.Bookings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error parsing bookings JSON!", err)
|
slog.Error("Error parsing bookings JSON!", "Error", err, "Json", bookings)
|
||||||
return nil
|
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()) {
|
if len(workDay.Bookings) >= 1 || !helper.IsWeekend(workDay.Date()) {
|
||||||
workDays = append(workDays, workDay)
|
workDays = append(workDays, workDay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = rows.Err(); err != nil {
|
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
|
||||||
}
|
}
|
||||||
return workDays
|
return workDays
|
||||||
|
|||||||
@@ -205,9 +205,15 @@
|
|||||||
.top-0 {
|
.top-0 {
|
||||||
top: calc(var(--spacing) * 0);
|
top: calc(var(--spacing) * 0);
|
||||||
}
|
}
|
||||||
|
.top-1 {
|
||||||
|
top: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
.top-1\/2 {
|
.top-1\/2 {
|
||||||
top: calc(1/2 * 100%);
|
top: calc(1/2 * 100%);
|
||||||
}
|
}
|
||||||
|
.top-2 {
|
||||||
|
top: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
.top-2\.5 {
|
.top-2\.5 {
|
||||||
top: calc(var(--spacing) * 2.5);
|
top: calc(var(--spacing) * 2.5);
|
||||||
}
|
}
|
||||||
@@ -217,9 +223,15 @@
|
|||||||
.right-1 {
|
.right-1 {
|
||||||
right: calc(var(--spacing) * 1);
|
right: calc(var(--spacing) * 1);
|
||||||
}
|
}
|
||||||
|
.right-2 {
|
||||||
|
right: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
.right-2\.5 {
|
.right-2\.5 {
|
||||||
right: calc(var(--spacing) * 2.5);
|
right: calc(var(--spacing) * 2.5);
|
||||||
}
|
}
|
||||||
|
.left-1 {
|
||||||
|
left: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
.left-1\/2 {
|
.left-1\/2 {
|
||||||
left: calc(1/2 * 100%);
|
left: calc(1/2 * 100%);
|
||||||
}
|
}
|
||||||
@@ -350,6 +362,9 @@
|
|||||||
.block {
|
.block {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
.contents {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
.flex {
|
.flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
@@ -383,6 +398,9 @@
|
|||||||
.h-2 {
|
.h-2 {
|
||||||
height: calc(var(--spacing) * 2);
|
height: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
|
.h-3 {
|
||||||
|
height: calc(var(--spacing) * 3);
|
||||||
|
}
|
||||||
.h-3\.5 {
|
.h-3\.5 {
|
||||||
height: calc(var(--spacing) * 3.5);
|
height: calc(var(--spacing) * 3.5);
|
||||||
}
|
}
|
||||||
@@ -407,6 +425,9 @@
|
|||||||
.w-2 {
|
.w-2 {
|
||||||
width: calc(var(--spacing) * 2);
|
width: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
|
.w-3 {
|
||||||
|
width: calc(var(--spacing) * 3);
|
||||||
|
}
|
||||||
.w-3\.5 {
|
.w-3\.5 {
|
||||||
width: calc(var(--spacing) * 3.5);
|
width: calc(var(--spacing) * 3.5);
|
||||||
}
|
}
|
||||||
@@ -416,6 +437,9 @@
|
|||||||
.w-5 {
|
.w-5 {
|
||||||
width: calc(var(--spacing) * 5);
|
width: calc(var(--spacing) * 5);
|
||||||
}
|
}
|
||||||
|
.w-9 {
|
||||||
|
width: calc(var(--spacing) * 9);
|
||||||
|
}
|
||||||
.w-9\/10 {
|
.w-9\/10 {
|
||||||
width: calc(9/10 * 100%);
|
width: calc(9/10 * 100%);
|
||||||
}
|
}
|
||||||
@@ -428,6 +452,9 @@
|
|||||||
.w-full {
|
.w-full {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.flex-shrink {
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
.flex-shrink-0 {
|
.flex-shrink-0 {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
@@ -443,10 +470,21 @@
|
|||||||
.basis-\[content\] {
|
.basis-\[content\] {
|
||||||
flex-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 {
|
.-translate-x-1\/2 {
|
||||||
--tw-translate-x: calc(calc(1/2 * 100%) * -1);
|
--tw-translate-x: calc(calc(1/2 * 100%) * -1);
|
||||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
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 {
|
.-translate-y-1\/2 {
|
||||||
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
|
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
|
||||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||||
@@ -457,33 +495,21 @@
|
|||||||
.cursor-pointer {
|
.cursor-pointer {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.resize {
|
||||||
|
resize: both;
|
||||||
|
}
|
||||||
.scroll-m-2 {
|
.scroll-m-2 {
|
||||||
scroll-margin: calc(var(--spacing) * 2);
|
scroll-margin: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
.appearance-none {
|
.appearance-none {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
}
|
}
|
||||||
.break-after-page {
|
|
||||||
break-after: page;
|
|
||||||
}
|
|
||||||
.auto-rows-min {
|
|
||||||
grid-auto-rows: min-content;
|
|
||||||
}
|
|
||||||
.grid-cols-2 {
|
.grid-cols-2 {
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
.grid-cols-5 {
|
.grid-cols-5 {
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
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-col {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@@ -534,11 +560,6 @@
|
|||||||
border-bottom-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
|
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-end {
|
||||||
justify-self: flex-end;
|
justify-self: flex-end;
|
||||||
}
|
}
|
||||||
@@ -565,18 +586,10 @@
|
|||||||
border-style: var(--tw-border-style);
|
border-style: var(--tw-border-style);
|
||||||
border-width: 0px;
|
border-width: 0px;
|
||||||
}
|
}
|
||||||
.border-r-0 {
|
|
||||||
border-right-style: var(--tw-border-style);
|
|
||||||
border-right-width: 0px;
|
|
||||||
}
|
|
||||||
.border-r-1 {
|
.border-r-1 {
|
||||||
border-right-style: var(--tw-border-style);
|
border-right-style: var(--tw-border-style);
|
||||||
border-right-width: 1px;
|
border-right-width: 1px;
|
||||||
}
|
}
|
||||||
.border-b-0 {
|
|
||||||
border-bottom-style: var(--tw-border-style);
|
|
||||||
border-bottom-width: 0px;
|
|
||||||
}
|
|
||||||
.border-dashed {
|
.border-dashed {
|
||||||
--tw-border-style: dashed;
|
--tw-border-style: dashed;
|
||||||
border-style: dashed;
|
border-style: dashed;
|
||||||
@@ -587,9 +600,6 @@
|
|||||||
.border-neutral-500 {
|
.border-neutral-500 {
|
||||||
border-color: var(--color-neutral-500);
|
border-color: var(--color-neutral-500);
|
||||||
}
|
}
|
||||||
.border-neutral-600 {
|
|
||||||
border-color: var(--color-neutral-600);
|
|
||||||
}
|
|
||||||
.border-slate-800 {
|
.border-slate-800 {
|
||||||
border-color: var(--color-slate-800);
|
border-color: var(--color-slate-800);
|
||||||
}
|
}
|
||||||
@@ -614,15 +624,15 @@
|
|||||||
.bg-red-600 {
|
.bg-red-600 {
|
||||||
background-color: var(--color-red-600);
|
background-color: var(--color-red-600);
|
||||||
}
|
}
|
||||||
|
.mask-repeat {
|
||||||
|
mask-repeat: repeat;
|
||||||
|
}
|
||||||
.p-1 {
|
.p-1 {
|
||||||
padding: calc(var(--spacing) * 1);
|
padding: calc(var(--spacing) * 1);
|
||||||
}
|
}
|
||||||
.p-2 {
|
.p-2 {
|
||||||
padding: calc(var(--spacing) * 2);
|
padding: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
.p-8 {
|
|
||||||
padding: calc(var(--spacing) * 8);
|
|
||||||
}
|
|
||||||
.px-3 {
|
.px-3 {
|
||||||
padding-inline: calc(var(--spacing) * 3);
|
padding-inline: calc(var(--spacing) * 3);
|
||||||
}
|
}
|
||||||
@@ -635,10 +645,6 @@
|
|||||||
.text-center {
|
.text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.text-2xl {
|
|
||||||
font-size: var(--text-2xl);
|
|
||||||
line-height: var(--tw-leading, var(--text-2xl--line-height));
|
|
||||||
}
|
|
||||||
.text-sm {
|
.text-sm {
|
||||||
font-size: var(--text-sm);
|
font-size: var(--text-sm);
|
||||||
line-height: var(--tw-leading, var(--text-sm--line-height));
|
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||||
@@ -654,15 +660,15 @@
|
|||||||
.whitespace-nowrap {
|
.whitespace-nowrap {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
.\!text-red-500 {
|
||||||
|
color: var(--color-red-500) !important;
|
||||||
|
}
|
||||||
.text-accent {
|
.text-accent {
|
||||||
color: var(--color-accent);
|
color: var(--color-accent);
|
||||||
}
|
}
|
||||||
.text-black {
|
.text-black {
|
||||||
color: var(--color-black);
|
color: var(--color-black);
|
||||||
}
|
}
|
||||||
.text-neutral-300 {
|
|
||||||
color: var(--color-neutral-300);
|
|
||||||
}
|
|
||||||
.text-neutral-500 {
|
.text-neutral-500 {
|
||||||
color: var(--color-neutral-500);
|
color: var(--color-neutral-500);
|
||||||
}
|
}
|
||||||
@@ -690,9 +696,16 @@
|
|||||||
.uppercase {
|
.uppercase {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
.underline {
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
.opacity-0 {
|
.opacity-0 {
|
||||||
opacity: 0%;
|
opacity: 0%;
|
||||||
}
|
}
|
||||||
|
.outline {
|
||||||
|
outline-style: var(--tw-outline-style);
|
||||||
|
outline-width: 1px;
|
||||||
|
}
|
||||||
.filter {
|
.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,);
|
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;
|
-webkit-user-select: none;
|
||||||
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 {
|
.group-hover\:text-black {
|
||||||
&:is(:where(.group):hover *) {
|
&:is(:where(.group):hover *) {
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
@@ -1138,6 +1139,11 @@
|
|||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
}
|
}
|
||||||
|
@property --tw-outline-style {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
initial-value: solid;
|
||||||
|
}
|
||||||
@property --tw-blur {
|
@property --tw-blur {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
@@ -1210,6 +1216,7 @@
|
|||||||
--tw-border-style: solid;
|
--tw-border-style: solid;
|
||||||
--tw-divide-y-reverse: 0;
|
--tw-divide-y-reverse: 0;
|
||||||
--tw-font-weight: initial;
|
--tw-font-weight: initial;
|
||||||
|
--tw-outline-style: solid;
|
||||||
--tw-blur: initial;
|
--tw-blur: initial;
|
||||||
--tw-brightness: initial;
|
--tw-brightness: initial;
|
||||||
--tw-contrast: initial;
|
--tw-contrast: initial;
|
||||||
|
|||||||
@@ -77,10 +77,13 @@ templ newBookingComponent(d models.IWorkDay) {
|
|||||||
|
|
||||||
templ bookingComponent(booking models.Booking) {
|
templ bookingComponent(booking models.Booking) {
|
||||||
<div>
|
<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>
|
<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"/>
|
<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() }
|
{ booking.GetBookingType() }
|
||||||
|
if !booking.Valid {
|
||||||
|
fehlerhafte Buchung, wird nicht zur Berechnung verwendet!
|
||||||
|
}
|
||||||
</p>
|
</p>
|
||||||
if booking.IsSubmittedAndChecked() {
|
if booking.IsSubmittedAndChecked() {
|
||||||
<p>submitted</p>
|
<p>submitted</p>
|
||||||
@@ -89,10 +92,10 @@ templ bookingComponent(booking models.Booking) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
templ workdayComponent(workDay *models.WorkDay) {
|
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>
|
<p class="text group-[.edit]:hidden">Keine Buchung gefunden. Bitte Arbeitsstunden oder Grund der Abwesenheit eingeben!</p>
|
||||||
} else {
|
} else {
|
||||||
if workDay.IsKurzArbeit() && len(workDay.Bookings) > 0 {
|
if workDay.IsKurzArbeit() {
|
||||||
@absenceComponent(workDay.GetKurzArbeit(), true)
|
@absenceComponent(workDay.GetKurzArbeit(), true)
|
||||||
}
|
}
|
||||||
for _, booking := range workDay.Bookings {
|
for _, booking := range workDay.Bookings {
|
||||||
|
|||||||
Reference in New Issue
Block a user