Skip to content

Commit 273c5e3

Browse files
committed
Settings + barcode adjustments
- Settings based on selected symbology - Values are stored when generating barcodes - Errors are now visible on-screen - Scaling adjustments makes all barcodes look nicer - More symbologies added
1 parent b3e0f23 commit 273c5e3

File tree

1 file changed

+195
-33
lines changed

1 file changed

+195
-33
lines changed

app/page.tsx

Lines changed: 195 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,49 +25,79 @@ interface BarcodeOptions {
2525
bcid: string
2626
text: string
2727
scale: number
28-
includetext: boolean
2928
textxalign: string
3029
}
3130

3231
declare global {
3332
interface Window {
3433
bwipjs: {
35-
toCanvas: (canvas: HTMLCanvasElement, options: BarcodeOptions) => void
36-
}
34+
toCanvas: (canvas: HTMLCanvasElement, options: {}) => void
35+
},
36+
symdesc?: Record<string, { sym: string; desc: string; text: string; opts: string }>;
3737
}
3838
}
3939

40+
let selectedOptions : Record<string, string> = {};
41+
4042
export default function BarcodeGenerator() {
43+
// Load bwip-js library
44+
const bwipLibscript = document.createElement("script")
45+
bwipLibscript.src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/bwip-js-min.js"
46+
bwipLibscript.async = true
47+
document.head.appendChild(bwipLibscript)
48+
// Load symdesc
49+
const descScript = document.createElement("script")
50+
descScript.src = "https://cdn.jsdelivr.net/npm/[email protected]/lib/symdesc.js"
51+
descScript.async = true
52+
document.head.appendChild(descScript)
53+
4154
const [barcodeText, setBarcodeText] = useState("AAA1234;BBB1234")
42-
const [symbology, setSymbology] = useState("code128")
43-
const [showText, setShowText] = useState(true)
55+
const [symbology, setSymbology] = useState("")
56+
const [initialSymbology, setInitialSymbology] = useState("");
4457
const [darkMode, setDarkMode] = useState(false)
4558
const [barcodes, setBarcodes] = useState<string[]>([])
4659
const [isGenerating, setIsGenerating] = useState(false)
60+
const [options, setOptions] = useState<Record<string, string>>({});
61+
62+
const [error, setError] = useState<string | null>(null); // State to store error messages
4763

4864
useEffect(() => {
65+
4966
// Load saved preferences
5067
const savedDarkMode = localStorage.getItem("darkModeEnabled") === "true"
5168
const savedSymbology = localStorage.getItem("lastSymbology")
5269
const savedRequest = localStorage.getItem("lastRequest")
5370

5471
if (savedDarkMode) setDarkMode(true)
55-
if (savedSymbology) setSymbology(savedSymbology)
72+
if (savedSymbology){
73+
console.log("savedSymbology: ", savedSymbology);
74+
setInitialSymbology(savedSymbology)
75+
setSymbology(savedSymbology)
76+
}
77+
else{
78+
setInitialSymbology("code128")
79+
setSymbology("code128")
80+
}
5681
if (savedRequest) setBarcodeText(savedRequest)
5782

58-
// Load bwip-js library
59-
const script = document.createElement("script")
60-
script.src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/bwip-js-min.js"
61-
script.async = true
62-
document.head.appendChild(script)
6383

6484
return () => {
65-
if (document.head.contains(script)) {
66-
document.head.removeChild(script)
85+
if (document.head.contains(bwipLibscript)) {
86+
document.head.removeChild(bwipLibscript)
87+
}
88+
if (document.head.contains(descScript)) {
89+
document.head.removeChild(descScript)
6790
}
6891
}
6992
}, [])
7093

94+
useEffect(() => {
95+
console.log(`effect triggered by: ${symbology}`);
96+
if (!symbology) return;
97+
loadOptions(symbology);
98+
if (symbology === initialSymbology) return;
99+
}, [symbology])
100+
71101
useEffect(() => {
72102
localStorage.setItem("darkModeEnabled", darkMode.toString())
73103
if (darkMode) {
@@ -77,15 +107,85 @@ export default function BarcodeGenerator() {
77107
}
78108
}, [darkMode])
79109

110+
function loadOptionsRecords(symbOptions: string) : Record<string, string>{
111+
let records : Record<string, string> = {};
112+
if (!symbOptions || symbOptions.length === 0) {
113+
return records;
114+
}
115+
const defOptions = symbOptions.split(" ");
116+
for (const defOption of defOptions) {
117+
if(defOption.includes("=")){
118+
const [key, value] = defOption.split("=");
119+
records[key] = value;
120+
}
121+
else{
122+
records[defOption] = "false";
123+
}
124+
}
125+
return records;
126+
}
127+
128+
const loadOptions = (symbology: string) => {
129+
selectedOptions = {}
130+
if (window.symdesc) {
131+
const symbologyInfo = window.symdesc[symbology];
132+
if (symbologyInfo) {
133+
console.log(`loading options for symbology: ${symbology}`);
134+
let storedOptions = localStorage.getItem(storedOptionsKey(symbology));
135+
console.log(`loading ${storedOptionsKey(symbology)}`, storedOptions);
136+
if (storedOptions && storedOptions != "{}") {
137+
const storedOptionsObj : Record<string,string> = JSON.parse(storedOptions)
138+
console.log("storedOptionsObj: ", storedOptionsObj);
139+
setOptions(storedOptionsObj)
140+
selectedOptions = storedOptionsObj
141+
}
142+
else{
143+
const defaultOptions = loadOptionsRecords(symbologyInfo.opts);
144+
console.log("defaultOptions: ", defaultOptions);
145+
setOptions(defaultOptions);
146+
selectedOptions = defaultOptions;
147+
}
148+
149+
} else {
150+
console.log(`no options available for symbology: ${symbology}`);
151+
setOptions({});
152+
}
153+
} else {
154+
console.log(`loading options failed, no symdesc available`);
155+
setOptions({});
156+
}
157+
};
158+
159+
const handleInputChange = (key: string, value: string) => {
160+
selectedOptions[key] = value;
161+
};
162+
163+
const handleSwitchChange = (key: string, value: boolean) => {
164+
selectedOptions[key] = value ? "true" : "false";
165+
};
166+
167+
const storedOptionsKey = (symbology: string) => {
168+
return `stored_${symbology}_opts`;
169+
}
170+
171+
172+
173+
80174
const generateBarcodes = async () => {
81175
if (!barcodeText.trim()) {
82-
setBarcodes([])
176+
setBarcodes([]);
177+
setError(null);
83178
return
84179
}
85180

86-
setIsGenerating(true)
87-
localStorage.setItem("lastRequest", barcodeText)
88-
localStorage.setItem("lastSymbology", symbology)
181+
setBarcodes([]);
182+
setIsGenerating(true);
183+
setError(null);
184+
185+
localStorage.setItem("lastRequest", barcodeText);
186+
localStorage.setItem("lastSymbology", symbology);
187+
localStorage.setItem(storedOptionsKey(symbology), JSON.stringify(selectedOptions));
188+
console.log(`storing ${storedOptionsKey(symbology)}`, selectedOptions);
89189

90190
try {
91191
// Determine separator
@@ -115,22 +215,28 @@ export default function BarcodeGenerator() {
115215
const canvas = document.createElement("canvas")
116216

117217
for (const entry of entries) {
118-
const options: BarcodeOptions = {
119-
bcid: symbology,
120-
text: entry,
121-
scale: 3,
122-
includetext: showText,
123-
textxalign: "center",
218+
let options = {};
219+
220+
for (const [key, value] of Object.entries(selectedOptions)) {
221+
options[key] = value;
124222
}
125223

224+
options.text = entry;
225+
options.bcid = symbology;
226+
options.scale = 3;
227+
228+
console.log("generating barcodes using: ", options);
126229
try {
127230
window.bwipjs.toCanvas(canvas, options)
128231
generatedBarcodes.push(canvas.toDataURL("image/png"))
129232
} catch (error) {
130-
console.error("Error generating barcode for:", entry, error)
233+
console.error("Error generating barcode for:", entry, error);
234+
setError(`Failed to generate barcode for: ${entry}
235+
${error}
236+
`);
237+
return;
131238
}
132239
}
133-
134240
setBarcodes(generatedBarcodes)
135241
} catch (error) {
136242
console.error("Error generating barcodes:", error)
@@ -306,7 +412,7 @@ export default function BarcodeGenerator() {
306412
</CardHeader>
307413
<CardContent className="space-y-4 pt-4">
308414
<div>
309-
<Label htmlFor="symbology" className="text-sm font-medium mb-2 block text-foreground">
415+
<Label htmlFor="symbology" className="text-sm font-bold mb-2 block text-foreground">
310416
Symbology
311417
</Label>
312418
<Select value={symbology} onValueChange={setSymbology}>
@@ -315,23 +421,79 @@ export default function BarcodeGenerator() {
315421
</SelectTrigger>
316422
<SelectContent>
317423
<SelectItem value="code128">Code 128</SelectItem>
318-
<SelectItem value="datamatrix">Data Matrix</SelectItem>
319-
<SelectItem value="gs1datamatrix">GS1 Data Matrix</SelectItem>
424+
<SelectItem value="interleaved2of5">Interleaved 2 of 5</SelectItem>
320425
<SelectItem value="pdf417">PDF417</SelectItem>
321426
<SelectItem value="qrcode">QR Code</SelectItem>
427+
<SelectItem value="dotcode">Dot code</SelectItem>
428+
<SelectItem value="datamatrix">Data Matrix</SelectItem>
429+
<SelectItem value="gs1datamatrix">GS1 Data Matrix</SelectItem>
430+
<SelectItem value="ean5">EAN-5</SelectItem>
431+
<SelectItem value="ean8">EAN-13</SelectItem>
322432
</SelectContent>
323433
</Select>
324434
</div>
325-
<div className="flex items-center space-x-2">
326-
<Switch id="show-text" checked={showText} onCheckedChange={setShowText} />
327-
<Label htmlFor="show-text" className="text-sm font-medium text-foreground">
328-
Show text below barcode
329-
</Label>
435+
436+
<div>
437+
438+
439+
440+
{Object.entries(options).length > 0 ? (
441+
<>
442+
<Label htmlFor="symbology" className="text-sm font-bold mb-2 block text-foreground">
443+
Options
444+
</Label>
445+
<ul className="text-gray-700 list-disc list-inside space-y-2">
446+
{Object.entries(options).map(([key,value], index) => {
447+
const hasBoolValue = value === "true" || value === "false";
448+
if (hasBoolValue) {
449+
//Switch input
450+
return (
451+
<div key={index} className="flex items-center space-x-2">
452+
<Switch
453+
id={`${symbology}_option_${key}`}
454+
defaultChecked={value === "true"}
455+
onCheckedChange={(checked) => handleSwitchChange(key, checked)}/>
456+
<Label htmlFor={`${symbology}_option_${key}`} className="text-sm font-medium text-foreground">
457+
{key}
458+
</Label>
459+
</div>
460+
);
461+
} else {
462+
return (
463+
//Text input
464+
<div key={`${symbology}_option_${key}`} className="flex items-center">
465+
<Label htmlFor={`${symbology}_option_${key}`} className="text-sm font-medium text-foreground mr-4">
466+
{key}:
467+
</Label>
468+
<input
469+
id={`${symbology}_option_${key}`}
470+
type="text"
471+
defaultValue={value}
472+
onChange={(e) => handleInputChange(key, e.target.value)}
473+
className="w-16 border border-gray-300 rounded-lg p-1 text-sm"
474+
/>
475+
</div>
476+
);
477+
}
478+
})}
479+
</ul>
480+
</>
481+
) : (
482+
<p className="text-gray-500 italic">No hay opciones disponibles</p>
483+
)}
484+
330485
</div>
331486
</CardContent>
332487
</Card>
333488
</div>
334489

490+
{/*Errors*/}
491+
{error && (
492+
<div className="error-message bg-red-100 text-red-700 p-4 my-4 rounded">
493+
<strong>Error:</strong> {error}
494+
</div>
495+
)}
496+
335497
{/* Barcodes Display */}
336498
{barcodes.length > 0 && (
337499
<Card className="bg-card/80 backdrop-blur-sm border-border">

0 commit comments

Comments
 (0)