From 6ccbff01602fc9fef768ebbb4156292ecdbc6566 Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Mon, 8 Jul 2024 22:07:14 -0300 Subject: [PATCH] feat: creating friends section --- src/locales/en/translation.json | 9 +- src/locales/pt/translation.json | 7 +- src/main/services/hydra-api.ts | 4 +- src/renderer/index.html | 2 +- src/renderer/src/hooks/use-user-details.ts | 5 + .../src/pages/user/user-add-friends-modal.tsx | 123 ++++++++++++++ src/renderer/src/pages/user/user-content.tsx | 160 +++++++++++++----- src/renderer/src/pages/user/user.css.ts | 32 +++- src/types/index.ts | 17 +- 9 files changed, 307 insertions(+), 52 deletions(-) create mode 100644 src/renderer/src/pages/user/user-add-friends-modal.tsx diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index e44dc7ea..2dadbcee 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -241,6 +241,13 @@ "successfully_signed_out": "Successfully signed out", "sign_out": "Sign out", "playing_for": "Playing for {{amount}}", - "sign_out_modal_text": "Your library is linked with your current account. When signing out, your library will not be visible anymore, and any progress will not be saved. Continue with sign out?" + "sign_out_modal_text": "Your library is linked with your current account. When signing out, your library will not be visible anymore, and any progress will not be saved. Continue with sign out?", + "add_friends": "Add Friends", + "friend_code": "Friend code", + "see_profile": "See profile", + "sending": "Sending", + "send": "Add friend", + "friend_request_sent": "Friend request sent", + "friends": "Friends" } } diff --git a/src/locales/pt/translation.json b/src/locales/pt/translation.json index 02c0879f..9ff165f9 100644 --- a/src/locales/pt/translation.json +++ b/src/locales/pt/translation.json @@ -241,6 +241,11 @@ "sign_out": "Sair da conta", "sign_out_modal_title": "Tem certeza?", "playing_for": "Jogando por {{amount}}", - "sign_out_modal_text": "Sua biblioteca de jogos está associada com a sua conta atual. Ao sair, sua biblioteca não aparecerá mais no Hydra e qualquer progresso não será salvo. Deseja continuar?" + "sign_out_modal_text": "Sua biblioteca de jogos está associada com a sua conta atual. Ao sair, sua biblioteca não aparecerá mais no Hydra e qualquer progresso não será salvo. Deseja continuar?", + "add_friends": "Adicionar Amigos", + "friend_code": "Código de amigo", + "see_profile": "Ver perfil", + "friend_request_sent": "Pedido de amizade enviado", + "friends": "Amigos" } } diff --git a/src/main/services/hydra-api.ts b/src/main/services/hydra-api.ts index 98b783f3..1abae98c 100644 --- a/src/main/services/hydra-api.ts +++ b/src/main/services/hydra-api.ts @@ -98,9 +98,9 @@ export class HydraApi { logger.error(config.method, config.baseURL, config.url, config.headers); if (error.response) { - logger.error(error.response.status, error.response.data); + logger.error("Response", error.response.status, error.response.data); } else if (error.request) { - logger.error(error.request); + logger.error("Request", error.request); } else { logger.error("Error", error.message); } diff --git a/src/renderer/index.html b/src/renderer/index.html index 543b85a9..52276268 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -6,7 +6,7 @@ Hydra diff --git a/src/renderer/src/hooks/use-user-details.ts b/src/renderer/src/hooks/use-user-details.ts index e87f8ff6..6495ba27 100644 --- a/src/renderer/src/hooks/use-user-details.ts +++ b/src/renderer/src/hooks/use-user-details.ts @@ -78,6 +78,10 @@ export function useUserDetails() { [updateUserDetails] ); + const sendFriendRequest = useCallback(async (userId: string) => { + console.log("sending friend request to", userId); + }, []); + return { userDetails, fetchUserDetails, @@ -85,6 +89,7 @@ export function useUserDetails() { clearUserDetails, updateUserDetails, patchUser, + sendFriendRequest, profileBackground, }; } diff --git a/src/renderer/src/pages/user/user-add-friends-modal.tsx b/src/renderer/src/pages/user/user-add-friends-modal.tsx new file mode 100644 index 00000000..a872abcf --- /dev/null +++ b/src/renderer/src/pages/user/user-add-friends-modal.tsx @@ -0,0 +1,123 @@ +import { Button, Modal, TextField } from "@renderer/components"; +import { PendingFriendRequest } from "@types"; +import * as styles from "./user.css"; +import { SPACING_UNIT } from "@renderer/theme.css"; +import { useEffect, useState } from "react"; +import { useToast, useUserDetails } from "@renderer/hooks"; +import { useTranslation } from "react-i18next"; +import { useNavigate } from "react-router-dom"; + +export interface UserAddFriendsModalProps { + visible: boolean; + onClose: () => void; +} + +export const UserAddFriendsModal = ({ + visible, + onClose, +}: UserAddFriendsModalProps) => { + const { t } = useTranslation("user_profile"); + + const [friendCode, setFriendCode] = useState(""); + const [isAddingFriend, setIsAddingFriend] = useState(false); + const [pendingRequests, setPendingRequests] = useState< + PendingFriendRequest[] + >([]); + + const navigate = useNavigate(); + + const { sendFriendRequest } = useUserDetails(); + + const { showSuccessToast, showErrorToast } = useToast(); + + const handleAddFriend: React.FormEventHandler = async ( + event + ) => { + event.preventDefault(); + setIsAddingFriend(true); + sendFriendRequest(friendCode) + .then(() => { + showSuccessToast(t("friend_request_sent")); + }) + .catch(() => { + showErrorToast("falhaaaa"); + }) + .finally(() => { + setIsAddingFriend(false); + }); + }; + + useEffect(() => { + setPendingRequests([]); + }); + + const handleSeeProfileClick = () => { + navigate(`profile/${friendCode}`); + }; + + const resetModal = () => { + setFriendCode(""); + }; + + const cleanFormAndClose = () => { + resetModal(); + onClose(); + }; + + return ( + <> + +
+ setFriendCode(e.target.value)} + /> + + + + +
+ {pendingRequests.map((request) => { + return ( +

+ {request.AId} - {request.BId} +

+ ); + })} +
+
+ + ); +}; diff --git a/src/renderer/src/pages/user/user-content.tsx b/src/renderer/src/pages/user/user-content.tsx index 6f897238..8e973e7f 100644 --- a/src/renderer/src/pages/user/user-content.tsx +++ b/src/renderer/src/pages/user/user-content.tsx @@ -14,10 +14,16 @@ import { } from "@renderer/hooks"; import { useNavigate } from "react-router-dom"; import { buildGameDetailsPath, steamUrlBuilder } from "@renderer/helpers"; -import { PersonIcon, TelescopeIcon } from "@primer/octicons-react"; +import { + PersonAddIcon, + PersonIcon, + PlusCircleIcon, + TelescopeIcon, +} from "@primer/octicons-react"; import { Button, Link } from "@renderer/components"; import { UserEditProfileModal } from "./user-edit-modal"; import { UserSignOutModal } from "./user-signout-modal"; +import { UserAddFriendsModal } from "./user-add-friends-modal"; const MAX_MINUTES_TO_SHOW_IN_PLAYTIME = 120; @@ -37,6 +43,7 @@ export function UserContent({ const [showEditProfileModal, setShowEditProfileModal] = useState(false); const [showSignOutModal, setShowSignOutModal] = useState(false); + const [showAddFriendsModal, setShowAddFriendsModal] = useState(false); const { gameRunning } = useAppSelector((state) => state.gameRunning); @@ -103,6 +110,11 @@ export function UserContent({ onConfirm={handleConfirmSignout} /> + setShowAddFriendsModal(false)} + /> +

{t("activity")}

- {!userProfile.recentGames.length ? ( + {!userProfile.recentGames?.length ? (
@@ -259,54 +271,116 @@ export function UserContent({ )}
-
-
-

{t("library")}

+
+
+
+

{t("library")}

+ +
+

+ {userProfile.libraryGames?.length} +

+
+ {t("total_play_time", { amount: formatPlayTime() })} +
+ {userProfile.libraryGames?.map((game) => ( + + ))} +
+
+ +
+
+

{t("friends")}

+ +
+ +
-

- {userProfile.libraryGames.length} -

-
- {t("total_play_time", { amount: formatPlayTime() })} -
- {userProfile.libraryGames.map((game) => ( + > - ))} + + +
diff --git a/src/renderer/src/pages/user/user.css.ts b/src/renderer/src/pages/user/user.css.ts index 299aa393..0128ec90 100644 --- a/src/renderer/src/pages/user/user.css.ts +++ b/src/renderer/src/pages/user/user.css.ts @@ -86,7 +86,13 @@ export const profileContent = style({ export const profileGameSection = style({ width: "100%", - height: "100%", + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT * 2}px`, +}); + +export const friendsSection = style({ + width: "100%", display: "flex", flexDirection: "column", gap: `${SPACING_UNIT * 2}px`, @@ -94,6 +100,9 @@ export const profileGameSection = style({ export const contentSidebar = style({ width: "100%", + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT * 3}px`, "@media": { "(min-width: 768px)": { width: "100%", @@ -116,12 +125,17 @@ export const libraryGameIcon = style({ borderRadius: "4px", }); +export const friendProfileIcon = style({ + height: "100%", +}); + export const feedItem = style({ color: vars.color.body, display: "flex", flexDirection: "row", gap: `${SPACING_UNIT * 2}px`, width: "100%", + overflow: "hidden", height: "72px", transition: "all ease 0.2s", cursor: "pointer", @@ -143,6 +157,22 @@ export const gameListItem = style({ }, }); +export const friendListItem = style({ + color: vars.color.body, + display: "flex", + flexDirection: "row", + gap: `${SPACING_UNIT}px`, + width: "100%", + height: "48px", + transition: "all ease 0.2s", + cursor: "pointer", + zIndex: "1", + overflow: "hidden", + ":hover": { + backgroundColor: "rgba(255, 255, 255, 0.15)", + }, +}); + export const gameInformation = style({ display: "flex", flexDirection: "column", diff --git a/src/types/index.ts b/src/types/index.ts index 71071620..17925ac0 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -269,14 +269,25 @@ export interface UserDetails { profileImageUrl: string | null; } +export interface UserFriend { + id: string; + displayName: string; + profileImageUrl: string | null; +} + +export interface PendingFriendRequest { + AId: string; + BId: string; +} + export interface UserProfile { id: string; displayName: string; - username: string; profileImageUrl: string | null; totalPlayTimeInSeconds: number; - libraryGames: UserGame[]; - recentGames: UserGame[]; + libraryGames: UserGame[] | null; + recentGames: UserGame[] | null; + friends: UserFriend[] | null; } export interface DownloadSource {