76 lines
2.5 KiB
TypeScript
76 lines
2.5 KiB
TypeScript
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
|