reloading user profile on update

This commit is contained in:
Zamitto 2024-06-18 13:50:31 -03:00
parent 9c37711bbf
commit eea19d43c2
6 changed files with 78 additions and 21 deletions

View File

@ -3,8 +3,12 @@ import { HydraApi } from "@main/services/hydra-api";
import axios from "axios"; import axios from "axios";
import fs from "node:fs"; import fs from "node:fs";
import mime from "mime"; import mime from "mime";
import { UserProfile } from "@types";
const patchUserProfile = (displayName: string, profileImageUrl?: string) => { const patchUserProfile = async (
displayName: string,
profileImageUrl?: string
) => {
if (profileImageUrl) { if (profileImageUrl) {
return HydraApi.patch("/profile", { return HydraApi.patch("/profile", {
displayName, displayName,
@ -21,10 +25,9 @@ const updateProfile = async (
_event: Electron.IpcMainInvokeEvent, _event: Electron.IpcMainInvokeEvent,
displayName: string, displayName: string,
newProfileImagePath: string | null newProfileImagePath: string | null
): Promise<any> => { ): Promise<UserProfile | null> => {
if (!newProfileImagePath) { if (!newProfileImagePath) {
patchUserProfile(displayName); return (await patchUserProfile(displayName)).data;
return;
} }
const stats = fs.statSync(newProfileImagePath); const stats = fs.statSync(newProfileImagePath);
@ -51,8 +54,7 @@ const updateProfile = async (
return undefined; return undefined;
}); });
console.log(profileImageUrl); return (await patchUserProfile(displayName, profileImageUrl)).data;
patchUserProfile(displayName, profileImageUrl);
}; };
registerEvent("updateProfile", updateProfile); registerEvent("updateProfile", updateProfile);

View File

@ -125,7 +125,7 @@ declare global {
updateProfile: ( updateProfile: (
displayName: string, displayName: string,
newProfileImagePath: string | null newProfileImagePath: string | null
) => Promise<void>; ) => Promise<UserProfile | null>;
} }
interface Window { interface Window {

View File

@ -47,11 +47,38 @@ export function useUserDetails() {
}); });
}, [dispatch]); }, [dispatch]);
const patchUser = useCallback(
async (displayName: string, imageProfileUrl: string | null) => {
return window.electron
.updateProfile(displayName, imageProfileUrl)
.then(async (userDetails) => {
if (userDetails) {
dispatch(setUserDetails(userDetails));
if (userDetails.profileImageUrl) {
const output = await average(userDetails.profileImageUrl, {
amount: 1,
format: "hex",
});
dispatch(
setProfileBackground(
`linear-gradient(135deg, ${darkenColor(output as string, 0.6)}, ${darkenColor(output as string, 0.7)})`
)
);
}
}
});
},
[dispatch]
);
return { return {
userDetails, userDetails,
updateUser, updateUser,
signOut, signOut,
clearUser, clearUser,
patchUser,
profileBackground, profileBackground,
}; };
} }

View File

@ -26,8 +26,7 @@ export function UserContent({
}: ProfileContentProps) { }: ProfileContentProps) {
const { t, i18n } = useTranslation("user_profile"); const { t, i18n } = useTranslation("user_profile");
const { userDetails, profileBackground, signOut, updateUser } = const { userDetails, profileBackground, signOut } = useUserDetails();
useUserDetails();
const [showEditProfileModal, setShowEditProfileModal] = useState(false); const [showEditProfileModal, setShowEditProfileModal] = useState(false);
@ -72,7 +71,6 @@ export function UserContent({
}; };
const handleUpdateUserProfile = async () => { const handleUpdateUserProfile = async () => {
updateUser();
updateUserProfile(); updateUserProfile();
}; };

View File

@ -1,10 +1,10 @@
import { Button, Modal, TextField } from "@renderer/components"; import { Button, Modal, TextField } from "@renderer/components";
import { UserProfile } from "@types"; import { UserProfile } from "@types";
import * as styles from "./user.css"; import * as styles from "./user.css";
import { PersonIcon } from "@primer/octicons-react"; import { PencilIcon, PersonIcon } from "@primer/octicons-react";
import { SPACING_UNIT } from "@renderer/theme.css"; import { SPACING_UNIT } from "@renderer/theme.css";
import { useState } from "react"; import { useState } from "react";
import { useToast } from "@renderer/hooks"; import { useToast, useUserDetails } from "@renderer/hooks";
export interface UserEditProfileModalProps { export interface UserEditProfileModalProps {
userProfile: UserProfile; userProfile: UserProfile;
@ -22,6 +22,9 @@ export const UserEditProfileModal = ({
const [displayName, setDisplayName] = useState(userProfile.displayName); const [displayName, setDisplayName] = useState(userProfile.displayName);
const [newImagePath, setNewImagePath] = useState<string | null>(null); const [newImagePath, setNewImagePath] = useState<string | null>(null);
const [newImageBase64, setNewImageBase64] = useState<string | null>(null); const [newImageBase64, setNewImageBase64] = useState<string | null>(null);
const [isSaving, setIsSaving] = useState(false);
const { patchUser } = useUserDetails();
const { showSuccessToast, showErrorToast } = useToast(); const { showSuccessToast, showErrorToast } = useToast();
@ -48,16 +51,19 @@ export const UserEditProfileModal = ({
}; };
const handleSaveProfile = async () => { const handleSaveProfile = async () => {
window.electron setIsSaving(true);
.updateProfile(displayName, newImagePath) patchUser(displayName, newImagePath)
.then(() => { .then(() => {
updateUser(); updateUser();
setNewImagePath(null); setNewImagePath(null);
showSuccessToast("Sucesso"); showSuccessToast("Salvo com sucesso");
onClose(); onClose();
}) })
.catch(() => { .catch(() => {
showErrorToast("Erro"); showErrorToast("Tente novamente");
})
.finally(() => {
setIsSaving(false);
}); });
}; };
return ( return (
@ -71,7 +77,7 @@ export const UserEditProfileModal = ({
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
gap: `${SPACING_UNIT * 3}px`, gap: `${SPACING_UNIT * 3}px`,
width: "300px", width: "350px",
}} }}
> >
<button <button
@ -87,6 +93,9 @@ export const UserEditProfileModal = ({
) : ( ) : (
<PersonIcon size={72} /> <PersonIcon size={72} />
)} )}
<div className={styles.editProfileImageBadge}>
<PencilIcon size={16} />
</div>
</button> </button>
<TextField <TextField
@ -95,8 +104,12 @@ export const UserEditProfileModal = ({
containerProps={{ style: { width: "100%" } }} containerProps={{ style: { width: "100%" } }}
onChange={(e) => setDisplayName(e.target.value)} onChange={(e) => setDisplayName(e.target.value)}
/> />
<Button style={{ alignSelf: "end" }} onClick={handleSaveProfile}> <Button
Salvar{" "} disabled={isSaving}
style={{ alignSelf: "end" }}
onClick={handleSaveProfile}
>
{isSaving ? "Salvando..." : "Salvar"}
</Button> </Button>
</section> </section>
</Modal> </Modal>

View File

@ -38,19 +38,22 @@ export const profileAvatarContainer = style({
export const profileAvatarEditContainer = style({ export const profileAvatarEditContainer = style({
width: "128px", width: "128px",
height: "128px", height: "128px",
borderRadius: "50%",
display: "flex", display: "flex",
borderRadius: "50%",
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
backgroundColor: vars.color.background, backgroundColor: vars.color.background,
position: "relative", position: "relative",
overflow: "hidden",
border: `solid 1px ${vars.color.border}`, border: `solid 1px ${vars.color.border}`,
boxShadow: "0px 0px 5px 0px rgba(0, 0, 0, 0.7)", boxShadow: "0px 0px 5px 0px rgba(0, 0, 0, 0.7)",
cursor: "pointer",
}); });
export const profileAvatar = style({ export const profileAvatar = style({
height: "100%", height: "100%",
aspectRatio: 1,
borderRadius: "50%",
overflow: "hidden",
objectFit: "cover", objectFit: "cover",
}); });
@ -158,3 +161,17 @@ export const gameInformation = style({
export const profileHeaderSkeleton = style({ export const profileHeaderSkeleton = style({
height: "200px", height: "200px",
}); });
export const editProfileImageBadge = style({
width: "28px",
height: "28px",
borderRadius: "50%",
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: vars.color.muted,
position: "absolute",
bottom: "0px",
right: "0px",
zIndex: "1",
});