import { Component } from 'react'; import Alert from '@mui/material/Alert'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import CircularProgress from '@mui/material/CircularProgress'; import FormControl from '@mui/material/FormControl'; import FormLabel from '@mui/material/FormLabel'; import InputAdornment from '@mui/material/InputAdornment'; import Stack from '@mui/material/Stack'; import TextInput from '../TextInput'; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; import { enqueueSnackbar } from 'notistack'; import BackendError from '../BackendError'; import SingleLineTextEdit from 'dashgui/SingleLineTextEdit'; import companyAutomat from '../../automats/companyAutomat'; import { ISO639_OPTIONS, parseTaxRate } from '../../utils/companyForm'; import { backendErrorFrom, isBackendFailure } from '../../utils/backendError'; import { notifyError } from '../../utils/notify'; export default class CompanySettingsPanel extends Component { constructor(props) { super(props); const current = companyAutomat.state.current; this.state = { isAdmin: current?.role === 'admin', status: current ? 'ready' : 'loading', busy: false, error: null, name: current?.name ?? '', iso639: current?.iso639 ?? 'de', taxrate: current?.taxrate != null ? String(current.taxrate) : '', reducedtaxrate: current?.reducedtaxrate != null ? String(current.reducedtaxrate) : '', }; this.handleSubmit = this.handleSubmit.bind(this); this.handleRetry = this.handleRetry.bind(this); this.loadCompany = this.loadCompany.bind(this); this.syncFormFromCompany = this.syncFormFromCompany.bind(this); } componentDidMount() { this.unsub = companyAutomat.subscribe(this, (state) => { if (state.current && this.state.status === 'loading') { this.syncFormFromCompany(state.current); } return { isAdmin: state.current?.role === 'admin', }; }); if (companyAutomat.state.current) { this.syncFormFromCompany(companyAutomat.state.current); } } componentWillUnmount() { this.unsub?.(); } syncFormFromCompany(companyRow) { if (!companyRow) return; this._initial = { name: companyRow.name ?? '', iso639: companyRow.iso639 ?? 'de', taxrate: companyRow.taxrate != null ? String(companyRow.taxrate) : '', reducedtaxrate: companyRow.reducedtaxrate != null ? String(companyRow.reducedtaxrate) : '', }; this.setState({ name: this._initial.name, iso639: this._initial.iso639, taxrate: this._initial.taxrate, reducedtaxrate: this._initial.reducedtaxrate, status: 'ready', }); } async loadCompany() { this.setState({ error: null }); try { const companyRow = await companyAutomat.actions.load(); this.syncFormFromCompany(companyRow); } catch (err) { notifyError(err); this.setState({ status: 'failed', error: backendErrorFrom(err) }); } } handleRetry() { void this.loadCompany(); } async handleSubmit(event) { event?.preventDefault?.(); if (!this.state.isAdmin) return; const { name, iso639, taxrate, reducedtaxrate } = this.state; const parsedTaxrate = parseTaxRate(taxrate); const parsedReducedtaxrate = parseTaxRate(reducedtaxrate); const canSave = name.trim() !== '' && ISO639_OPTIONS.includes(iso639) && parsedTaxrate != null && parsedReducedtaxrate != null; if (!canSave) { this.setState({ error: 'Bitte alle Pflichtfelder ausfüllen.' }); return; } this.setState({ busy: true, error: null }); try { await companyAutomat.actions.update({ name: name.trim(), iso639, taxrate: parsedTaxrate, reducedtaxrate: parsedReducedtaxrate, }); this._initial = { name: name.trim(), iso639, taxrate: String(parsedTaxrate), reducedtaxrate: String(parsedReducedtaxrate), }; enqueueSnackbar('Unternehmen gespeichert.', { variant: 'success' }); } catch (err) { this.setState({ error: backendErrorFrom(err) }); } finally { this.setState({ busy: false }); } } render() { const { isAdmin, status, busy, error, name, iso639, taxrate, reducedtaxrate } = this.state; if (status === 'loading' && !name) { return ( ); } if (status === 'failed' && !name) { return ; } const parsedTaxrate = parseTaxRate(taxrate); const parsedReducedtaxrate = parseTaxRate(reducedtaxrate); const isDirty = Boolean(this._initial) && (name.trim() !== this._initial.name.trim() || iso639 !== this._initial.iso639 || taxrate.trim() !== this._initial.taxrate.trim() || reducedtaxrate.trim() !== this._initial.reducedtaxrate.trim()); const canSave = isAdmin && isDirty && name.trim() !== '' && ISO639_OPTIONS.includes(iso639) && parsedTaxrate != null && parsedReducedtaxrate != null; return ( {error ? ( isBackendFailure(error) ? ( ) : ( {typeof error === 'string' ? error : error.message} ) ) : null} this.setState({ name: nextName })} autoComplete="off" autoFocus /> Sprache { if (value) this.setState({ iso639: value }); }} > Deutsch English this.setState({ taxrate: e.target.value })} error={taxrate !== '' && parsedTaxrate == null} slotProps={{ input: { endAdornment: %, }, htmlInput: { min: 0, max: 100, step: 0.01, required: true }, }} /> this.setState({ reducedtaxrate: e.target.value })} error={reducedtaxrate !== '' && parsedReducedtaxrate == null} slotProps={{ input: { endAdornment: %, }, htmlInput: { min: 0, max: 100, step: 0.01, required: true }, }} /> ); } }