Reisezeit aus Start/Ende, Pause pro Eintrag in Minuten

- Reisezeit wird aus Reise-Beginn/-Ende zur Laufzeit berechnet (Spalte reisezeit entfernt),
  Anzeige in Vorschau und Liste wie Mehrarbeit
- Pause pro Eintrag in Minuten (Feld zwischen Beginn und Ende), Default aus globaler Einstellung
- Eingabefelder werden nach dem Speichern eines neuen Eintrags geleert
- DB-Migrationen für reise_beginn/reise_ende/pause-Spalten
- Version 0.1.2

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 17:00:57 +02:00
parent 74eedf7c3d
commit cb168fbd18
10 changed files with 147 additions and 66 deletions
+9 -3
View File
@@ -48,10 +48,16 @@ und liefern 401 ohne Session.
## Datenmodell & Berechnungen ## Datenmodell & Berechnungen
Tabelle `arbeitszeit`: `datum`, `ort` (Kunde FFM | Homeoffice | Andrena), `beginn`, `ende` Tabelle `arbeitszeit`: `datum`, `ort` (Kunde FFM | Homeoffice | Andrena), `beginn`, `ende`
(je HH:MM), `reisezeit`, `vertriebsunterstuetzung` (default 2), `kommentar` (max. 500). (je HH:MM), `reise_beginn`, `reise_ende` (je HH:MM, optional), `pause` (dezimale Stunden),
`vertriebsunterstuetzung` (default 2), `kommentar` (max. 500).
- `Arbeitszeit = Ende Beginn` (dezimale Stunden) - `Arbeitszeit = Ende Beginn` (dezimale Stunden)
- `Reisezeit = Reise-Ende Reise-Beginn`: im Formular werden Start/Ende eingegeben, die
Reisezeit wird wie Mehrarbeit zur Laufzeit berechnet (nicht gespeichert) und in Vorschau
und Liste angezeigt. Beim Speichern koppelt sie nur die Vertriebsunterstützung.
- `Mehrarbeit = Arbeitszeit 8 Pause` - `Mehrarbeit = Arbeitszeit 8 Pause`
- Die Spalte „Arbeitszeit Kunde" ist fix 8 h (`ARBEITSZEIT_KUNDE_FIX`). - Die Spalte „Arbeitszeit Kunde" ist fix 8 h (`ARBEITSZEIT_KUNDE_FIX`).
- Die **Pause** ist eine globale Einstellung in der `settings`-Tabelle (Tab „Einstellungen"). - Die **Pause** wird pro Eintrag gespeichert (Spalte `pause`, dezimale Stunden; Eingabe im
Mehrarbeit wird zur Laufzeit berechnet, nicht gespeichert. Formular in Minuten zwischen Beginn und Ende). Standard ist die globale Pause-Einstellung
in der `settings`-Tabelle (Tab „Einstellungen"). Mehrarbeit wird je Eintrag aus dieser
Pause zur Laufzeit berechnet, nicht gespeichert.
+1 -2
View File
@@ -121,7 +121,6 @@ export default function MainClient({ username }: Props) {
</button> </button>
</div> </div>
<ArbeitszeitList <ArbeitszeitList
pause={pause}
refreshKey={refreshKey} refreshKey={refreshKey}
onEdit={handleEdit} onEdit={handleEdit}
limit={10} limit={10}
@@ -135,7 +134,7 @@ export default function MainClient({ username }: Props) {
{/* Liste-Tab */} {/* Liste-Tab */}
{activeTab === 'liste' && ( {activeTab === 'liste' && (
<div className="border-2 border-gray-400 rounded-xl bg-white p-3 print:border-0 print:rounded-none print:p-0"> <div className="border-2 border-gray-400 rounded-xl bg-white p-3 print:border-0 print:rounded-none print:p-0">
<ArbeitszeitList pause={pause} refreshKey={refreshKey} onEdit={handleEdit} limit={100} /> <ArbeitszeitList refreshKey={refreshKey} onEdit={handleEdit} limit={100} />
</div> </div>
)} )}
+72 -21
View File
@@ -44,7 +44,12 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
const [ort, setOrt] = useState<string>(editEntry?.ort ?? ORTE[0]); const [ort, setOrt] = useState<string>(editEntry?.ort ?? ORTE[0]);
const [beginn, setBeginn] = useState(editEntry?.beginn ?? ''); const [beginn, setBeginn] = useState(editEntry?.beginn ?? '');
const [ende, setEnde] = useState(editEntry?.ende ?? ''); const [ende, setEnde] = useState(editEntry?.ende ?? '');
const [reisezeit, setReisezeit] = useState(editEntry ? numToStr(editEntry.reisezeit) : '0'); // Pause pro Eintrag in Minuten; Standard ist die globale Einstellung (Stunden → Minuten).
const [pauseMin, setPauseMin] = useState(
String(Math.round((editEntry?.pause ?? pause) * 60))
);
const [reiseBeginn, setReiseBeginn] = useState(editEntry?.reise_beginn ?? '');
const [reiseEnde, setReiseEnde] = useState(editEntry?.reise_ende ?? '');
const [vertrieb, setVertrieb] = useState(editEntry ? numToStr(editEntry.vertriebsunterstuetzung) : '0'); const [vertrieb, setVertrieb] = useState(editEntry ? numToStr(editEntry.vertriebsunterstuetzung) : '0');
const [kommentar, setKommentar] = useState(editEntry?.kommentar ?? ''); const [kommentar, setKommentar] = useState(editEntry?.kommentar ?? '');
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
@@ -53,21 +58,31 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
const zeiten = hatZeiten(beginn, ende); const zeiten = hatZeiten(beginn, ende);
const arbeitszeit = toDecimalHours(beginn, ende); const arbeitszeit = toDecimalHours(beginn, ende);
const mehr = mehrarbeit(arbeitszeit, pause); const pauseStd = Math.max(0, toNum(pauseMin)) / 60;
const vertriebFrei = vertriebEditierbar(toNum(reisezeit)); const mehr = mehrarbeit(arbeitszeit, pauseStd);
const reisezeit = toDecimalHours(reiseBeginn, reiseEnde);
const reiseZeiten = hatZeiten(reiseBeginn, reiseEnde);
const vertriebFrei = vertriebEditierbar(reisezeit);
// Vertriebsunterstützung an die Reisezeit koppeln (siehe applyVertriebsregel): // Vertriebsunterstützung an die (aus den Reise-Zeiten berechnete) Reisezeit koppeln
// (siehe applyVertriebsregel):
// =0 ⇒ 0, <2 ⇒ = Reisezeit, ≥2 ⇒ 2 beim Überschreiten der Schwelle, danach frei änderbar. // =0 ⇒ 0, <2 ⇒ = Reisezeit, ≥2 ⇒ 2 beim Überschreiten der Schwelle, danach frei änderbar.
function handleReisezeit(raw: string) { function koppleVertrieb(altReise: number, neuReise: number) {
const alt = toNum(reisezeit); if (neuReise <= 0) setVertrieb('0');
const neu = toNum(raw); else if (neuReise < 2) setVertrieb(numToStr(neuReise));
setReisezeit(raw); else if (altReise < 2) setVertrieb('2'); // Schwelle 2h überschritten → Standard 2h
if (neu <= 0) setVertrieb('0');
else if (neu < 2) setVertrieb(numToStr(neu));
else if (alt < 2) setVertrieb('2'); // Schwelle 2h überschritten → Standard 2h
// neu ≥ 2 und alt ≥ 2: bestehenden (ggf. geänderten) Wert beibehalten // neu ≥ 2 und alt ≥ 2: bestehenden (ggf. geänderten) Wert beibehalten
} }
function handleReiseBeginn(raw: string) {
koppleVertrieb(reisezeit, toDecimalHours(raw, reiseEnde));
setReiseBeginn(raw);
}
function handleReiseEnde(raw: string) {
koppleVertrieb(reisezeit, toDecimalHours(reiseBeginn, raw));
setReiseEnde(raw);
}
async function handleSubmit(e: React.FormEvent) { async function handleSubmit(e: React.FormEvent) {
e.preventDefault(); e.preventDefault();
setError(''); setError('');
@@ -84,6 +99,17 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
return; return;
} }
const reiseBeginnLeer = reiseBeginn === '';
const reiseEndeLeer = reiseEnde === '';
if (reiseBeginnLeer !== reiseEndeLeer) {
setError('Bitte Reise-Start und -Ende gemeinsam angeben oder beide leer lassen.');
return;
}
if (!reiseBeginnLeer && !reiseEndeLeer && reisezeit <= 0) {
setError('Reise-Ende muss nach dem Reise-Start liegen.');
return;
}
setSaving(true); setSaving(true);
const body = { const body = {
@@ -91,7 +117,9 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
ort, ort,
beginn, beginn,
ende, ende,
reisezeit: toNum(reisezeit), reise_beginn: reiseBeginn,
reise_ende: reiseEnde,
pause: pauseStd,
vertriebsunterstuetzung: toNum(vertrieb), vertriebsunterstuetzung: toNum(vertrieb),
kommentar, kommentar,
}; };
@@ -111,6 +139,18 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
} }
setSuccess(true); setSuccess(true);
setTimeout(() => setSuccess(false), 4000); setTimeout(() => setSuccess(false), 4000);
// Beim Anlegen die Eingabefelder wieder auf die Startwerte zurücksetzen.
if (!editEntry) {
setDatum(todayDate());
setOrt(ORTE[0]);
setBeginn('');
setEnde('');
setPauseMin(String(Math.round(pause * 60)));
setReiseBeginn('');
setReiseEnde('');
setVertrieb('0');
setKommentar('');
}
onSaved(); onSaved();
} catch (err) { } catch (err) {
setError(err instanceof Error ? err.message : 'Fehler beim Speichern.'); setError(err instanceof Error ? err.message : 'Fehler beim Speichern.');
@@ -160,19 +200,27 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
<label className={labelCls}>Beginn</label> <label className={labelCls}>Beginn</label>
<TimeInput value={beginn} onChange={setBeginn} className="w-24" /> <TimeInput value={beginn} onChange={setBeginn} className="w-24" />
</div> </div>
<div className="shrink-0">
<label className={labelCls}>Pause (min)</label>
<input
type="text"
inputMode="numeric"
value={pauseMin}
onChange={(e) => setPauseMin(e.target.value.replace(/[^0-9]/g, ''))}
className={numCls}
/>
</div>
<div className="shrink-0"> <div className="shrink-0">
<label className={labelCls}>Ende</label> <label className={labelCls}>Ende</label>
<TimeInput value={ende} onChange={setEnde} className="w-24" /> <TimeInput value={ende} onChange={setEnde} className="w-24" />
</div> </div>
<div className="shrink-0"> <div className="shrink-0">
<label className={labelCls}>Reisezeit (h)</label> <label className={labelCls}>Reise-Beginn</label>
<input <TimeInput value={reiseBeginn} onChange={handleReiseBeginn} className="w-24" />
type="text" </div>
inputMode="decimal" <div className="shrink-0">
value={reisezeit} <label className={labelCls}>Reise-Ende</label>
onChange={(e) => handleReisezeit(e.target.value)} <TimeInput value={reiseEnde} onChange={handleReiseEnde} className="w-24" />
className={numCls}
/>
</div> </div>
<div className="shrink-0"> <div className="shrink-0">
<label className={labelCls}>Vertriebsunterst. (h)</label> <label className={labelCls}>Vertriebsunterst. (h)</label>
@@ -212,7 +260,7 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
Arbeitszeit Kunde: <strong>{zeiten ? `${formatHours(ARBEITSZEIT_KUNDE_FIX)} h` : '—'}</strong> Arbeitszeit Kunde: <strong>{zeiten ? `${formatHours(ARBEITSZEIT_KUNDE_FIX)} h` : '—'}</strong>
</span> </span>
<span> <span>
Pause: <strong>{formatHours(pause)} h</strong> Pause: <strong>{formatHours(pauseStd)} h</strong>
</span> </span>
<span> <span>
Mehrarbeit:{' '} Mehrarbeit:{' '}
@@ -220,6 +268,9 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
{zeiten ? `${formatHours(mehr)} h` : '—'} {zeiten ? `${formatHours(mehr)} h` : '—'}
</strong> </strong>
</span> </span>
<span>
Reisezeit: <strong>{reiseZeiten ? `${formatHours(reisezeit)} h` : '—'}</strong>
</span>
</div> </div>
{error && ( {error && (
+4 -4
View File
@@ -5,7 +5,6 @@ import { ARBEITSZEIT_KUNDE_FIX, type ArbeitszeitEintrag } from '@/types/arbeitsz
import { toDecimalHours, mehrarbeit, weekdayName, formatHours, hatZeiten } from '@/lib/calc'; import { toDecimalHours, mehrarbeit, weekdayName, formatHours, hatZeiten } from '@/lib/calc';
interface Props { interface Props {
pause: number;
refreshKey: number; refreshKey: number;
onEdit: (entry: ArbeitszeitEintrag) => void; onEdit: (entry: ArbeitszeitEintrag) => void;
limit?: number; limit?: number;
@@ -36,7 +35,7 @@ function formatDate(d: string) {
return m ? `${m[3]}.${m[2]}.${m[1]}` : d; return m ? `${m[3]}.${m[2]}.${m[1]}` : d;
} }
export default function ArbeitszeitList({ pause, refreshKey, onEdit, limit = 15, compact = false }: Props) { export default function ArbeitszeitList({ refreshKey, onEdit, limit = 15, compact = false }: Props) {
const [entries, setEntries] = useState<ArbeitszeitEintrag[]>([]); const [entries, setEntries] = useState<ArbeitszeitEintrag[]>([]);
const [month, setMonth] = useState(compact ? '' : currentMonth()); const [month, setMonth] = useState(compact ? '' : currentMonth());
const [deleteId, setDeleteId] = useState<number | null>(null); const [deleteId, setDeleteId] = useState<number | null>(null);
@@ -132,7 +131,8 @@ export default function ArbeitszeitList({ pause, refreshKey, onEdit, limit = 15,
</tr> </tr>
) : entries.map((e) => { ) : entries.map((e) => {
const zeiten = hatZeiten(e.beginn, e.ende); const zeiten = hatZeiten(e.beginn, e.ende);
const mehr = mehrarbeit(toDecimalHours(e.beginn, e.ende), pause); const mehr = mehrarbeit(toDecimalHours(e.beginn, e.ende), e.pause);
const reisezeit = toDecimalHours(e.reise_beginn, e.reise_ende);
return ( return (
<tr key={e.id} className="hover:bg-gray-50"> <tr key={e.id} className="hover:bg-gray-50">
<td className={`${cell} whitespace-nowrap`}>{formatDate(e.datum)}</td> <td className={`${cell} whitespace-nowrap`}>{formatDate(e.datum)}</td>
@@ -140,7 +140,7 @@ export default function ArbeitszeitList({ pause, refreshKey, onEdit, limit = 15,
<td className={cell}>{e.ort}</td> <td className={cell}>{e.ort}</td>
<td className={`${cell} text-right`}>{zeiten ? formatHours(ARBEITSZEIT_KUNDE_FIX) : '—'}</td> <td className={`${cell} text-right`}>{zeiten ? formatHours(ARBEITSZEIT_KUNDE_FIX) : '—'}</td>
<td className={`${cell} text-right ${zeiten && mehr < 0 ? 'text-red-600' : ''}`}>{zeiten ? formatHours(mehr) : '—'}</td> <td className={`${cell} text-right ${zeiten && mehr < 0 ? 'text-red-600' : ''}`}>{zeiten ? formatHours(mehr) : '—'}</td>
<td className={`${cell} text-right`}>{e.reisezeit ? formatHours(e.reisezeit) : '—'}</td> <td className={`${cell} text-right`}>{reisezeit ? formatHours(reisezeit) : '—'}</td>
<td className={`${cell} text-right`}>{e.vertriebsunterstuetzung ? formatHours(e.vertriebsunterstuetzung) : '—'}</td> <td className={`${cell} text-right`}>{e.vertriebsunterstuetzung ? formatHours(e.vertriebsunterstuetzung) : '—'}</td>
<td className={cell}>{e.kommentar}</td> <td className={cell}>{e.kommentar}</td>
<td className={`${cell} text-center whitespace-nowrap print:hidden`}> <td className={`${cell} text-center whitespace-nowrap print:hidden`}>
+29 -1
View File
@@ -25,7 +25,9 @@ export function getDb(): Database.Database {
ort TEXT NOT NULL, ort TEXT NOT NULL,
beginn TEXT NOT NULL, beginn TEXT NOT NULL,
ende TEXT NOT NULL, ende TEXT NOT NULL,
reisezeit REAL NOT NULL DEFAULT 0, reise_beginn TEXT NOT NULL DEFAULT '',
reise_ende TEXT NOT NULL DEFAULT '',
pause REAL NOT NULL DEFAULT 0.5,
vertriebsunterstuetzung REAL NOT NULL DEFAULT 2, vertriebsunterstuetzung REAL NOT NULL DEFAULT 2,
kommentar TEXT NOT NULL DEFAULT '', kommentar TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL DEFAULT (datetime('now')) created_at TEXT NOT NULL DEFAULT (datetime('now'))
@@ -49,11 +51,37 @@ export function getDb(): Database.Database {
); );
`); `);
// Migration: Reise-Start/-Ende für bestehende Datenbanken ergänzen.
const cols = (db.prepare(`PRAGMA table_info(arbeitszeit)`).all() as { name: string }[]).map(
(c) => c.name
);
if (!cols.includes('reise_beginn')) {
db.exec(`ALTER TABLE arbeitszeit ADD COLUMN reise_beginn TEXT NOT NULL DEFAULT ''`);
}
if (!cols.includes('reise_ende')) {
db.exec(`ALTER TABLE arbeitszeit ADD COLUMN reise_ende TEXT NOT NULL DEFAULT ''`);
}
// Reisezeit wird zur Laufzeit aus reise_beginn/reise_ende berechnet, nicht mehr gespeichert.
if (cols.includes('reisezeit')) {
db.exec(`ALTER TABLE arbeitszeit DROP COLUMN reisezeit`);
}
// Standard-Pause beim ersten Start setzen (0,5 h) // Standard-Pause beim ersten Start setzen (0,5 h)
db.prepare( db.prepare(
`INSERT INTO settings (key, value) VALUES ('pause', '0.5') `INSERT INTO settings (key, value) VALUES ('pause', '0.5')
ON CONFLICT(key) DO NOTHING` ON CONFLICT(key) DO NOTHING`
).run(); ).run();
// Migration: Pause pro Eintrag ergänzen. Bestehende Zeilen bekommen die aktuelle
// globale Pause-Einstellung als Wert.
if (!cols.includes('pause')) {
const row = db.prepare(`SELECT value FROM settings WHERE key = 'pause'`).get() as
| { value: string }
| undefined;
const globalPause = row ? parseFloat(row.value) : 0.5;
const def = isNaN(globalPause) ? 0.5 : globalPause;
db.exec(`ALTER TABLE arbeitszeit ADD COLUMN pause REAL NOT NULL DEFAULT ${def}`);
}
return db; return db;
} }
+4 -3
View File
@@ -43,8 +43,8 @@ export function createArbeitszeit(input: ArbeitszeitInput): ArbeitszeitEintrag {
const db = getDb(); const db = getDb();
const info = db const info = db
.prepare( .prepare(
`INSERT INTO arbeitszeit (datum, ort, beginn, ende, reisezeit, vertriebsunterstuetzung, kommentar) `INSERT INTO arbeitszeit (datum, ort, beginn, ende, reise_beginn, reise_ende, pause, vertriebsunterstuetzung, kommentar)
VALUES (@datum, @ort, @beginn, @ende, @reisezeit, @vertriebsunterstuetzung, @kommentar)` VALUES (@datum, @ort, @beginn, @ende, @reise_beginn, @reise_ende, @pause, @vertriebsunterstuetzung, @kommentar)`
) )
.run(input); .run(input);
return getArbeitszeit(Number(info.lastInsertRowid))!; return getArbeitszeit(Number(info.lastInsertRowid))!;
@@ -58,7 +58,8 @@ export function updateArbeitszeit(
db.prepare( db.prepare(
`UPDATE arbeitszeit SET `UPDATE arbeitszeit SET
datum = @datum, ort = @ort, beginn = @beginn, ende = @ende, datum = @datum, ort = @ort, beginn = @beginn, ende = @ende,
reisezeit = @reisezeit, vertriebsunterstuetzung = @vertriebsunterstuetzung, reise_beginn = @reise_beginn, reise_ende = @reise_ende,
pause = @pause, vertriebsunterstuetzung = @vertriebsunterstuetzung,
kommentar = @kommentar kommentar = @kommentar
WHERE id = @id` WHERE id = @id`
).run({ ...input, id }); ).run({ ...input, id });
+21 -4
View File
@@ -1,5 +1,6 @@
import { ORTE, type ArbeitszeitInput, type Ort } from '@/types/arbeitszeit'; import { ORTE, type ArbeitszeitInput, type Ort } from '@/types/arbeitszeit';
import { parseHM, applyVertriebsregel } from './calc'; import { parseHM, applyVertriebsregel, toDecimalHours } from './calc';
import { getPause } from './repo';
/** /**
* Validiert und normalisiert einen JSON-Body zu einem ArbeitszeitInput. * Validiert und normalisiert einen JSON-Body zu einem ArbeitszeitInput.
@@ -24,9 +25,25 @@ export function parseArbeitszeitInput(body: unknown): ArbeitszeitInput {
throw new Error('Bitte Start- und Endzeit gemeinsam angeben oder beide leer lassen.'); throw new Error('Bitte Start- und Endzeit gemeinsam angeben oder beide leer lassen.');
} }
const reisezeit = toNumber(b.reisezeit, 0); // Reise-Start/-Ende sind optional (analog Beginn/Ende). Wenn angegeben,
// müssen sie gültig sein; entweder beide leer oder beide gesetzt.
const reise_beginn = String(b.reise_beginn ?? '');
const reise_ende = String(b.reise_ende ?? '');
if (reise_beginn !== '' && parseHM(reise_beginn) === null)
throw new Error('Ungültige Reise-Startzeit.');
if (reise_ende !== '' && parseHM(reise_ende) === null)
throw new Error('Ungültige Reise-Endzeit.');
if ((reise_beginn === '') !== (reise_ende === '')) {
throw new Error('Bitte Reise-Start und -Ende gemeinsam angeben oder beide leer lassen.');
}
// Reisezeit wird zur Laufzeit aus den Reise-Zeiten berechnet (nicht gespeichert),
// dient hier aber zur Kopplung der Vertriebsunterstützung.
const reisezeit = toDecimalHours(reise_beginn, reise_ende);
// Pause pro Eintrag (dezimale Stunden). Standard ist die globale Einstellung.
const pause = toNumber(b.pause, getPause());
let vertriebsunterstuetzung = toNumber(b.vertriebsunterstuetzung, 2); let vertriebsunterstuetzung = toNumber(b.vertriebsunterstuetzung, 2);
if (reisezeit < 0 || vertriebsunterstuetzung < 0) { if (pause < 0 || vertriebsunterstuetzung < 0) {
throw new Error('Zeitwerte dürfen nicht negativ sein.'); throw new Error('Zeitwerte dürfen nicht negativ sein.');
} }
// Regel: Vertriebsunterstützung an die Reisezeit koppeln. // Regel: Vertriebsunterstützung an die Reisezeit koppeln.
@@ -35,7 +52,7 @@ export function parseArbeitszeitInput(body: unknown): ArbeitszeitInput {
const kommentar = String(b.kommentar ?? '').slice(0, 500); const kommentar = String(b.kommentar ?? '').slice(0, 500);
return { datum, ort, beginn, ende, reisezeit, vertriebsunterstuetzung, kommentar }; return { datum, ort, beginn, ende, reise_beginn, reise_ende, pause, vertriebsunterstuetzung, kommentar };
} }
function toNumber(value: unknown, fallback: number): number { function toNumber(value: unknown, fallback: number): number {
+3 -26
View File
@@ -1,12 +1,12 @@
{ {
"name": "arbeitszeit", "name": "arbeitszeit",
"version": "0.1.1", "version": "0.1.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "arbeitszeit", "name": "arbeitszeit",
"version": "0.1.1", "version": "0.1.2",
"dependencies": { "dependencies": {
"@simplewebauthn/browser": "^13.3.0", "@simplewebauthn/browser": "^13.3.0",
"@simplewebauthn/server": "^13.3.1", "@simplewebauthn/server": "^13.3.1",
@@ -282,30 +282,6 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.1",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
"integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/wasi-threads": { "node_modules/@emnapi/wasi-threads": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
@@ -3691,6 +3667,7 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@rtsao/scc": "^1.1.0", "@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9", "array-includes": "^3.1.9",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "arbeitszeit", "name": "arbeitszeit",
"version": "0.1.1", "version": "0.1.2",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
+3 -1
View File
@@ -10,7 +10,9 @@ export interface ArbeitszeitEintrag {
ort: Ort; ort: Ort;
beginn: string; // HH:MM beginn: string; // HH:MM
ende: string; // HH:MM ende: string; // HH:MM
reisezeit: number; // dezimale Stunden reise_beginn: string; // HH:MM, leer wenn keine Reise
reise_ende: string; // HH:MM, leer wenn keine Reise
pause: number; // dezimale Stunden (Eingabe im Formular in Minuten)
vertriebsunterstuetzung: number; // dezimale Stunden vertriebsunterstuetzung: number; // dezimale Stunden
kommentar: string; kommentar: string;
created_at: string; created_at: string;