Files
hydra/src/renderer/src/pages/profile/profile-content/profile-content.tsx
2024-09-13 23:56:27 +01:00

233 lines
6.8 KiB
TypeScript

import { userProfileContext } from "@renderer/context";
import { useCallback, useContext, useEffect, useMemo } from "react";
import { ProfileHero } from "../profile-hero/profile-hero";
import { useAppDispatch, useFormat } from "@renderer/hooks";
import { setHeaderTitle } from "@renderer/features";
import { steamUrlBuilder } from "@shared";
import { SPACING_UNIT } from "@renderer/theme.css";
import * as styles from "./profile-content.css";
import { ClockIcon } from "@primer/octicons-react";
import { Link } from "@renderer/components";
import { useTranslation } from "react-i18next";
import { UserGame } from "@types";
import { MAX_MINUTES_TO_SHOW_IN_PLAYTIME } from "@renderer/constants";
import { buildGameDetailsPath } from "@renderer/helpers";
import { useNavigate } from "react-router-dom";
import { LockedProfile } from "./locked-profile";
export function ProfileContent() {
const { userProfile, isMe } = useContext(userProfileContext);
const dispatch = useAppDispatch();
const { t } = useTranslation("user_profile");
useEffect(() => {
if (userProfile) {
dispatch(setHeaderTitle(userProfile.displayName));
}
}, [userProfile, dispatch]);
const truncatedGamesList = useMemo(() => {
if (!userProfile) return [];
return userProfile?.libraryGames.slice(0, 12);
}, [userProfile]);
const { numberFormatter } = useFormat();
const navigate = useNavigate();
const formatPlayTime = useCallback(
(game: UserGame) => {
const seconds = game?.playTimeInSeconds || 0;
const minutes = seconds / 60;
if (minutes < MAX_MINUTES_TO_SHOW_IN_PLAYTIME) {
return t("amount_minutes", {
amount: minutes.toFixed(0),
});
}
const hours = minutes / 60;
return t("amount_hours", { amount: numberFormatter.format(hours) });
},
[numberFormatter, t]
);
const buildUserGameDetailsPath = (game: UserGame) =>
buildGameDetailsPath({
...game,
objectID: game.objectId,
});
const usersAreFriends = useMemo(() => {
return userProfile?.relation?.status === "ACCEPTED";
}, [userProfile]);
const content = useMemo(() => {
if (!userProfile) return null;
const shouldLockProfile =
userProfile.profileVisibility === "PRIVATE" ||
(userProfile.profileVisibility === "FRIENDS" && !usersAreFriends);
if (!isMe && shouldLockProfile) {
return <LockedProfile />;
}
return (
<section
style={{
display: "flex",
gap: `${SPACING_UNIT * 3}px`,
padding: `${SPACING_UNIT * 3}px`,
}}
>
<div style={{ flex: 1 }}>
<div className={styles.sectionHeader}>
<h2>{t("library")}</h2>
<h3>{numberFormatter.format(userProfile.libraryGames.length)}</h3>
</div>
<ul className={styles.gamesGrid}>
{truncatedGamesList.map((game) => (
<li
key={game.objectId}
style={{
borderRadius: 4,
overflow: "hidden",
position: "relative",
}}
className={styles.game}
>
<button
type="button"
style={{
cursor: "pointer",
}}
className={styles.gameCover}
onClick={() => navigate(buildUserGameDetailsPath(game))}
>
<img
src={steamUrlBuilder.cover(game.objectId)}
alt={game.title}
style={{
width: "100%",
objectFit: "cover",
borderRadius: 4,
}}
/>
</button>
</li>
))}
</ul>
</div>
<div className={styles.rightContent}>
<div>
<div className={styles.sectionHeader}>
<h2>Played recently</h2>
</div>
<div className={styles.box}>
<ul className={styles.list}>
{userProfile?.recentGames.map((game) => (
<li key={`${game.shop}-${game.objectId}`}>
<Link
to={buildUserGameDetailsPath(game)}
className={styles.listItem}
>
<img
src={game.iconUrl!}
alt={game.title}
style={{
width: "30px",
height: "30px",
borderRadius: "4px",
}}
/>
<div
style={{
display: "flex",
flexDirection: "column",
gap: `${SPACING_UNIT / 2}px`,
}}
>
<span style={{ fontWeight: "bold" }}>{game.title}</span>
<div
style={{
display: "flex",
alignItems: "center",
gap: `${SPACING_UNIT}px`,
}}
>
<ClockIcon />
<small>{formatPlayTime(game)}</small>
</div>
</div>
</Link>
</li>
))}
</ul>
</div>
</div>
<div>
<div className={styles.sectionHeader}>
<h2>{t("friends")}</h2>
<span>{userProfile?.totalFriends}</span>
</div>
<div className={styles.box}>
<ul className={styles.list}>
{userProfile?.friends.map((friend) => (
<li key={friend.id}>
<Link
to={`/profile/${friend.id}`}
className={styles.listItem}
>
<img
src={friend.profileImageUrl!}
alt={friend.displayName}
style={{
width: "30px",
height: "30px",
borderRadius: "4px",
}}
/>
<span className={styles.friendName}>
{friend.displayName}
</span>
</Link>
</li>
))}
</ul>
</div>
</div>
</div>
</section>
);
}, [
userProfile,
formatPlayTime,
numberFormatter,
t,
truncatedGamesList,
usersAreFriends,
isMe,
navigate,
]);
return (
<div>
<ProfileHero />
{content}
</div>
);
}