Files
dashfront/src/components/tiles/ArticleTile.jsx
2026-09-30 09:47:47 +02:00

164 lines
4.3 KiB
JavaScript

import Inventory2OutlinedIcon from '@mui/icons-material/Inventory2Outlined';
import Box from '@mui/material/Box';
import ButtonBase from '@mui/material/ButtonBase';
import Typography from '@mui/material/Typography';
import { Tile, tileBaseSx } from 'dashgui/tiles';
import { formatPrice } from '../../utils/price';
import { articleSku } from '../article/articleRoute';
import ArticlePhoto from '../article/ArticlePhoto';
import { BrandLabel } from '../brand';
export class ArticleTile extends Tile {
hasPhoto() {
const { article } = this.props;
return article?.thumbHash != null || article?.fullHash != null;
}
renderIcon() {
return <Inventory2OutlinedIcon color="action" sx={{ fontSize: 36 }} />;
}
renderSecondary() {
const { article } = this.props;
if (!article) return null;
const sku = articleSku(article);
const brand = article.brand;
return (
<>
{brand?.name ? (
<BrandLabel
brand={brand}
name={brand.name}
size={16}
spacing={0.5}
typographyProps={{
variant: 'caption',
color: 'text.secondary',
fontWeight: 500,
noWrap: true,
}}
/>
) : null}
{sku ? (
<Typography variant="caption" color="text.secondary" noWrap sx={{ maxWidth: '100%' }}>
{sku}
</Typography>
) : null}
{article.net != null && (
<Typography variant="caption" fontWeight={600}>
{formatPrice(article.net)}
</Typography>
)}
</>
);
}
renderExtra() {
const childCount = Number(this.props.article?.childCount) || 0;
if (childCount <= 0) return null;
return (
<Box
sx={{
position: 'absolute',
top: 6,
right: 6,
zIndex: 1,
px: 0.75,
py: 0.25,
borderRadius: 999,
bgcolor: 'rgba(0, 0, 0, 0.65)',
color: 'common.white',
fontSize: 11,
fontWeight: 600,
lineHeight: 1.2,
whiteSpace: 'nowrap',
pointerEvents: 'none',
}}
>
{childCount}
</Box>
);
}
render() {
if (!this.hasPhoto()) {
return super.render();
}
const { article, label, sx, disabled } = this.props;
const sku = articleSku(article);
return (
<ButtonBase
component="button"
type="button"
disabled={disabled}
onClick={this.handleClick}
sx={{
...tileBaseSx,
p: 0,
gap: 0,
position: 'relative',
...(disabled ? { opacity: 0.5, pointerEvents: 'none' } : {}),
...sx,
}}
>
<Box sx={{ position: 'absolute', inset: 0 }}>
<ArticlePhoto
fill
photo={{
fullHash: article.fullHash,
thumbW: article.thumbW,
thumbH: article.thumbH,
thumbHash: article.thumbHash,
}}
/>
</Box>
{this.renderExtra()}
<Box
sx={{
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
px: 1,
py: 0.75,
background: 'linear-gradient(transparent, rgba(0,0,0,0.65))',
textAlign: 'left',
}}
>
{article?.brand?.name ? (
<BrandLabel
brand={article.brand}
name={article.brand.name}
size={14}
spacing={0.5}
typographyProps={{
variant: 'caption',
noWrap: true,
sx: { color: 'rgba(255,255,255,0.9)', fontWeight: 500, lineHeight: 1.1 },
}}
sx={{ mb: 0.25 }}
/>
) : null}
{label ? (
<Typography
variant="body2"
fontWeight={600}
noWrap
sx={{ color: '#fff', lineHeight: 1.2 }}
>
{label}
</Typography>
) : null}
{sku ? (
<Typography variant="caption" noWrap sx={{ color: 'rgba(255,255,255,0.85)' }}>
{sku}
</Typography>
) : null}
</Box>
</ButtonBase>
);
}
}