This commit is contained in:
seb
2026-10-09 21:57:57 +02:00
parent d04a5f104f
commit 082771b9c3
3 changed files with 75 additions and 109 deletions

View File

@@ -7,7 +7,7 @@ description: >-
# Dash API Routes Overview (All)
Overview of all 205 API endpoints across all modules.
Overview of all 206 API endpoints across all modules.
### Notation
@@ -620,6 +620,9 @@ _none_
#### Create package for a shipping — `POST /shipping/{id}/package`
- Params: `id: int, body: { entityaddressId: int, type: str, state: str, details?: str }`
- Returns: `201 { package: { id: int, shippingId: int, entityaddressId: int, number: str, type: str, state: str, details?: str|null } }`
#### Small thumb image by hash — `GET /smallthumb/{fullHash}`
- Params: `fullHash: str`
- Returns: `200 avif`
#### Adjust stock manually — `POST /stock/adjust`
- Params: `body: { sku?: str, warehouseId?: int, amount?: num, text?: str|null, lines?: { sku: str, amount: num, warehouseId?: int, text?: str }[] }`
- Returns: `201 { manifest: { id: int, number: str, type: str, date: str, createdAt: str }, lines: { manifestarticle_id: int, sku: str, name: str, warehouse_id: int, amount: num, text: str }[], ledger: T15[] }`

View File

@@ -1,119 +1,82 @@
import { PureComponent } from 'react';
import Box from '@mui/material/Box';
import ThumbHashImage, { getThumbHashDimensions } from '../article/ThumbHashImage';
import brandAutomat from '../../automats/brandAutomat';
import ThumbHashImage from '../article/ThumbHashImage';
import {
SHADOW_THUMB_RING,
TINT_ROW_HOVER,
} from '../../colors';
/**
* Extracts thumbHash from various brand representations:
* - Direct thumbHash / thumbhash property
* - Brand with pics array (e.g. brand.pics[0].thumbHash)
* - Brand by name or id looked up in brandAutomat.state.brands
*/
export function extractBrandThumbInfo(brand, thumbHashOverride) {
if (thumbHashOverride) {
const dims = getThumbHashDimensions(thumbHashOverride);
return {
thumbHash: thumbHashOverride,
thumbW: dims?.w ?? null,
thumbH: dims?.h ?? null,
};
}
export default class BrandThumb extends PureComponent {
render() {
const {
brand,
size = 20,
fallback = null,
sx,
} = this.props;
const pic = brand?.pics?.[0];
if (!brand) return null;
if (!pic?.thumbHash) {
return fallback;
}
// Direct thumbHash on brand object
let hash = brand.thumbHash ?? brand.thumbhash;
let thumbW = brand.thumbW ?? brand.thumbw;
let thumbH = brand.thumbH ?? brand.thumbh;
// Check pics array
if (!hash && Array.isArray(brand.pics) && brand.pics.length > 0) {
const firstPic = brand.pics[0];
hash = firstPic?.thumbHash ?? firstPic?.thumbhash;
thumbW = firstPic?.thumbW ?? firstPic?.thumbw;
thumbH = firstPic?.thumbH ?? firstPic?.thumbh;
}
// Fallback: look up in brandAutomat
if (!hash) {
const brands = brandAutomat.state?.brands;
if (Array.isArray(brands)) {
const id = typeof brand === 'object' ? brand.id : (typeof brand === 'number' ? brand : null);
const name = typeof brand === 'object' ? brand.name : (typeof brand === 'string' ? brand : null);
const found = brands.find(
(b) =>
(id != null && b.id === id) ||
(name && String(b.name || '').trim().toLowerCase() === String(name).trim().toLowerCase())
);
if (found) {
hash = found.thumbHash ?? found.thumbhash ?? found.pics?.[0]?.thumbHash ?? found.pics?.[0]?.thumbhash;
thumbW = found.thumbW ?? found.thumbw ?? found.pics?.[0]?.thumbW ?? found.pics?.[0]?.thumbw;
thumbH = found.thumbH ?? found.thumbh ?? found.pics?.[0]?.thumbH ?? found.pics?.[0]?.thumbh;
const { thumbHash, thumbW, thumbH } = pic;
const ratio = thumbW && thumbH ? thumbW / thumbH : 1;
// Contain-fit inside a square `size x size` box, preserving aspect ratio.
let innerW = size;
let innerH = size;
if (Number.isFinite(ratio) && ratio > 0) {
if (ratio >= 1) {
innerW = size;
innerH = Math.max(1, Math.round(size / ratio));
} else {
innerH = size;
innerW = Math.max(1, Math.round(size * ratio));
}
}
return (
<Box
component="span"
sx={{
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
height: size,
width: size,
minWidth: size,
maxWidth: size,
flexShrink: 0,
verticalAlign: 'middle',
lineHeight: 0,
my: 0,
boxSizing: 'border-box',
...sx,
}}
>
<Box
component="span"
sx={{
display: 'block',
width: innerW,
height: innerH,
borderRadius: size >= 24 ? '4px' : '3px',
overflow: 'hidden',
flexShrink: 0,
lineHeight: 0,
boxSizing: 'border-box',
bgcolor: TINT_ROW_HOVER,
boxShadow: SHADOW_THUMB_RING,
}}
>
<ThumbHashImage
thumbHash={thumbHash}
width={innerW}
height={innerH}
sx={{ width: innerW, height: innerH, flexShrink: 0 }}
/>
</Box>
</Box>
);
}
if (!hash) return null;
if (thumbW == null || thumbH == null) {
const dims = getThumbHashDimensions(hash);
if (dims) {
thumbW = dims.w;
thumbH = dims.h;
}
}
return { thumbHash: hash, thumbW, thumbH };
}
export default function BrandThumb({
brand,
thumbHash: thumbHashProp,
size = 20,
fallback = null,
sx,
}) {
const info = extractBrandThumbInfo(brand, thumbHashProp);
if (!info?.thumbHash) {
return fallback;
}
const { thumbHash, thumbW, thumbH } = info;
const ratio = (thumbW && thumbH) ? (thumbW / thumbH) : 1;
const calcWidth = Math.round(size * Math.max(0.6, Math.min(ratio, 2.5)));
return (
<Box
component="span"
sx={{
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
height: size,
width: calcWidth,
minWidth: Math.round(size * 0.6),
maxWidth: Math.round(size * 2.5),
borderRadius: size >= 24 ? '4px' : '3px',
overflow: 'hidden',
flexShrink: 0,
verticalAlign: 'middle',
lineHeight: 0,
my: 0,
boxSizing: 'border-box',
bgcolor: TINT_ROW_HOVER,
boxShadow: SHADOW_THUMB_RING,
...sx,
}}
>
<ThumbHashImage
thumbHash={thumbHash}
width={calcWidth}
height={size}
/>
</Box>
);
}

View File

@@ -1,4 +1,4 @@
export { default as BrandThumb, extractBrandThumbInfo } from './BrandThumb';
export { default as BrandThumb } from './BrandThumb';
export { default as BrandLabel } from './BrandLabel';
export { default as BrandImageSearchDialog } from './BrandImageSearchDialog';
export { default as ArtikelMarke } from './ArtikelMarke';