3import React, { useState, useEffect } from 'react';
4import { Icon } from '@/contexts/IconContext';
6interface ScannerSettings {
7 barcodeAutoUSB: boolean;
8 scannerUSBAlways: boolean;
9 barcodeAutoSerial: boolean;
10 barcodePosBeep: boolean;
11 devScanEAN13L0: boolean;
13 barcodeToPid: boolean;
14 barcodeFlybuyScanEnabled: boolean;
15 barcodeAIMCode: boolean;
16 barcodeSinglePid: boolean;
17 barcodeWebsitePid: string;
21export default function BarcodeScannersPage() {
22 const [settings, setSettings] = useState<ScannerSettings>({
23 barcodeAutoUSB: false,
24 scannerUSBAlways: false,
25 barcodeAutoSerial: false,
26 barcodePosBeep: false,
27 devScanEAN13L0: false,
30 barcodeFlybuyScanEnabled: false,
31 barcodeAIMCode: false,
32 barcodeSinglePid: false,
33 barcodeWebsitePid: '',
37 const [qrUrl, setQrUrl] = useState('HTTP://FIELDPINE.COM');
44 updateQrPreview(settings.barcodeWebsitePid);
45 }, [settings.barcodeWebsitePid]);
47 const loadData = async () => {
49 // Load settings from API
50 console.log('Loading barcode scanner settings...');
51 // Mock data would go here
53 console.error('Error loading scanner settings:', error);
57 const saveSetting = (settingName: string, value: boolean | string) => {
58 console.log('Saving setting:', settingName, '=', value);
60 // API call to save setting
63 // <f8_s>retailmax.elink.config.basesetting.edit</f8_s>
65 // <f100_s>{settingName}</f100_s>
66 // <f101_E or f101_s>{value}</f101_E or f101_s>
71 const handleToggle = (field: keyof ScannerSettings, settingName: string) => {
72 const newValue = !settings[field];
73 setSettings(prev => ({ ...prev, [field]: newValue }));
74 saveSetting(settingName, newValue);
77 const handleTextChange = (field: keyof ScannerSettings, value: string) => {
78 setSettings(prev => ({ ...prev, [field]: value }));
81 const handleTextBlur = (settingName: string, value: string) => {
82 saveSetting(settingName, value);
85 const updateQrPreview = (url: string) => {
87 if (previewUrl.length <= 3) {
88 previewUrl = "HTTP://FIELDPINE.COM";
90 previewUrl = previewUrl.replace(/%pid%/g, "1234").replace(/%PID%/g, "1234");
95 const ToggleSwitch = ({ checked, onChange }: { checked: boolean; onChange: () => void }) => (
96 <label className="relative inline-flex items-center cursor-pointer">
99 className="sr-only peer"
103 <div className="w-11 h-6 bg-surface-2 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-brand/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-surface after:border-border after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-brand"></div>
108 <div className="p-6 min-h-screen bg-bg">
110 <div className="mb-6">
111 <h1 className="text-3xl font-bold text-text mb-2 flex items-center gap-2">
112 <Icon name="qr_code_scanner" size={32} />
115 <p className="text-muted">
116 Configure barcode scanner settings and behavior
120 <div className="max-w-[1400px] mx-auto">
121 <div className="bg-surface rounded-lg shadow-md p-6 mb-6">
122 <div className="space-y-8">
123 {/* Auto Detect USB Scanners */}
124 <div className="flex gap-4 items-start">
125 <div className="pt-1">
127 checked={settings.barcodeAutoUSB}
128 onChange={() => handleToggle('barcodeAutoUSB', 'BarcodeAutoUSB')}
131 <div className="flex-1">
132 <h3 className="text-lg font-semibold text-brand mb-2">
133 Auto Detect Barcode Scanners
134 <span className="text-xs text-muted ml-3 font-normal">P2040</span>
136 <p className="text-sm text-text mb-2">
137 Some USB scanners can be automatically detected when used on certain platforms, but detection isn't reliable on every platform.
138 Enabling this option can sometimes save effort when new scanners are plugged in.
140 <p className="text-sm text-muted">
141 This is likely to work for the following brands: Honeywell/Metrologic, Symbol, Zebex.
146 {/* Scanners Always Active */}
147 <div className="flex gap-4 items-start">
148 <div className="pt-1">
150 checked={settings.scannerUSBAlways}
151 onChange={() => handleToggle('scannerUSBAlways', 'ScannerUSBAlways')}
154 <div className="flex-1">
155 <h3 className="text-lg font-semibold text-brand mb-2">
156 Scanners are always active
157 <span className="text-xs text-muted ml-3 font-normal">P2263</span>
159 <p className="text-sm text-text">
160 Should USB scanners that are auto detected always be active or only when the POS is active? Turning this on means that all barcode scans
161 should be trapped and actioned even if the POS is not the active program. Turning this off means the POS will ignore scans if another
162 program is currently active in Windows.
167 {/* Auto Detect Serial Scanners */}
168 <div className="flex gap-4 items-start">
169 <div className="pt-1">
171 checked={settings.barcodeAutoSerial}
172 onChange={() => handleToggle('barcodeAutoSerial', 'BarcodeAutoSerial')}
175 <div className="flex-1">
176 <h3 className="text-lg font-semibold text-brand mb-2">
177 Auto Detect Serial Scanners
178 <span className="text-xs text-muted ml-3 font-normal">P2134</span>
180 <p className="text-sm text-text mb-2">
181 Automatically detect Serial scanners. This only applies to scanners that are USB scanners using CDC emulation mode.
183 <p className="text-sm text-muted">
184 This is likely to work for the following scanners: Zebra DS2208. See{' '}
185 <a href="https://fieldpine.com/docs/cfg/BarcodeScanners.htm" target="_blank" className="text-brand hover:underline">
186 https://fieldpine.com/docs/cfg/BarcodeScanners.htm
193 {/* Pos Beeps on Scan */}
194 <div className="flex gap-4 items-start">
195 <div className="pt-1">
197 checked={settings.barcodePosBeep}
198 onChange={() => handleToggle('barcodePosBeep', 'BarcodePosBeep')}
201 <div className="flex-1">
202 <h3 className="text-lg font-semibold text-brand mb-2">
203 Pos beeps on good scan
204 <span className="text-xs text-muted ml-3 font-normal">P2134</span>
206 <p className="text-sm text-text">
207 Should the Pos beep on receipt of a good barcode scan? This requires the scanner to be programmed not to beep and the scanner is not
208 using USB HID mode, which is the most commonly used mode.
215 {/* Barcode Handling Behaviour */}
216 <div className="bg-surface rounded-lg shadow-md p-6 mb-6">
217 <h2 className="text-2xl font-bold text-text mb-6 pb-3 border-b-2 border-dotted border-brand">
218 Barcode Handling Behaviour
221 <div className="space-y-8">
222 {/* Convert 12 to 13 digit */}
223 <div className="flex gap-4 items-start">
224 <div className="pt-1">
226 checked={settings.devScanEAN13L0}
227 onChange={() => handleToggle('devScanEAN13L0', 'DevScanEAN13L0')}
230 <div className="flex-1">
231 <h3 className="text-lg font-semibold text-brand mb-2">
232 Convert 12 digit barcodes to 13
233 <span className="text-xs text-muted ml-3 font-normal">P2040</span>
235 <p className="text-sm text-text">
236 If the POS receives a 12 digit barcode that starts with a "2", it can be automatically converted to have a leading "0" and become
237 an EAN "02" weighed item barcode. You would only need to disable this if your store DOES have true 12 digit barcodes that start
238 with a "2", which is rare.
243 {/* 02 Barcodes 5 digits */}
244 <div className="flex gap-4 items-start">
245 <div className="pt-1">
247 checked={settings.bar02P5}
248 onChange={() => handleToggle('bar02P5', 'Bar02P5')}
251 <div className="flex-1">
252 <h3 className="text-lg font-semibold text-brand mb-2">
253 02 Barcodes use 5 Pricing Digits
254 <span className="text-xs text-muted ml-3 font-normal">P2040</span>
256 <p className="text-sm text-text">
257 If this is enabled, then when extracting the price from a 02 barcode we use 5 digits from the barcode. If it is disabled we use 4 digits.
258 The original standard was for 4 digits but many instore printing scales support 5 digit pricing. If you do not use 02 barcodes, and most
259 retailers do not, you can ignore this setting.
264 {/* Convert to PIDs */}
265 <div className="flex gap-4 items-start">
266 <div className="pt-1">
268 checked={settings.barcodeToPid}
269 onChange={() => handleToggle('barcodeToPid', 'BarcodeToPid')}
272 <div className="flex-1">
273 <h3 className="text-lg font-semibold text-brand mb-2">
274 Convert Barcodes to Pids
275 <span className="text-xs text-muted ml-3 font-normal">P2040</span>
277 <p className="text-sm text-text">
278 If an unknown barcode is scanned, should the POS assume it is a Product Id? (PID) This option should only be enabled for sites that
279 print their own barcodes and the barcode numbers are identical to the PID values.
284 {/* FlyBuy Card Scanning */}
285 <div className="flex gap-4 items-start">
286 <div className="pt-1">
288 checked={settings.barcodeFlybuyScanEnabled}
289 onChange={() => handleToggle('barcodeFlybuyScanEnabled', 'BarcodeFlybuyScanEnabled')}
292 <div className="flex-1">
293 <h3 className="text-lg font-semibold text-brand mb-2">
294 Enable FlyBuy Card Scanning
295 <span className="text-xs text-muted ml-3 font-normal">P2040</span>
297 <p className="text-sm text-text">
298 Allow a Flybuy card to be scanned and recorded against the sale
303 {/* Decode AIM codes */}
304 <div className="flex gap-4 items-start">
305 <div className="pt-1">
307 checked={settings.barcodeAIMCode}
308 onChange={() => handleToggle('barcodeAIMCode', 'BarcodeAIMCode')}
311 <div className="flex-1">
312 <h3 className="text-lg font-semibold text-brand mb-2">
313 Decode AIM codes if scanners send them
314 <span className="text-xs text-muted ml-3 font-normal">P2050</span>
316 <p className="text-sm text-text">
317 Barcode scanners can be configured to send AIM Code identifiers before the actual barcode which is useful for getting full details about
318 the barcode. You should leave this setting on unless you have a specific reason not too.
323 {/* Single PID per barcode */}
324 <div className="flex gap-4 items-start">
325 <div className="pt-1">
327 checked={settings.barcodeSinglePid}
328 onChange={() => handleToggle('barcodeSinglePid', 'BarcodeSinglePid')}
331 <div className="flex-1">
332 <h3 className="text-lg font-semibold text-brand mb-2">
333 Barcodes can only point to one product
334 <span className="text-xs text-muted ml-3 font-normal">Feb 2020</span>
336 <p className="text-sm text-text mb-2">
337 Should barcodes only point to one product, or can a barcode be shared betweeen multiple products. Technically speaking barcodes are not
338 product specific over time, so the same barcode can potentially be seen on different products. In reality though it is extremly rare so
339 many retailers prefer to only allow a single product per barcode.
341 <p className="text-sm text-muted">
342 When enabled, this controls newly added barcodes only and removes the barcode from any other products using it. Existing products with
343 multiple barcodes already defined are not rechecked and may continue to have multiple products per barcode.
350 {/* QR Style Barcodes */}
351 <div className="bg-surface rounded-lg shadow-md p-6">
352 <h2 className="text-2xl font-bold text-text mb-4">QR Style Barcodes</h2>
354 <p className="text-text mb-6">
355 If you place QR codes on your products, the POS is able to use these QR codes as normal barcodes in some cases. This means the QR code can
356 be a URL which customers can scan and go to your product specific webpage, while the POS treats it as a normal 1D barcode and sells the item.
359 <div className="mb-6">
360 <h3 className="text-lg font-semibold text-brand mb-2">Your website Product Specific URL</h3>
364 value={settings.barcodeWebsitePid}
366 handleTextChange('barcodeWebsitePid', e.target.value);
367 updateQrPreview(e.target.value);
369 onBlur={(e) => handleTextBlur('BarcodeWebsitePid', e.target.value)}
370 placeholder="https://mywebsite.com/product/%pid%"
371 className="w-full max-w-3xl border border-border rounded px-3 py-2 focus:ring-2 focus:ring-brand focus:border-transparent"
373 <p className="text-sm text-text mt-2">
374 Enter the URL using the string "%pid%" where the Product id is located. To use this functionality a common URL must exist with PID as some constant.
376 Often these URLs use a 302 Redirect to the true product information page. Your web developer will understand this. Tip: Use UPPERCASE as this creates smaller QR codes
380 <p className="text-sm font-semibold text-text mb-4">
381 Example output with increasing levels of error correction or "ECC". The codes towards the left are less resilent to errors or barcode damage.
384 <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
385 {['L', 'M', 'Q', 'H'].map((ecc, index) => (
386 <div key={ecc} className="flex flex-col items-center p-4 border border-border rounded">
387 <div className="w-48 h-48 mb-2 bg-surface border-2 border-border flex items-center justify-center">
389 src={`https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(qrUrl)}&ecc=${ecc}`}
390 alt={`QR Code ECC ${ecc}`}
391 className="w-full h-full object-contain"
394 <div className="text-xs text-muted break-all text-center mb-1">{qrUrl}</div>
395 <div className="text-sm font-medium text-text">ECC "{ecc}"</div>
400 {/* URL Shortening */}
401 <div className="flex gap-4 items-start border-t pt-6">
402 <div className="pt-1">
404 checked={settings.barcodeQRM9}
405 onChange={() => handleToggle('barcodeQRM9', 'BarcodeQRM9')}
408 <div className="flex-1">
409 <h3 className="text-lg font-semibold text-brand mb-2">
410 Use URL shortening service
411 <span className="text-xs text-muted ml-3 font-normal">P2230</span>
413 <p className="text-sm text-text mb-4">
414 Shorter URLs create QR codes that can be smaller and scan more easily, making them more reliable. When this setting is enabled, the Pos
415 will generate short URLs that generate a 302 redirect to your Product Specific URL(s)
418 <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mt-4">
419 {['L', 'M', 'Q', 'H'].map((ecc, index) => (
420 <div key={ecc} className="flex flex-col items-center p-4 border border-border rounded bg-surface-2">
421 <div className="w-32 h-32 mb-2 bg-surface border-2 border-border flex items-center justify-center">
423 src={`https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent('HTTP://M9.NZ/11111123401234')}&ecc=${ecc}`}
424 alt={`Short QR Code ECC ${ecc}`}
425 className="w-full h-full object-contain"
428 <div className="text-sm font-medium text-text">ECC "{ecc}"</div>