Step 5 migration: add localStorage to DB import flow
This commit is contained in:
79
app.js
79
app.js
@@ -11,6 +11,7 @@ const initialState = {
|
||||
};
|
||||
|
||||
const state = loadState();
|
||||
let pendingLocalImport = payloadHasCatalogData(state) ? structuredClone(state) : null;
|
||||
let dataMode = "local";
|
||||
let apiReachable = false;
|
||||
|
||||
@@ -31,6 +32,7 @@ const brandTabs = document.getElementById("brandTabs");
|
||||
const consoleTabs = document.getElementById("consoleTabs");
|
||||
const gameSectionTitle = document.getElementById("gameSectionTitle");
|
||||
const dataModeInfo = document.getElementById("dataModeInfo");
|
||||
const migrateBtn = document.getElementById("migrateBtn");
|
||||
const gamesList = document.getElementById("gamesList");
|
||||
const gameCardTemplate = document.getElementById("gameCardTemplate");
|
||||
let editingGameId = null;
|
||||
@@ -45,7 +47,7 @@ platformForm.addEventListener("submit", async (event) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (apiReachable) {
|
||||
if (apiReachable && dataMode !== "local-pending-import") {
|
||||
try {
|
||||
await apiRequest("/api/catalog/consoles", {
|
||||
method: "POST",
|
||||
@@ -72,6 +74,7 @@ platformForm.addEventListener("submit", async (event) => {
|
||||
|
||||
platformForm.reset();
|
||||
persist();
|
||||
markLocalDataForImport();
|
||||
render();
|
||||
});
|
||||
|
||||
@@ -83,7 +86,7 @@ gameForm.addEventListener("submit", async (event) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (apiReachable) {
|
||||
if (apiReachable && dataMode !== "local-pending-import") {
|
||||
const payload = {
|
||||
brand: state.selectedBrand,
|
||||
consoleName: state.selectedConsole,
|
||||
@@ -149,6 +152,7 @@ gameForm.addEventListener("submit", async (event) => {
|
||||
|
||||
resetEditMode();
|
||||
persist();
|
||||
markLocalDataForImport();
|
||||
render();
|
||||
});
|
||||
|
||||
@@ -220,7 +224,7 @@ gamesList.addEventListener("click", async (event) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (apiReachable) {
|
||||
if (apiReachable && dataMode !== "local-pending-import") {
|
||||
try {
|
||||
if (action === "delete") {
|
||||
await apiRequest(`/api/catalog/games/${id}`, { method: "DELETE" });
|
||||
@@ -253,6 +257,7 @@ gamesList.addEventListener("click", async (event) => {
|
||||
}
|
||||
|
||||
persist();
|
||||
markLocalDataForImport();
|
||||
render();
|
||||
});
|
||||
|
||||
@@ -260,6 +265,33 @@ cancelEditBtn.addEventListener("click", () => {
|
||||
resetEditMode();
|
||||
});
|
||||
|
||||
migrateBtn.addEventListener("click", async () => {
|
||||
if (!apiReachable || !pendingLocalImport || !payloadHasCatalogData(pendingLocalImport)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = window.confirm(
|
||||
"Importer les donnees locales dans la base de donnees ? (deduplication par console + titre + annee)",
|
||||
);
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await apiRequest("/api/catalog/import", {
|
||||
method: "POST",
|
||||
body: pendingLocalImport,
|
||||
});
|
||||
|
||||
pendingLocalImport = null;
|
||||
await refreshFromApi(state.selectedBrand, state.selectedConsole);
|
||||
alert(`Migration terminee: ${result.insertedGames || 0} jeu(x) importe(s).`);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert("Echec de la migration locale vers DB.");
|
||||
}
|
||||
});
|
||||
|
||||
function render() {
|
||||
renderDataMode();
|
||||
renderBrandTabs();
|
||||
@@ -274,20 +306,22 @@ function renderDataMode() {
|
||||
|
||||
if (dataMode === "api") {
|
||||
dataModeInfo.textContent = "Source: API (lecture/ecriture active sur la base de donnees).";
|
||||
return;
|
||||
}
|
||||
|
||||
if (dataMode === "api-empty") {
|
||||
} else if (dataMode === "api-empty") {
|
||||
dataModeInfo.textContent = "Source: API (base vide). Ajoute une section pour demarrer.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (dataMode === "local-fallback") {
|
||||
} else if (dataMode === "local-pending-import") {
|
||||
dataModeInfo.textContent = "Source: localStorage detectee. Migration vers DB disponible.";
|
||||
} else if (dataMode === "local-fallback") {
|
||||
dataModeInfo.textContent = "Source: localStorage (fallback). API indisponible.";
|
||||
return;
|
||||
} else {
|
||||
dataModeInfo.textContent = "Source: localStorage";
|
||||
}
|
||||
|
||||
dataModeInfo.textContent = "Source: localStorage";
|
||||
const showMigrateBtn = apiReachable && pendingLocalImport && payloadHasCatalogData(pendingLocalImport);
|
||||
if (showMigrateBtn) {
|
||||
migrateBtn.classList.remove("hidden");
|
||||
} else {
|
||||
migrateBtn.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function renderBrandTabs() {
|
||||
@@ -431,6 +465,10 @@ function persist() {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
|
||||
}
|
||||
|
||||
function markLocalDataForImport() {
|
||||
pendingLocalImport = payloadHasCatalogData(state) ? structuredClone(state) : null;
|
||||
}
|
||||
|
||||
async function apiRequest(path, options = {}) {
|
||||
const requestOptions = {
|
||||
method: options.method || "GET",
|
||||
@@ -500,8 +538,19 @@ function payloadHasCatalogData(payload) {
|
||||
async function refreshFromApi(preferredBrand, preferredConsole) {
|
||||
const payload = await apiRequest("/api/catalog/full");
|
||||
apiReachable = true;
|
||||
dataMode = payloadHasCatalogData(payload) ? "api" : "api-empty";
|
||||
applyCatalogPayload(payload, preferredBrand, preferredConsole);
|
||||
const payloadHasData = payloadHasCatalogData(payload);
|
||||
|
||||
if (payloadHasData) {
|
||||
dataMode = "api";
|
||||
applyCatalogPayload(payload, preferredBrand, preferredConsole);
|
||||
} else if (pendingLocalImport && payloadHasCatalogData(pendingLocalImport)) {
|
||||
dataMode = "local-pending-import";
|
||||
applyCatalogPayload(pendingLocalImport, preferredBrand, preferredConsole);
|
||||
} else {
|
||||
dataMode = "api-empty";
|
||||
applyCatalogPayload(payload, preferredBrand, preferredConsole);
|
||||
}
|
||||
|
||||
persist();
|
||||
render();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user