second commit
This commit is contained in:
+9
-7
@@ -118,7 +118,7 @@ final class App
|
||||
}
|
||||
|
||||
if ($password !== $passwordConfirm) {
|
||||
flash('error', 'Die Passwoerter stimmen nicht ueberein.');
|
||||
flash('error', 'Die Passwörter stimmen nicht überein.');
|
||||
redirect('/setup');
|
||||
}
|
||||
|
||||
@@ -153,12 +153,12 @@ final class App
|
||||
|
||||
if (!$this->auth->attempt($username, $password)) {
|
||||
$this->throttle->hit($throttleKey);
|
||||
flash('error', 'Login fehlgeschlagen. Bitte pruefe Benutzername und Passwort.');
|
||||
flash('error', 'Login fehlgeschlagen. Bitte prüfe Benutzername und Passwort.');
|
||||
redirect('/login');
|
||||
}
|
||||
|
||||
$this->throttle->clear($throttleKey);
|
||||
flash('success', 'Willkommen zurueck.');
|
||||
flash('success', 'Willkommen zurück.');
|
||||
redirect('/');
|
||||
}
|
||||
|
||||
@@ -219,6 +219,8 @@ final class App
|
||||
'entry' => $entry,
|
||||
'evaluation' => $evaluation,
|
||||
'settings' => $settings,
|
||||
'trackMood' => $evaluation['sentiment'],
|
||||
'topbarDate' => $entry['date'],
|
||||
'trackPayload' => encode_payload([
|
||||
'settings' => $settings,
|
||||
'entry' => $entry,
|
||||
@@ -246,7 +248,7 @@ final class App
|
||||
]);
|
||||
|
||||
if (!$this->isValidDate($entry['date'])) {
|
||||
flash('error', 'Bitte waehle ein gueltiges Datum.');
|
||||
flash('error', 'Bitte wähle ein gültiges Datum.');
|
||||
redirect('/track');
|
||||
}
|
||||
|
||||
@@ -344,7 +346,7 @@ final class App
|
||||
}
|
||||
|
||||
if ($new !== $confirm) {
|
||||
flash('error', 'Die neuen Passwoerter stimmen nicht ueberein.');
|
||||
flash('error', 'Die neuen Passwörter stimmen nicht überein.');
|
||||
redirect('/options');
|
||||
}
|
||||
|
||||
@@ -359,7 +361,7 @@ final class App
|
||||
$isAdmin = isset($_POST['is_admin']) && $_POST['is_admin'] === '1';
|
||||
|
||||
if (!$this->isValidUsername($username)) {
|
||||
flash('error', 'Bitte nutze fuer neue Accounts einen sauberen Benutzernamen.');
|
||||
flash('error', 'Bitte nutze für neue Accounts einen sauberen Benutzernamen.');
|
||||
redirect('/options');
|
||||
}
|
||||
|
||||
@@ -538,7 +540,7 @@ final class App
|
||||
{
|
||||
if (!verify_csrf($_POST['_token'] ?? null)) {
|
||||
http_response_code(419);
|
||||
exit('Ungueltiges Formular-Token.');
|
||||
exit('Ungültiges Formular-Token.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ final class EntryRepository
|
||||
'energy' => (int) ($this->extract('/^- Energie:\s*(.+)$/m', $content) ?? 5),
|
||||
'stress' => (int) ($this->extract('/^- Stress:\s*(.+)$/m', $content) ?? 5),
|
||||
'sleep_hours' => (float) ($this->extract('/^- Schlafdauer:\s*(.+)$/m', $content) ?? 0),
|
||||
'sleep_feeling' => (int) ($this->extract('/^- Schlafgefuehl:\s*(.+)$/m', $content) ?? 3),
|
||||
'sleep_feeling' => (int) ($this->extract('/^- Schlaf(?:gefühl|gefuehl):\s*(.+)$/mu', $content) ?? 3),
|
||||
'sport_minutes' => (int) ($this->extract('/^- Sport:\s*(.+)$/m', $content) ?? 0),
|
||||
'walk_minutes' => (int) ($this->extract('/^- Spaziergang:\s*(.+)$/m', $content) ?? 0),
|
||||
'note' => $this->extractNote($content),
|
||||
@@ -112,7 +112,7 @@ final class EntryRepository
|
||||
'- Energie: ' . $entry['energy'],
|
||||
'- Stress: ' . $entry['stress'],
|
||||
'- Schlafdauer: ' . $entry['sleep_hours'],
|
||||
'- Schlafgefuehl: ' . $entry['sleep_feeling'],
|
||||
'- Schlafgefühl: ' . $entry['sleep_feeling'],
|
||||
'- Sport: ' . $entry['sport_minutes'],
|
||||
'- Spaziergang: ' . $entry['walk_minutes'],
|
||||
'',
|
||||
@@ -125,7 +125,7 @@ final class EntryRepository
|
||||
'- Energie: ' . format_points((float) $evaluation['components']['energy']),
|
||||
'- Stress: ' . format_points((float) $evaluation['components']['stress']),
|
||||
'- Schlafdauer: ' . format_points((float) $evaluation['components']['sleep_hours']),
|
||||
'- Schlafgefuehl: ' . format_points((float) $evaluation['components']['sleep_feeling']),
|
||||
'- Schlafgefühl: ' . format_points((float) $evaluation['components']['sleep_feeling']),
|
||||
'- Sport: ' . format_points((float) $evaluation['components']['sport_minutes']),
|
||||
'- Spaziergang: ' . format_points((float) $evaluation['components']['walk_minutes']),
|
||||
'- Notiz: ' . format_points((float) $evaluation['components']['note']),
|
||||
|
||||
@@ -72,6 +72,7 @@ final class ScoringService
|
||||
'max_total' => $maxTotal,
|
||||
'label' => $label,
|
||||
'guardrail' => $guardrail,
|
||||
'sentiment' => $this->sentimentForLabel($label, $ratings),
|
||||
'percentage' => $maxTotal > 0 ? round(($total / $maxTotal) * 100, 1) : 0,
|
||||
];
|
||||
}
|
||||
@@ -168,5 +169,24 @@ final class ScoringService
|
||||
|
||||
return $currentIndex > $capIndex ? $cap : $current;
|
||||
}
|
||||
}
|
||||
|
||||
private function sentimentForLabel(string $label, array $ratings): string
|
||||
{
|
||||
$order = array_values(array_map(static fn (array $rating): string => (string) $rating['label'], $ratings));
|
||||
$index = array_search($label, $order, true);
|
||||
|
||||
if ($index === false || count($order) <= 1) {
|
||||
return 'steady';
|
||||
}
|
||||
|
||||
$ratio = $index / max(count($order) - 1, 1);
|
||||
|
||||
return match (true) {
|
||||
$ratio <= 0.1 => 'storm',
|
||||
$ratio <= 0.35 => 'heavy',
|
||||
$ratio <= 0.65 => 'steady',
|
||||
$ratio <= 0.9 => 'bright',
|
||||
default => 'radiant',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ final class UserRepository
|
||||
$normalized = normalize_username($username);
|
||||
|
||||
if ($normalized === '' || $this->find($normalized) !== null) {
|
||||
throw new RuntimeException('Benutzername existiert bereits oder ist ungueltig.');
|
||||
throw new RuntimeException('Benutzername existiert bereits oder ist ungültig.');
|
||||
}
|
||||
|
||||
$users = $this->all();
|
||||
@@ -100,4 +100,3 @@ final class UserRepository
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,3 +122,56 @@ function encode_payload(array $payload): string
|
||||
return base64_encode((string) json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
|
||||
function shift_date(string $date, int $days): string
|
||||
{
|
||||
$current = DateTimeImmutable::createFromFormat('Y-m-d', $date);
|
||||
|
||||
if ($current === false) {
|
||||
return today();
|
||||
}
|
||||
|
||||
return $current->modify(($days >= 0 ? '+' : '') . $days . ' day')->format('Y-m-d');
|
||||
}
|
||||
|
||||
function format_display_date(string $date, bool $withWeekday = true): string
|
||||
{
|
||||
$current = DateTimeImmutable::createFromFormat('Y-m-d', $date);
|
||||
|
||||
if ($current === false) {
|
||||
return $date;
|
||||
}
|
||||
|
||||
$weekdays = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
|
||||
$months = [
|
||||
1 => 'Januar',
|
||||
2 => 'Februar',
|
||||
3 => 'März',
|
||||
4 => 'April',
|
||||
5 => 'Mai',
|
||||
6 => 'Juni',
|
||||
7 => 'Juli',
|
||||
8 => 'August',
|
||||
9 => 'September',
|
||||
10 => 'Oktober',
|
||||
11 => 'November',
|
||||
12 => 'Dezember',
|
||||
];
|
||||
|
||||
$label = $current->format('j.') . ' ' . $months[(int) $current->format('n')] . ' ' . $current->format('Y');
|
||||
|
||||
if (!$withWeekday) {
|
||||
return $label;
|
||||
}
|
||||
|
||||
return $weekdays[(int) $current->format('w')] . ', ' . $label;
|
||||
}
|
||||
|
||||
function icon_path(string $name): string
|
||||
{
|
||||
return '/assets/icons/' . $name . '.svg';
|
||||
}
|
||||
|
||||
function mood_icon_path(string $sentiment): string
|
||||
{
|
||||
return icon_path('mood-' . $sentiment);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user