mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-03 00:33:49 +03:00
feat: ui improvement
This commit is contained in:
parent
313ebc6055
commit
c8566dd2be
@ -168,8 +168,7 @@
|
|||||||
"select_folder": "Select folder",
|
"select_folder": "Select folder",
|
||||||
"backup_from": "Backup from {{date}}",
|
"backup_from": "Backup from {{date}}",
|
||||||
"custom_backup_location_set": "Custom backup location set",
|
"custom_backup_location_set": "Custom backup location set",
|
||||||
"no_directory_selected": "No directory selected",
|
"no_directory_selected": "No directory selected"
|
||||||
"available_points": "Available points:"
|
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "Activate Hydra",
|
"title": "Activate Hydra",
|
||||||
@ -367,11 +366,14 @@
|
|||||||
"uploading_banner": "Uploading banner…",
|
"uploading_banner": "Uploading banner…",
|
||||||
"background_image_updated": "Background image updated",
|
"background_image_updated": "Background image updated",
|
||||||
"stats": "Stats",
|
"stats": "Stats",
|
||||||
"achievements": "Achievements",
|
"achievements": "achievements",
|
||||||
"games": "Games",
|
"games": "Games",
|
||||||
"top_percentile": "Top {{percentile}}%",
|
"top_percentile": "Top {{percentile}}%",
|
||||||
"ranking_updated_weekly": "Ranking is updated weekly",
|
"ranking_updated_weekly": "Ranking is updated weekly",
|
||||||
"playing": "Playing {{game}}"
|
"playing": "Playing {{game}}",
|
||||||
|
"achievements_unlocked": "Achievements Unlocked",
|
||||||
|
"earned_points": "Earned points",
|
||||||
|
"show_achievements_on_profile": "Show your achievements and earned points on your profile"
|
||||||
},
|
},
|
||||||
"achievement": {
|
"achievement": {
|
||||||
"achievement_unlocked": "Achievement unlocked",
|
"achievement_unlocked": "Achievement unlocked",
|
||||||
@ -383,7 +385,9 @@
|
|||||||
"achievement_progress": "{{unlockedCount}}/{{totalCount}} achievements",
|
"achievement_progress": "{{unlockedCount}}/{{totalCount}} achievements",
|
||||||
"achievements_unlocked_for_game": "Unlocked {{achievementCount}} new achievements for {{gameTitle}}",
|
"achievements_unlocked_for_game": "Unlocked {{achievementCount}} new achievements for {{gameTitle}}",
|
||||||
"hidden_achievement_tooltip": "This is a hidden achievement",
|
"hidden_achievement_tooltip": "This is a hidden achievement",
|
||||||
"achievement_earn_points": "Earn {{points}} points with this achievement"
|
"achievement_earn_points": "Earn {{points}} points with this achievement",
|
||||||
|
"earned_points": "Earned points:",
|
||||||
|
"available_points": "Available points:"
|
||||||
},
|
},
|
||||||
"hydra_cloud": {
|
"hydra_cloud": {
|
||||||
"subscription_tour_title": "Hydra Cloud Subscription",
|
"subscription_tour_title": "Hydra Cloud Subscription",
|
||||||
|
@ -164,8 +164,7 @@
|
|||||||
"select_folder": "Selecione a pasta",
|
"select_folder": "Selecione a pasta",
|
||||||
"manage_files_description": "Gerencie quais arquivos serão feitos backup",
|
"manage_files_description": "Gerencie quais arquivos serão feitos backup",
|
||||||
"clear": "Limpar",
|
"clear": "Limpar",
|
||||||
"no_directory_selected": "Nenhum diretório selecionado",
|
"no_directory_selected": "Nenhum diretório selecionado"
|
||||||
"available_points": "Pontos disponíveis:"
|
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "Ativação",
|
"title": "Ativação",
|
||||||
@ -365,10 +364,13 @@
|
|||||||
"uploading_banner": "Carregando banner…",
|
"uploading_banner": "Carregando banner…",
|
||||||
"background_image_updated": "Imagem de fundo salva",
|
"background_image_updated": "Imagem de fundo salva",
|
||||||
"stats": "Estatísticas",
|
"stats": "Estatísticas",
|
||||||
"achievements": "Conquistas",
|
"achievements": "conquistas",
|
||||||
"games": "Jogos",
|
"games": "Jogos",
|
||||||
"ranking_updated_weekly": "Ranking é atualizado semanalmente",
|
"ranking_updated_weekly": "O ranking é atualizado semanalmente",
|
||||||
"playing": "Jogando {{game}}"
|
"playing": "Jogando {{game}}",
|
||||||
|
"achievements_unlocked": "Conquistas desbloqueadas",
|
||||||
|
"earned_points": "Pontos ganhos",
|
||||||
|
"show_achievements_on_profile": "Exiba suas conquistas e pontos no perfil"
|
||||||
},
|
},
|
||||||
"achievement": {
|
"achievement": {
|
||||||
"achievement_unlocked": "Conquista desbloqueada",
|
"achievement_unlocked": "Conquista desbloqueada",
|
||||||
@ -380,7 +382,9 @@
|
|||||||
"achievement_progress": "{{unlockedCount}}/{{totalCount}} conquistas",
|
"achievement_progress": "{{unlockedCount}}/{{totalCount}} conquistas",
|
||||||
"achievements_unlocked_for_game": "Desbloqueadas {{achievementCount}} novas conquistas em {{gameTitle}}",
|
"achievements_unlocked_for_game": "Desbloqueadas {{achievementCount}} novas conquistas em {{gameTitle}}",
|
||||||
"hidden_achievement_tooltip": "Está é uma conquista oculta",
|
"hidden_achievement_tooltip": "Está é uma conquista oculta",
|
||||||
"achievement_earn_points": "Ganhe {{points}} pontos com essa conquista"
|
"achievement_earn_points": "Ganhe {{points}} pontos com essa conquista",
|
||||||
|
"earned_points": "Pontos ganhos:",
|
||||||
|
"available_points": "Pontos disponíveis:"
|
||||||
},
|
},
|
||||||
"hydra_cloud": {
|
"hydra_cloud": {
|
||||||
"subscription_tour_title": "Assinatura Hydra Cloud",
|
"subscription_tour_title": "Assinatura Hydra Cloud",
|
||||||
|
@ -13,6 +13,9 @@ const getComparedUnlockedAchievements = async (
|
|||||||
where: { id: 1 },
|
where: { id: 1 },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const showHiddenAchievementsDescription =
|
||||||
|
userPreferences?.showHiddenAchievementsDescription || false;
|
||||||
|
|
||||||
return HydraApi.get<ComparedAchievements>(
|
return HydraApi.get<ComparedAchievements>(
|
||||||
`/users/${userId}/games/achievements/compare`,
|
`/users/${userId}/games/achievements/compare`,
|
||||||
{
|
{
|
||||||
@ -21,7 +24,8 @@ const getComparedUnlockedAchievements = async (
|
|||||||
language: userPreferences?.language || "en",
|
language: userPreferences?.language || "en",
|
||||||
}
|
}
|
||||||
).then((achievements) => {
|
).then((achievements) => {
|
||||||
const sortedAchievements = achievements.achievements.sort((a, b) => {
|
const sortedAchievements = achievements.achievements
|
||||||
|
.sort((a, b) => {
|
||||||
if (a.targetStat.unlocked && !b.targetStat.unlocked) return -1;
|
if (a.targetStat.unlocked && !b.targetStat.unlocked) return -1;
|
||||||
if (!a.targetStat.unlocked && b.targetStat.unlocked) return 1;
|
if (!a.targetStat.unlocked && b.targetStat.unlocked) return 1;
|
||||||
if (a.targetStat.unlocked && b.targetStat.unlocked) {
|
if (a.targetStat.unlocked && b.targetStat.unlocked) {
|
||||||
@ -29,6 +33,25 @@ const getComparedUnlockedAchievements = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Number(a.hidden) - Number(b.hidden);
|
return Number(a.hidden) - Number(b.hidden);
|
||||||
|
})
|
||||||
|
.map((achievement) => {
|
||||||
|
if (!achievement.hidden) return achievement;
|
||||||
|
|
||||||
|
if (!achievement.ownerStat) {
|
||||||
|
return {
|
||||||
|
...achievement,
|
||||||
|
description: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!showHiddenAchievementsDescription && achievement.hidden) {
|
||||||
|
return {
|
||||||
|
...achievement,
|
||||||
|
description: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return achievement;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -4,13 +4,25 @@ import { gameDetailsContext } from "@renderer/context";
|
|||||||
import * as styles from "./achievement-panel.css";
|
import * as styles from "./achievement-panel.css";
|
||||||
|
|
||||||
import HydraIcon from "@renderer/assets/icons/hydra.svg?react";
|
import HydraIcon from "@renderer/assets/icons/hydra.svg?react";
|
||||||
|
import { UserAchievement } from "@types";
|
||||||
|
|
||||||
export interface HeroPanelProps {
|
export interface AchievementPanelProps {
|
||||||
isHeaderStuck: boolean;
|
achievements: UserAchievement[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AchievementPanel({ isHeaderStuck }: HeroPanelProps) {
|
export function AchievementPanel({ achievements }: AchievementPanelProps) {
|
||||||
const { t } = useTranslation("game_details");
|
const { t } = useTranslation("achievement");
|
||||||
|
|
||||||
|
const achievementsPointsTotal = achievements.reduce(
|
||||||
|
(acc, achievement) => acc + (achievement.points ?? 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const achievementsPointsEarnedSum = achievements.reduce(
|
||||||
|
(acc, achievement) =>
|
||||||
|
acc + (achievement.unlocked ? (achievement.points ?? 0) : 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
const {} = useContext(gameDetailsContext);
|
const {} = useContext(gameDetailsContext);
|
||||||
|
|
||||||
@ -18,7 +30,8 @@ export function AchievementPanel({ isHeaderStuck }: HeroPanelProps) {
|
|||||||
<>
|
<>
|
||||||
<div className={styles.panel}>
|
<div className={styles.panel}>
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
Pontos desbloqueados: <HydraIcon width={20} height={20} /> 69/420
|
{t("earned_points")} <HydraIcon width={20} height={20} />
|
||||||
|
{achievementsPointsEarnedSum} / {achievementsPointsTotal}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -329,7 +329,7 @@ export function AchievementsContent({
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<AchievementPanel isHeaderStuck={false} />
|
<AchievementPanel achievements={achievements!} />
|
||||||
<AchievementList achievements={achievements!} />
|
<AchievementList achievements={achievements!} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
import type { ComparedAchievements } from "@types";
|
import type { ComparedAchievements } from "@types";
|
||||||
import * as styles from "./achievements.css";
|
import * as styles from "./achievements.css";
|
||||||
import { CheckCircleIcon, LockIcon } from "@primer/octicons-react";
|
import {
|
||||||
|
CheckCircleIcon,
|
||||||
|
EyeClosedIcon,
|
||||||
|
LockIcon,
|
||||||
|
} from "@primer/octicons-react";
|
||||||
import { useDate } from "@renderer/hooks";
|
import { useDate } from "@renderer/hooks";
|
||||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export interface ComparedAchievementListProps {
|
export interface ComparedAchievementListProps {
|
||||||
achievements: ComparedAchievements;
|
achievements: ComparedAchievements;
|
||||||
@ -11,6 +16,7 @@ export interface ComparedAchievementListProps {
|
|||||||
export function ComparedAchievementList({
|
export function ComparedAchievementList({
|
||||||
achievements,
|
achievements,
|
||||||
}: ComparedAchievementListProps) {
|
}: ComparedAchievementListProps) {
|
||||||
|
const { t } = useTranslation("achievement");
|
||||||
const { formatDateTime } = useDate();
|
const { formatDateTime } = useDate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -43,7 +49,17 @@ export function ComparedAchievementList({
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<h4>{achievement.displayName}</h4>
|
<h4 style={{ display: "flex", alignItems: "center", gap: "4px" }}>
|
||||||
|
{achievement.hidden && (
|
||||||
|
<span
|
||||||
|
style={{ display: "flex" }}
|
||||||
|
title={t("hidden_achievement_tooltip")}
|
||||||
|
>
|
||||||
|
<EyeClosedIcon size={12} />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{achievement.displayName}
|
||||||
|
</h4>
|
||||||
<p>{achievement.description}</p>
|
<p>{achievement.description}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,7 @@ export interface ComparedAchievementPanelProps {
|
|||||||
export function ComparedAchievementPanel({
|
export function ComparedAchievementPanel({
|
||||||
achievements,
|
achievements,
|
||||||
}: ComparedAchievementPanelProps) {
|
}: ComparedAchievementPanelProps) {
|
||||||
const { t } = useTranslation("game_details");
|
const { t } = useTranslation("achievement");
|
||||||
|
|
||||||
const {} = useContext(gameDetailsContext);
|
const {} = useContext(gameDetailsContext);
|
||||||
|
|
||||||
|
@ -41,9 +41,7 @@ export function FriendsBox() {
|
|||||||
{friend.displayName}
|
{friend.displayName}
|
||||||
</span>
|
</span>
|
||||||
{friend.currentGame && (
|
{friend.currentGame && (
|
||||||
<Link to={buildGameDetailsPath({ ...friend.currentGame })}>
|
|
||||||
<p>{t("playing", { game: friend.currentGame.title })}</p>
|
<p>{t("playing", { game: friend.currentGame.title })}</p>
|
||||||
</Link>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -105,6 +105,22 @@ export const listItem = style({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const statsListItem = style({
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
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}px`,
|
||||||
|
":hover": {
|
||||||
|
backgroundColor: "rgba(255, 255, 255, 0.15)",
|
||||||
|
textDecoration: "none",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export const gamesGrid = style({
|
export const gamesGrid = style({
|
||||||
listStyle: "none",
|
listStyle: "none",
|
||||||
margin: "0",
|
margin: "0",
|
||||||
|
@ -22,6 +22,7 @@ import {
|
|||||||
} from "@renderer/helpers";
|
} from "@renderer/helpers";
|
||||||
import { MAX_MINUTES_TO_SHOW_IN_PLAYTIME } from "@renderer/constants";
|
import { MAX_MINUTES_TO_SHOW_IN_PLAYTIME } from "@renderer/constants";
|
||||||
import { UserStatsBox } from "./user-stats-box";
|
import { UserStatsBox } from "./user-stats-box";
|
||||||
|
import HydraIcon from "@renderer/assets/icons/hydra.svg?react";
|
||||||
|
|
||||||
export function ProfileContent() {
|
export function ProfileContent() {
|
||||||
const { userProfile, isMe, userStats } = useContext(userProfileContext);
|
const { userProfile, isMe, userStats } = useContext(userProfileContext);
|
||||||
@ -157,7 +158,7 @@ export function ProfileContent() {
|
|||||||
height: "100%",
|
height: "100%",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
background:
|
background:
|
||||||
"linear-gradient(0deg, rgba(0, 0, 0, 0.7) 20%, transparent 100%)",
|
"linear-gradient(0deg, rgba(0, 0, 0, 0.75) 25%, transparent 100%)",
|
||||||
padding: 8,
|
padding: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -187,6 +188,22 @@ export function ProfileContent() {
|
|||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{game.achievementsPointsEarnedSum > 0 && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "start",
|
||||||
|
gap: 8,
|
||||||
|
marginBottom: 4,
|
||||||
|
color: vars.color.muted,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<HydraIcon width={16} height={16} />
|
||||||
|
{numberFormatter.format(
|
||||||
|
game.achievementsPointsEarnedSum
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
@ -6,14 +6,13 @@ import { useFormat } from "@renderer/hooks";
|
|||||||
import { MAX_MINUTES_TO_SHOW_IN_PLAYTIME } from "@renderer/constants";
|
import { MAX_MINUTES_TO_SHOW_IN_PLAYTIME } from "@renderer/constants";
|
||||||
import HydraIcon from "@renderer/assets/icons/hydra.svg?react";
|
import HydraIcon from "@renderer/assets/icons/hydra.svg?react";
|
||||||
import { useSubscription } from "@renderer/hooks/use-subscription";
|
import { useSubscription } from "@renderer/hooks/use-subscription";
|
||||||
|
import { ClockIcon, TrophyIcon } from "@primer/octicons-react";
|
||||||
|
import { vars } from "@renderer/theme.css";
|
||||||
|
|
||||||
export function UserStatsBox() {
|
export function UserStatsBox() {
|
||||||
const { showHydraCloudModal } = useSubscription();
|
const { showHydraCloudModal } = useSubscription();
|
||||||
|
const { userStats, isMe } = useContext(userProfileContext);
|
||||||
const { userStats } = useContext(userProfileContext);
|
|
||||||
|
|
||||||
const { t } = useTranslation("user_profile");
|
const { t } = useTranslation("user_profile");
|
||||||
|
|
||||||
const { numberFormatter } = useFormat();
|
const { numberFormatter } = useFormat();
|
||||||
|
|
||||||
const formatPlayTime = useCallback(
|
const formatPlayTime = useCallback(
|
||||||
@ -43,22 +42,46 @@ export function UserStatsBox() {
|
|||||||
|
|
||||||
<div className={styles.box}>
|
<div className={styles.box}>
|
||||||
<ul className={styles.list}>
|
<ul className={styles.list}>
|
||||||
<li>
|
{(isMe || userStats.unlockedAchievementSum !== undefined) && (
|
||||||
<h3 className={styles.listItemTitle}>{t("achievements")}</h3>
|
<li className={styles.statsListItem}>
|
||||||
{userStats.achievementsPointsEarnedSum !== undefined ? (
|
<h3 className={styles.listItemTitle}>
|
||||||
<>
|
{t("achievements_unlocked")}
|
||||||
|
</h3>
|
||||||
|
{userStats.unlockedAchievementSum !== undefined ? (
|
||||||
<div
|
<div
|
||||||
style={{ display: "flex", justifyContent: "space-between" }}
|
style={{ display: "flex", justifyContent: "space-between" }}
|
||||||
>
|
>
|
||||||
<p
|
<p className={styles.listItemDescription}>
|
||||||
style={{
|
<TrophyIcon /> {userStats.unlockedAchievementSum}{" "}
|
||||||
display: "flex",
|
{t("achievements")}
|
||||||
alignItems: "center",
|
</p>
|
||||||
gap: "4px",
|
</div>
|
||||||
}}
|
) : (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={showHydraCloudModal}
|
||||||
|
className={styles.link}
|
||||||
>
|
>
|
||||||
|
<small style={{ color: vars.color.warning }}>
|
||||||
|
{t("show_achievements_on_profile")}
|
||||||
|
</small>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(isMe || userStats.achievementsPointsEarnedSum !== undefined) && (
|
||||||
|
<li className={styles.statsListItem}>
|
||||||
|
<h3 className={styles.listItemTitle}>{t("earned_points")}</h3>
|
||||||
|
{userStats.achievementsPointsEarnedSum !== undefined ? (
|
||||||
|
<div
|
||||||
|
style={{ display: "flex", justifyContent: "space-between" }}
|
||||||
|
>
|
||||||
|
<p className={styles.listItemDescription}>
|
||||||
<HydraIcon width={20} height={20} />
|
<HydraIcon width={20} height={20} />
|
||||||
{userStats.achievementsPointsEarnedSum.value}
|
{numberFormatter.format(
|
||||||
|
userStats.achievementsPointsEarnedSum.value
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
<p title={t("ranking_updated_weekly")}>
|
<p title={t("ranking_updated_weekly")}>
|
||||||
{t("top_percentile", {
|
{t("top_percentile", {
|
||||||
@ -67,25 +90,27 @@ export function UserStatsBox() {
|
|||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p>Unlock count: {userStats.unlockedAchievementSum}</p>
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={showHydraCloudModal}
|
onClick={showHydraCloudModal}
|
||||||
className={styles.link}
|
className={styles.link}
|
||||||
>
|
>
|
||||||
<small>
|
<small style={{ color: vars.color.warning }}>
|
||||||
Saiba como exibir suas conquistas e pontos no perfil
|
{t("show_achievements_on_profile")}
|
||||||
</small>
|
</small>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
|
)}
|
||||||
|
|
||||||
<li>
|
<li className={styles.statsListItem}>
|
||||||
<h3 className={styles.listItemTitle}>{t("total_play_time")}</h3>
|
<h3 className={styles.listItemTitle}>{t("total_play_time")}</h3>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||||||
<p>{formatPlayTime(userStats.totalPlayTimeInSeconds.value)}</p>
|
<p className={styles.listItemDescription}>
|
||||||
|
<ClockIcon />
|
||||||
|
{formatPlayTime(userStats.totalPlayTimeInSeconds.value)}
|
||||||
|
</p>
|
||||||
<p title={t("ranking_updated_weekly")}>
|
<p title={t("ranking_updated_weekly")}>
|
||||||
{t("top_percentile", {
|
{t("top_percentile", {
|
||||||
percentile: userStats.totalPlayTimeInSeconds.topPercentile,
|
percentile: userStats.totalPlayTimeInSeconds.topPercentile,
|
||||||
|
@ -99,6 +99,7 @@ export interface UserGame {
|
|||||||
lastTimePlayed: Date | null;
|
lastTimePlayed: Date | null;
|
||||||
unlockedAchievementCount: number;
|
unlockedAchievementCount: number;
|
||||||
achievementCount: number;
|
achievementCount: number;
|
||||||
|
achievementsPointsEarnedSum: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DownloadQueue {
|
export interface DownloadQueue {
|
||||||
|
Loading…
Reference in New Issue
Block a user