From 47a5f4d32762f2f43ca0ebfd6251862e62d4f3a8 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Tue, 17 Dec 2024 11:10:25 -0300 Subject: [PATCH 01/24] feat: add reset achievements modal --- src/locales/en/translation.json | 5 +- src/locales/pt-BR/translation.json | 5 +- .../modals/game-options-modal.tsx | 19 ++++++++ .../modals/reset-achievements-modal.tsx | 46 +++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 940e3185b..f2adae8b2 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -168,7 +168,10 @@ "select_folder": "Select folder", "backup_from": "Backup from {{date}}", "custom_backup_location_set": "Custom backup location set", - "no_directory_selected": "No directory selected" + "no_directory_selected": "No directory selected", + "reset_achievements": "Reset achievements", + "reset_achievements_description": "This will reset all achievements for {{game}}", + "reset_achievements_title": "Are you sure?" }, "activation": { "title": "Activate Hydra", diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index e724cdc37..30d8f3222 100644 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -164,7 +164,10 @@ "select_folder": "Selecione a pasta", "manage_files_description": "Gerencie quais arquivos serão feitos backup", "clear": "Limpar", - "no_directory_selected": "Nenhum diretório selecionado" + "no_directory_selected": "Nenhum diretório selecionado", + "reset_achievements": "Resetar conquistas", + "reset_achievements_description": "Isso irá resetar todas as conquistas de {{game}}", + "reset_achievements_title": "Tem certeza?" }, "activation": { "title": "Ativação", diff --git a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx index e5c83ec48..0d1fdc2c5 100644 --- a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx @@ -7,6 +7,7 @@ import { gameDetailsContext } from "@renderer/context"; import { DeleteGameModal } from "@renderer/pages/downloads/delete-game-modal"; import { useDownload, useToast } from "@renderer/hooks"; import { RemoveGameFromLibraryModal } from "./remove-from-library-modal"; +import { ResetAchievementsModal } from "./reset-achievements-modal"; import { FileDirectoryIcon, FileIcon } from "@primer/octicons-react"; export interface GameOptionsModalProps { @@ -29,6 +30,8 @@ export function GameOptionsModal({ const [showDeleteModal, setShowDeleteModal] = useState(false); const [showRemoveGameModal, setShowRemoveGameModal] = useState(false); + const [showResetAchievementsModal, setShowResetAchievementsModal] = + useState(false); const { removeGameInstaller, @@ -134,6 +137,13 @@ export function GameOptionsModal({ game={game} /> + setShowResetAchievementsModal(false)} + // resetAchievements={handleResetAchievements} + game={game} + /> + {t("remove_from_library")} + + + + + + + + ); +} From ac6eb247df4cfe5d57172bc10fbda0ccefbc31b1 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Tue, 17 Dec 2024 13:15:55 -0300 Subject: [PATCH 02/24] feat: implement reset game achievements functionality --- src/main/events/index.ts | 1 + .../events/library/reset-game-achievements.ts | 52 +++++++++++++++++++ src/preload/index.ts | 2 + src/renderer/src/declaration.d.ts | 2 +- .../modals/game-options-modal.tsx | 7 ++- .../modals/reset-achievements-modal.tsx | 6 +-- 6 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 src/main/events/library/reset-game-achievements.ts diff --git a/src/main/events/index.ts b/src/main/events/index.ts index eff625318..e26ed91c7 100644 --- a/src/main/events/index.ts +++ b/src/main/events/index.ts @@ -25,6 +25,7 @@ import "./library/verify-executable-path"; import "./library/remove-game"; import "./library/remove-game-from-library"; import "./library/select-game-wine-prefix"; +import "./library/reset-game-achievements"; import "./misc/open-checkout"; import "./misc/open-external"; import "./misc/show-open-dialog"; diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts new file mode 100644 index 000000000..7780c3edb --- /dev/null +++ b/src/main/events/library/reset-game-achievements.ts @@ -0,0 +1,52 @@ +import { gameAchievementRepository, gameRepository } from "@main/repository"; +import { registerEvent } from "../register-event"; +import { findAchievementFiles } from "@main/services/achievements/find-achivement-files"; +import fs from "fs"; +import { WindowManager } from "@main/services"; +import { getUnlockedAchievements } from "../user/get-unlocked-achievements"; + +const resetGameAchievements = async ( + _event: Electron.IpcMainInvokeEvent, + gameId: number +) => { + const game = await gameRepository.findOne({ where: { id: gameId } }); + + if (!game) return; + + const achievementFiles = findAchievementFiles(game); + + if (achievementFiles.length) { + try { + await Promise.all( + achievementFiles.map(async (achievementFile) => { + await fs.promises.rm(achievementFile.filePath, { recursive: true }); + }) + ); + } catch (error) { + console.error(error); + } + } + + await gameAchievementRepository.update( + { objectId: game.objectID }, + { + unlockedAchievements: null, + achievements: null, + } + ); + + // TODO: remove from db + + const gameAchievements = await getUnlockedAchievements( + game.objectID, + game.shop, + false + ); + + WindowManager.mainWindow?.webContents.send( + `on-update-achievements-${game.objectID}-${game.shop}`, + gameAchievements + ); +}; + +registerEvent("resetGameAchievements", resetGameAchievements); diff --git a/src/preload/index.ts b/src/preload/index.ts index f9d196448..d100228f1 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -110,6 +110,8 @@ contextBridge.exposeInMainWorld("electron", { ipcRenderer.invoke("deleteGameFolder", gameId), getGameByObjectId: (objectId: string) => ipcRenderer.invoke("getGameByObjectId", objectId), + resetGameAchievements: (gameId: number) => + ipcRenderer.invoke("resetGameAchievements", gameId), onGamesRunning: ( cb: ( gamesRunning: Pick[] diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts index 93c423e0d..343c3ffe8 100644 --- a/src/renderer/src/declaration.d.ts +++ b/src/renderer/src/declaration.d.ts @@ -105,7 +105,7 @@ declare global { ) => void ) => () => Electron.IpcRenderer; onLibraryBatchComplete: (cb: () => void) => () => Electron.IpcRenderer; - + resetGameAchievements: (gameId: number) => Promise; /* User preferences */ getUserPreferences: () => Promise; updateUserPreferences: ( diff --git a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx index 0d1fdc2c5..c4592e13a 100644 --- a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx @@ -122,6 +122,11 @@ export function GameOptionsModal({ const shouldShowWinePrefixConfiguration = window.electron.platform === "linux"; + const handleResetAchievements = async () => { + await window.electron.resetGameAchievements(game.id); + updateGame(); + }; + return ( <> setShowResetAchievementsModal(false)} - // resetAchievements={handleResetAchievements} + resetAchievements={handleResetAchievements} game={game} /> diff --git a/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx b/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx index 409fedbeb..d8861076e 100644 --- a/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx @@ -7,19 +7,19 @@ interface ResetAchievementsModalProps { visible: boolean; game: Game; onClose: () => void; -// resetAchievements: () => Promise; + resetAchievements: () => Promise; } export function ResetAchievementsModal({ onClose, game, visible, -// resetAchievements, + resetAchievements, }: ResetAchievementsModalProps) { const { t } = useTranslation("game_details"); const handleResetAchievements = async () => { - // await resetAchievements(); + await resetAchievements(); onClose(); }; From afcfcbf4828314fd09ec886e37881c8d4e8d8ed8 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Tue, 17 Dec 2024 13:55:45 -0300 Subject: [PATCH 03/24] refactor: clean up reset game achievements logic --- src/main/events/library/reset-game-achievements.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 7780c3edb..253440767 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -31,7 +31,6 @@ const resetGameAchievements = async ( { objectId: game.objectID }, { unlockedAchievements: null, - achievements: null, } ); @@ -40,7 +39,7 @@ const resetGameAchievements = async ( const gameAchievements = await getUnlockedAchievements( game.objectID, game.shop, - false + true ); WindowManager.mainWindow?.webContents.send( From bfdc2787d46dd24487bd24d31d8de1349ca3a0a6 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Thu, 2 Jan 2025 06:14:56 -0300 Subject: [PATCH 04/24] feat: remove hame achievements from remote db --- src/main/events/library/reset-game-achievements.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 253440767..2a1dc11d6 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -4,6 +4,7 @@ import { findAchievementFiles } from "@main/services/achievements/find-achivemen import fs from "fs"; import { WindowManager } from "@main/services"; import { getUnlockedAchievements } from "../user/get-unlocked-achievements"; +import { HydraApi } from "@main/services/hydra-api"; const resetGameAchievements = async ( _event: Electron.IpcMainInvokeEvent, @@ -34,7 +35,11 @@ const resetGameAchievements = async ( } ); - // TODO: remove from db + try { + await HydraApi.delete(`/profile/games/${game.remoteId}/achievements`); + } catch (error) { + console.error(error); + } const gameAchievements = await getUnlockedAchievements( game.objectID, From 10766526c51b6910765bf720454812374e628755 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Thu, 2 Jan 2025 06:28:32 -0300 Subject: [PATCH 05/24] refactor: streamline resetGameAchievements with a single try catch --- .../events/library/reset-game-achievements.ts | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 2a1dc11d6..ca8584607 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -10,47 +10,44 @@ const resetGameAchievements = async ( _event: Electron.IpcMainInvokeEvent, gameId: number ) => { - const game = await gameRepository.findOne({ where: { id: gameId } }); + try { + const game = await gameRepository.findOne({ where: { id: gameId } }); - if (!game) return; + if (!game) return; - const achievementFiles = findAchievementFiles(game); + const achievementFiles = findAchievementFiles(game); - if (achievementFiles.length) { - try { + if (achievementFiles.length) { await Promise.all( achievementFiles.map(async (achievementFile) => { await fs.promises.rm(achievementFile.filePath, { recursive: true }); }) ); - } catch (error) { - console.error(error); } - } - await gameAchievementRepository.update( - { objectId: game.objectID }, - { - unlockedAchievements: null, - } - ); + await gameAchievementRepository.update( + { objectId: game.objectID }, + { + unlockedAchievements: null, + } + ); - try { await HydraApi.delete(`/profile/games/${game.remoteId}/achievements`); + + const gameAchievements = await getUnlockedAchievements( + game.objectID, + game.shop, + true + ); + + WindowManager.mainWindow?.webContents.send( + `on-update-achievements-${game.objectID}-${game.shop}`, + gameAchievements + ); + } catch (error) { console.error(error); } - - const gameAchievements = await getUnlockedAchievements( - game.objectID, - game.shop, - true - ); - - WindowManager.mainWindow?.webContents.send( - `on-update-achievements-${game.objectID}-${game.shop}`, - gameAchievements - ); }; registerEvent("resetGameAchievements", resetGameAchievements); From addc2a74d32761d4679cb93d58cda1802d11b5d8 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Thu, 2 Jan 2025 06:28:45 -0300 Subject: [PATCH 06/24] lint --- src/main/events/library/reset-game-achievements.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index ca8584607..5d16f270e 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -44,7 +44,6 @@ const resetGameAchievements = async ( `on-update-achievements-${game.objectID}-${game.shop}`, gameAchievements ); - } catch (error) { console.error(error); } From 9849fbb31ce39f97d9cd5d0f29e270baaf72134c Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Thu, 2 Jan 2025 06:36:55 -0300 Subject: [PATCH 07/24] refactor: change ResetAchievementsModalProps to use Readonly type for better immutability --- .../pages/game-details/modals/reset-achievements-modal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx b/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx index d8861076e..b053060f1 100644 --- a/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx @@ -3,12 +3,12 @@ import { Button, Modal } from "@renderer/components"; import * as styles from "./remove-from-library-modal.css"; import type { Game } from "@types"; -interface ResetAchievementsModalProps { +type ResetAchievementsModalProps = Readonly<{ visible: boolean; game: Game; onClose: () => void; resetAchievements: () => Promise; -} +}>; export function ResetAchievementsModal({ onClose, From 52c159fe511536e6139773ce18ceee4ddb8e52e2 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Thu, 2 Jan 2025 09:34:28 -0300 Subject: [PATCH 08/24] fix: replace console.error with achievementsLogger.error --- src/main/events/library/reset-game-achievements.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 5d16f270e..5006f0751 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -2,7 +2,7 @@ import { gameAchievementRepository, gameRepository } from "@main/repository"; import { registerEvent } from "../register-event"; import { findAchievementFiles } from "@main/services/achievements/find-achivement-files"; import fs from "fs"; -import { WindowManager } from "@main/services"; +import { achievementsLogger, WindowManager } from "@main/services"; import { getUnlockedAchievements } from "../user/get-unlocked-achievements"; import { HydraApi } from "@main/services/hydra-api"; @@ -45,7 +45,7 @@ const resetGameAchievements = async ( gameAchievements ); } catch (error) { - console.error(error); + achievementsLogger.error(error); } }; From e2f798c627cc932a82be8012be60bc1b8e432df3 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Thu, 2 Jan 2025 09:35:05 -0300 Subject: [PATCH 09/24] refactor: simplify resetGameAchievements by replacing Promise.all with a for loop --- src/main/events/library/reset-game-achievements.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 5006f0751..763c06748 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -18,11 +18,9 @@ const resetGameAchievements = async ( const achievementFiles = findAchievementFiles(game); if (achievementFiles.length) { - await Promise.all( - achievementFiles.map(async (achievementFile) => { - await fs.promises.rm(achievementFile.filePath, { recursive: true }); - }) - ); + for (const achievementFile of achievementFiles) { + await fs.promises.rm(achievementFile.filePath); + } } await gameAchievementRepository.update( From 9672e649e41d0ed55ebde7237deaf4a0556f91a2 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Thu, 2 Jan 2025 09:36:09 -0300 Subject: [PATCH 10/24] feat: log deleted achievement files --- src/main/events/library/reset-game-achievements.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 763c06748..d7ea13cd1 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -18,6 +18,11 @@ const resetGameAchievements = async ( const achievementFiles = findAchievementFiles(game); if (achievementFiles.length) { + achievementsLogger.info( + `deleting achievement files: ${achievementFiles + .map((file) => file.filePath) + .join(", ")}` + ); for (const achievementFile of achievementFiles) { await fs.promises.rm(achievementFile.filePath); } From f3d617a13a20e784ad89d4c6e21104a411e0733c Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Thu, 2 Jan 2025 09:37:23 -0300 Subject: [PATCH 11/24] feat: log response after deleting game achievements --- src/main/events/library/reset-game-achievements.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index d7ea13cd1..3fa6e0a84 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -35,7 +35,8 @@ const resetGameAchievements = async ( } ); - await HydraApi.delete(`/profile/games/${game.remoteId}/achievements`); + await HydraApi.delete(`/profile/games/${game.remoteId}/achievements`).then( + (res) => console.info(res)); const gameAchievements = await getUnlockedAchievements( game.objectID, From 257a71d62665a681314119b0bcb1d0dd896b2303 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Thu, 2 Jan 2025 09:37:58 -0300 Subject: [PATCH 12/24] fix: change console.info to console.log --- src/main/events/library/reset-game-achievements.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 3fa6e0a84..3677fc659 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -36,7 +36,8 @@ const resetGameAchievements = async ( ); await HydraApi.delete(`/profile/games/${game.remoteId}/achievements`).then( - (res) => console.info(res)); + (res) => console.log(res) + ); const gameAchievements = await getUnlockedAchievements( game.objectID, From 8cf549ff05e8e0b286681ef4f336c770f36a846b Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 12:16:32 -0300 Subject: [PATCH 13/24] refactor: enhance logging in resetGameAchievement --- .../events/library/reset-game-achievements.ts | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 3677fc659..cfd0dc8a3 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -2,9 +2,8 @@ import { gameAchievementRepository, gameRepository } from "@main/repository"; import { registerEvent } from "../register-event"; import { findAchievementFiles } from "@main/services/achievements/find-achivement-files"; import fs from "fs"; -import { achievementsLogger, WindowManager } from "@main/services"; +import { achievementsLogger, HydraApi, WindowManager } from "@main/services"; import { getUnlockedAchievements } from "../user/get-unlocked-achievements"; -import { HydraApi } from "@main/services/hydra-api"; const resetGameAchievements = async ( _event: Electron.IpcMainInvokeEvent, @@ -18,12 +17,8 @@ const resetGameAchievements = async ( const achievementFiles = findAchievementFiles(game); if (achievementFiles.length) { - achievementsLogger.info( - `deleting achievement files: ${achievementFiles - .map((file) => file.filePath) - .join(", ")}` - ); for (const achievementFile of achievementFiles) { + achievementsLogger.log(`deleting ${achievementFile.filePath}`); await fs.promises.rm(achievementFile.filePath); } } @@ -35,9 +30,9 @@ const resetGameAchievements = async ( } ); - await HydraApi.delete(`/profile/games/${game.remoteId}/achievements`).then( - (res) => console.log(res) - ); + await HydraApi.delete(`/profile/games/${game.remoteId}/achievements`) + .catch((err) => achievementsLogger.error(err)) + .then((res) => achievementsLogger.log(res)); const gameAchievements = await getUnlockedAchievements( game.objectID, From 93b86f8c6c1df579eb9586cb254361134f2269a0 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 12:38:06 -0300 Subject: [PATCH 14/24] refactor: improve reset achievements handling and modal state management --- .../game-details/modals/game-options-modal.tsx | 15 ++++++++++----- .../modals/reset-achievements-modal.tsx | 10 ++++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx index 5289870ef..346f47000 100644 --- a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx @@ -31,10 +31,10 @@ export function GameOptionsModal({ const [showDeleteModal, setShowDeleteModal] = useState(false); const [showRemoveGameModal, setShowRemoveGameModal] = useState(false); + const [launchOptions, setLaunchOptions] = useState(game.launchOptions ?? ""); const [showResetAchievementsModal, setShowResetAchievementsModal] = useState(false); - - const [launchOptions, setLaunchOptions] = useState(game.launchOptions ?? ""); + const [isDeleting, setIsDeleting] = useState(false); const { removeGameInstaller, @@ -146,8 +146,13 @@ export function GameOptionsModal({ window.electron.platform === "linux"; const handleResetAchievements = async () => { - await window.electron.resetGameAchievements(game.id); - updateGame(); + setIsDeleting(true); + try { + await window.electron.resetGameAchievements(game.id); + } finally { + await updateGame(); + setIsDeleting(false); + } }; const shouldShowLaunchOptionsConfiguration = false; @@ -333,7 +338,7 @@ export function GameOptionsModal({ diff --git a/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx b/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx index b053060f1..642d32baa 100644 --- a/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/reset-achievements-modal.tsx @@ -2,7 +2,6 @@ import { useTranslation } from "react-i18next"; import { Button, Modal } from "@renderer/components"; import * as styles from "./remove-from-library-modal.css"; import type { Game } from "@types"; - type ResetAchievementsModalProps = Readonly<{ visible: boolean; game: Game; @@ -19,18 +18,21 @@ export function ResetAchievementsModal({ const { t } = useTranslation("game_details"); const handleResetAchievements = async () => { - await resetAchievements(); - onClose(); + try { + await resetAchievements(); + } finally { + onClose(); + } }; return (
From b68fe300ba8325d2c711983f61c5cc052dbdd08f Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 17:24:37 -0300 Subject: [PATCH 16/24] refactor: rename state variable for clarity --- .../src/pages/game-details/modals/game-options-modal.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx index b2d47dcbd..e751a67b0 100644 --- a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx @@ -34,7 +34,7 @@ export function GameOptionsModal({ const [launchOptions, setLaunchOptions] = useState(game.launchOptions ?? ""); const [showResetAchievementsModal, setShowResetAchievementsModal] = useState(false); - const [isDeleting, setIsDeleting] = useState(false); + const [isDeletingAchievements, setIsDeletingAchievements] = useState(false); const { removeGameInstaller, @@ -146,12 +146,12 @@ export function GameOptionsModal({ window.electron.platform === "linux"; const handleResetAchievements = async () => { - setIsDeleting(true); + setIsDeletingAchievements(true); try { await window.electron.resetGameAchievements(game.id); } finally { await updateGame(); - setIsDeleting(false); + setIsDeletingAchievements(false); } }; @@ -338,7 +338,7 @@ export function GameOptionsModal({ From ef3bf9890353996baabdf75a99263b3bd829b599 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 17:36:55 -0300 Subject: [PATCH 17/24] feat: add success and error toast --- src/locales/en/translation.json | 4 +++- src/locales/pt-BR/translation.json | 4 +++- src/main/events/library/reset-game-achievements.ts | 3 ++- .../src/pages/game-details/modals/game-options-modal.tsx | 5 ++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 3aea8facc..4e3dcb37c 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -182,7 +182,9 @@ "no_write_permission": "Cannot download into this directory. Click here to learn more.", "reset_achievements": "Reset achievements", "reset_achievements_description": "This will reset all achievements for {{game}}", - "reset_achievements_title": "Are you sure?" + "reset_achievements_title": "Are you sure?", + "reset_achievements_success": "Achievements successfully reset", + "reset_achievements_error": "Failed to reset achievements" }, "activation": { "title": "Activate Hydra", diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index b6f2360bd..2a80084f3 100644 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -170,7 +170,9 @@ "no_directory_selected": "Nenhum diretório selecionado", "reset_achievements": "Resetar conquistas", "reset_achievements_description": "Isso irá resetar todas as conquistas de {{game}}", - "reset_achievements_title": "Tem certeza?" + "reset_achievements_title": "Tem certeza?", + "reset_achievements_success": "Conquistas resetadas com sucesso", + "reset_achievements_error": "Falha ao resetar conquistas" }, "activation": { "title": "Ativação", diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index cfd0dc8a3..eb55a412b 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -30,7 +30,7 @@ const resetGameAchievements = async ( } ); - await HydraApi.delete(`/profile/games/${game.remoteId}/achievements`) + await HydraApi.delete(`/profile/games/achievements/${game.remoteId}`) .catch((err) => achievementsLogger.error(err)) .then((res) => achievementsLogger.log(res)); @@ -46,6 +46,7 @@ const resetGameAchievements = async ( ); } catch (error) { achievementsLogger.error(error); + throw error; } }; diff --git a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx index e751a67b0..fad02a969 100644 --- a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx @@ -149,8 +149,11 @@ export function GameOptionsModal({ setIsDeletingAchievements(true); try { await window.electron.resetGameAchievements(game.id); - } finally { await updateGame(); + showSuccessToast(t("reset_achievements_success")); + } catch (error) { + showErrorToast(t("reset_achievements_error")); + } finally { setIsDeletingAchievements(false); } }; From 2ddda4e4d225860a5d5b77850db3c096cc61217d Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 17:56:13 -0300 Subject: [PATCH 18/24] refactor: remove error logging --- src/main/events/library/reset-game-achievements.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index eb55a412b..17e00d5d8 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -31,7 +31,6 @@ const resetGameAchievements = async ( ); await HydraApi.delete(`/profile/games/achievements/${game.remoteId}`) - .catch((err) => achievementsLogger.error(err)) .then((res) => achievementsLogger.log(res)); const gameAchievements = await getUnlockedAchievements( From e6d76a5dbeaaa56c21a196cb50b31d12e16e4045 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 17:56:39 -0300 Subject: [PATCH 19/24] lint --- src/main/events/library/reset-game-achievements.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 17e00d5d8..4d591a5d0 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -30,8 +30,9 @@ const resetGameAchievements = async ( } ); - await HydraApi.delete(`/profile/games/achievements/${game.remoteId}`) - .then((res) => achievementsLogger.log(res)); + await HydraApi.delete(`/profile/games/achievements/${game.remoteId}`).then( + (res) => achievementsLogger.log(res) + ); const gameAchievements = await getUnlockedAchievements( game.objectID, From 190ddeb46ea30087f78d2c76dc1b24e727054ab5 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 18:22:13 -0300 Subject: [PATCH 20/24] refactor: improve logging for deleted game achievements --- src/main/events/library/reset-game-achievements.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 4d591a5d0..25b9e6d78 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -31,7 +31,7 @@ const resetGameAchievements = async ( ); await HydraApi.delete(`/profile/games/achievements/${game.remoteId}`).then( - (res) => achievementsLogger.log(res) + () => achievementsLogger.log(`Deleted achievements from ${game.remoteId} - ${game.objectID} - ${game.title}`) ); const gameAchievements = await getUnlockedAchievements( From 50616955003f6b75dd6780fa0303ac9960d33b19 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 18:22:25 -0300 Subject: [PATCH 21/24] lint --- src/main/events/library/reset-game-achievements.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/events/library/reset-game-achievements.ts b/src/main/events/library/reset-game-achievements.ts index 25b9e6d78..8d52a3a69 100644 --- a/src/main/events/library/reset-game-achievements.ts +++ b/src/main/events/library/reset-game-achievements.ts @@ -31,7 +31,10 @@ const resetGameAchievements = async ( ); await HydraApi.delete(`/profile/games/achievements/${game.remoteId}`).then( - () => achievementsLogger.log(`Deleted achievements from ${game.remoteId} - ${game.objectID} - ${game.title}`) + () => + achievementsLogger.log( + `Deleted achievements from ${game.remoteId} - ${game.objectID} - ${game.title}` + ) ); const gameAchievements = await getUnlockedAchievements( From 2df57b071dab55d85bb6623c5cd740b5ac17fc20 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 18:50:02 -0300 Subject: [PATCH 22/24] feat: disable reset achievement button if has no achievements --- .../src/pages/game-details/modals/game-options-modal.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx index fad02a969..3afc38709 100644 --- a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx @@ -26,7 +26,7 @@ export function GameOptionsModal({ const { showSuccessToast, showErrorToast } = useToast(); - const { updateGame, setShowRepacksModal, repacks, selectGameExecutable } = + const { updateGame, setShowRepacksModal, repacks, selectGameExecutable, achievements } = useContext(gameDetailsContext); const [showDeleteModal, setShowDeleteModal] = useState(false); @@ -43,6 +43,10 @@ export function GameOptionsModal({ cancelDownload, } = useDownload(); + const hasAchievements = + (achievements?.filter((achievement) => achievement.unlocked).length ?? 0) > + 0; + const deleting = isGameDeleting(game.id); const { lastPacket } = useDownload(); @@ -341,7 +345,7 @@ export function GameOptionsModal({ From 3efb1425b9835f191f8221e5902c6fc7cb522b2f Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 18:50:13 -0300 Subject: [PATCH 23/24] lint --- .../src/pages/game-details/modals/game-options-modal.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx index 3afc38709..a677e4b94 100644 --- a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx @@ -26,8 +26,13 @@ export function GameOptionsModal({ const { showSuccessToast, showErrorToast } = useToast(); - const { updateGame, setShowRepacksModal, repacks, selectGameExecutable, achievements } = - useContext(gameDetailsContext); + const { + updateGame, + setShowRepacksModal, + repacks, + selectGameExecutable, + achievements, + } = useContext(gameDetailsContext); const [showDeleteModal, setShowDeleteModal] = useState(false); const [showRemoveGameModal, setShowRemoveGameModal] = useState(false); From cade56bb128c8da09301d2d2ddd1996624c96de0 Mon Sep 17 00:00:00 2001 From: Hachi-R Date: Fri, 3 Jan 2025 19:15:31 -0300 Subject: [PATCH 24/24] feat: disable reset achievements button if user is not logged in --- .../pages/game-details/modals/game-options-modal.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx index a677e4b94..b06de28a8 100644 --- a/src/renderer/src/pages/game-details/modals/game-options-modal.tsx +++ b/src/renderer/src/pages/game-details/modals/game-options-modal.tsx @@ -5,7 +5,7 @@ import type { Game } from "@types"; import * as styles from "./game-options-modal.css"; import { gameDetailsContext } from "@renderer/context"; import { DeleteGameModal } from "@renderer/pages/downloads/delete-game-modal"; -import { useDownload, useToast } from "@renderer/hooks"; +import { useDownload, useToast, useUserDetails } from "@renderer/hooks"; import { RemoveGameFromLibraryModal } from "./remove-from-library-modal"; import { ResetAchievementsModal } from "./reset-achievements-modal"; import { FileDirectoryIcon, FileIcon } from "@primer/octicons-react"; @@ -48,6 +48,8 @@ export function GameOptionsModal({ cancelDownload, } = useDownload(); + const { userDetails } = useUserDetails(); + const hasAchievements = (achievements?.filter((achievement) => achievement.unlocked).length ?? 0) > 0; @@ -350,7 +352,12 @@ export function GameOptionsModal({