From 9b47190d477edabf6dfdd9207a082aff63e0d222 Mon Sep 17 00:00:00 2001 From: seb Date: Fri, 9 Oct 2026 20:55:26 +0200 Subject: [PATCH] u --- src/routes/artikel/marken.jsx | 164 ++++++++++++++-------------------- 1 file changed, 69 insertions(+), 95 deletions(-) diff --git a/src/routes/artikel/marken.jsx b/src/routes/artikel/marken.jsx index 61f8d78..ab8e8df 100644 --- a/src/routes/artikel/marken.jsx +++ b/src/routes/artikel/marken.jsx @@ -14,37 +14,69 @@ import { enqueueSnackbar } from 'notistack'; import { BrandImageSearchDialog, ArtikelMarke, - ArtikelMarkenTable, } from '../../components/brand'; import { PURPLE_PANEL, } from '../../colors'; -function BrandRowMeasureSample() { - // Same component as real rows so the measured height matches exactly. - return ( - - - - ); + +class ArtikelMarkeNew extends PureComponent { + constructor(props) { + super(props); + this.state = { newName: '' }; + } + + async submit() { + const name = this.state.newName.trim(); + if (!name) return; + await this.props.onCreate?.(name); + this.setState({ newName: '' }); + } + + render() { + const { rowRef } = this.props; + const { newName } = this.state; + return ( + + this.setState({ newName: next })} + onKeyDown={(event) => { + if (event.key === 'Enter') { + event.preventDefault(); + void this.submit(); + } + }} + sx={{ flex: 1 }} + /> + + + ); + } } class ArtikelMarkenPage extends PureComponent { constructor(props) { super(props); this.state = { - status: brandAutomat.state.status === 'succeeded' ? 'ready' : 'loading', + status: brandAutomat.state.status, error: brandAutomat.state.error ? backendErrorFrom({ message: brandAutomat.state.error }) : null, - brands: brandAutomat.state.brands || [], - newName: '', - busyKey: null, + brands: brandAutomat.state.brands, searchBrand: null, }; this._cancelled = false; this.createRowRef = createRef(); this.handleCreate = this.handleCreate.bind(this); this.handleRetry = this.handleRetry.bind(this); - this.loadBrands = this.loadBrands.bind(this); this.handleRename = this.handleRename.bind(this); this.handleDelete = this.handleDelete.bind(this); this.handleSearchLogo = this.handleSearchLogo.bind(this); @@ -54,18 +86,13 @@ class ArtikelMarkenPage extends PureComponent { setLastArticleSku(null); this._cancelled = false; - this.unsub = brandAutomat.subscribe((state) => { - if (this._cancelled) return; - if (state.status === 'succeeded') { - this.applyBrands(state.brands); - } else if (state.status === 'failed') { - this.setState({ status: 'failed', error: backendErrorFrom({ message: state.error }) }); - } - }); - - if (brandAutomat.state.status !== 'succeeded') { - void this.loadBrands(); - } + // Mirror the automat's brands slice directly — the automat owns + // fetching (auth/SSE), the component never triggers loads. + this.unsub = brandAutomat.subscribe(this, (state) => ({ + brands: state.brands, + status: state.status, + error: state.error ? backendErrorFrom({ message: state.error }) : null, + })); } componentWillUnmount() { @@ -73,88 +100,61 @@ class ArtikelMarkenPage extends PureComponent { this.unsub?.(); } - applyBrands(brands) { - this.setState({ status: 'ready', error: null, brands }); - } - - async loadBrands() { - if (brandAutomat.state.status !== 'succeeded') { - this.setState({ status: 'loading', error: null }); - } - try { - const list = await brandAutomat.actions.load(); - if (this._cancelled) return; - this.applyBrands(list); - } catch (err) { - if (this._cancelled) return; - this.setState({ status: 'failed', error: backendErrorFrom(err) }); - } - } - handleRetry() { - void this.loadBrands(); + // The automat owns fetching; just ask it to load again. + void brandAutomat.actions.load().catch((err) => notifyError(err)); } handleSearchLogo(brand) { this.setState({ searchBrand: brand }); } - async handleCreate() { - const name = this.state.newName.trim(); - if (!name || this.state.busyKey != null) return; + async handleCreate(name) { + const trimmed = String(name ?? '').trim(); + if (!trimmed) return; - this.setState({ busyKey: 'new' }); try { - const row = await brandAutomat.actions.create({ name }); + const row = await brandAutomat.actions.create({ name: trimmed }); if (this._cancelled) return; - this.setState({ newName: '', busyKey: null }); - enqueueSnackbar(`Marke „${row.name || name}" angelegt.`, { variant: 'success' }); + enqueueSnackbar(`Marke „${row.name || trimmed}" angelegt.`, { variant: 'success' }); } catch (err) { if (this._cancelled) return; notifyError(err); - this.setState({ busyKey: null }); + throw err; } } async handleRename(brand, draft) { const nextName = String(draft ?? '').trim(); - if (!nextName || nextName === brand.name || this.state.busyKey != null) return; + if (!nextName || nextName === brand.name) return; - this.setState({ busyKey: brand.id }); try { await brandAutomat.actions.rename(brand.id, { name: nextName }); if (this._cancelled) return; - this.setState({ busyKey: null }); enqueueSnackbar('Marke gespeichert.', { variant: 'success' }); } catch (err) { if (this._cancelled) return; notifyError(err); - this.setState({ busyKey: null }); } } async handleDelete(brand) { - if (this.state.busyKey != null) return; if (!window.confirm(`Marke „${brand.name}" wirklich löschen?`)) return; - this.setState({ busyKey: brand.id }); try { await brandAutomat.actions.remove(brand.id); if (this._cancelled) return; - this.setState({ busyKey: null }); enqueueSnackbar('Marke gelöscht.', { variant: 'success' }); } catch (err) { if (this._cancelled) return; notifyError(err); - this.setState({ busyKey: null }); } } render() { - const { status, error, brands, newName, busyKey } = this.state; - const busy = busyKey != null; + const { status, error, brands } = this.state; - if (status === 'loading') { + if (status === 'loading' || status === 'idle') { return ( @@ -173,46 +173,20 @@ class ArtikelMarkenPage extends PureComponent { aboveRef={[]} belowRef={this.createRowRef} reserveBottom={32} - minPageSize={10} - measureElement={} + minPageSize={8} minHeight={0} items={brands} - renderPage={(pageBrands) => ( - ( + )} /> - - this.setState({ newName: next })} - onKeyDown={(event) => { - if (event.key === 'Enter') { - event.preventDefault(); - void this.handleCreate(); - } - }} - sx={{ flex: 1 }} - /> - - +