@@ -78,6 +78,10 @@ function SettingsContent() {
7878 const [ enabledFilters , setEnabledFilters ] = useState < string [ ] > ( [ ] ) ;
7979 const [ savingFilters , setSavingFilters ] = useState ( false ) ;
8080
81+ // QR base URL state
82+ const [ qrBaseUrl , setQrBaseUrl ] = useState ( '' ) ;
83+ const [ savingQrUrl , setSavingQrUrl ] = useState ( false ) ;
84+
8185 // Alert configuration states
8286 const [ alertConfig , setAlertConfig ] = useState < AlertConfig > ( {
8387 enabled : false ,
@@ -151,6 +155,9 @@ function SettingsContent() {
151155 if ( data . spoolman ) {
152156 setSpoolmanUrl ( data . spoolman . url ) ;
153157 }
158+ if ( data . qrBaseUrl !== undefined ) {
159+ setQrBaseUrl ( data . qrBaseUrl ) ;
160+ }
154161 } catch {
155162 toast . error ( 'Failed to load settings' ) ;
156163 } finally {
@@ -1163,6 +1170,55 @@ function SettingsContent() {
11631170 </ >
11641171 ) }
11651172
1173+ { /* QR Code Base URL */ }
1174+ < Card >
1175+ < CardHeader >
1176+ < CardTitle > QR Code / NFC URL</ CardTitle >
1177+ < CardDescription >
1178+ Override the base URL used in generated QR code labels and NFC tags.
1179+ Leave empty to use the current browser URL automatically.
1180+ </ CardDescription >
1181+ </ CardHeader >
1182+ < CardContent className = "space-y-3" >
1183+ < div className = "space-y-2" >
1184+ < Label htmlFor = "qrBaseUrl" > Base URL</ Label >
1185+ < div className = "flex gap-2" >
1186+ < Input
1187+ id = "qrBaseUrl"
1188+ value = { qrBaseUrl }
1189+ onChange = { ( e ) => setQrBaseUrl ( e . target . value ) }
1190+ placeholder = "e.g., http://192.168.1.100:3000"
1191+ />
1192+ < Button
1193+ onClick = { async ( ) => {
1194+ setSavingQrUrl ( true ) ;
1195+ try {
1196+ const res = await fetch ( '/api/settings' , {
1197+ method : 'POST' ,
1198+ headers : { 'Content-Type' : 'application/json' } ,
1199+ body : JSON . stringify ( { type : 'qr_base_url' , url : qrBaseUrl } ) ,
1200+ } ) ;
1201+ if ( ! res . ok ) throw new Error ( ) ;
1202+ toast . success ( qrBaseUrl . trim ( ) ? 'QR base URL saved' : 'QR base URL cleared' ) ;
1203+ } catch {
1204+ toast . error ( 'Failed to save QR base URL' ) ;
1205+ } finally {
1206+ setSavingQrUrl ( false ) ;
1207+ }
1208+ } }
1209+ disabled = { savingQrUrl }
1210+ >
1211+ { savingQrUrl ? 'Saving...' : 'Save' }
1212+ </ Button >
1213+ </ div >
1214+ < p className = "text-xs text-muted-foreground" >
1215+ Useful when accessing SpoolmanSync through a reverse proxy or custom domain.
1216+ QR codes will link to this URL instead of the browser address bar URL.
1217+ </ p >
1218+ </ div >
1219+ </ CardContent >
1220+ </ Card >
1221+
11661222 </ div >
11671223
11681224 { /* Add Printer Dialog */ }
0 commit comments