Feature: add Google Drive backup and restore integration

This commit is contained in:
Ponte
2026-02-11 20:19:16 +01:00
parent 621beee036
commit 81d966b64a
9 changed files with 484 additions and 0 deletions

105
app.js
View File

@@ -46,6 +46,10 @@ const backupBtn = document.getElementById("backupBtn");
const restoreMergeBtn = document.getElementById("restoreMergeBtn");
const restoreReplaceBtn = document.getElementById("restoreReplaceBtn");
const restoreFileInput = document.getElementById("restoreFileInput");
const googleDriveState = document.getElementById("googleDriveState");
const googleConnectBtn = document.getElementById("googleConnectBtn");
const googleBackupBtn = document.getElementById("googleBackupBtn");
const googleRestoreBtn = document.getElementById("googleRestoreBtn");
const quickSearchInput = document.getElementById("quickSearchInput");
const quickSearchResults = document.getElementById("quickSearchResults");
const gamesList = document.getElementById("gamesList");
@@ -53,6 +57,7 @@ const gameCardTemplate = document.getElementById("gameCardTemplate");
let editingGameId = null;
let pendingRestoreMode = "merge";
let quickSearchTerm = "";
let googleStatus = { configured: false, connected: false, email: "" };
toolsToggleBtn.addEventListener("click", () => {
toolsDrawer.classList.toggle("open");
@@ -81,6 +86,48 @@ document.addEventListener("keydown", (event) => {
}
});
googleConnectBtn.addEventListener("click", async () => {
try {
const payload = await apiRequest("/api/google/connect-url");
if (!payload.url) {
throw new Error("Missing Google connect URL");
}
window.location.href = payload.url;
} catch (error) {
console.error(error);
alert("Connexion Google indisponible. Verifie la configuration OAuth.");
}
});
googleBackupBtn.addEventListener("click", async () => {
try {
const payload = await apiRequest("/api/google/backup/upload", { method: "POST" });
await refreshGoogleStatus();
alert(`Sauvegarde Drive OK: ${payload.fileName || "fichier cree"}.`);
} catch (error) {
console.error(error);
alert("Echec sauvegarde Google Drive.");
}
});
googleRestoreBtn.addEventListener("click", async () => {
const confirmed = window.confirm("Restaurer depuis le dernier backup Google Drive ?");
if (!confirmed) {
return;
}
try {
const payload = await apiRequest("/api/google/backup/restore", {
method: "POST",
body: { mode: "merge" },
});
await refreshFromApi(state.selectedBrand, state.selectedConsole);
alert(`Restauration Drive OK (${payload.mode})`);
} catch (error) {
console.error(error);
alert("Echec restauration Google Drive.");
}
});
quickSearchInput.addEventListener("input", (event) => {
quickSearchTerm = event.target.value.trim();
renderSearchResults();
@@ -435,6 +482,7 @@ restoreFileInput.addEventListener("change", async (event) => {
function render() {
renderDataMode();
renderGoogleStatus();
renderBrandTabs();
renderConsoleTabs();
renderGames();
@@ -491,6 +539,34 @@ function renderDataMode() {
}
}
function renderGoogleStatus() {
if (!googleDriveState) {
return;
}
if (!googleStatus.configured) {
googleDriveState.textContent = "Etat Google Drive: non configure (OAuth manquant).";
googleConnectBtn.disabled = true;
googleBackupBtn.disabled = true;
googleRestoreBtn.disabled = true;
return;
}
if (!googleStatus.connected) {
googleDriveState.textContent = "Etat Google Drive: non connecte.";
googleConnectBtn.disabled = false;
googleBackupBtn.disabled = true;
googleRestoreBtn.disabled = true;
return;
}
const email = googleStatus.email ? ` (${googleStatus.email})` : "";
googleDriveState.textContent = `Etat Google Drive: connecte${email}.`;
googleConnectBtn.disabled = false;
googleBackupBtn.disabled = false;
googleRestoreBtn.disabled = false;
}
function findBrandByConsole(consoleName) {
for (const [brand, consoles] of Object.entries(state.brands)) {
if (Array.isArray(consoles) && consoles.includes(consoleName)) {
@@ -829,6 +905,15 @@ async function refreshFromApi(preferredBrand, preferredConsole) {
render();
}
async function refreshGoogleStatus() {
try {
googleStatus = await apiRequest("/api/google/status");
} catch {
googleStatus = { configured: false, connected: false, email: "" };
}
renderGoogleStatus();
}
async function hydrateFromApi() {
try {
await refreshFromApi(state.selectedBrand, state.selectedConsole);
@@ -839,9 +924,29 @@ async function hydrateFromApi() {
}
async function bootstrap() {
await refreshGoogleStatus();
await hydrateFromApi();
normalizeState();
render();
handleGoogleCallbackResult();
}
bootstrap();
function handleGoogleCallbackResult() {
const url = new URL(window.location.href);
const googleParam = url.searchParams.get("google");
if (!googleParam) {
return;
}
if (googleParam === "connected") {
alert("Google Drive connecte avec succes.");
refreshGoogleStatus();
} else if (googleParam === "error") {
alert("Connexion Google Drive echouee.");
}
url.searchParams.delete("google");
window.history.replaceState({}, "", url.toString());
}