feat: create achievements page

This commit is contained in:
Zamitto 2024-10-07 17:13:30 -03:00
parent 6d4f957e2b
commit 39af661720
8 changed files with 76 additions and 20 deletions

View file

@ -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<GameAchievement[]> => {
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<UnlockedAchievement[]>(
`/users/${userId}/games/achievements`,
{ shop, objectId, language: "en" }
);
return { achievementsData, unlockedAchievements };
};
const getGameAchievements = async (
_event: Electron.IpcMainInvokeEvent,
objectId: string,
shop: GameShop,
userId?: string
): Promise<GameAchievement[]> => {
const { achievementsData, unlockedAchievements } = await getAchievements(
shop,
objectId,
userId
);
return achievementsData
.map((achievementData) => {

View file

@ -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,

View file

@ -68,7 +68,8 @@ declare global {
getTrendingGames: () => Promise<TrendingGame[]>;
getGameAchievements: (
objectId: string,
shop: GameShop
shop: GameShop,
userId?: string
) => Promise<GameAchievement[]>;
onAchievementUnlocked: (
cb: (

View file

@ -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(
<Route path="/search" Component={SearchResults} />
<Route path="/settings" Component={Settings} />
<Route path="/profile/:userId" Component={Profile} />
<Route path="/achievements" Component={Achievement} />
</Route>
<Route path="/achievement-notification" Component={Achievement} />
<Route
path="/achievement-notification"
Component={AchievementNotification}
/>
</Routes>
</HashRouter>
</RepacksContextProvider>

View file

@ -0,0 +1,11 @@
import { useSearchParams } from "react-router-dom";
export function Achievement() {
const [searchParams] = useSearchParams();
return (
<div>
<h1>Achievement</h1>
</div>
);
}

View file

@ -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({

View file

@ -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);

View file

@ -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<keyof SteamAppDetails["pc_requirements"]>("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})
</span>
</h3>
<span>
<Link to={buildGameAchievementPath()}>Ver todas</Link>
<a></a>
</span>
</div>
<div
style={{
@ -70,7 +79,7 @@ export function Sidebar() {
padding: `${SPACING_UNIT * 2}px`,
}}
>
{achievements.map((achievement, index) => (
{achievements.slice(0, 6).map((achievement, index) => (
<div
key={index}
style={{