This commit is contained in:
seb
2026-09-21 03:19:32 +02:00
parent 5594c59d88
commit 366d2517d6
17 changed files with 467 additions and 269 deletions

View File

@@ -1,9 +1,8 @@
import { Component } from 'react';
import { connect } from 'react-redux';
import { enqueueSnackbar } from 'notistack';
import { notifyError } from '../utils/notify';
import { StorageManagerContext } from '../api/storageManagerContext';
import { bootstrapSession as bootstrapSessionThunk } from '../store/authSlice';
import authAutomat from '../automats/authAutomat';
let sessionBootstrapped = false;
@@ -19,7 +18,7 @@ class AuthBootstrap extends Component {
if (session.forbidden) {
enqueueSnackbar(session.message, { variant: 'warning' });
}
return this.props.bootstrapSession(session).unwrap();
return authAutomat.actions.bootstrapSession(session);
})
.catch((err) => {
notifyError(err);
@@ -31,8 +30,4 @@ class AuthBootstrap extends Component {
}
}
const mapDispatchToProps = (dispatch) => ({
bootstrapSession: (session) => dispatch(bootstrapSessionThunk(session)),
});
export default connect(null, mapDispatchToProps)(AuthBootstrap);
export default AuthBootstrap;

View File

@@ -1,5 +1,4 @@
import { Component } from 'react';
import { connect } from 'react-redux';
import Alert from '@mui/material/Alert';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
@@ -23,11 +22,7 @@ import BusinessIcon from '@mui/icons-material/Business';
import BackendError from './BackendError';
import { company } from '../api';
import { StorageManagerContext } from '../api/storageManagerContext';
import {
createCompany as createCompanyThunk,
logout as logoutThunk,
selectCompany as selectCompanyThunk,
} from '../store/authSlice';
import authAutomat from '../automats/authAutomat';
import {
defaultIso639,
ISO639_OPTIONS,
@@ -75,7 +70,7 @@ class CompanySetupDialog extends Component {
async handleSelect(companyId) {
this.setState({ busy: true, error: null });
try {
await this.props.selectCompany(companyId).unwrap();
await authAutomat.actions.selectCompany(companyId);
await this.context.updateAuthMe();
} catch (err) {
this.setState({ error: backendErrorFrom(err) });
@@ -102,14 +97,12 @@ class CompanySetupDialog extends Component {
this.setState({ busy: true, error: null });
try {
await this.props
.createCompany({
name: name.trim(),
iso639,
taxrate: parsedTaxrate,
reducedtaxrate: parsedReducedtaxrate,
})
.unwrap();
await authAutomat.actions.createCompany({
name: name.trim(),
iso639,
taxrate: parsedTaxrate,
reducedtaxrate: parsedReducedtaxrate,
});
await this.context.updateAuthMe();
await this.context.updateCompany();
} catch (err) {
@@ -121,7 +114,7 @@ class CompanySetupDialog extends Component {
async handleLogout() {
try {
await this.props.logout().unwrap();
await authAutomat.actions.logout();
await this.context.updateAuthMe();
} catch (err) {
this.setState({ error: backendErrorFrom(err) });
@@ -293,10 +286,4 @@ class CompanySetupDialog extends Component {
}
}
const mapDispatchToProps = (dispatch) => ({
createCompany: (payload) => dispatch(createCompanyThunk(payload)),
selectCompany: (companyId) => dispatch(selectCompanyThunk(companyId)),
logout: () => dispatch(logoutThunk()),
});
export default connect(null, mapDispatchToProps)(CompanySetupDialog);
export default CompanySetupDialog;

View File

@@ -1,11 +1,10 @@
import { Component } from 'react';
import { connect } from 'react-redux';
import { PureComponent } from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import GoogleIcon from '@mui/icons-material/Google';
import { enqueueSnackbar } from 'notistack';
import { notifyErrorMessage } from '../utils/notify';
import { loginWithGoogle, selectAuthStatus, selectGoogleClientId } from '../store/authSlice';
import authAutomat from '../automats/authAutomat';
import { StorageManagerContext } from '../api/storageManagerContext';
import {
abortGoogleSignIn,
@@ -16,17 +15,25 @@ import {
requestGoogleIdToken,
} from '../auth/googleSignIn';
class LoginPage extends Component {
class LoginPage extends PureComponent {
static contextType = StorageManagerContext;
constructor(props) {
super(props);
this.state = { busy: false };
this.state = { ...authAutomat.state, busy: false };
this.handleLogin = this.handleLogin.bind(this);
}
componentDidMount() {
this.unsubscribe = authAutomat.subscribe(this, ['status', 'googleClientId']);
}
componentWillUnmount() {
this.unsubscribe?.();
}
async handleLogin() {
const { googleClientId } = this.props;
const { googleClientId } = this.state;
abortGoogleSignIn();
try {
const idToken = await requestGoogleIdToken(googleClientId, {
@@ -38,7 +45,7 @@ class LoginPage extends Component {
},
});
this.setState({ busy: true });
await this.props.loginWithGoogle(idToken).unwrap();
await authAutomat.actions.loginWithGoogle(idToken);
await this.context.updateAuthMe();
} catch (err) {
if (err instanceof GoogleSignInCancelledError) return;
@@ -74,8 +81,7 @@ class LoginPage extends Component {
}
render() {
const { busy } = this.state;
const { status, googleClientId } = this.props;
const { busy, status, googleClientId } = this.state;
const loading = status === 'loading';
const ready = Boolean(googleClientId);
@@ -103,13 +109,4 @@ class LoginPage extends Component {
}
}
const mapStateToProps = (state) => ({
status: selectAuthStatus(state),
googleClientId: selectGoogleClientId(state),
});
const mapDispatchToProps = (dispatch) => ({
loginWithGoogle: (credential) => dispatch(loginWithGoogle(credential)),
});
export default connect(mapStateToProps, mapDispatchToProps)(LoginPage);
export default LoginPage;

View File

@@ -1,5 +1,4 @@
import { Component } from 'react';
import { connect } from 'react-redux';
import { PureComponent } from 'react';
import Avatar from '@mui/material/Avatar';
import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton';
@@ -11,12 +10,12 @@ import LogoutIcon from '@mui/icons-material/Logout';
import BusinessIcon from '@mui/icons-material/Business';
import SettingsIcon from '@mui/icons-material/Settings';
import { StorageManagerContext } from '../api/storageManagerContext';
import { logout } from '../store/authSlice';
import authAutomat from '../automats/authAutomat';
import CompanySettingsDialog from './CompanySettingsDialog';
import SettingsDialog from './settings/SettingsDialog';
import { notifyError } from '../utils/notify';
class UserMenu extends Component {
class UserMenu extends PureComponent {
static contextType = StorageManagerContext;
constructor(props) {
@@ -25,7 +24,7 @@ class UserMenu extends Component {
anchorEl: null,
settingsOpen: false,
numbersOpen: false,
user: null,
user: authAutomat.state.user,
};
this.handleOpenMenu = this.handleOpenMenu.bind(this);
this.handleCloseMenu = this.handleCloseMenu.bind(this);
@@ -37,16 +36,11 @@ class UserMenu extends Component {
}
componentDidMount() {
void this.loadUser();
this.unsubscribe = authAutomat.subscribe(this, 'user');
}
async loadUser() {
try {
const session = await this.context.authMePromise;
this.setState({ user: session.user });
} catch (err) {
notifyError(err);
}
componentWillUnmount() {
this.unsubscribe?.();
}
handleOpenMenu(event) {
@@ -76,7 +70,7 @@ class UserMenu extends Component {
async handleLogout() {
this.setState({ anchorEl: null });
try {
await this.props.logout().unwrap();
await authAutomat.actions.logout();
await this.context.updateAuthMe();
} catch (err) {
notifyError(err);
@@ -134,8 +128,4 @@ class UserMenu extends Component {
}
}
const mapDispatchToProps = (dispatch) => ({
logout: () => dispatch(logout()),
});
export default connect(null, mapDispatchToProps)(UserMenu);
export default UserMenu;