Feature: barcode lookup with auto-fill and owned detection

This commit is contained in:
Ponte
2026-02-14 22:46:30 +01:00
parent 80a126bd6e
commit 832004b591
3 changed files with 233 additions and 8 deletions

68
app.js
View File

@@ -20,6 +20,7 @@ const gameForm = document.getElementById("gameForm");
const brandInput = document.getElementById("brandInput");
const consoleInput = document.getElementById("consoleInput");
const titleInput = document.getElementById("titleInput");
const barcodeInput = document.getElementById("barcodeInput");
const versionInput = document.getElementById("versionInput");
const genreInput = document.getElementById("genreInput");
const publisherInput = document.getElementById("publisherInput");
@@ -241,6 +242,7 @@ gameForm.addEventListener("submit", async (event) => {
brand: state.selectedBrand,
consoleName: state.selectedConsole,
title,
barcode: barcodeInput.value.trim(),
version: versionInput.value.trim(),
genre: genreInput.value.trim(),
publisher: publisherInput.value.trim(),
@@ -283,6 +285,7 @@ gameForm.addEventListener("submit", async (event) => {
games[idx] = {
...games[idx],
title,
barcode: barcodeInput.value.trim(),
version: versionInput.value.trim(),
genre: genreInput.value.trim(),
publisher: publisherInput.value.trim(),
@@ -298,6 +301,7 @@ gameForm.addEventListener("submit", async (event) => {
const game = {
id: crypto.randomUUID(),
title,
barcode: barcodeInput.value.trim(),
version: versionInput.value.trim(),
genre: genreInput.value.trim(),
publisher: publisherInput.value.trim(),
@@ -686,6 +690,7 @@ function buildGamePayload(game, brand, consoleName, overrides = {}) {
brand,
consoleName,
title: game.title || "",
barcode: game.barcode || "",
version: game.version || "",
genre: game.genre || "",
publisher: game.publisher || "",
@@ -865,6 +870,7 @@ function renderGames() {
const metaParts = [
showLoanedOnly ? `${game.brand} / ${game.consoleName}` : null,
game.barcode ? `Code: ${game.barcode}` : null,
game.version ? `Version: ${game.version}` : null,
game.genre ? `Genre: ${game.genre}` : null,
game.publisher ? `Editeur: ${game.publisher}` : null,
@@ -898,6 +904,7 @@ function renderGames() {
function startEditMode(game) {
editingGameId = game.id;
titleInput.value = game.title || "";
barcodeInput.value = game.barcode || "";
versionInput.value = game.version || "";
genreInput.value = game.genre || "";
publisherInput.value = game.publisher || "";
@@ -1029,6 +1036,10 @@ async function scanLoop() {
}
function applyScannedCode(codeValue) {
if (barcodeInput) {
barcodeInput.value = codeValue;
}
if (scannerLastCode) {
scannerLastCode.textContent = `Dernier code detecte: ${codeValue}`;
scannerLastCode.classList.remove("hidden");
@@ -1043,6 +1054,63 @@ function applyScannedCode(codeValue) {
if (titleInput && !normalizeText(titleInput.value)) {
titleInput.value = codeValue;
}
lookupScannedBarcode(codeValue).catch((error) => {
console.error(error);
updateScannerStatus(`Code detecte: ${codeValue} (lookup indisponible).`);
});
}
async function lookupScannedBarcode(codeValue) {
const normalized = normalizeText(codeValue);
if (!normalized) {
return;
}
const result = await apiRequest(`/api/barcode/lookup/${encodeURIComponent(normalized)}`, { timeoutMs: 7000 });
if (!result || result.status !== "ok") {
updateScannerStatus(`Code detecte: ${normalized}`);
return;
}
const owned = result.owned && result.game;
if (owned) {
const ownedTitle = normalizeText(result.game.title) || "Jeu inconnu";
const ownedConsole = normalizeText(result.game.consoleName);
const ownedLabel = ownedConsole ? `${ownedTitle} (${ownedConsole})` : ownedTitle;
updateScannerStatus(`Deja possede: ${ownedLabel}`);
alert(`Deja dans ta collection: ${ownedLabel}`);
if (quickSearchInput) {
quickSearchInput.value = ownedTitle;
quickSearchTerm = ownedTitle;
renderSearchResults();
}
if (titleInput) {
titleInput.value = ownedTitle;
}
if (publisherInput && !normalizeText(publisherInput.value) && result.game.publisher) {
publisherInput.value = result.game.publisher;
}
return;
}
const hasAutoData = result.lookup && normalizeText(result.lookup.title);
if (hasAutoData) {
titleInput.value = result.lookup.title;
if (publisherInput && !normalizeText(publisherInput.value) && result.lookup.publisher) {
publisherInput.value = result.lookup.publisher;
}
if (quickSearchInput) {
quickSearchInput.value = result.lookup.title;
quickSearchTerm = result.lookup.title;
renderSearchResults();
}
updateScannerStatus(`Titre trouve automatiquement: ${result.lookup.title}`);
return;
}
updateScannerStatus(`Code detecte: ${normalized} (aucune fiche auto).`);
}
function normalizeText(value) {