From 39af661720f7e3a59b49a95a88d4c03623c94e18 Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Mon, 7 Oct 2024 17:13:30 -0300 Subject: [PATCH] feat: create achievements page --- .../events/catalogue/get-game-achievements.ts | 48 +++++++++++++++---- src/preload/index.ts | 4 +- src/renderer/src/declaration.d.ts | 3 +- src/renderer/src/main.tsx | 9 +++- .../src/pages/achievement/achievements.tsx | 11 +++++ .../achievement-notification.css.ts} | 2 +- .../achievement-notification.tsx} | 4 +- .../pages/game-details/sidebar/sidebar.tsx | 15 ++++-- 8 files changed, 76 insertions(+), 20 deletions(-) create mode 100644 src/renderer/src/pages/achievement/achievements.tsx rename src/renderer/src/pages/achievement/{achievement.css.ts => notification/achievement-notification.css.ts} (95%) rename src/renderer/src/pages/achievement/{achievement.tsx => notification/achievement-notification.tsx} (96%) diff --git a/src/main/events/catalogue/get-game-achievements.ts b/src/main/events/catalogue/get-game-achievements.ts index 456babf4..7d0baa5c 100644 --- a/src/main/events/catalogue/get-game-achievements.ts +++ b/src/main/events/catalogue/get-game-achievements.ts @@ -1,13 +1,19 @@ -import type { GameAchievement, GameShop } from "@types"; +import type { GameAchievement, GameShop, UnlockedAchievement } from "@types"; import { registerEvent } from "../register-event"; -import { gameAchievementRepository } from "@main/repository"; +import { + gameAchievementRepository, + userAuthRepository, +} from "@main/repository"; import { getGameAchievementData } from "@main/services/achievements/get-game-achievement-data"; +import { HydraApi } from "@main/services"; -const getGameAchievements = async ( - _event: Electron.IpcMainInvokeEvent, +const getAchievements = async ( + shop: string, objectId: string, - shop: GameShop -): Promise => { + userId?: string +) => { + const userAuth = await userAuthRepository.findOne({ where: { userId } }); + const cachedAchievements = await gameAchievementRepository.findOne({ where: { objectId, shop }, }); @@ -16,9 +22,33 @@ const getGameAchievements = async ( ? JSON.parse(cachedAchievements.achievements) : await getGameAchievementData(objectId, shop); - const unlockedAchievements = JSON.parse( - cachedAchievements?.unlockedAchievements || "[]" - ) as { name: string; unlockTime: number }[]; + if (!userId || userAuth) { + const unlockedAchievements = JSON.parse( + cachedAchievements?.unlockedAchievements || "[]" + ) as UnlockedAchievement[]; + + return { achievementsData, unlockedAchievements }; + } + + const unlockedAchievements = await HydraApi.get( + `/users/${userId}/games/achievements`, + { shop, objectId, language: "en" } + ); + + return { achievementsData, unlockedAchievements }; +}; + +const getGameAchievements = async ( + _event: Electron.IpcMainInvokeEvent, + objectId: string, + shop: GameShop, + userId?: string +): Promise => { + const { achievementsData, unlockedAchievements } = await getAchievements( + shop, + objectId, + userId + ); return achievementsData .map((achievementData) => { diff --git a/src/preload/index.ts b/src/preload/index.ts index b24d1440..0a7e8fce 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -49,8 +49,8 @@ contextBridge.exposeInMainWorld("electron", { getGameStats: (objectId: string, shop: GameShop) => ipcRenderer.invoke("getGameStats", objectId, shop), getTrendingGames: () => ipcRenderer.invoke("getTrendingGames"), - getGameAchievements: (objectId: string, shop: GameShop) => - ipcRenderer.invoke("getGameAchievements", objectId, shop), + getGameAchievements: (objectId: string, shop: GameShop, userId?: string) => + ipcRenderer.invoke("getGameAchievements", objectId, shop, userId), onAchievementUnlocked: ( cb: ( objectId: string, diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts index 9db51497..351b8e0a 100644 --- a/src/renderer/src/declaration.d.ts +++ b/src/renderer/src/declaration.d.ts @@ -68,7 +68,8 @@ declare global { getTrendingGames: () => Promise; getGameAchievements: ( objectId: string, - shop: GameShop + shop: GameShop, + userId?: string ) => Promise; onAchievementUnlocked: ( cb: ( diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx index bcb8fe80..5312530d 100644 --- a/src/renderer/src/main.tsx +++ b/src/renderer/src/main.tsx @@ -28,10 +28,11 @@ import { import { store } from "./store"; import resources from "@locales"; -import { Achievement } from "./pages/achievement/achievement"; +import { AchievementNotification } from "./pages/achievement/notification/achievement-notification"; import "./workers"; import { RepacksContextProvider } from "./context"; +import { Achievement } from "./pages/achievement/achievements"; Sentry.init({}); @@ -69,8 +70,12 @@ ReactDOM.createRoot(document.getElementById("root")!).render( + - + diff --git a/src/renderer/src/pages/achievement/achievements.tsx b/src/renderer/src/pages/achievement/achievements.tsx new file mode 100644 index 00000000..40cb01c5 --- /dev/null +++ b/src/renderer/src/pages/achievement/achievements.tsx @@ -0,0 +1,11 @@ +import { useSearchParams } from "react-router-dom"; + +export function Achievement() { + const [searchParams] = useSearchParams(); + + return ( +
+

Achievement

+
+ ); +} diff --git a/src/renderer/src/pages/achievement/achievement.css.ts b/src/renderer/src/pages/achievement/notification/achievement-notification.css.ts similarity index 95% rename from src/renderer/src/pages/achievement/achievement.css.ts rename to src/renderer/src/pages/achievement/notification/achievement-notification.css.ts index d5cb180b..ba9469bb 100644 --- a/src/renderer/src/pages/achievement/achievement.css.ts +++ b/src/renderer/src/pages/achievement/notification/achievement-notification.css.ts @@ -1,5 +1,5 @@ import { recipe } from "@vanilla-extract/recipes"; -import { vars } from "../../theme.css"; +import { vars } from "../../../theme.css"; import { keyframes, style } from "@vanilla-extract/css"; const animationIn = keyframes({ diff --git a/src/renderer/src/pages/achievement/achievement.tsx b/src/renderer/src/pages/achievement/notification/achievement-notification.tsx similarity index 96% rename from src/renderer/src/pages/achievement/achievement.tsx rename to src/renderer/src/pages/achievement/notification/achievement-notification.tsx index f78d8f49..d33cb231 100644 --- a/src/renderer/src/pages/achievement/achievement.tsx +++ b/src/renderer/src/pages/achievement/notification/achievement-notification.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import achievementSound from "@renderer/assets/audio/achievement.wav"; import { useTranslation } from "react-i18next"; -import * as styles from "./achievement.css"; +import * as styles from "./achievement-notification.css"; interface AchievementInfo { displayName: string; @@ -10,7 +10,7 @@ interface AchievementInfo { const NOTIFICATION_TIMEOUT = 4000; -export function Achievement() { +export function AchievementNotification() { const { t } = useTranslation("achievement"); const [isClosing, setIsClosing] = useState(false); diff --git a/src/renderer/src/pages/game-details/sidebar/sidebar.tsx b/src/renderer/src/pages/game-details/sidebar/sidebar.tsx index e4063217..c0c066a1 100644 --- a/src/renderer/src/pages/game-details/sidebar/sidebar.tsx +++ b/src/renderer/src/pages/game-details/sidebar/sidebar.tsx @@ -1,7 +1,7 @@ import { useContext, useState } from "react"; import type { HowLongToBeatCategory, SteamAppDetails } from "@types"; import { useTranslation } from "react-i18next"; -import { Button } from "@renderer/components"; +import { Button, Link } from "@renderer/components"; import * as styles from "./sidebar.css"; import { gameDetailsContext } from "@renderer/context"; @@ -18,7 +18,7 @@ export function Sidebar() { const [activeRequirement, setActiveRequirement] = useState("minimum"); - const { gameTitle, shopDetails, stats, achievements } = + const { gameTitle, shopDetails, stats, achievements, shop, objectID } = useContext(gameDetailsContext); const { t } = useTranslation("game_details"); @@ -26,6 +26,11 @@ export function Sidebar() { const { numberFormatter } = useFormat(); + const buildGameAchievementPath = () => { + const urlParams = new URLSearchParams({ objectId: objectID!, shop }); + return `/achievements?${urlParams.toString()}`; + }; + // useEffect(() => { // if (objectID) { // setHowLongToBeat({ isLoading: true, data: null }); @@ -61,6 +66,10 @@ export function Sidebar() { {achievements.length}) + + Ver todas + +
- {achievements.map((achievement, index) => ( + {achievements.slice(0, 6).map((achievement, index) => (