diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index b80f8bd6..6d2ea93b 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -333,6 +333,8 @@ "your_friend_code": "Your friend code:" }, "achievement": { - "achievement_unlocked": "Achievement unlocked" + "achievement_unlocked": "Achievement unlocked", + "user_achievements": "{{displayName}}'s Achievements", + "your_achievements": "Your Achievements" } } diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index c5a15f6b..f5d91d46 100644 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -335,6 +335,8 @@ "your_friend_code": "Seu código de amigo:" }, "achievement": { - "achievement_unlocked": "Conquista desbloqueada" + "achievement_unlocked": "Conquista desbloqueada", + "your_achievements": "Suas Conquistas", + "user_achievements": "Conquistas de {{displayName}}" } } diff --git a/src/main/events/catalogue/get-game-achievements.ts b/src/main/events/catalogue/get-game-achievements.ts index 07bc2e91..8b040874 100644 --- a/src/main/events/catalogue/get-game-achievements.ts +++ b/src/main/events/catalogue/get-game-achievements.ts @@ -83,9 +83,9 @@ export const getGameAchievements = async ( unlocked: false, unlockTime: null, icongray, - }; + } as GameAchievement; }) - .sort((a: GameAchievement, b: GameAchievement) => { + .sort((a, b) => { if (a.unlocked && !b.unlocked) return -1; if (!a.unlocked && b.unlocked) return 1; if (a.unlocked && b.unlocked) { diff --git a/src/main/services/achievements/find-achivement-files.ts b/src/main/services/achievements/find-achivement-files.ts index 917e5351..dc43f827 100644 --- a/src/main/services/achievements/find-achivement-files.ts +++ b/src/main/services/achievements/find-achivement-files.ts @@ -53,7 +53,7 @@ const getPathFromCracker = (cracker: Cracker) => { if (cracker === Cracker.onlineFix) { return [ { - folderPath: path.join(publicDocuments, Cracker.onlineFix), + folderPath: path.join(publicDocuments, "OnlineFix"), fileLocation: ["Stats", "Achievements.ini"], }, ]; diff --git a/src/renderer/src/helpers.ts b/src/renderer/src/helpers.ts index a9fc3cdd..2eb83df6 100644 --- a/src/renderer/src/helpers.ts +++ b/src/renderer/src/helpers.ts @@ -34,5 +34,20 @@ export const buildGameDetailsPath = ( return `/game/${game.shop}/${game.objectId}?${searchParams.toString()}`; }; +export const buildGameAchievementPath = ( + game: { shop: GameShop; objectId: string; title: string }, + user?: { userId: string; displayName: string } +) => { + const searchParams = new URLSearchParams({ + title: game.title, + shop: game.shop, + objectId: game.objectId, + userId: user?.userId || "", + displayName: user?.displayName || "", + }); + + return `/achievements/?${searchParams.toString()}`; +}; + export const darkenColor = (color: string, amount: number, alpha: number = 1) => new Color(color).darken(amount).alpha(alpha).toString(); diff --git a/src/renderer/src/pages/achievement/achievements.css.ts b/src/renderer/src/pages/achievement/achievements.css.ts new file mode 100644 index 00000000..f5f548e6 --- /dev/null +++ b/src/renderer/src/pages/achievement/achievements.css.ts @@ -0,0 +1,82 @@ +import { SPACING_UNIT, vars } from "../../theme.css"; +import { style } from "@vanilla-extract/css"; +import { recipe } from "@vanilla-extract/recipes"; + +export const container = style({ + width: "100%", + padding: `${SPACING_UNIT * 2}px`, + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT * 2}px`, +}); + +export const header = style({ + display: "flex", + gap: `${SPACING_UNIT}px`, + width: "50%", +}); + +export const headerImage = style({ + borderRadius: "4px", + objectFit: "cover", + cursor: "pointer", + height: "160px", + transition: "all ease 0.2s", + ":hover": { + transform: "scale(1.05)", + }, +}); + +export const list = style({ + listStyle: "none", + margin: "0", + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT * 2}px`, + padding: 0, +}); + +export const listItem = style({ + display: "flex", + transition: "all ease 0.1s", + color: vars.color.muted, + width: "100%", + overflow: "hidden", + borderRadius: "4px", + padding: `${SPACING_UNIT}px ${SPACING_UNIT}px`, + gap: `${SPACING_UNIT * 2}px`, + alignItems: "center", + textAlign: "left", + ":hover": { + backgroundColor: "rgba(255, 255, 255, 0.15)", + textDecoration: "none", + }, +}); + +export const listItemImage = recipe({ + base: { + width: "54px", + height: "54px", + borderRadius: "4px", + objectFit: "cover", + }, + variants: { + unlocked: { + false: { + filter: "grayscale(100%)", + }, + }, + }, +}); + +export const achievementsProgressBar = style({ + width: "100%", + height: "8px", + transition: "all ease 0.2s", + "::-webkit-progress-bar": { + backgroundColor: "rgba(255, 255, 255, 0.15)", + }, + "::-webkit-progress-value": { + backgroundColor: vars.color.muted, + }, +}); diff --git a/src/renderer/src/pages/achievement/achievements.tsx b/src/renderer/src/pages/achievement/achievements.tsx index dd50c0ab..19152f9c 100644 --- a/src/renderer/src/pages/achievement/achievements.tsx +++ b/src/renderer/src/pages/achievement/achievements.tsx @@ -1,9 +1,17 @@ import { setHeaderTitle } from "@renderer/features"; import { useAppDispatch, useDate } from "@renderer/hooks"; -import { SPACING_UNIT } from "@renderer/theme.css"; -import { GameAchievement, GameShop } from "@types"; +import { steamUrlBuilder } from "@shared"; +import type { GameAchievement, GameShop } from "@types"; import { useEffect, useState } from "react"; -import { useSearchParams } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { useNavigate, useSearchParams } from "react-router-dom"; +import * as styles from "./achievements.css"; +import { + buildGameDetailsPath, + formatDownloadProgress, +} from "@renderer/helpers"; +import { TrophyIcon } from "@primer/octicons-react"; +import { vars } from "@renderer/theme.css"; export function Achievement() { const [searchParams] = useSearchParams(); @@ -11,8 +19,12 @@ export function Achievement() { const shop = searchParams.get("shop"); const title = searchParams.get("title"); const userId = searchParams.get("userId"); + const displayName = searchParams.get("displayName"); + + const { t } = useTranslation("achievement"); const { format } = useDate(); + const navigate = useNavigate(); const dispatch = useAppDispatch(); @@ -30,53 +42,109 @@ export function Achievement() { useEffect(() => { if (title) { - dispatch(setHeaderTitle(title + " Achievements")); + dispatch(setHeaderTitle(title)); } }, [dispatch, title]); - return ( -
{achievement.displayName}
{achievement.description}
- {achievement.unlockTime && format(achievement.unlockTime)} + + {achievement.unlockTime && format(achievement.unlockTime)} +