@micha.bigler/ui-core-micha 1.4.28 → 1.4.30
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.
- package/dist/components/AccessCodeManager.js +0 -1
- package/dist/components/LoginForm.js +4 -4
- package/dist/components/MFAComponent.js +3 -3
- package/dist/components/MfaLoginComponent.js +3 -3
- package/dist/components/PasskeysComponent.js +3 -3
- package/dist/components/PasswordChangeForm.js +3 -3
- package/dist/components/PasswordResetRequestForm.js +3 -3
- package/dist/components/PasswordSetForm.js +3 -3
- package/dist/components/ProfileComponent.js +0 -1
- package/dist/components/SecurityComponent.js +4 -4
- package/dist/components/SocialLoginButtons.js +3 -3
- package/dist/components/SupportRecoveryRequestsTab.js +3 -3
- package/dist/pages/LoginPage.js +0 -1
- package/dist/pages/PasswordChangePage.js +0 -1
- package/dist/pages/PasswordInvitePage.js +0 -1
- package/dist/pages/PasswordResetRequestPage.js +0 -1
- package/dist/pages/SignUpPage.js +0 -1
- package/package.json +1 -1
- package/src/components/AccessCodeManager.jsx +0 -1
- package/src/components/LoginForm.jsx +2 -4
- package/src/components/MFAComponent.jsx +2 -2
- package/src/components/MfaLoginComponent.jsx +1 -2
- package/src/components/PasskeysComponent.jsx +1 -2
- package/src/components/PasswordChangeForm.jsx +1 -2
- package/src/components/PasswordResetRequestForm.jsx +1 -2
- package/src/components/PasswordSetForm.jsx +1 -2
- package/src/components/ProfileComponent.jsx +0 -2
- package/src/components/SecurityComponent.jsx +2 -3
- package/src/components/SocialLoginButtons.jsx +1 -2
- package/src/components/SupportRecoveryRequestsTab.jsx +1 -2
- package/src/pages/LoginPage.jsx +1 -3
- package/src/pages/PasswordChangePage.jsx +0 -3
- package/src/pages/PasswordInvitePage.jsx +0 -2
- package/src/pages/PasswordResetRequestPage.jsx +0 -2
- package/src/pages/SignUpPage.jsx +0 -2
|
@@ -98,4 +98,3 @@ export function AccessCodeManager() {
|
|
|
98
98
|
? t('Auth.SAVE_BUTTON_LOADING')
|
|
99
99
|
: t('Auth.ACCESS_CODE_GENERATE_BUTTON') })] }), _jsxs(Box, { sx: { mb: 2, maxWidth: 360 }, children: [_jsx(Typography, { variant: "subtitle1", gutterBottom: true, children: t('Auth.ACCESS_CODE_SECTION_MANUAL') }), _jsxs(Box, { sx: { display: 'flex', gap: 1 }, children: [_jsx(TextField, { label: t('Auth.ACCESS_CODE_LABEL'), fullWidth: true, value: manualCode, onChange: (e) => setManualCode(e.target.value), disabled: submitting }), _jsx(Button, { variant: "outlined", onClick: handleAddManual, disabled: submitting, children: t('Auth.ACCESS_CODE_ADD_BUTTON') })] })] })] }));
|
|
100
100
|
}
|
|
101
|
-
export default AccessCodeManager;
|
|
@@ -3,8 +3,8 @@ import React, { useState, useEffect } from 'react';
|
|
|
3
3
|
import { Box, TextField, Button, Typography, Divider, } from '@mui/material';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import SocialLoginButtons from './SocialLoginButtons';
|
|
6
|
-
|
|
7
|
-
disabled = false, initialIdentifier = '', })
|
|
6
|
+
export function LoginForm({ onSubmit, onForgotPassword, onSocialLogin, onPasskeyLogin, onSignUp, error, // bereits übersetzter Text oder t(errorKey) aus dem Parent
|
|
7
|
+
disabled = false, initialIdentifier = '', }) {
|
|
8
8
|
const { t } = useTranslation();
|
|
9
9
|
const [identifier, setIdentifier] = useState(initialIdentifier);
|
|
10
10
|
const [password, setPassword] = useState('');
|
|
@@ -22,5 +22,5 @@ disabled = false, initialIdentifier = '', }) => {
|
|
|
22
22
|
typeof window !== 'undefined' &&
|
|
23
23
|
!!window.PublicKeyCredential;
|
|
24
24
|
return (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 3 }, children: [error && (_jsx(Typography, { color: "error", gutterBottom: true, children: error })), supportsPasskey && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "contained", fullWidth: true, type: "button", onClick: onPasskeyLogin, disabled: disabled, children: t('Auth.LOGIN_USE_PASSKEY_BUTTON') }), _jsx(Divider, { sx: { my: 2 }, children: t('Auth.LOGIN_OR') })] })), _jsxs(Box, { component: "form", onSubmit: handleSubmit, sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx(TextField, { label: t('Auth.EMAIL_LABEL'), type: "email", required: true, fullWidth: true, value: identifier, onChange: (e) => setIdentifier(e.target.value), disabled: disabled }), _jsx(TextField, { label: t('Auth.LOGIN_PASSWORD_LABEL'), type: "password", required: true, fullWidth: true, value: password, onChange: (e) => setPassword(e.target.value), disabled: disabled }), _jsx(Button, { type: "submit", variant: "contained", fullWidth: true, disabled: disabled, children: t('Auth.PAGE_LOGIN_TITLE') })] }), _jsxs(Box, { children: [_jsx(Divider, { sx: { my: 2 }, children: t('Auth.LOGIN_OR') }), _jsx(SocialLoginButtons, { onProviderClick: onSocialLogin })] }), _jsxs(Box, { children: [_jsx(Typography, { variant: "subtitle2", sx: { mb: 1 }, children: t('Auth.LOGIN_ACCOUNT_RECOVERY_TITLE') }), _jsxs(Box, { sx: { display: 'flex', gap: 1, flexWrap: 'wrap' }, children: [onSignUp && (_jsx(Button, { type: "button", variant: "outlined", onClick: onSignUp, disabled: disabled, children: t('Auth.LOGIN_SIGNUP_BUTTON') })), _jsx(Button, { type: "button", variant: "outlined", onClick: onForgotPassword, disabled: disabled, children: t('Auth.LOGIN_FORGOT_PASSWORD_BUTTON') })] })] })] }));
|
|
25
|
-
}
|
|
26
|
-
|
|
25
|
+
}
|
|
26
|
+
;
|
|
@@ -7,7 +7,7 @@ import DeleteIcon from '@mui/icons-material/Delete';
|
|
|
7
7
|
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
|
8
8
|
import { useTranslation } from 'react-i18next';
|
|
9
9
|
import { fetchAuthenticators, requestTotpKey, activateTotp, deactivateTotp, fetchRecoveryCodes, generateRecoveryCodes } from '../auth/authApi';
|
|
10
|
-
|
|
10
|
+
export function MFAComponent() {
|
|
11
11
|
const { t } = useTranslation();
|
|
12
12
|
const [authenticators, setAuthenticators] = useState([]);
|
|
13
13
|
const [loading, setLoading] = useState(true);
|
|
@@ -162,5 +162,5 @@ const MFAComponent = () => {
|
|
|
162
162
|
alignItems: 'center',
|
|
163
163
|
gap: 1,
|
|
164
164
|
}, children: [code, _jsx(Tooltip, { title: t('Auth.MFA_RECOVERY_COPY_TOOLTIP'), children: _jsx(IconButton, { size: "small", onClick: () => handleCopyCode(code), children: _jsx(ContentCopyIcon, { fontSize: "small" }) }) })] }, code))) }), _jsx(Button, { sx: { mt: 2 }, size: "small", onClick: handleGenerateNewRecoveryCodes, children: t('Auth.MFA_RECOVERY_GENERATE_NEW') })] }))] }));
|
|
165
|
-
}
|
|
166
|
-
|
|
165
|
+
}
|
|
166
|
+
;
|
|
@@ -5,7 +5,7 @@ import { Box, Typography, TextField, Button, Stack, Alert, Divider, Dialog, Dial
|
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { authenticateWithMFA, fetchCurrentUser, requestMfaSupportHelp } from '../auth/authApi';
|
|
7
7
|
import { loginWithPasskey } from '../utils/authService';
|
|
8
|
-
|
|
8
|
+
export function MfaLoginComponent({ availableTypes, identifier, onSuccess, onCancel }) {
|
|
9
9
|
const { t } = useTranslation();
|
|
10
10
|
const [code, setCode] = useState('');
|
|
11
11
|
const [submitting, setSubmitting] = useState(false);
|
|
@@ -78,5 +78,5 @@ const MfaLoginComponent = ({ availableTypes, identifier, onSuccess, onCancel })
|
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
return (_jsxs(Box, { children: [_jsx(Typography, { variant: "body2", sx: { mb: 2 }, children: t('Auth.MFA_SUBTITLE', 'Please confirm your login using one of the available methods.') }), errorKey && (_jsx(Alert, { severity: "error", sx: { mb: 2 }, children: t(errorKey) })), infoKey && (_jsx(Alert, { severity: "info", sx: { mb: 2 }, children: t(infoKey) })), _jsxs(Stack, { spacing: 2, children: [supportsWebauthn && (_jsx(Button, { variant: "contained", fullWidth: true, onClick: handlePasskey, disabled: submitting || helpRequested, children: t('Auth.LOGIN_USE_PASSKEY_BUTTON', 'Use passkey / security key') })), _jsx(Divider, { sx: { my: 2 }, children: t('Auth.LOGIN_OR') }), supportsTotpOrRecovery && (_jsxs(Box, { component: "form", onSubmit: handleSubmitCode, children: [_jsx(TextField, { label: t('Auth.MFA_CODE_LABEL', 'Authenticator code (or recovery code)'), value: code, onChange: (e) => setCode(e.target.value), fullWidth: true, disabled: submitting || helpRequested, autoComplete: "one-time-code", sx: { mb: 2 } }), _jsx(Button, { type: "submit", variant: "contained", fullWidth: true, disabled: submitting || !code.trim() || helpRequested, children: t('Auth.MFA_VERIFY', 'Verify') })] })), _jsx(Divider, { sx: { my: 2 }, children: t('Auth.LOGIN_OR') }), _jsxs(Stack, { direction: "row", spacing: 1, sx: { mt: 1 }, children: [_jsx(Button, { fullWidth: true, size: "small", variant: "outlined", onClick: onCancel, disabled: submitting, children: t('Auth.MFA_BACK_TO_LOGIN', 'Back to login') }), _jsx(Button, { fullWidth: true, size: "small", variant: "outlined", color: "secondary", onClick: openHelpDialog, disabled: submitting || helpRequested, children: t('Auth.MFA_NEED_HELP', "I can't use any of these methods") })] })] }), _jsxs(Dialog, { open: helpDialogOpen, onClose: () => setHelpDialogOpen(false), fullWidth: true, maxWidth: "sm", children: [_jsx(DialogTitle, { children: t('Auth.MFA_HELP_DIALOG_TITLE', 'Need help with sign-in') }), _jsxs(DialogContent, { dividers: true, children: [_jsx(Typography, { variant: "body2", sx: { mb: 2 }, children: t('Auth.MFA_HELP_DIALOG_DESCRIPTION', 'Describe briefly why you cannot use the available methods. A support person will review your request.') }), _jsx(TextField, { label: t('Auth.MFA_HELP_MESSAGE_LABEL', 'Your message to support'), multiline: true, minRows: 3, fullWidth: true, value: helpMessage, onChange: (e) => setHelpMessage(e.target.value), disabled: submitting })] }), _jsxs(DialogActions, { children: [_jsx(Button, { onClick: () => setHelpDialogOpen(false), disabled: submitting, children: t('Common.CANCEL', 'Cancel') }), _jsx(Button, { onClick: handleNeedHelp, disabled: submitting, variant: "contained", children: t('Auth.MFA_HELP_SUBMIT', 'Send request') })] })] })] }));
|
|
81
|
-
}
|
|
82
|
-
|
|
81
|
+
}
|
|
82
|
+
;
|
|
@@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
7
7
|
import { fetchPasskeys, deletePasskey } from '../auth/authApi';
|
|
8
8
|
import { registerPasskey } from '../utils/authService';
|
|
9
9
|
import { FEATURES } from '../auth/authConfig';
|
|
10
|
-
|
|
10
|
+
export function PasskeysComponent() {
|
|
11
11
|
const { t } = useTranslation();
|
|
12
12
|
const [passkeys, setPasskeys] = useState([]);
|
|
13
13
|
const [loading, setLoading] = useState(true);
|
|
@@ -97,5 +97,5 @@ const PasskeysComponent = () => {
|
|
|
97
97
|
value: pk.created_at,
|
|
98
98
|
})
|
|
99
99
|
: undefined }), _jsx(ListItemSecondaryAction, { children: _jsx(Tooltip, { title: t('Auth.PASSKEY_DELETE_TOOLTIP'), children: _jsx("span", { children: _jsx(IconButton, { edge: "end", "aria-label": "delete", onClick: () => handleDelete(pk.id), disabled: deletingIds.has(pk.id), size: "small", children: deletingIds.has(pk.id) ? (_jsx(CircularProgress, { size: 18 })) : (_jsx(DeleteIcon, { fontSize: "small" })) }) }) }) })] }, pk.id))) }))] }))] }));
|
|
100
|
-
}
|
|
101
|
-
|
|
100
|
+
}
|
|
101
|
+
;
|
|
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
* A simplified form to handle password changes.
|
|
7
7
|
* Does not require password confirmation.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
export function PasswordChangeForm({ onSubmit, submitting = false }) {
|
|
10
10
|
const { t } = useTranslation();
|
|
11
11
|
const [currentPassword, setCurrentPassword] = useState('');
|
|
12
12
|
const [newPassword, setNewPassword] = useState('');
|
|
@@ -23,5 +23,5 @@ const PasswordChangeForm = ({ onSubmit, submitting = false }) => {
|
|
|
23
23
|
return (_jsx(Box, { component: "form", onSubmit: handleSubmit, sx: { maxWidth: 500 }, children: _jsxs(Stack, { spacing: 2, children: [_jsx(TextField, { label: t('Auth.CURRENT_PASSWORD_LABEL'), type: "password", value: currentPassword, onChange: (e) => setCurrentPassword(e.target.value), required: true, fullWidth: true, disabled: submitting }), _jsx(TextField, { label: t('Auth.NEW_PASSWORD_LABEL'), type: "password", value: newPassword, onChange: (e) => setNewPassword(e.target.value), required: true, fullWidth: true, disabled: submitting }), _jsx(Box, { children: _jsx(Button, { type: "submit", variant: "contained", disabled: submitting, children: submitting
|
|
24
24
|
? t('Auth.CHANGE_PASSWORD_BUTTON_LOADING')
|
|
25
25
|
: t('Auth.CHANGE_PASSWORD_BUTTON') }) })] }) }));
|
|
26
|
-
}
|
|
27
|
-
|
|
26
|
+
}
|
|
27
|
+
;
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import React, { useState } from 'react';
|
|
4
4
|
import { Box, TextField, Button } from '@mui/material';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
|
-
|
|
6
|
+
export function PasswordResetRequestForm({ onSubmit, submitting = false }) {
|
|
7
7
|
const { t } = useTranslation();
|
|
8
8
|
const [email, setEmail] = useState('');
|
|
9
9
|
const handleSubmit = (event) => {
|
|
@@ -15,5 +15,5 @@ const PasswordResetRequestForm = ({ onSubmit, submitting = false }) => {
|
|
|
15
15
|
return (_jsxs(Box, { component: "form", onSubmit: handleSubmit, sx: { display: 'flex', flexDirection: 'column', gap: 2, mt: 2 }, children: [_jsx(TextField, { label: t('Auth.EMAIL_LABEL'), type: "email", required: true, fullWidth: true, value: email, onChange: (e) => setEmail(e.target.value), disabled: submitting }), _jsx(Button, { type: "submit", variant: "contained", disabled: submitting, children: submitting
|
|
16
16
|
? t('Auth.RESET_REQUEST_BUTTON_LOADING')
|
|
17
17
|
: t('Auth.RESET_REQUEST_BUTTON') })] }));
|
|
18
|
-
}
|
|
19
|
-
|
|
18
|
+
}
|
|
19
|
+
;
|
|
@@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
7
7
|
* Simple form to set a new password (once, with confirmation).
|
|
8
8
|
* Caller passes onSubmit(newPassword) and handles redirect / API call.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
export function PasswordSetForm({ onSubmit, submitting = false }) {
|
|
11
11
|
const { t } = useTranslation();
|
|
12
12
|
const [password1, setPassword1] = useState('');
|
|
13
13
|
const [password2, setPassword2] = useState('');
|
|
@@ -30,5 +30,5 @@ const PasswordSetForm = ({ onSubmit, submitting = false }) => {
|
|
|
30
30
|
return (_jsxs(Box, { component: "form", onSubmit: handleSubmit, sx: { display: 'flex', flexDirection: 'column', gap: 2, mt: 2 }, children: [localErrorKey && (_jsx(Box, { sx: { color: 'error.main', fontSize: 14 }, children: t(localErrorKey) })), _jsx(TextField, { label: t('Auth.NEW_PASSWORD_LABEL'), type: "password", fullWidth: true, autoComplete: "new-password", value: password1, onChange: (e) => setPassword1(e.target.value), disabled: submitting }), _jsx(TextField, { label: t('Auth.PASSWORD_CONFIRM_LABEL'), type: "password", fullWidth: true, autoComplete: "new-password", value: password2, onChange: (e) => setPassword2(e.target.value), disabled: submitting }), _jsx(Button, { type: "submit", variant: "contained", disabled: submitting, children: submitting
|
|
31
31
|
? t('Auth.PASSWORD_SET_BUTTON_LOADING')
|
|
32
32
|
: t('Auth.PASSWORD_SET_BUTTON') })] }));
|
|
33
|
-
}
|
|
34
|
-
|
|
33
|
+
}
|
|
34
|
+
;
|
|
@@ -70,4 +70,3 @@ export function ProfileComponent({ onSubmit, submitText, showName = true, showPr
|
|
|
70
70
|
const submitLabelLoading = t('Profile.SAVE_BUTTON_LOADING');
|
|
71
71
|
return (_jsxs(Box, { component: "form", onSubmit: handleSubmit, sx: { maxWidth: 600, display: 'flex', flexDirection: 'column', gap: 2 }, children: [errorKey && (_jsx(Alert, { severity: "error", children: t(errorKey) })), successKey && (_jsx(Alert, { severity: "success", children: t(successKey) })), _jsxs(Stack, { spacing: 2, children: [_jsx(TextField, { label: t('Profile.USERNAME_LABEL'), value: username, fullWidth: true, disabled: true }), _jsx(TextField, { label: t('Auth.EMAIL_LABEL'), type: "email", value: email, fullWidth: true, disabled: true })] }), showName && (_jsxs(Stack, { spacing: 2, direction: { xs: 'column', sm: 'row' }, children: [_jsx(TextField, { label: t('Profile.FIRST_NAME_LABEL'), value: firstName, onChange: (e) => setFirstName(e.target.value), fullWidth: true }), _jsx(TextField, { label: t('Profile.LAST_NAME_LABEL'), value: lastName, onChange: (e) => setLastName(e.target.value), fullWidth: true })] })), (showPrivacy || showCookies) && (_jsxs(Box, { sx: { mt: 1 }, children: [_jsx(Typography, { variant: "subtitle1", gutterBottom: true, children: t('Profile.PRIVACY_SECTION_TITLE') }), _jsxs(Stack, { spacing: 1, children: [showPrivacy && (_jsx(FormControlLabel, { control: _jsx(Checkbox, { checked: acceptedPrivacy, onChange: (e) => setAcceptedPrivacy(e.target.checked) }), label: t('Profile.ACCEPT_PRIVACY_LABEL') })), showCookies && (_jsx(FormControlLabel, { control: _jsx(Checkbox, { checked: acceptedCookies, onChange: (e) => setAcceptedCookies(e.target.checked) }), label: t('Profile.ACCEPT_COOKIES_LABEL') }))] })] })), _jsx(Box, { sx: { mt: 2 }, children: _jsx(Button, { type: "submit", variant: "contained", disabled: saving, children: saving ? submitLabelLoading : submitLabel }) })] }));
|
|
72
72
|
}
|
|
73
|
-
export default ProfileComponent;
|
|
@@ -9,8 +9,8 @@ import PasskeysComponent from './PasskeysComponent';
|
|
|
9
9
|
import MFAComponent from './MFAComponent';
|
|
10
10
|
import { changePassword } from '../auth/authApi';
|
|
11
11
|
import { startSocialLogin } from '../utils/authService';
|
|
12
|
-
|
|
13
|
-
})
|
|
12
|
+
export function SecurityComponent({ fromRecovery = false, fromWeakLogin = false, // optional: wenn du später weak-login-Redirect nutzt
|
|
13
|
+
}) {
|
|
14
14
|
const { t } = useTranslation();
|
|
15
15
|
const [messageKey, setMessageKey] = useState(null);
|
|
16
16
|
const [errorKey, setErrorKey] = useState(null);
|
|
@@ -37,5 +37,5 @@ const SecurityComponent = ({ fromRecovery = false, fromWeakLogin = false, // opt
|
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
return (_jsxs(Box, { children: [fromRecovery && (_jsx(Alert, { severity: "warning", sx: { mb: 2 }, children: t('Security.RECOVERY_LOGIN_WARNING') })), fromWeakLogin && (_jsx(Alert, { severity: "warning", sx: { mb: 2 }, children: t('Security.WEAK_LOGIN_WARNING') })), messageKey && (_jsx(Alert, { severity: "success", sx: { mb: 2 }, children: t(messageKey) })), errorKey && (_jsx(Alert, { severity: "error", sx: { mb: 2 }, children: t(errorKey) })), _jsx(Typography, { variant: "h6", gutterBottom: true, children: t('Security.LOGIN_PASSWORD_LABEL') }), _jsx(PasswordChangeForm, { onSubmit: handlePasswordChange }), _jsx(Divider, { sx: { my: 3 } }), _jsx(Typography, { variant: "h6", gutterBottom: true, children: t('Security.SOCIAL_SECTION_TITLE') }), _jsx(Typography, { variant: "body2", sx: { mb: 1 }, children: t('Security.SOCIAL_SECTION_DESCRIPTION') }), _jsx(SocialLoginButtons, { onProviderClick: handleSocialClick }), _jsx(Divider, { sx: { my: 3 } }), _jsx(PasskeysComponent, {}), _jsx(Divider, { sx: { my: 3 } }), _jsx(MFAComponent, {})] }));
|
|
40
|
-
}
|
|
41
|
-
|
|
40
|
+
}
|
|
41
|
+
;
|
|
@@ -8,7 +8,7 @@ import { SOCIAL_PROVIDERS } from '../auth/authConfig';
|
|
|
8
8
|
* Renders buttons for social login providers.
|
|
9
9
|
* The caller passes a handler that receives the provider key.
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
export function SocialLoginButtons({ onProviderClick }) {
|
|
12
12
|
const { t } = useTranslation();
|
|
13
13
|
const handleClick = (provider) => {
|
|
14
14
|
if (onProviderClick) {
|
|
@@ -33,5 +33,5 @@ const SocialLoginButtons = ({ onProviderClick }) => {
|
|
|
33
33
|
gridTemplateRows: '1fr 1fr',
|
|
34
34
|
gap: '1px',
|
|
35
35
|
}, children: [_jsx(Box, { sx: { bgcolor: 'primary.main', opacity: 0.9 } }), _jsx(Box, { sx: { bgcolor: 'primary.main', opacity: 0.7 } }), _jsx(Box, { sx: { bgcolor: 'primary.main', opacity: 0.7 } }), _jsx(Box, { sx: { bgcolor: 'primary.main', opacity: 0.9 } })] }), children: t('Auth.LOGIN_SOCIAL_MICROSOFT') })] }));
|
|
36
|
-
}
|
|
37
|
-
|
|
36
|
+
}
|
|
37
|
+
;
|
|
@@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react';
|
|
|
4
4
|
import { Box, Typography, Table, TableHead, TableBody, TableRow, TableCell, TableContainer, Paper, Button, CircularProgress, Alert, Stack, Dialog, DialogTitle, DialogContent, DialogActions, TextField, } from '@mui/material';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { fetchRecoveryRequests, approveRecoveryRequest, rejectRecoveryRequest } from '../auth/authApi';
|
|
7
|
-
|
|
7
|
+
export function SupportRecoveryRequestsTab() {
|
|
8
8
|
const { t } = useTranslation();
|
|
9
9
|
const [requests, setRequests] = useState([]);
|
|
10
10
|
const [loading, setLoading] = useState(true);
|
|
@@ -83,5 +83,5 @@ const SupportRecoveryRequestsTab = () => {
|
|
|
83
83
|
whiteSpace: 'pre-wrap',
|
|
84
84
|
fontSize: '0.875rem',
|
|
85
85
|
}, children: selectedRequest.message || t('Support.RECOVERY_NO_MESSAGE', 'No message provided.') })] })), _jsx(TextField, { label: t('Support.RECOVERY_NOTE_LABEL', 'Reason for your decision'), helperText: t('Support.RECOVERY_NOTE_HELP', 'Explain briefly why you approve or reject this request.'), multiline: true, minRows: 3, fullWidth: true, value: dialogNote, onChange: (e) => setDialogNote(e.target.value) })] }), _jsxs(DialogActions, { children: [_jsx(Button, { onClick: closeDialog, children: t('Support.CANCEL', 'Cancel') }), _jsx(Button, { onClick: handleReject, color: "error", disabled: !dialogNote.trim(), children: t('Support.RECOVERY_REJECT_SUBMIT', 'Reject request') }), _jsx(Button, { onClick: handleApprove, variant: "contained", disabled: !dialogNote.trim(), children: t('Support.RECOVERY_APPROVE_SUBMIT', 'Approve and send link') })] })] })] }));
|
|
86
|
-
}
|
|
87
|
-
|
|
86
|
+
}
|
|
87
|
+
;
|
package/dist/pages/LoginPage.js
CHANGED
|
@@ -112,4 +112,3 @@ export function LoginPage() {
|
|
|
112
112
|
// --- Render ---
|
|
113
113
|
return (_jsxs(NarrowPage, { title: t('Auth.PAGE_LOGIN_TITLE'), subtitle: t('Auth.PAGE_LOGIN_SUBTITLE'), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.PAGE_LOGIN_TITLE')] }) }), errorKey && (_jsx(Alert, { severity: "error", sx: { mb: 2 }, children: t(errorKey) })), recoveryToken && !errorKey && (_jsx(Alert, { severity: "info", sx: { mb: 2 }, children: t('Auth.RECOVERY_LOGIN_WARNING', 'Recovery link validated. Please enter your password.') })), step === 'credentials' && (_jsx(LoginForm, { onSubmit: handleSubmitCredentials, onForgotPassword: () => navigate('/reset-request-password'), onSocialLogin: (provider) => startSocialLogin(provider), onPasskeyLogin: handlePasskeyLoginInitial, onSignUp: () => navigate('/signup'), disabled: submitting, initialIdentifier: recoveryEmail })), step === 'mfa' && mfaState && (_jsx(Box, { children: _jsx(MfaLoginComponent, { availableTypes: mfaState.availableTypes, identifier: mfaState.identifier, onSuccess: handleMfaSuccess, onCancel: handleMfaCancel }) }))] }));
|
|
114
114
|
}
|
|
115
|
-
export default LoginPage;
|
|
@@ -29,4 +29,3 @@ export function PasswordChangePage() {
|
|
|
29
29
|
};
|
|
30
30
|
return (_jsxs(NarrowPage, { title: t('Auth.CHANGE_PASSWORD_BUTTON'), subtitle: t('Auth.PAGE_CHANGE_PASSWORD_SUBTITLE'), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.CHANGE_PASSWORD_BUTTON')] }) }), successKey && (_jsx(Typography, { color: "primary", gutterBottom: true, children: t(successKey) })), errorKey && (_jsx(Typography, { color: "error", gutterBottom: true, children: t(errorKey) })), _jsx(PasswordChangeForm, { onSubmit: handleSubmit, submitting: submitting })] }));
|
|
31
31
|
}
|
|
32
|
-
export default PasswordChangePage;
|
|
@@ -72,4 +72,3 @@ export function PasswordInvitePage() {
|
|
|
72
72
|
}
|
|
73
73
|
return (_jsxs(NarrowPage, { title: t(pageTitleKey), subtitle: t(pageSubtitleKey), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t(pageTitleKey)] }) }), errorKey && (_jsx(Typography, { color: "error", gutterBottom: true, children: t(errorKey) })), successKey && (_jsx(Typography, { color: "primary", gutterBottom: true, children: t(successKey) })), !successKey && !errorKey && (_jsx(PasswordSetForm, { onSubmit: handleSubmit, submitting: submitting }))] }));
|
|
74
74
|
}
|
|
75
|
-
export default PasswordInvitePage;
|
|
@@ -34,4 +34,3 @@ export function PasswordResetRequestPage() {
|
|
|
34
34
|
};
|
|
35
35
|
return (_jsxs(NarrowPage, { title: t('Auth.PAGE_RESET_PASSWORD_TITLE'), subtitle: t('Auth.PAGE_RESET_REQUEST_SUBTITLE'), children: [_jsx(Helmet, { children: _jsxs("title", { children: [t('App.NAME'), " \u2013 ", t('Auth.PAGE_RESET_PASSWORD_TITLE')] }) }), successKey && (_jsx(Typography, { color: "primary", gutterBottom: true, children: t(successKey) })), errorKey && (_jsx(Typography, { color: "error", gutterBottom: true, children: t(errorKey) })), _jsx(PasswordResetRequestForm, { onSubmit: handleSubmit, submitting: submitting })] }));
|
|
36
36
|
}
|
|
37
|
-
export default PasswordResetRequestPage;
|
package/dist/pages/SignUpPage.js
CHANGED
|
@@ -54,4 +54,3 @@ export function SignUpPage() {
|
|
|
54
54
|
? t('Auth.SIGNUP_SUBMITTING')
|
|
55
55
|
: t('Auth.SIGNUP_SUBMIT') })] }), _jsx(Box, { sx: { mt: 3 }, children: _jsxs(Typography, { variant: "body2", children: [t('Auth.SIGNUP_ALREADY_HAVE_ACCOUNT'), ' ', _jsx(Button, { onClick: handleGoToLogin, variant: "text", size: "small", children: t('Auth.SIGNUP_GO_TO_LOGIN') })] }) })] }));
|
|
56
56
|
}
|
|
57
|
-
export default SignUpPage;
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import { useTranslation } from 'react-i18next';
|
|
10
10
|
import SocialLoginButtons from './SocialLoginButtons';
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
export function LoginForm({
|
|
13
13
|
onSubmit,
|
|
14
14
|
onForgotPassword,
|
|
15
15
|
onSocialLogin,
|
|
@@ -18,7 +18,7 @@ const LoginForm = ({
|
|
|
18
18
|
error, // bereits übersetzter Text oder t(errorKey) aus dem Parent
|
|
19
19
|
disabled = false,
|
|
20
20
|
initialIdentifier = '',
|
|
21
|
-
})
|
|
21
|
+
}) {
|
|
22
22
|
const { t } = useTranslation();
|
|
23
23
|
|
|
24
24
|
const [identifier, setIdentifier] = useState(initialIdentifier);
|
|
@@ -142,5 +142,3 @@ const LoginForm = ({
|
|
|
142
142
|
</Box>
|
|
143
143
|
);
|
|
144
144
|
};
|
|
145
|
-
|
|
146
|
-
export default LoginForm;
|
|
@@ -20,7 +20,7 @@ import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
|
|
20
20
|
import { useTranslation } from 'react-i18next';
|
|
21
21
|
import { fetchAuthenticators, requestTotpKey, activateTotp, deactivateTotp, fetchRecoveryCodes, generateRecoveryCodes } from '../auth/authApi';
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
export function MFAComponent() {
|
|
24
24
|
const { t } = useTranslation();
|
|
25
25
|
|
|
26
26
|
const [authenticators, setAuthenticators] = useState([]);
|
|
@@ -338,4 +338,4 @@ const MFAComponent = () => {
|
|
|
338
338
|
);
|
|
339
339
|
};
|
|
340
340
|
|
|
341
|
-
|
|
341
|
+
|
|
@@ -17,7 +17,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
17
17
|
import { authenticateWithMFA, fetchCurrentUser, requestMfaSupportHelp } from '../auth/authApi';
|
|
18
18
|
import { loginWithPasskey } from '../utils/authService';
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
export function MfaLoginComponent({ availableTypes, identifier, onSuccess, onCancel }) {
|
|
21
21
|
const { t } = useTranslation();
|
|
22
22
|
const [code, setCode] = useState('');
|
|
23
23
|
const [submitting, setSubmitting] = useState(false);
|
|
@@ -237,4 +237,3 @@ const MfaLoginComponent = ({ availableTypes, identifier, onSuccess, onCancel })
|
|
|
237
237
|
};
|
|
238
238
|
|
|
239
239
|
|
|
240
|
-
export default MfaLoginComponent;
|
|
@@ -22,7 +22,7 @@ import { fetchPasskeys, deletePasskey } from '../auth/authApi';
|
|
|
22
22
|
import { registerPasskey } from '../utils/authService';
|
|
23
23
|
import { FEATURES } from '../auth/authConfig';
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
export function PasskeysComponent() {
|
|
26
26
|
const { t } = useTranslation();
|
|
27
27
|
|
|
28
28
|
const [passkeys, setPasskeys] = useState([]);
|
|
@@ -246,4 +246,3 @@ const PasskeysComponent = () => {
|
|
|
246
246
|
);
|
|
247
247
|
};
|
|
248
248
|
|
|
249
|
-
export default PasskeysComponent;
|
|
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
* A simplified form to handle password changes.
|
|
7
7
|
* Does not require password confirmation.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
export function PasswordChangeForm({ onSubmit, submitting = false }) {
|
|
10
10
|
const { t } = useTranslation();
|
|
11
11
|
const [currentPassword, setCurrentPassword] = useState('');
|
|
12
12
|
const [newPassword, setNewPassword] = useState('');
|
|
@@ -60,4 +60,3 @@ const PasswordChangeForm = ({ onSubmit, submitting = false }) => {
|
|
|
60
60
|
);
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
export default PasswordChangeForm;
|
|
@@ -3,7 +3,7 @@ import React, { useState } from 'react';
|
|
|
3
3
|
import { Box, TextField, Button } from '@mui/material';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
export function PasswordResetRequestForm({ onSubmit, submitting = false }) {
|
|
7
7
|
const { t } = useTranslation();
|
|
8
8
|
const [email, setEmail] = useState('');
|
|
9
9
|
|
|
@@ -41,4 +41,3 @@ const PasswordResetRequestForm = ({ onSubmit, submitting = false }) => {
|
|
|
41
41
|
);
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
export default PasswordResetRequestForm;
|
|
@@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
7
7
|
* Simple form to set a new password (once, with confirmation).
|
|
8
8
|
* Caller passes onSubmit(newPassword) and handles redirect / API call.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
export function PasswordSetForm({ onSubmit, submitting = false }) {
|
|
11
11
|
const { t } = useTranslation();
|
|
12
12
|
|
|
13
13
|
const [password1, setPassword1] = useState('');
|
|
@@ -78,4 +78,3 @@ const PasswordSetForm = ({ onSubmit, submitting = false }) => {
|
|
|
78
78
|
);
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
-
export default PasswordSetForm;
|
|
@@ -14,10 +14,10 @@ import MFAComponent from './MFAComponent';
|
|
|
14
14
|
import { changePassword } from '../auth/authApi';
|
|
15
15
|
import { startSocialLogin } from '../utils/authService';
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
export function SecurityComponent({
|
|
18
18
|
fromRecovery = false,
|
|
19
19
|
fromWeakLogin = false, // optional: wenn du später weak-login-Redirect nutzt
|
|
20
|
-
})
|
|
20
|
+
}) {
|
|
21
21
|
const { t } = useTranslation();
|
|
22
22
|
|
|
23
23
|
const [messageKey, setMessageKey] = useState(null);
|
|
@@ -102,4 +102,3 @@ const SecurityComponent = ({
|
|
|
102
102
|
);
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
-
export default SecurityComponent;
|
|
@@ -8,7 +8,7 @@ import { SOCIAL_PROVIDERS } from '../auth/authConfig';
|
|
|
8
8
|
* Renders buttons for social login providers.
|
|
9
9
|
* The caller passes a handler that receives the provider key.
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
export function SocialLoginButtons({ onProviderClick }) {
|
|
12
12
|
const { t } = useTranslation();
|
|
13
13
|
|
|
14
14
|
const handleClick = (provider) => {
|
|
@@ -72,4 +72,3 @@ const SocialLoginButtons = ({ onProviderClick }) => {
|
|
|
72
72
|
);
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
-
export default SocialLoginButtons;
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
import { useTranslation } from 'react-i18next';
|
|
24
24
|
import { fetchRecoveryRequests, approveRecoveryRequest, rejectRecoveryRequest } from '../auth/authApi';
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
export function SupportRecoveryRequestsTab() {
|
|
27
27
|
const { t } = useTranslation();
|
|
28
28
|
|
|
29
29
|
const [requests, setRequests] = useState([]);
|
|
@@ -281,4 +281,3 @@ const SupportRecoveryRequestsTab = () => {
|
|
|
281
281
|
);
|
|
282
282
|
};
|
|
283
283
|
|
|
284
|
-
export default SupportRecoveryRequestsTab
|
package/src/pages/LoginPage.jsx
CHANGED