feat: add sorting to user profile games grid

This commit is contained in:
Gustavo Francisco 2024-10-27 21:48:48 -03:00
parent 5705de7d7a
commit 9766059250
5 changed files with 122 additions and 13 deletions

View File

@ -1,5 +0,0 @@
MAIN_VITE_API_URL=API_URL
MAIN_VITE_AUTH_URL=AUTH_URL
MAIN_VITE_STEAMGRIDDB_API_KEY=YOUR_API_KEY
MAIN_VITE_SENTRY_DSN=YOUR_SENTRY_DSN
SENTRY_AUTH_TOKEN=

View File

@ -44,7 +44,7 @@
"@vanilla-extract/recipes": "^0.5.2",
"auto-launch": "^5.0.6",
"axios": "^1.7.7",
"better-sqlite3": "^11.3.0",
"better-sqlite3": "^11.5.0",
"check-disk-space": "^3.4.0",
"classnames": "^2.5.1",
"color": "^4.2.3",

View File

@ -203,3 +203,44 @@ export const achievementsProgressBar = style({
borderRadius: "4px",
},
});
export const gridSorting = style({
display: "flex", // Usa flexbox para organizar o layout
justifyContent: "space-between", // Espaça o label e os botões
alignItems: "center", // Centraliza verticalmente
marginBottom: `${SPACING_UNIT * 2}px`,
});
export const sortOption = style({
transition: "all ease 0.2s",
display: "inline-flex", // Altera para inline-flex para alinhar itens no botão
alignItems: "center", // Centraliza o ícone e o texto verticalmente
gap: "10px", // Define o espaçamento entre o ícone e o texto
color: vars.color.body,
":hover": {
color: "white",
cursor: "pointer",
},
});
export const selectedSortOption = style({
transition: "all ease 0.2s",
display: "inline-flex", // Altera para inline-flex para alinhar itens no botão
alignItems: "center", // Centraliza o ícone e o texto verticalmente
color: "white",
gap: "10px", // Define o espaçamento entre o ícone e o texto
":hover": {
cursor: "pointer",
},
});
export const sortOptionsWrapper = style({
display: "flex",
flexDirection: "row",
gap: "5px",
});
export const sortDivider = style({
border: `0.5px solid ${vars.color.body}`,
margin: "0px 5px"
});

View File

@ -1,5 +1,5 @@
import { userProfileContext } from "@renderer/context";
import { useCallback, useContext, useEffect, useMemo } from "react";
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
import { ProfileHero } from "../profile-hero/profile-hero";
import { useAppDispatch, useFormat } from "@renderer/hooks";
import { setHeaderTitle } from "@renderer/features";
@ -7,7 +7,12 @@ import { steamUrlBuilder } from "@shared";
import { SPACING_UNIT, vars } from "@renderer/theme.css";
import * as styles from "./profile-content.css";
import { ClockIcon, TelescopeIcon, TrophyIcon } from "@primer/octicons-react";
import {
ClockIcon,
TelescopeIcon,
TrophyIcon,
HistoryIcon,
} from "@primer/octicons-react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { LockedProfile } from "./locked-profile";
@ -21,6 +26,7 @@ import {
formatDownloadProgress,
} from "@renderer/helpers";
import { MAX_MINUTES_TO_SHOW_IN_PLAYTIME } from "@renderer/constants";
import { sortBy } from "lodash-es";
export function ProfileContent() {
const { userProfile, isMe, userStats } = useContext(userProfileContext);
@ -29,6 +35,8 @@ export function ProfileContent() {
const { t } = useTranslation("user_profile");
const [sortOption, setSortOption] = useState("lastPlayed"); // Estado para o critério de ordenação
useEffect(() => {
dispatch(setHeaderTitle(""));
@ -78,6 +86,25 @@ export function ProfileContent() {
[numberFormatter, t]
);
const sortGames = (games) => {
if (sortOption === "playtime") {
return sortBy(games, (game) => -game.playTimeInSeconds);
} else if (sortOption === "achievements") {
return sortBy(games, (game) => {
return game.achievementCount > 0
? -(game.unlockedAchievementCount / game.achievementCount)
: 0;
});
} else if (sortOption === "lastPlayed") {
return sortBy(games, (game) => {
return game.lastTimePlayed
? -new Date(game.lastTimePlayed).getTime()
: 0;
});
}
return games;
};
const content = useMemo(() => {
if (!userProfile) return null;
@ -93,6 +120,8 @@ export function ProfileContent() {
const shouldShowRightContent = hasGames || userProfile.friends.length > 0;
const sortedGames = sortGames(userProfile.libraryGames || []); // Ordena os jogos conforme o critério
return (
<section
style={{
@ -122,8 +151,51 @@ export function ProfileContent() {
)}
</div>
<div className={styles.gridSorting}>
<div>
<label htmlFor="sort-options">Ordenar por: </label>
</div>
<div className={styles.sortOptionsWrapper}>
<button
className={`${sortOption === "lastPlayed" ? styles.selectedSortOption : styles.sortOption}`}
onClick={() => setSortOption("lastPlayed")}
onKeyDown={(e) =>
e.key === "Enter" && setSortOption("lastPlayed")
} // Add keyboard support
tabIndex={0} // Optional if you keep using <span>
>
<HistoryIcon size={14} />
Jogados recentemente
</button>
<div className={styles.sortDivider} />
<button
className={`${sortOption === "playtime" ? styles.selectedSortOption : styles.sortOption}`}
onClick={() => setSortOption("playtime")}
onKeyDown={(e) =>
e.key === "Enter" && setSortOption("playtime")
} // Add keyboard support
tabIndex={0} // Optional if you keep using <span>
>
<ClockIcon size={14} />
Tempo jogado
</button>
<div className={styles.sortDivider} />
<button
className={`${sortOption === "achievements" ? styles.selectedSortOption : styles.sortOption}`}
onClick={() => setSortOption("achievements")}
onKeyDown={(e) =>
e.key === "Enter" && setSortOption("achievements")
} // Add keyboard support
tabIndex={0} // Optional if you keep using <span>
>
<TrophyIcon size={14} />
Conquistas obtidas
</button>
</div>
</div>
<ul className={styles.gamesGrid}>
{userProfile?.libraryGames?.map((game) => (
{sortedGames.map((game) => (
<li
key={game.objectId}
style={{
@ -261,6 +333,7 @@ export function ProfileContent() {
t,
formatPlayTime,
navigate,
sortOption,
]);
return (

View File

@ -3255,10 +3255,10 @@ bep53-range@^2.0.0:
resolved "https://registry.yarnpkg.com/bep53-range/-/bep53-range-2.0.0.tgz#a1770475661b4b814c4359e4b66f7cbd88de2b10"
integrity sha512-sMm2sV5PRs0YOVk0LTKtjuIprVzxgTQUsrGX/7Yph2Rm4FO2Fqqtq7hNjsOB5xezM4v4+5rljCgK++UeQJZguA==
better-sqlite3@^11.3.0:
version "11.3.0"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.3.0.tgz#f10b32ddff665c33176d148e707bd1e57dfd0284"
integrity sha512-iHt9j8NPYF3oKCNOO5ZI4JwThjt3Z6J6XrcwG85VNMVzv1ByqrHWv5VILEbCMFWDsoHhXvQ7oC8vgRXFAKgl9w==
better-sqlite3@^11.5.0:
version "11.5.0"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.5.0.tgz#58faa51e02845a578dd154f0083487132ead0695"
integrity sha512-e/6eggfOutzoK0JWiU36jsisdWoHOfN9iWiW/SieKvb7SAa6aGNmBM/UKyp+/wWSXpLlWNN8tCPwoDNPhzUvuQ==
dependencies:
bindings "^1.5.0"
prebuild-install "^7.1.1"