feat: pending requests on modal

This commit is contained in:
Zamitto 2024-07-09 16:14:47 -03:00
parent 6ccbff0160
commit 6cc8e8f5fe
5 changed files with 244 additions and 55 deletions

View file

@ -1,11 +1,11 @@
import { Button, Modal, TextField } from "@renderer/components"; import { Button, Modal, TextField } from "@renderer/components";
import { PendingFriendRequest } from "@types"; import { PendingFriendRequest } from "@types";
import * as styles from "./user.css";
import { SPACING_UNIT } from "@renderer/theme.css"; import { SPACING_UNIT } from "@renderer/theme.css";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useToast, useUserDetails } from "@renderer/hooks"; import { useToast, useUserDetails } from "@renderer/hooks";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { UserFriendPendingRequest } from "./user-friend-pending-request";
export interface UserAddFriendsModalProps { export interface UserAddFriendsModalProps {
visible: boolean; visible: boolean;
@ -26,14 +26,11 @@ export const UserAddFriendsModal = ({
const navigate = useNavigate(); const navigate = useNavigate();
const { sendFriendRequest } = useUserDetails(); const { userDetails, sendFriendRequest } = useUserDetails();
const { showSuccessToast, showErrorToast } = useToast(); const { showSuccessToast, showErrorToast } = useToast();
const handleAddFriend: React.FormEventHandler<HTMLFormElement> = async ( const handleClickAddFriend = () => {
event
) => {
event.preventDefault();
setIsAddingFriend(true); setIsAddingFriend(true);
sendFriendRequest(friendCode) sendFriendRequest(friendCode)
.then(() => { .then(() => {
@ -47,12 +44,46 @@ export const UserAddFriendsModal = ({
}); });
}; };
useEffect(() => { const handleClickFriend = (userId: string) => {
setPendingRequests([]); navigate(userId);
}); };
const handleSeeProfileClick = () => { useEffect(() => {
navigate(`profile/${friendCode}`); setPendingRequests([
{
AId: "abcd1234",
ADisplayName: "Punheta Master 123",
AProfileImageUrl:
"https://cdn.discordapp.com/avatars/1239959140785455295/4aff4b901c7a9f5f814b4379b6cfd58a.webp",
BId: "BMmNRmP3",
BDisplayName: "Hydra",
BProfileImageUrl: null,
},
{
AId: "BMmNRmP3",
ADisplayName: "Hydra",
AProfileImageUrl: null,
BId: "12345678",
BDisplayName: "Deyvis0n",
BProfileImageUrl: null,
},
]);
}, []);
const handleClickSeeProfile = () => {
// navigate(`profile/${friendCode}`);
};
const handleClickCancelFriendRequest = (userId: string) => {
console.log(userId);
};
const handleClickAcceptFriendRequest = (userId: string) => {
console.log(userId);
};
const handleClickRefuseFriendRequest = (userId: string) => {
console.log(userId);
}; };
const resetModal = () => { const resetModal = () => {
@ -71,51 +102,89 @@ export const UserAddFriendsModal = ({
title={t("add_friends")} title={t("add_friends")}
onClose={cleanFormAndClose} onClose={cleanFormAndClose}
> >
<form <div
onSubmit={handleAddFriend}
style={{ style={{
display: "flex", display: "flex",
width: "500px",
flexDirection: "column", flexDirection: "column",
justifyContent: "center", gap: `${SPACING_UNIT * 2}px`,
alignItems: "center",
gap: `${SPACING_UNIT * 3}px`,
width: "350px",
}} }}
> >
<TextField <div
label={t("friend_code")} style={{
value={friendCode} display: "flex",
required flexDirection: "row",
minLength={8} justifyContent: "center",
maxLength={8} alignItems: "center",
containerProps={{ style: { width: "100%" } }} gap: `${SPACING_UNIT}px`,
onChange={(e) => setFriendCode(e.target.value)} }}
/>
<Button
disabled={isAddingFriend}
style={{ alignSelf: "end" }}
type="submit"
> >
{isAddingFriend ? t("sending") : t("send")} <TextField
</Button> label={t("friend_code")}
<Button value={friendCode}
onClick={handleSeeProfileClick} minLength={8}
disabled={isAddingFriend} maxLength={8}
style={{ alignSelf: "end" }} containerProps={{ style: { width: "100%" } }}
type="button" onChange={(e) => setFriendCode(e.target.value)}
> />
{t("see_profile")} <Button
</Button> disabled={isAddingFriend}
</form> style={{ alignSelf: "end" }}
type="button"
onClick={handleClickAddFriend}
>
{isAddingFriend ? t("sending") : t("send")}
</Button>
<Button
onClick={handleClickSeeProfile}
disabled={isAddingFriend}
style={{ alignSelf: "end" }}
type="button"
>
{t("see_profile")}
</Button>
</div>
<div> <div
{pendingRequests.map((request) => { style={{
return ( display: "flex",
<p> flexDirection: "column",
{request.AId} - {request.BId} gap: `${SPACING_UNIT * 2}px`,
</p> }}
); >
})} <h3>Pendentes</h3>
{pendingRequests.map((request) => {
if (request.AId === userDetails?.id) {
return (
<UserFriendPendingRequest
key={request.AId}
displayName={request.BDisplayName}
isRequestSent={true}
profileImageUrl={request.BProfileImageUrl}
userId={request.BId}
onClickAcceptRequest={handleClickAcceptFriendRequest}
onClickCancelRequest={handleClickCancelFriendRequest}
onClickRefuseRequest={handleClickRefuseFriendRequest}
onClickRequest={handleClickFriend}
/>
);
}
return (
<UserFriendPendingRequest
key={request.BId}
displayName={request.ADisplayName}
isRequestSent={false}
profileImageUrl={request.AProfileImageUrl}
userId={request.AId}
onClickAcceptRequest={handleClickAcceptFriendRequest}
onClickCancelRequest={handleClickCancelFriendRequest}
onClickRefuseRequest={handleClickRefuseFriendRequest}
onClickRequest={handleClickFriend}
/>
);
})}
</div>
</div> </div>
</Modal> </Modal>
</> </>

View file

@ -17,7 +17,6 @@ import { buildGameDetailsPath, steamUrlBuilder } from "@renderer/helpers";
import { import {
PersonAddIcon, PersonAddIcon,
PersonIcon, PersonIcon,
PlusCircleIcon,
TelescopeIcon, TelescopeIcon,
} from "@primer/octicons-react"; } from "@primer/octicons-react";
import { Button, Link } from "@renderer/components"; import { Button, Link } from "@renderer/components";
@ -79,6 +78,10 @@ export function UserContent({
setShowEditProfileModal(true); setShowEditProfileModal(true);
}; };
const handleOnClickFriend = (userId: string) => {
console.log(userId);
};
const handleConfirmSignout = async () => { const handleConfirmSignout = async () => {
await signOut(); await signOut();
@ -359,6 +362,7 @@ export function UserContent({
> >
<button <button
className={cn(styles.friendListItem, styles.profileContentBox)} className={cn(styles.friendListItem, styles.profileContentBox)}
onClick={() => handleOnClickFriend("123abcde")}
> >
<img <img
className={styles.friendProfileIcon} className={styles.friendProfileIcon}
@ -373,11 +377,15 @@ export function UserContent({
<button <button
className={cn(styles.friendListItem, styles.profileContentBox)} className={cn(styles.friendListItem, styles.profileContentBox)}
> >
<img {userProfile.profileImageUrl ? (
className={styles.friendProfileIcon} <img
src={userProfile.profileImageUrl || ""} className={styles.friendProfileIcon}
alt={"Hydra Launcher"} alt={userProfile.displayName}
/> src={userProfile.profileImageUrl}
/>
) : (
<PersonIcon size={48} />
)}
<h4>Hydra Launcher</h4> <h4>Hydra Launcher</h4>
</button> </button>
</div> </div>

View file

@ -0,0 +1,81 @@
import { CheckCircleIcon, XCircleIcon } from "@primer/octicons-react";
import { SPACING_UNIT, vars } from "@renderer/theme.css";
import * as styles from "./user.css";
import cn from "classnames";
export interface UserFriendPendingRequestProps {
userId: string;
profileImageUrl: string | null;
displayName: string;
isRequestSent: boolean;
onClickCancelRequest: (userId: string) => void;
onClickAcceptRequest: (userId: string) => void;
onClickRefuseRequest: (userId: string) => void;
onClickRequest: (userId: string) => void;
}
export const UserFriendPendingRequest = ({
userId,
profileImageUrl,
displayName,
isRequestSent,
onClickCancelRequest,
onClickAcceptRequest,
onClickRefuseRequest,
onClickRequest,
}: UserFriendPendingRequestProps) => {
return (
<button
type="button"
className={cn(styles.friendListItem, styles.profileContentBox)}
onClick={() => onClickRequest(userId)}
style={{
display: "flex",
flexDirection: "row",
gap: `${SPACING_UNIT}px`,
alignItems: "center",
}}
>
<img
style={{ width: "32px", borderRadius: "50%" }}
src={profileImageUrl || ""}
/>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
flex: "1",
minWidth: 0,
gap: `${SPACING_UNIT / 2}px`,
}}
>
<h4>{displayName}</h4>
<small>{isRequestSent ? "Pedido enviado" : "Pedido recebido"}</small>
</div>
{isRequestSent ? (
<button
style={{ color: vars.color.body }}
onClick={() => onClickCancelRequest(userId)}
>
<XCircleIcon size={28} className={styles.cancelRequestButton} />
</button>
) : (
<>
<button
className={styles.acceptRequestButton}
onClick={() => onClickAcceptRequest(userId)}
>
<CheckCircleIcon size={28} />
</button>
<button
className={styles.cancelRequestButton}
onClick={() => onClickRefuseRequest(userId)}
>
<XCircleIcon size={28} />
</button>
</>
)}
</button>
);
};

View file

@ -245,3 +245,30 @@ export const profileBackground = style({
top: "0", top: "0",
borderRadius: "4px", borderRadius: "4px",
}); });
export const friendRequestItem = style({
color: vars.color.body,
":hover": {
backgroundColor: "rgba(255, 255, 255, 0.15)",
},
});
export const acceptRequestButton = style({
cursor: "pointer",
color: vars.color.body,
width: "28px",
height: "28px",
":hover": {
color: vars.color.success,
},
});
export const cancelRequestButton = style({
cursor: "pointer",
color: vars.color.body,
width: "28px",
height: "28px",
":hover": {
color: vars.color.danger,
},
});

View file

@ -277,7 +277,11 @@ export interface UserFriend {
export interface PendingFriendRequest { export interface PendingFriendRequest {
AId: string; AId: string;
ADisplayName: string;
AProfileImageUrl: string | null;
BId: string; BId: string;
BDisplayName: string;
BProfileImageUrl: string | null;
} }
export interface UserProfile { export interface UserProfile {