feat: adding modal to edit profile

This commit is contained in:
Zamitto 2024-06-17 21:55:43 -03:00
parent 79ca354da1
commit af69509c61
9 changed files with 219 additions and 7 deletions

View file

@ -121,6 +121,10 @@ declare global {
/* Profile */
getMe: () => Promise<UserProfile | null>;
updateProfile: (
displayName: string,
newProfileImagePath: string | null
) => Promise<void>;
}
interface Window {

View file

@ -3,7 +3,7 @@ import cn from "classnames";
import * as styles from "./user.css";
import { SPACING_UNIT, vars } from "@renderer/theme.css";
import { useMemo } from "react";
import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
import { useDate, useUserDetails } from "@renderer/hooks";
@ -11,6 +11,7 @@ import { useNavigate } from "react-router-dom";
import { buildGameDetailsPath } from "@renderer/helpers";
import { PersonIcon } from "@primer/octicons-react";
import { Button } from "@renderer/components";
import { UserEditProfileModal } from "./user-edit-modal";
const MAX_MINUTES_TO_SHOW_IN_PLAYTIME = 120;
@ -23,6 +24,8 @@ export function UserContent({ userProfile }: ProfileContentProps) {
const { userDetails, profileBackground, signOut } = useUserDetails();
const [showEditProfileModal, setShowEditProfileModal] = useState(false);
const navigate = useNavigate();
const numberFormatter = useMemo(() => {
@ -54,6 +57,10 @@ export function UserContent({ userProfile }: ProfileContentProps) {
navigate(buildGameDetailsPath(game));
};
const handleEditProfile = () => {
setShowEditProfileModal(true);
};
const handleSignout = async () => {
await signOut();
navigate("/");
@ -69,10 +76,17 @@ export function UserContent({ userProfile }: ProfileContentProps) {
return (
<>
<UserEditProfileModal
visible={showEditProfileModal}
onClose={() => setShowEditProfileModal(false)}
userProfile={userProfile}
/>
<section
className={styles.profileContentBox}
style={{
background: profileContentBoxBackground,
padding: `${SPACING_UNIT * 4}px ${SPACING_UNIT * 2}px`,
}}
>
<div className={styles.profileAvatarContainer}>
@ -93,9 +107,23 @@ export function UserContent({ userProfile }: ProfileContentProps) {
{isMe && (
<div style={{ flex: 1, display: "flex", justifyContent: "end" }}>
<Button theme="danger" onClick={handleSignout}>
{t("sign_out")}
</Button>
<div
style={{
display: "flex",
flexDirection: "column",
gap: `${SPACING_UNIT}px`,
}}
>
<>
<Button theme="outline" onClick={handleEditProfile}>
Editar perfil
</Button>
<Button theme="danger" onClick={handleSignout}>
{t("sign_out")}
</Button>
</>
</div>
</div>
)}
</section>

View file

@ -0,0 +1,90 @@
import { Button, Modal, TextField } from "@renderer/components";
import { UserProfile } from "@types";
import * as styles from "./user.css";
import { PersonIcon } from "@primer/octicons-react";
import { SPACING_UNIT } from "@renderer/theme.css";
import { useState } from "react";
export interface UserEditProfileModalProps {
userProfile: UserProfile;
visible: boolean;
onClose: () => void;
}
export const UserEditProfileModal = ({
userProfile,
visible,
onClose,
}: UserEditProfileModalProps) => {
const [displayName, setDisplayName] = useState(userProfile.displayName);
const [newImagePath, setNewImagePath] = useState<string | null>(null);
const handleChangeProfileAvatar = async () => {
const { filePaths } = await window.electron.showOpenDialog({
properties: ["openFile"],
filters: [
{
name: "Profile avatar",
extensions: ["jpg", "png", "gif"],
},
],
});
const path = filePaths[0];
console.log(path);
setNewImagePath(path);
};
const handleSaveProfile = async () => {
await window.electron
.updateProfile(displayName, newImagePath)
.catch((err) => {
console.log("errro", err);
});
setNewImagePath(null);
onClose();
};
return (
<>
<Modal visible={visible} title="Editar Perfil" onClose={onClose}>
<section
style={{
padding: `${SPACING_UNIT * 2}px ${SPACING_UNIT * 2}px`,
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
gap: `${SPACING_UNIT * 3}px`,
width: "300px",
}}
>
<button
className={styles.profileAvatarEditContainer}
onClick={handleChangeProfileAvatar}
>
{userProfile.profileImageUrl ? (
<img
className={styles.profileAvatar}
alt={userProfile.displayName}
src={newImagePath ?? userProfile.profileImageUrl}
/>
) : (
<PersonIcon size={72} />
)}
</button>
<TextField
label="Nome de exibição"
value={displayName}
containerProps={{ style: { width: "100%" } }}
onChange={(e) => setDisplayName(e.target.value)}
/>
<Button style={{ alignSelf: "end" }} onClick={handleSaveProfile}>
Salvar{" "}
</Button>
</section>
</Modal>
</>
);
};

View file

@ -12,7 +12,6 @@ export const wrapper = style({
export const profileContentBox = style({
display: "flex",
gap: `${SPACING_UNIT * 3}px`,
padding: `${SPACING_UNIT * 4}px ${SPACING_UNIT * 2}px`,
alignItems: "center",
borderRadius: "4px",
border: `solid 1px ${vars.color.border}`,
@ -36,12 +35,35 @@ export const profileAvatarContainer = style({
boxShadow: "0px 0px 5px 0px rgba(0, 0, 0, 0.7)",
});
export const profileAvatarEditContainer = style({
width: "128px",
height: "128px",
borderRadius: "50%",
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: vars.color.background,
position: "relative",
overflow: "hidden",
border: `solid 1px ${vars.color.border}`,
boxShadow: "0px 0px 5px 0px rgba(0, 0, 0, 0.7)",
});
export const profileAvatar = style({
width: "96px",
height: "96px",
height: "100%",
objectFit: "cover",
});
export const profileAvatarEditOverlay = style({
position: "absolute",
width: "100%",
height: "100%",
backgroundColor: "#00000055",
color: vars.color.muted,
zIndex: 1,
cursor: "pointer",
});
export const profileInformation = style({
display: "flex",
flexDirection: "column",