Files
dashfront/docs/brandAutomat.md
2026-09-23 17:24:33 +02:00

4.6 KiB

brandAutomat

Source File: src/automats/brandAutomat.js
Registration Key: 'brand' (Automat.get('brand') / window.__AUTOMATS__.get('brand'))


1. Overview & Purpose

brandAutomat manages the active company's catalog brands (manufacturers). Brands are referenced by articles for catalog organization, filtering, and GPSR (General Product Safety Regulation) manufacturer compliance info.

Core Responsibilities

  • Company Scoping: Caches all brands for the currently selected company.
  • Alphabetical Sorting: Automatically sorts brands by name using German ('de') collation.
  • Autonomous Bootstrap: Automatically triggers load() when authAutomat enters 'authed' with a selected company, and calls reset() when the session ends.
  • Upsert Mutation: Handles creating or updating a brand with immediate in-memory cache synchronization.

2. State Structure

interface Brand {
  id: number | string;
  name: string;
  gsprpinfo?: string | null;
  [key: string]: any;
}

interface BrandState {
  /** Alphabetically sorted list of company brands. */
  brands: Array<Brand>;
  /** Async lifecycle status. */
  status: 'idle' | 'loading' | 'succeeded' | 'failed';
  /** Error message if loading failed. */
  error: string | null;
}

Initial State

const initialState = {
  brands: [],
  status: 'idle',
  error: null,
};

3. Configuration & Options

new Automat(initialState, actions, { name: 'brand' });
  • name: 'brand'
  • persist: false

4. Actions & Methods

Access actions via brandAutomat.actions.<method>().

load(): Promise<Array<Brand>>

Fetches all brands for the current company via GET /api/brand. Sorts them by name, updates status to 'succeeded', and returns the array. If the request fails, sets status to 'failed' and records error.

upsert(body: { name: string, gsprpinfo?: string }): Promise<Brand>

Creates or updates a brand via POST /api/brand/upsert. Merges the updated brand into state.brands, re-sorts the list, updates state, and returns the modified brand object.

reset(): void

Resets the state back to initialState (brands: [], status: 'idle', error: null).


5. Cross-Automat Subscriptions

brandAutomat subscribes to authAutomat at module initialization:

authAutomat.subscribe((auth) => {
  const companyId = auth.user?.selectedCompanyId;
  if (auth.status === 'authed' && companyId) {
    void brandAutomat.actions.load();
  } else if (auth.status === 'anon') {
    brandAutomat.actions.reset();
  }
});

6. Usage Examples

A. React PureComponent Brand Selector Dropdown

import { PureComponent } from 'react';
import PropTypes from 'prop-types';
import brandAutomat from '../automats/brandAutomat';

export class BrandSelect extends PureComponent {
  static propTypes = {
    value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    onChange: PropTypes.func.isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      brands: brandAutomat.state.brands,
      status: brandAutomat.state.status,
    };
  }

  componentDidMount() {
    this.unsub = brandAutomat.subscribe(this, ['brands', 'status']);
    if (this.state.status === 'idle') {
      brandAutomat.actions.load().catch(console.error);
    }
  }

  componentWillUnmount() {
    this.unsub?.();
  }

  render() {
    const { brands, status } = this.state;
    const { value, onChange } = this.props;

    if (status === 'loading') {
      return <select disabled><option>Marken laden...</option></select>;
    }

    return (
      <select value={value ?? ''} onChange={(e) => onChange(e.target.value)}>
        <option value="">-- Keine Marke --</option>
        {brands.map((b) => (
          <option key={b.id} value={b.id}>{b.name}</option>
        ))}
      </select>
    );
  }
}

B. Creating or Updating a Brand

import brandAutomat from '../automats/brandAutomat';

async function handleSaveBrand(name, gsprpinfo) {
  try {
    const brand = await brandAutomat.actions.upsert({ name, gsprpinfo });
    console.log('Saved brand:', brand);
  } catch (err) {
    console.error('Failed to save brand:', err);
  }
}

7. Best Practices & Gotchas

  1. Automatic Loading: In normal usage, you rarely need to invoke load() manually; authAutomat triggers it as soon as the user logs in or switches company.
  2. Alphabetical Guarantee: The brands array in state is guaranteed to be sorted alphabetically (localeCompare with German rules).