fix: using local state for game running

This commit is contained in:
Chubby Granny Chaser 2024-09-14 02:27:58 +01:00
parent 6368bd66d3
commit d15ca88714
No known key found for this signature in database
9 changed files with 112 additions and 37 deletions

View file

@ -293,6 +293,7 @@
"image_process_failure": "Falha ao processar a imagem",
"required_field": "Este campo é obrigatório",
"displayname_min_length": "Nome de exibição deve ter pelo menos 3 caracteres",
"displayname_max_length": "Nome de exibição deve ter no máximo 50 caracteres"
"displayname_max_length": "Nome de exibição deve ter no máximo 50 caracteres",
"locked_profile": "Este perfil é privado"
}
}

View file

@ -1,7 +1,7 @@
import { useNavigate } from "react-router-dom";
import { PeopleIcon, PersonIcon } from "@primer/octicons-react";
import * as styles from "./sidebar-profile.css";
import { useUserDetails } from "@renderer/hooks";
import { useAppSelector, useUserDetails } from "@renderer/hooks";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { UserFriendModalTab } from "@renderer/pages/shared-modals/user-friend-modal";
@ -13,6 +13,8 @@ export function SidebarProfile() {
const { userDetails, friendRequests, showFriendsModal } = useUserDetails();
const { gameRunning } = useAppSelector((state) => state.gameRunning);
const receivedRequests = useMemo(() => {
return friendRequests.filter((request) => request.type === "RECEIVED");
}, [friendRequests]);
@ -74,19 +76,19 @@ export function SidebarProfile() {
{userDetails ? userDetails.displayName : t("sign_in")}
</p>
{userDetails && userDetails.currentGame && (
{userDetails && gameRunning && (
<div>
<small>{userDetails.currentGame.title}</small>
<small>{gameRunning.title}</small>
</div>
)}
</div>
{userDetails && userDetails.currentGame && (
{userDetails && gameRunning && (
<img
alt={userDetails.currentGame.title}
alt={gameRunning.title}
width={24}
style={{ borderRadius: 4 }}
src={userDetails.currentGame.iconUrl!}
src={gameRunning.iconUrl!}
/>
)}
</div>

View file

@ -23,6 +23,8 @@ const SIDEBAR_MAX_WIDTH = 450;
const initialSidebarWidth = window.localStorage.getItem("sidebarWidth");
export function Sidebar() {
const filterRef = useRef<HTMLInputElement>(null);
const { t } = useTranslation("sidebar");
const { library, updateLibrary } = useLibrary();
const navigate = useNavigate();
@ -78,6 +80,10 @@ export function Sidebar() {
useEffect(() => {
setFilteredLibrary(sortedLibrary);
if (filterRef.current) {
filterRef.current.value = "";
}
}, [sortedLibrary]);
useEffect(() => {
@ -139,7 +145,7 @@ export function Sidebar() {
navigate(path);
}
if (event.detail == 2) {
if (event.detail === 2) {
if (game.executablePath) {
window.electron.openGame(game.id, game.executablePath);
} else {
@ -190,6 +196,7 @@ export function Sidebar() {
<small className={styles.sectionTitle}>{t("my_library")}</small>
<TextField
ref={filterRef}
placeholder={t("filter")}
onChange={handleFilter}
theme="dark"

View file

@ -110,6 +110,7 @@ export function GameDetails() {
};
const handleNSFWContentRefuse = () => {
setHasNSFWContentBlocked(false);
navigate(-1);
};

View file

@ -7,10 +7,6 @@ export const contentSidebar = style({
width: "100%",
height: "100%",
"@media": {
"(min-width: 768px)": {
width: "100%",
maxWidth: "200px",
},
"(min-width: 1024px)": {
maxWidth: "300px",
width: "100%",
@ -90,6 +86,14 @@ export const statsSection = style({
gap: `${SPACING_UNIT * 2}px`,
padding: `${SPACING_UNIT * 2}px`,
justifyContent: "space-between",
"@media": {
"(min-width: 1024px)": {
flexDirection: "column",
},
"(min-width: 1280px)": {
flexDirection: "row",
},
},
});
export const statsCategoryTitle = style({
@ -104,7 +108,6 @@ export const statsCategory = style({
display: "flex",
flexDirection: "column",
gap: `${SPACING_UNIT / 2}px`,
alignItems: "flex-end",
});
globalStyle(`${requirementsDetails} a`, {

View file

@ -124,3 +124,24 @@ export const gamesGrid = style({
},
},
});
export const telescopeIcon = style({
width: "60px",
height: "60px",
borderRadius: "50%",
backgroundColor: "rgba(255, 255, 255, 0.06)",
display: "flex",
alignItems: "center",
justifyContent: "center",
marginBottom: `${SPACING_UNIT * 2}px`,
});
export const noGames = style({
display: "flex",
width: "100%",
height: "100%",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
gap: `${SPACING_UNIT}px`,
});

View file

@ -29,11 +29,6 @@ export function ProfileContent() {
}
}, [userProfile, dispatch]);
const truncatedGamesList = useMemo(() => {
if (!userProfile) return [];
return userProfile?.libraryGames.slice(0, 12);
}, [userProfile]);
const { numberFormatter } = useFormat();
const navigate = useNavigate();
@ -91,8 +86,16 @@ export function ProfileContent() {
<h3>{numberFormatter.format(userProfile.libraryGames.length)}</h3>
</div>
{/* <div className={styles.noGames}>
<div className={styles.telescopeIcon}>
<TelescopeIcon size={24} />
</div>
<h2>{t("no_recent_activity_title")}</h2>
{isMe && <p>{t("no_recent_activity_description")}</p>}
</div> */}
<ul className={styles.gamesGrid}>
{truncatedGamesList.map((game) => (
{userProfile?.libraryGames?.map((game) => (
<li
key={game.objectId}
style={{
@ -128,7 +131,7 @@ export function ProfileContent() {
<div className={styles.rightContent}>
<div>
<div className={styles.sectionHeader}>
<h2>Played recently</h2>
<h2>{t("activity")}</h2>
</div>
<div className={styles.box}>
@ -216,7 +219,6 @@ export function ProfileContent() {
formatPlayTime,
numberFormatter,
t,
truncatedGamesList,
usersAreFriends,
isMe,
navigate,

View file

@ -4,8 +4,10 @@ import * as styles from "./profile-hero.css";
import { useCallback, useContext, useMemo, useState } from "react";
import { userProfileContext } from "@renderer/context";
import {
BlockedIcon,
CheckCircleFillIcon,
PencilIcon,
PersonAddIcon,
PersonIcon,
SignOutIcon,
XCircleFillIcon,
@ -13,7 +15,12 @@ import {
import { buildGameDetailsPath } from "@renderer/helpers";
import { Button, Link } from "@renderer/components";
import { useTranslation } from "react-i18next";
import { useDate, useToast, useUserDetails } from "@renderer/hooks";
import {
useAppSelector,
useDate,
useToast,
useUserDetails,
} from "@renderer/hooks";
import { addSeconds } from "date-fns";
import { useNavigate } from "react-router-dom";
@ -37,10 +44,11 @@ export function ProfileHero() {
blockUser,
} = useUserDetails();
const { gameRunning } = useAppSelector((state) => state.gameRunning);
const { isMe, heroBackground, getUserProfile } = context;
const userProfile = context.userProfile!;
const { currentGame } = userProfile;
const { t } = useTranslation("user_profile");
const { formatDistance } = useDate();
@ -63,17 +71,17 @@ export function ProfileHero() {
}, [navigate, signOut, showSuccessToast, t]);
const handleFriendAction = useCallback(
(userId: string, action: FriendAction) => {
async (userId: string, action: FriendAction) => {
setIsPerformingAction(true);
try {
if (action === "UNDO_FRIENDSHIP") {
undoFriendship(userId).then(getUserProfile);
await undoFriendship(userId).then(getUserProfile);
return;
}
if (action === "BLOCK") {
blockUser(userId).then(() => {
await blockUser(userId).then(() => {
showSuccessToast(t("user_blocked_successfully"));
navigate(-1);
});
@ -82,11 +90,11 @@ export function ProfileHero() {
}
if (action === "SEND") {
sendFriendRequest(userProfile.id).then(getUserProfile);
await sendFriendRequest(userProfile.id).then(getUserProfile);
return;
}
updateFriendRequestState(userId, action).then(getUserProfile);
await updateFriendRequestState(userId, action).then(getUserProfile);
} catch (err) {
showErrorToast(t("try_again"));
} finally {
@ -140,6 +148,7 @@ export function ProfileHero() {
onClick={() => handleFriendAction(userProfile.id, "SEND")}
disabled={isPerformingAction}
>
<PersonAddIcon />
{t("add_friend")}
</Button>
@ -148,6 +157,7 @@ export function ProfileHero() {
onClick={() => handleFriendAction(userProfile.id, "BLOCK")}
disabled={isPerformingAction}
>
<BlockedIcon />
{t("block_user")}
</Button>
</>
@ -218,6 +228,20 @@ export function ProfileHero() {
}
}, [isMe]);
const currentGame = useMemo(() => {
if (isMe) {
if (gameRunning)
return {
...gameRunning,
objectId: gameRunning.objectID,
sessionDurationInSeconds: gameRunning.sessionDurationInMillis / 1000,
};
return null;
}
return userProfile.currentGame;
}, [isMe, userProfile, gameRunning]);
return (
<>
{/* <ConfirmationModal
@ -289,8 +313,14 @@ export function ProfileHero() {
</div>
<div className={styles.heroPanel}>
<div></div>
<div style={{ display: "flex", gap: `${SPACING_UNIT}px` }}>
<div
style={{
display: "flex",
gap: `${SPACING_UNIT}px`,
justifyContent: "flex-end",
flex: 1,
}}
>
{profileActions}
</div>
</div>

View file

@ -12,17 +12,25 @@ import {
SettingsContextProvider,
} from "@renderer/context";
import { SettingsPrivacy } from "./settings-privacy";
import { useUserDetails } from "@renderer/hooks";
import { useMemo } from "react";
export function Settings() {
const { t } = useTranslation("settings");
const categories = [
t("general"),
t("behavior"),
t("download_sources"),
"Real-Debrid",
t("privacy"),
];
const { userDetails } = useUserDetails();
const categories = useMemo(() => {
const categories = [
t("general"),
t("behavior"),
t("download_sources"),
"Real-Debrid",
];
if (userDetails) return [...categories, t("privacy")];
return categories;
}, [userDetails, t]);
return (
<SettingsContextProvider>