@open-mercato/core 0.5.1-develop.2975.ccbadc8198 → 0.5.1-develop.2996.ce62fd491c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/sidebar_variant/index.js +25 -0
  3. package/dist/generated/entities/sidebar_variant/index.js.map +7 -0
  4. package/dist/generated/entities.ids.generated.js +1 -0
  5. package/dist/generated/entities.ids.generated.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +13 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/helpers/integration/authUi.js +1 -1
  9. package/dist/helpers/integration/authUi.js.map +2 -2
  10. package/dist/modules/audit_logs/services/actionLogService.js +4 -5
  11. package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
  12. package/dist/modules/auth/api/sidebar/preferences/route.js +224 -35
  13. package/dist/modules/auth/api/sidebar/preferences/route.js.map +3 -3
  14. package/dist/modules/auth/api/sidebar/variants/[id]/route.js +161 -0
  15. package/dist/modules/auth/api/sidebar/variants/[id]/route.js.map +7 -0
  16. package/dist/modules/auth/api/sidebar/variants/route.js +142 -0
  17. package/dist/modules/auth/api/sidebar/variants/route.js.map +7 -0
  18. package/dist/modules/auth/backend/sidebar-customization/page.js +16 -0
  19. package/dist/modules/auth/backend/sidebar-customization/page.js.map +7 -0
  20. package/dist/modules/auth/backend/sidebar-customization/page.meta.js +28 -0
  21. package/dist/modules/auth/backend/sidebar-customization/page.meta.js.map +7 -0
  22. package/dist/modules/auth/data/entities.js +45 -4
  23. package/dist/modules/auth/data/entities.js.map +2 -2
  24. package/dist/modules/auth/data/validators.js +63 -1
  25. package/dist/modules/auth/data/validators.js.map +2 -2
  26. package/dist/modules/auth/migrations/Migration20260427081815.js +15 -0
  27. package/dist/modules/auth/migrations/Migration20260427081815.js.map +7 -0
  28. package/dist/modules/auth/migrations/Migration20260427124900.js +15 -0
  29. package/dist/modules/auth/migrations/Migration20260427124900.js.map +7 -0
  30. package/dist/modules/auth/migrations/Migration20260427143311.js +72 -0
  31. package/dist/modules/auth/migrations/Migration20260427143311.js.map +7 -0
  32. package/dist/modules/auth/services/sidebarPreferencesService.js +176 -16
  33. package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
  34. package/dist/modules/customers/backend/customers/companies/[id]/page.js +3 -1
  35. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  36. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +4 -2
  37. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  38. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +8 -3
  39. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  40. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -2
  41. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  42. package/dist/modules/customers/components/formConfig.js +3 -3
  43. package/dist/modules/customers/components/formConfig.js.map +2 -2
  44. package/dist/modules/customers/lib/displayName.js +12 -0
  45. package/dist/modules/customers/lib/displayName.js.map +2 -2
  46. package/dist/modules/entities/cli.js +5 -6
  47. package/dist/modules/entities/cli.js.map +2 -2
  48. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js +124 -0
  49. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js.map +7 -0
  50. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.meta.js +11 -0
  51. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.meta.js.map +7 -0
  52. package/generated/entities/sidebar_variant/index.ts +11 -0
  53. package/generated/entities.ids.generated.ts +1 -0
  54. package/generated/entity-fields-registry.ts +13 -0
  55. package/package.json +6 -6
  56. package/src/helpers/integration/authUi.ts +1 -1
  57. package/src/modules/audit_logs/services/actionLogService.ts +5 -6
  58. package/src/modules/auth/api/sidebar/preferences/route.ts +266 -34
  59. package/src/modules/auth/api/sidebar/variants/[id]/route.ts +183 -0
  60. package/src/modules/auth/api/sidebar/variants/route.ts +157 -0
  61. package/src/modules/auth/backend/sidebar-customization/page.meta.ts +34 -0
  62. package/src/modules/auth/backend/sidebar-customization/page.tsx +17 -0
  63. package/src/modules/auth/data/entities.ts +48 -2
  64. package/src/modules/auth/data/validators.ts +70 -0
  65. package/src/modules/auth/migrations/.snapshot-open-mercato.json +790 -71
  66. package/src/modules/auth/migrations/Migration20260427081815.ts +16 -0
  67. package/src/modules/auth/migrations/Migration20260427124900.ts +19 -0
  68. package/src/modules/auth/migrations/Migration20260427143311.ts +83 -0
  69. package/src/modules/auth/services/sidebarPreferencesService.ts +243 -18
  70. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +5 -4
  71. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +6 -5
  72. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +13 -9
  73. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +3 -2
  74. package/src/modules/customers/components/formConfig.tsx +3 -3
  75. package/src/modules/customers/lib/displayName.ts +21 -0
  76. package/src/modules/entities/cli.ts +5 -6
  77. package/src/modules/portal/frontend/[orgSlug]/portal/reset-password/page.meta.ts +9 -0
  78. package/src/modules/portal/frontend/[orgSlug]/portal/reset-password/page.tsx +168 -0
  79. package/src/modules/portal/i18n/de.json +20 -0
  80. package/src/modules/portal/i18n/en.json +20 -0
  81. package/src/modules/portal/i18n/es.json +20 -0
  82. package/src/modules/portal/i18n/pl.json +20 -0
@@ -0,0 +1,168 @@
1
+ "use client"
2
+ import { useCallback, useMemo, useState, useEffect } from 'react'
3
+ import { useSearchParams } from 'next/navigation'
4
+ import Link from 'next/link'
5
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
6
+ import { Input } from '@open-mercato/ui/primitives/input'
7
+ import { Label } from '@open-mercato/ui/primitives/label'
8
+ import { Button } from '@open-mercato/ui/primitives/button'
9
+ import { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'
10
+ import { Spinner } from '@open-mercato/ui/primitives/spinner'
11
+ import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
12
+ import { usePortalContext } from '@open-mercato/ui/portal/PortalContext'
13
+ import { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'
14
+ import { PortalInjectionSpots } from '@open-mercato/ui/backend/injection/spotIds'
15
+
16
+ type Props = { params: { orgSlug: string } }
17
+
18
+ export default function PortalResetPasswordPage({ params }: Props) {
19
+ const t = useT()
20
+ const orgSlug = params.orgSlug
21
+ const { tenant } = usePortalContext()
22
+ const searchParams = useSearchParams()
23
+
24
+ const [password, setPassword] = useState('')
25
+ const [confirmPassword, setConfirmPassword] = useState('')
26
+ const [error, setError] = useState<string | null>(null)
27
+ const [success, setSuccess] = useState(false)
28
+ const [submitting, setSubmitting] = useState(false)
29
+ const [token, setToken] = useState<string | null>(null)
30
+
31
+ useEffect(() => {
32
+ const tokenParam = searchParams.get('token')
33
+ if (!tokenParam) {
34
+ setError(t('portal.resetPassword.error.noToken', 'Invalid or missing reset token.'))
35
+ } else {
36
+ setToken(tokenParam)
37
+ }
38
+ }, [searchParams, t])
39
+
40
+ const handleSubmit = useCallback(
41
+ async (event: React.FormEvent) => {
42
+ event.preventDefault()
43
+ setError(null)
44
+
45
+ if (!token) {
46
+ setError(t('portal.resetPassword.error.noToken', 'Invalid or missing reset token.'))
47
+ return
48
+ }
49
+
50
+ if (password !== confirmPassword) {
51
+ setError(t('portal.resetPassword.error.passwordMismatch', 'Passwords do not match.'))
52
+ return
53
+ }
54
+
55
+ if (password.length < 8) {
56
+ setError(t('portal.resetPassword.error.passwordTooShort', 'Password must be at least 8 characters long.'))
57
+ return
58
+ }
59
+
60
+ setSubmitting(true)
61
+ try {
62
+ const result = await apiCall<{ ok: boolean; error?: string }>('/api/customer_accounts/password/reset-confirm', {
63
+ method: 'POST',
64
+ headers: { 'Content-Type': 'application/json' },
65
+ body: JSON.stringify({ token, password }),
66
+ })
67
+
68
+ if (result.ok && result.result?.ok) {
69
+ setSuccess(true)
70
+ return
71
+ }
72
+
73
+ if (result.status === 400) {
74
+ setError(t('portal.resetPassword.error.invalidToken', 'Invalid or expired reset token.'))
75
+ } else {
76
+ setError(result.result?.error || t('portal.resetPassword.error.generic', 'Password reset failed. Please try again.'))
77
+ }
78
+ } catch {
79
+ setError(t('portal.resetPassword.error.generic', 'Password reset failed. Please try again.'))
80
+ } finally {
81
+ setSubmitting(false)
82
+ }
83
+ },
84
+ [token, password, confirmPassword, t],
85
+ )
86
+
87
+ const injectionContext = useMemo(
88
+ () => ({ orgSlug }),
89
+ [orgSlug],
90
+ )
91
+
92
+ if (tenant.loading) {
93
+ return <div className="flex items-center justify-center py-20"><Spinner /></div>
94
+ }
95
+
96
+ if (tenant.error) {
97
+ return (
98
+ <div className="mx-auto w-full max-w-md py-12">
99
+ <Alert variant="destructive">
100
+ <AlertDescription>{t('portal.org.invalid', 'Organization not found.')}</AlertDescription>
101
+ </Alert>
102
+ </div>
103
+ )
104
+ }
105
+
106
+ if (success) {
107
+ return (
108
+ <div className="mx-auto w-full max-w-sm">
109
+ <div className="mb-8 text-center">
110
+ <h1 className="text-2xl font-bold tracking-tight">{t('portal.resetPassword.success.title', 'Password Reset Complete')}</h1>
111
+ <p className="mt-1.5 text-sm text-muted-foreground">{t('portal.resetPassword.success.description', 'Your password has been successfully reset.')}</p>
112
+ </div>
113
+
114
+ <Alert>
115
+ <AlertDescription>{t('portal.resetPassword.success.message', 'You can now sign in with your new password.')}</AlertDescription>
116
+ </Alert>
117
+
118
+ <div className="mt-6 text-center">
119
+ <Link href={`/${orgSlug}/portal/login`} className="font-medium text-foreground underline underline-offset-4 hover:opacity-80">
120
+ {t('portal.resetPassword.success.loginLink', 'Go to Sign In')}
121
+ </Link>
122
+ </div>
123
+ </div>
124
+ )
125
+ }
126
+
127
+ return (
128
+ <div className="mx-auto w-full max-w-sm">
129
+ <div className="mb-8 text-center">
130
+ <h1 className="text-2xl font-bold tracking-tight">{t('portal.resetPassword.title', 'Reset Password')}</h1>
131
+ <p className="mt-1.5 text-sm text-muted-foreground">{t('portal.resetPassword.description', 'Enter your new password below.')}</p>
132
+ </div>
133
+
134
+ <InjectionSpot spotId={PortalInjectionSpots.pageBefore('reset-password')} context={injectionContext} />
135
+
136
+ <form onSubmit={handleSubmit} className="flex flex-col gap-4">
137
+ {error ? (
138
+ <Alert variant="destructive">
139
+ <AlertDescription>{error}</AlertDescription>
140
+ </Alert>
141
+ ) : null}
142
+
143
+ <div className="flex flex-col gap-1.5">
144
+ <Label htmlFor="reset-password" className="text-overline font-semibold uppercase tracking-wider text-muted-foreground/70">{t('portal.resetPassword.password', 'New Password')}</Label>
145
+ <Input id="reset-password" type="password" autoComplete="new-password" required placeholder={t('portal.resetPassword.password.placeholder', '••••••••')} value={password} onChange={(e) => setPassword(e.target.value)} disabled={submitting || !token} className="rounded-lg" />
146
+ </div>
147
+
148
+ <div className="flex flex-col gap-1.5">
149
+ <Label htmlFor="confirm-password" className="text-overline font-semibold uppercase tracking-wider text-muted-foreground/70">{t('portal.resetPassword.confirmPassword', 'Confirm New Password')}</Label>
150
+ <Input id="confirm-password" type="password" autoComplete="new-password" required placeholder={t('portal.resetPassword.confirmPassword.placeholder', '••••••••')} value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} disabled={submitting || !token} className="rounded-lg" />
151
+ </div>
152
+
153
+ <Button type="submit" disabled={submitting || !token} className="mt-1 w-full rounded-lg">
154
+ {submitting ? t('portal.resetPassword.submitting', 'Resetting password...') : t('portal.resetPassword.submit', 'Reset Password')}
155
+ </Button>
156
+
157
+ <p className="text-center text-sm text-muted-foreground">
158
+ {t('portal.resetPassword.backToLogin', 'Remember your password?')}{' '}
159
+ <Link href={`/${orgSlug}/portal/login`} className="font-medium text-foreground underline underline-offset-4 hover:opacity-80">
160
+ {t('portal.resetPassword.loginLink', 'Sign in')}
161
+ </Link>
162
+ </p>
163
+ </form>
164
+
165
+ <InjectionSpot spotId={PortalInjectionSpots.pageAfter('reset-password')} context={injectionContext} />
166
+ </div>
167
+ )
168
+ }
@@ -52,6 +52,7 @@
52
52
  "portal.nav.login": "Anmelden",
53
53
  "portal.nav.logout": "Abmelden",
54
54
  "portal.nav.profile": "Profil",
55
+ "portal.nav.resetPassword": "Passwort zurücksetzen",
55
56
  "portal.nav.signup": "Registrieren",
56
57
  "portal.notifications.badge": "{count} ungelesen",
57
58
  "portal.notifications.daysAgo": "vor {d} Tagen",
@@ -73,6 +74,25 @@
73
74
  "portal.org.noOrganization": "Kein Organisationskontext verfügbar.",
74
75
  "portal.profile.label": "Konto",
75
76
  "portal.profile.title": "Profil",
77
+ "portal.resetPassword.backToLogin": "Erinnern Sie sich an Ihr Passwort?",
78
+ "portal.resetPassword.confirmPassword": "Neues Passwort bestätigen",
79
+ "portal.resetPassword.confirmPassword.placeholder": "••••••••",
80
+ "portal.resetPassword.description": "Geben Sie unten Ihr neues Passwort ein.",
81
+ "portal.resetPassword.error.generic": "Passwort-Zurücksetzung fehlgeschlagen. Bitte versuchen Sie es erneut.",
82
+ "portal.resetPassword.error.invalidToken": "Ungültiges oder abgelaufenes Zurücksetzungs-Token.",
83
+ "portal.resetPassword.error.noToken": "Ungültiges oder fehlendes Zurücksetzungs-Token.",
84
+ "portal.resetPassword.error.passwordMismatch": "Passwörter stimmen nicht überein.",
85
+ "portal.resetPassword.error.passwordTooShort": "Das Passwort muss mindestens 8 Zeichen lang sein.",
86
+ "portal.resetPassword.loginLink": "Anmelden",
87
+ "portal.resetPassword.password": "Neues Passwort",
88
+ "portal.resetPassword.password.placeholder": "••••••••",
89
+ "portal.resetPassword.submit": "Passwort zurücksetzen",
90
+ "portal.resetPassword.submitting": "Passwort wird zurückgesetzt…",
91
+ "portal.resetPassword.success.description": "Ihr Passwort wurde erfolgreich zurückgesetzt.",
92
+ "portal.resetPassword.success.loginLink": "Zur Anmeldung",
93
+ "portal.resetPassword.success.message": "Sie können sich jetzt mit Ihrem neuen Passwort anmelden.",
94
+ "portal.resetPassword.success.title": "Passwort zurückgesetzt",
95
+ "portal.resetPassword.title": "Passwort zurücksetzen",
76
96
  "portal.signup.description": "Registrieren Sie ein neues Kundenkonto.",
77
97
  "portal.signup.displayName": "Anzeigename",
78
98
  "portal.signup.displayName.placeholder": "Ihr Name",
@@ -52,6 +52,7 @@
52
52
  "portal.nav.login": "Log In",
53
53
  "portal.nav.logout": "Log Out",
54
54
  "portal.nav.profile": "Profile",
55
+ "portal.nav.resetPassword": "Reset Password",
55
56
  "portal.nav.signup": "Sign Up",
56
57
  "portal.notifications.badge": "{count} unread",
57
58
  "portal.notifications.daysAgo": "{d}d ago",
@@ -73,6 +74,25 @@
73
74
  "portal.org.noOrganization": "No organization context available.",
74
75
  "portal.profile.label": "Account",
75
76
  "portal.profile.title": "Profile",
77
+ "portal.resetPassword.backToLogin": "Remember your password?",
78
+ "portal.resetPassword.confirmPassword": "Confirm New Password",
79
+ "portal.resetPassword.confirmPassword.placeholder": "••••••••",
80
+ "portal.resetPassword.description": "Enter your new password below.",
81
+ "portal.resetPassword.error.generic": "Password reset failed. Please try again.",
82
+ "portal.resetPassword.error.invalidToken": "Invalid or expired reset token.",
83
+ "portal.resetPassword.error.noToken": "Invalid or missing reset token.",
84
+ "portal.resetPassword.error.passwordMismatch": "Passwords do not match.",
85
+ "portal.resetPassword.error.passwordTooShort": "Password must be at least 8 characters long.",
86
+ "portal.resetPassword.loginLink": "Sign in",
87
+ "portal.resetPassword.password": "New Password",
88
+ "portal.resetPassword.password.placeholder": "••••••••",
89
+ "portal.resetPassword.submit": "Reset Password",
90
+ "portal.resetPassword.submitting": "Resetting password…",
91
+ "portal.resetPassword.success.description": "Your password has been successfully reset.",
92
+ "portal.resetPassword.success.loginLink": "Go to Sign In",
93
+ "portal.resetPassword.success.message": "You can now sign in with your new password.",
94
+ "portal.resetPassword.success.title": "Password Reset Complete",
95
+ "portal.resetPassword.title": "Reset Password",
76
96
  "portal.signup.description": "Register for a new customer account.",
77
97
  "portal.signup.displayName": "Display Name",
78
98
  "portal.signup.displayName.placeholder": "Your name",
@@ -52,6 +52,7 @@
52
52
  "portal.nav.login": "Iniciar sesión",
53
53
  "portal.nav.logout": "Cerrar sesión",
54
54
  "portal.nav.profile": "Perfil",
55
+ "portal.nav.resetPassword": "Restablecer contraseña",
55
56
  "portal.nav.signup": "Registrarse",
56
57
  "portal.notifications.badge": "{count} sin leer",
57
58
  "portal.notifications.daysAgo": "hace {d} días",
@@ -73,6 +74,25 @@
73
74
  "portal.org.noOrganization": "No hay contexto de organización disponible.",
74
75
  "portal.profile.label": "Cuenta",
75
76
  "portal.profile.title": "Perfil",
77
+ "portal.resetPassword.backToLogin": "¿Recuerdas tu contraseña?",
78
+ "portal.resetPassword.confirmPassword": "Confirmar nueva contraseña",
79
+ "portal.resetPassword.confirmPassword.placeholder": "••••••••",
80
+ "portal.resetPassword.description": "Introduce tu nueva contraseña a continuación.",
81
+ "portal.resetPassword.error.generic": "El restablecimiento de la contraseña falló. Inténtalo de nuevo.",
82
+ "portal.resetPassword.error.invalidToken": "Token de restablecimiento no válido o expirado.",
83
+ "portal.resetPassword.error.noToken": "Token de restablecimiento no válido o faltante.",
84
+ "portal.resetPassword.error.passwordMismatch": "Las contraseñas no coinciden.",
85
+ "portal.resetPassword.error.passwordTooShort": "La contraseña debe tener al menos 8 caracteres.",
86
+ "portal.resetPassword.loginLink": "Iniciar sesión",
87
+ "portal.resetPassword.password": "Nueva contraseña",
88
+ "portal.resetPassword.password.placeholder": "••••••••",
89
+ "portal.resetPassword.submit": "Restablecer contraseña",
90
+ "portal.resetPassword.submitting": "Restableciendo contraseña…",
91
+ "portal.resetPassword.success.description": "Tu contraseña se ha restablecido correctamente.",
92
+ "portal.resetPassword.success.loginLink": "Ir a Iniciar sesión",
93
+ "portal.resetPassword.success.message": "Ahora puedes iniciar sesión con tu nueva contraseña.",
94
+ "portal.resetPassword.success.title": "Contraseña restablecida",
95
+ "portal.resetPassword.title": "Restablecer contraseña",
76
96
  "portal.signup.description": "Regístrate para una nueva cuenta de cliente.",
77
97
  "portal.signup.displayName": "Nombre para mostrar",
78
98
  "portal.signup.displayName.placeholder": "Tu nombre",
@@ -52,6 +52,7 @@
52
52
  "portal.nav.login": "Zaloguj się",
53
53
  "portal.nav.logout": "Wyloguj się",
54
54
  "portal.nav.profile": "Profil",
55
+ "portal.nav.resetPassword": "Reset hasła",
55
56
  "portal.nav.signup": "Rejestracja",
56
57
  "portal.notifications.badge": "{count} nieprzeczytanych",
57
58
  "portal.notifications.daysAgo": "{d} dni temu",
@@ -73,6 +74,25 @@
73
74
  "portal.org.noOrganization": "Brak kontekstu organizacji.",
74
75
  "portal.profile.label": "Konto",
75
76
  "portal.profile.title": "Profil",
77
+ "portal.resetPassword.backToLogin": "Pamiętasz hasło?",
78
+ "portal.resetPassword.confirmPassword": "Potwierdź nowe hasło",
79
+ "portal.resetPassword.confirmPassword.placeholder": "••••••••",
80
+ "portal.resetPassword.description": "Wprowadź nowe hasło poniżej.",
81
+ "portal.resetPassword.error.generic": "Reset hasła nie powiódł się. Spróbuj ponownie.",
82
+ "portal.resetPassword.error.invalidToken": "Nieprawidłowy lub wygasły token resetowania.",
83
+ "portal.resetPassword.error.noToken": "Nieprawidłowy lub brakujący token resetowania.",
84
+ "portal.resetPassword.error.passwordMismatch": "Hasła nie pasują do siebie.",
85
+ "portal.resetPassword.error.passwordTooShort": "Hasło musi mieć co najmniej 8 znaków.",
86
+ "portal.resetPassword.loginLink": "Zaloguj się",
87
+ "portal.resetPassword.password": "Nowe hasło",
88
+ "portal.resetPassword.password.placeholder": "••••••••",
89
+ "portal.resetPassword.submit": "Zresetuj hasło",
90
+ "portal.resetPassword.submitting": "Resetowanie hasła…",
91
+ "portal.resetPassword.success.description": "Twoje hasło zostało pomyślnie zresetowane.",
92
+ "portal.resetPassword.success.loginLink": "Przejdź do logowania",
93
+ "portal.resetPassword.success.message": "Możesz teraz zalogować się przy użyciu nowego hasła.",
94
+ "portal.resetPassword.success.title": "Hasło zresetowane",
95
+ "portal.resetPassword.title": "Zresetuj hasło",
76
96
  "portal.signup.description": "Zarejestruj nowe konto klienta.",
77
97
  "portal.signup.displayName": "Nazwa wyświetlana",
78
98
  "portal.signup.displayName.placeholder": "Twoje imię",