sozsoft-platform/ui/src/components/shared/BarcodeViewer.tsx

77 lines
2.5 KiB
TypeScript
Raw Normal View History

2026-09-21 19:53:48 +00:00
import { useEffect, useState } from 'react'
import classNames from 'classnames'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { writeBarcodeSvg, type BarcodeWriteFormat } from '@/utils/barcode'
export type BarcodeViewerProps = {
/** Barkoda çevrilecek veri. Form içinde kolona bağlanan alan budur. */
value?: string
format?: BarcodeWriteFormat
label?: string
/** Kodun altına okunabilir metni de basar. */
showText?: boolean
/** Modül (en ince çubuk) kalınlığı; büyüdükçe kod büyür. */
scale?: number
/** Kodu kapsayıcının genişliğine yayar; kapalıyken `scale` boyutu korunur. */
fitWidth?: boolean
className?: string
}
/**
* Herhangi bir veriyi barkod/QR olarak çizer. Tasarımcıdan sürüklenip bırakılan
* düğüm ve üretilen kod aynı bileşeni kullanır; `value` bir Form'un kaydına
* bağlandığında alan değiştikçe kod da yeniden çizilir.
*
* Kod SVG olarak üretilir: baskıda ve büyütmede kırılmaz, karanlık temada da
* okunabilir kalsın diye beyaz zemin üstünde çizilir.
*/
const BarcodeViewer = ({
value,
format = 'QRCode',
label,
showText = false,
scale = 4,
fitWidth = false,
className,
}: BarcodeViewerProps) => {
const { translate } = useLocalization()
const [svg, setSvg] = useState('')
const [error, setError] = useState('')
const text = value === undefined || value === null ? '' : String(value)
useEffect(() => {
let cancelled = false
void writeBarcodeSvg(text, { format, scale, showText }).then((result) => {
if (cancelled) return
setSvg(result.svg)
setError(result.error)
})
return () => {
cancelled = true
}
}, [text, format, scale, showText])
return (
<div className={className}>
{label && <label className="mb-1 block text-sm font-semibold">{label}</label>}
{!text ? (
<span className="text-sm opacity-70">{translate('::App.BarcodeViewer.NoValue')}</span>
) : error ? (
<span className="text-sm text-red-500">{error}</span>
) : (
<div
// zxing'in ürettiği SVG'dir, kullanıcı verisi değil: metin HRI içine
// kaçışlanarak yazılır, bu yüzden gömmek güvenlidir.
dangerouslySetInnerHTML={{ __html: svg }}
className={classNames(
'inline-block rounded bg-white p-2',
fitWidth && 'block w-full [&>svg]:h-auto [&>svg]:w-full',
)}
/>
)}
</div>
)
}
export default BarcodeViewer