Use custom alert sound for invalid scans

- Serve bundled sound resources from the Resources folder

- Play alert.wav when a scan has invalid QR format or missing data

- Play alert.wav when the scanned unique number is not found in the database

- Keep the alert silent for other failures, such as service errors or shipment mark update failures

- Include alert.wav in build and publish output
main
SYED MUSTUFA AHMED NAQVI 2026-05-06 18:08:28 +05:00
parent 20482ec357
commit fd1655947e
4 changed files with 30 additions and 20 deletions

View File

@ -13,4 +13,8 @@
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="Resources\Sound\alert.wav" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>
</Project>

View File

@ -4,6 +4,7 @@ using AVSCartonShipmentVerifier.Repositories;
using AVSCartonShipmentVerifier.ScanHistory;
using AVSCartonShipmentVerifier.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
@ -50,6 +51,11 @@ if (!app.Environment.IsDevelopment())
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.ContentRootPath, "Resources")),
RequestPath = "/resources"
});
app.MapStaticAssets();
app.MapControllerRoute(
@ -58,4 +64,3 @@ app.MapControllerRoute(
.WithStaticAssets();
app.Run();

BIN
Resources/Sound/alert.wav Normal file

Binary file not shown.

View File

@ -17,6 +17,8 @@
};
const antiForgeryToken = document.querySelector('input[name="__RequestVerificationToken"]')?.value;
const failureAlarm = new Audio("/resources/Sound/alert.wav");
failureAlarm.preload = "auto";
let isSubmitting = false;
qrInput.addEventListener("keydown", async event => {
@ -70,7 +72,6 @@
if (!response.ok) {
const fallbackMessage = "Verification service is unavailable.";
setFailedState(payload.message ?? fallbackMessage);
triggerFailureAlarm();
resetDetails();
return;
}
@ -97,7 +98,19 @@
}
setFailedState(result.message);
triggerFailureAlarm();
if (shouldTriggerFailureAlarm(result)) {
triggerFailureAlarm();
}
}
function shouldTriggerFailureAlarm(result) {
const message = (result.message ?? "").toLowerCase();
return !result.existsInSystem
&& (
message.includes("invalid qr format")
|| message.includes("qr value is required")
|| message.includes("not found")
);
}
function setFailedState(message) {
@ -183,22 +196,10 @@
}
function triggerFailureAlarm() {
const context = new AudioContext();
const oscillator = context.createOscillator();
const gainNode = context.createGain();
oscillator.type = "sawtooth";
oscillator.frequency.setValueAtTime(740, context.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(320, context.currentTime + 0.4);
oscillator.connect(gainNode);
gainNode.connect(context.destination);
gainNode.gain.setValueAtTime(0.0001, context.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.5, context.currentTime + 0.05);
gainNode.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + 0.45);
oscillator.start(context.currentTime);
oscillator.stop(context.currentTime + 0.45);
oscillator.onended = () => context.close();
failureAlarm.pause();
failureAlarm.currentTime = 0;
failureAlarm.play().catch(() => {
// Some browsers block audio until the scanner input is treated as a user gesture.
});
}
})();