diff --git a/web/src/app/features/auth/login.component.ts b/web/src/app/features/auth/login.component.ts
index 9310134..05c69fb 100644
--- a/web/src/app/features/auth/login.component.ts
+++ b/web/src/app/features/auth/login.component.ts
@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common';
-import { Component, inject, signal } from '@angular/core';
+import { Component, computed, inject, signal } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { AppSettingsService } from '../../core/services/app-settings.service';
@@ -24,50 +24,26 @@ import { UiService } from '../../core/services/ui.service';
{{ mode() === 'login' ? loginSubtitle() : registerSubtitle() }}
-
@@ -89,16 +65,26 @@ import { UiService } from '../../core/services/ui.service';
+ @if (errorMessage()) {
+ {{ errorMessage() }}
+ }
+
+
+
@if (appSettings.registrationEnabled()) {
@@ -121,6 +107,8 @@ export class LoginComponent {
readonly loading = signal(false);
readonly mode = signal<'login' | 'register'>('login');
+ readonly errorMessage = signal(null);
+ readonly currentLanguageLabel = computed(() => this.ui.language() === 'pl' ? 'Polski' : 'English');
readonly form = this.fb.nonNullable.group({
email: ['', [Validators.required, Validators.email]],
@@ -134,6 +122,7 @@ export class LoginComponent {
submit() {
if (this.form.invalid) return;
+ this.errorMessage.set(null);
this.loading.set(true);
const raw = this.form.getRawValue();
@@ -144,8 +133,10 @@ export class LoginComponent {
this.router.navigate(['/']);
},
error: (error) => {
+ const message = error.error?.message ?? 'Nie udało się zalogować.';
this.loading.set(false);
- this.toast.error(error.error?.message ?? 'Nie udało się zalogować.');
+ this.errorMessage.set(message);
+ this.toast.error(message);
}
});
return;
@@ -154,16 +145,28 @@ export class LoginComponent {
this.auth.register({ email: raw.email, password: raw.password, fullName: raw.fullName || raw.email }).subscribe({
next: () => {
this.loading.set(false);
+ this.errorMessage.set(null);
this.toast.success('Konto zostało utworzone.');
this.mode.set('login');
},
error: (error) => {
+ const message = error.error?.message ?? 'Nie udało się utworzyć konta.';
this.loading.set(false);
- this.toast.error(error.error?.message ?? 'Nie udało się utworzyć konta.');
+ this.errorMessage.set(message);
+ this.toast.error(message);
}
});
}
+ toggleLanguage() {
+ this.ui.setLanguage(this.ui.language() === 'pl' ? 'en' : 'pl');
+ }
+
+ switchMode() {
+ this.errorMessage.set(null);
+ this.mode.set(this.mode() === 'login' ? 'register' : 'login');
+ }
+
loginSubtitle() {
return this.ui.language() === 'pl'
? 'Zaloguj się, aby zarządzać wydatkami, kontrahentami i raportami.'
diff --git a/web/src/styles.scss b/web/src/styles.scss
index 2e2b5f9..760e988 100644
--- a/web/src/styles.scss
+++ b/web/src/styles.scss
@@ -3,16 +3,18 @@
:root {
--tblr-primary: #111827;
--tblr-primary-rgb: 17, 24, 39;
- --tblr-border-radius: 0.75rem;
- --tblr-border-radius-lg: 0.9rem;
- --tblr-border-radius-sm: 0.45rem;
- --tblr-card-border-radius: 0.9rem;
+ --tblr-border-radius: 1rem;
+ --tblr-border-radius-lg: 1rem;
+ --tblr-border-radius-sm: 0.75rem;
+ --tblr-card-border-radius: 1rem;
--tblr-body-bg: #f4f6f8;
--ec-shell-bg: #f4f6f8;
--ec-card-shadow: 0 2px 8px rgba(15, 23, 42, 0.05);
--ec-card-border: rgba(15, 23, 42, 0.08);
--ec-navbar-bg: rgba(255, 255, 255, 0.95);
--ec-subnav-bg: rgba(255, 255, 255, 0.9);
+ --ec-light-radius-sm: 0.75rem;
+ --ec-light-radius-md: 1rem;
}
html,
@@ -24,6 +26,41 @@ body {
background: var(--ec-shell-bg);
}
+[data-bs-theme="light"] {
+ --tblr-border-radius: var(--ec-light-radius-md);
+ --tblr-border-radius-lg: var(--ec-light-radius-md);
+ --tblr-border-radius-sm: var(--ec-light-radius-sm);
+ --tblr-card-border-radius: var(--ec-light-radius-md);
+}
+
+[data-bs-theme="light"] .card,
+[data-bs-theme="light"] .pv-card,
+[data-bs-theme="light"] .login-card,
+[data-bs-theme="light"] .modal-content,
+[data-bs-theme="light"] .alert,
+[data-bs-theme="light"] .toast,
+[data-bs-theme="light"] .dropdown-menu,
+[data-bs-theme="light"] .table-responsive,
+[data-bs-theme="light"] .form-control,
+[data-bs-theme="light"] .form-select,
+[data-bs-theme="light"] .form-check-input,
+[data-bs-theme="light"] .input-group-text,
+[data-bs-theme="light"] .btn,
+[data-bs-theme="light"] .nav-segmented,
+[data-bs-theme="light"] .nav-pills .nav-link,
+[data-bs-theme="light"] .nav-tabs .nav-link,
+[data-bs-theme="light"] .page-link {
+ border-radius: var(--ec-light-radius-md);
+}
+
+[data-bs-theme="light"] .rounded-3 {
+ border-radius: var(--ec-light-radius-md) !important;
+}
+
+[data-bs-theme="light"] .rounded-2 {
+ border-radius: var(--ec-light-radius-sm) !important;
+}
+
[data-bs-theme="dark"] {
--tblr-primary: #0f172a;
--tblr-primary-rgb: 15, 23, 42;
@@ -158,7 +195,21 @@ body {
}
.login-card-enhanced {
+ position: relative;
overflow: hidden;
+ border-width: 1px;
+}
+
+.login-card-enhanced::before {
+ content: "";
+ position: absolute;
+ inset: 0 0 auto 0;
+ height: 5px;
+ background: linear-gradient(90deg, rgba(32, 107, 196, 0.95), rgba(47, 179, 68, 0.9));
+}
+
+.login-card-enhanced .card-body {
+ position: relative;
}
.login-input-stack {
@@ -175,6 +226,8 @@ body {
.login-footer-note {
margin-top: 1rem;
+ padding-top: 1rem;
+ border-top: 1px solid rgba(148, 163, 184, 0.18);
color: var(--tblr-secondary);
font-size: 0.875rem;
}