mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-15 04:32:13 +00:00
feat: refactor friends requests
This commit is contained in:
parent
b3f87d5662
commit
ef0699dbea
11 changed files with 74 additions and 34 deletions
|
@ -45,6 +45,7 @@ import "./auth/get-session-hash";
|
||||||
import "./user/get-user";
|
import "./user/get-user";
|
||||||
import "./profile/get-friend-requests";
|
import "./profile/get-friend-requests";
|
||||||
import "./profile/get-me";
|
import "./profile/get-me";
|
||||||
|
import "./profile/update-friend-request";
|
||||||
import "./profile/update-profile";
|
import "./profile/update-profile";
|
||||||
|
|
||||||
ipcMain.handle("ping", () => "pong");
|
ipcMain.handle("ping", () => "pong");
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { registerEvent } from "../register-event";
|
import { registerEvent } from "../register-event";
|
||||||
import { HydraApi } from "@main/services";
|
import { HydraApi } from "@main/services";
|
||||||
import { PendingFriendRequest } from "@types";
|
import { FriendRequest } from "@types";
|
||||||
|
|
||||||
const getFriendRequests = async (
|
const getFriendRequests = async (
|
||||||
_event: Electron.IpcMainInvokeEvent
|
_event: Electron.IpcMainInvokeEvent
|
||||||
): Promise<PendingFriendRequest[] | null> => {
|
): Promise<FriendRequest[] | null> => {
|
||||||
try {
|
try {
|
||||||
const response = await HydraApi.get(`/profile/friend-requests`);
|
const response = await HydraApi.get(`/profile/friend-requests`);
|
||||||
return response.data;
|
return response.data;
|
||||||
|
|
19
src/main/events/profile/update-friend-request.ts
Normal file
19
src/main/events/profile/update-friend-request.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { registerEvent } from "../register-event";
|
||||||
|
import { HydraApi } from "@main/services";
|
||||||
|
import { FriendRequestAction } from "@types";
|
||||||
|
|
||||||
|
const updateFriendRequest = async (
|
||||||
|
_event: Electron.IpcMainInvokeEvent,
|
||||||
|
userId: string,
|
||||||
|
action: FriendRequestAction
|
||||||
|
) => {
|
||||||
|
if (action == "CANCEL") {
|
||||||
|
return HydraApi.delete(`/profile/friend-requests/${userId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return HydraApi.patch(`/profile/friend-requests/${userId}`, {
|
||||||
|
requestState: action,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
registerEvent("updateFriendRequest", updateFriendRequest);
|
|
@ -9,6 +9,7 @@ import type {
|
||||||
AppUpdaterEvent,
|
AppUpdaterEvent,
|
||||||
StartGameDownloadPayload,
|
StartGameDownloadPayload,
|
||||||
GameRunning,
|
GameRunning,
|
||||||
|
FriendRequestAction,
|
||||||
} from "@types";
|
} from "@types";
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld("electron", {
|
contextBridge.exposeInMainWorld("electron", {
|
||||||
|
@ -137,6 +138,8 @@ contextBridge.exposeInMainWorld("electron", {
|
||||||
updateProfile: (displayName: string, newProfileImagePath: string | null) =>
|
updateProfile: (displayName: string, newProfileImagePath: string | null) =>
|
||||||
ipcRenderer.invoke("updateProfile", displayName, newProfileImagePath),
|
ipcRenderer.invoke("updateProfile", displayName, newProfileImagePath),
|
||||||
getFriendRequests: () => ipcRenderer.invoke("getFriendRequests"),
|
getFriendRequests: () => ipcRenderer.invoke("getFriendRequests"),
|
||||||
|
updateFriendRequest: (userId: string, action: FriendRequestAction) =>
|
||||||
|
ipcRenderer.invoke("updateFriendRequest", userId, action),
|
||||||
|
|
||||||
/* User */
|
/* User */
|
||||||
getUser: (userId: string) => ipcRenderer.invoke("getUser", userId),
|
getUser: (userId: string) => ipcRenderer.invoke("getUser", userId),
|
||||||
|
|
9
src/renderer/src/declaration.d.ts
vendored
9
src/renderer/src/declaration.d.ts
vendored
|
@ -14,7 +14,8 @@ import type {
|
||||||
RealDebridUser,
|
RealDebridUser,
|
||||||
DownloadSource,
|
DownloadSource,
|
||||||
UserProfile,
|
UserProfile,
|
||||||
PendingFriendRequest,
|
FriendRequest,
|
||||||
|
FriendRequestAction,
|
||||||
} from "@types";
|
} from "@types";
|
||||||
import type { DiskSpace } from "check-disk-space";
|
import type { DiskSpace } from "check-disk-space";
|
||||||
|
|
||||||
|
@ -133,7 +134,11 @@ declare global {
|
||||||
displayName: string,
|
displayName: string,
|
||||||
newProfileImagePath: string | null
|
newProfileImagePath: string | null
|
||||||
) => Promise<UserProfile>;
|
) => Promise<UserProfile>;
|
||||||
getFriendRequests: () => Promise<PendingFriendRequest[] | null>;
|
getFriendRequests: () => Promise<FriendRequest[] | null>;
|
||||||
|
updateFriendRequest: (
|
||||||
|
userId: string,
|
||||||
|
action: FriendRequestAction
|
||||||
|
) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
||||||
import type { UserDetails } from "@types";
|
import type { FriendRequest, UserDetails } from "@types";
|
||||||
|
|
||||||
export interface UserDetailsState {
|
export interface UserDetailsState {
|
||||||
userDetails: UserDetails | null;
|
userDetails: UserDetails | null;
|
||||||
profileBackground: null | string;
|
profileBackground: null | string;
|
||||||
|
friendRequests: FriendRequest[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: UserDetailsState = {
|
const initialState: UserDetailsState = {
|
||||||
userDetails: null,
|
userDetails: null,
|
||||||
profileBackground: null,
|
profileBackground: null,
|
||||||
|
friendRequests: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userDetailsSlice = createSlice({
|
export const userDetailsSlice = createSlice({
|
||||||
|
@ -21,8 +23,14 @@ export const userDetailsSlice = createSlice({
|
||||||
setProfileBackground: (state, action: PayloadAction<string | null>) => {
|
setProfileBackground: (state, action: PayloadAction<string | null>) => {
|
||||||
state.profileBackground = action.payload;
|
state.profileBackground = action.payload;
|
||||||
},
|
},
|
||||||
|
setFriendRequests: (
|
||||||
|
state,
|
||||||
|
action: PayloadAction<FriendRequest[] | null>
|
||||||
|
) => {
|
||||||
|
state.friendRequests = action.payload;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const { setUserDetails, setProfileBackground } =
|
export const { setUserDetails, setProfileBackground, setFriendRequests } =
|
||||||
userDetailsSlice.actions;
|
userDetailsSlice.actions;
|
||||||
|
|
|
@ -2,14 +2,18 @@ import { useCallback } from "react";
|
||||||
import { average } from "color.js";
|
import { average } from "color.js";
|
||||||
|
|
||||||
import { useAppDispatch, useAppSelector } from "./redux";
|
import { useAppDispatch, useAppSelector } from "./redux";
|
||||||
import { setProfileBackground, setUserDetails } from "@renderer/features";
|
import {
|
||||||
|
setProfileBackground,
|
||||||
|
setUserDetails,
|
||||||
|
setFriendRequests,
|
||||||
|
} from "@renderer/features";
|
||||||
import { darkenColor } from "@renderer/helpers";
|
import { darkenColor } from "@renderer/helpers";
|
||||||
import { UserDetails } from "@types";
|
import { UserDetails } from "@types";
|
||||||
|
|
||||||
export function useUserDetails() {
|
export function useUserDetails() {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const { userDetails, profileBackground } = useAppSelector(
|
const { userDetails, profileBackground, friendRequests } = useAppSelector(
|
||||||
(state) => state.userDetails
|
(state) => state.userDetails
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -82,19 +86,21 @@ export function useUserDetails() {
|
||||||
console.log("sending friend request to", userId);
|
console.log("sending friend request to", userId);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchPendingRequests = useCallback(async () => {
|
const updateFriendRequests = useCallback(async () => {
|
||||||
return window.electron.getFriendRequests();
|
const friendRequests = await window.electron.getFriendRequests();
|
||||||
}, []);
|
dispatch(setFriendRequests(friendRequests));
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
userDetails,
|
userDetails,
|
||||||
|
profileBackground,
|
||||||
|
friendRequests,
|
||||||
fetchUserDetails,
|
fetchUserDetails,
|
||||||
signOut,
|
signOut,
|
||||||
clearUserDetails,
|
clearUserDetails,
|
||||||
updateUserDetails,
|
updateUserDetails,
|
||||||
patchUser,
|
patchUser,
|
||||||
sendFriendRequest,
|
sendFriendRequest,
|
||||||
fetchPendingRequests,
|
updateFriendRequests,
|
||||||
profileBackground,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,19 @@
|
||||||
import { Button, Modal, TextField } from "@renderer/components";
|
import { Button, Modal, TextField } from "@renderer/components";
|
||||||
import { PendingFriendRequest } from "@types";
|
|
||||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||||
import { useState } from "react";
|
import { 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";
|
import { UserFriendRequest } from "./user-friend-request";
|
||||||
|
|
||||||
export interface UserAddFriendsModalProps {
|
export interface UserAddFriendsModalProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
pendingRequests: PendingFriendRequest[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UserAddFriendsModal = ({
|
export const UserAddFriendsModal = ({
|
||||||
visible,
|
visible,
|
||||||
onClose,
|
onClose,
|
||||||
pendingRequests,
|
|
||||||
}: UserAddFriendsModalProps) => {
|
}: UserAddFriendsModalProps) => {
|
||||||
const { t } = useTranslation("user_profile");
|
const { t } = useTranslation("user_profile");
|
||||||
|
|
||||||
|
@ -25,7 +22,8 @@ export const UserAddFriendsModal = ({
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { sendFriendRequest } = useUserDetails();
|
const { sendFriendRequest, updateFriendRequests, friendRequests } =
|
||||||
|
useUserDetails();
|
||||||
|
|
||||||
const { showSuccessToast, showErrorToast } = useToast();
|
const { showSuccessToast, showErrorToast } = useToast();
|
||||||
|
|
||||||
|
@ -33,6 +31,7 @@ export const UserAddFriendsModal = ({
|
||||||
setIsAddingFriend(true);
|
setIsAddingFriend(true);
|
||||||
sendFriendRequest(friendCode)
|
sendFriendRequest(friendCode)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
updateFriendRequests();
|
||||||
showSuccessToast(t("friend_request_sent"));
|
showSuccessToast(t("friend_request_sent"));
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
@ -54,14 +53,17 @@ export const UserAddFriendsModal = ({
|
||||||
|
|
||||||
const handleClickCancelFriendRequest = (userId: string) => {
|
const handleClickCancelFriendRequest = (userId: string) => {
|
||||||
console.log(userId);
|
console.log(userId);
|
||||||
|
updateFriendRequests();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClickAcceptFriendRequest = (userId: string) => {
|
const handleClickAcceptFriendRequest = (userId: string) => {
|
||||||
console.log(userId);
|
console.log(userId);
|
||||||
|
updateFriendRequests();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClickRefuseFriendRequest = (userId: string) => {
|
const handleClickRefuseFriendRequest = (userId: string) => {
|
||||||
console.log(userId);
|
console.log(userId);
|
||||||
|
updateFriendRequests();
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetModal = () => {
|
const resetModal = () => {
|
||||||
|
@ -131,9 +133,9 @@ export const UserAddFriendsModal = ({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<h3>Pendentes</h3>
|
<h3>Pendentes</h3>
|
||||||
{pendingRequests.map((request) => {
|
{friendRequests?.map((request) => {
|
||||||
return (
|
return (
|
||||||
<UserFriendPendingRequest
|
<UserFriendRequest
|
||||||
key={request.userId}
|
key={request.userId}
|
||||||
displayName={request.displayName}
|
displayName={request.displayName}
|
||||||
isRequestSent={request.type === "SENT"}
|
isRequestSent={request.type === "SENT"}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PendingFriendRequest, UserGame, UserProfile } from "@types";
|
import { UserGame, UserProfile } from "@types";
|
||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
import * as styles from "./user.css";
|
import * as styles from "./user.css";
|
||||||
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
||||||
|
@ -36,7 +36,8 @@ export function UserContent({
|
||||||
}: ProfileContentProps) {
|
}: ProfileContentProps) {
|
||||||
const { t, i18n } = useTranslation("user_profile");
|
const { t, i18n } = useTranslation("user_profile");
|
||||||
|
|
||||||
const { userDetails, profileBackground, signOut } = useUserDetails();
|
const { userDetails, profileBackground, signOut, updateFriendRequests } =
|
||||||
|
useUserDetails();
|
||||||
const { showSuccessToast } = useToast();
|
const { showSuccessToast } = useToast();
|
||||||
|
|
||||||
const [showEditProfileModal, setShowEditProfileModal] = useState(false);
|
const [showEditProfileModal, setShowEditProfileModal] = useState(false);
|
||||||
|
@ -89,16 +90,10 @@ export function UserContent({
|
||||||
navigate("/");
|
navigate("/");
|
||||||
};
|
};
|
||||||
|
|
||||||
const [pendingRequests, setPendingRequests] = useState<
|
|
||||||
PendingFriendRequest[]
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
const isMe = userDetails?.id == userProfile.id;
|
const isMe = userDetails?.id == userProfile.id;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.electron.getFriendRequests().then((friendsRequests) => {
|
if (isMe) updateFriendRequests();
|
||||||
setPendingRequests(friendsRequests ?? []);
|
|
||||||
});
|
|
||||||
}, [isMe]);
|
}, [isMe]);
|
||||||
|
|
||||||
const profileContentBoxBackground = useMemo(() => {
|
const profileContentBoxBackground = useMemo(() => {
|
||||||
|
@ -123,7 +118,6 @@ export function UserContent({
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UserAddFriendsModal
|
<UserAddFriendsModal
|
||||||
pendingRequests={pendingRequests}
|
|
||||||
visible={showAddFriendsModal}
|
visible={showAddFriendsModal}
|
||||||
onClose={() => setShowAddFriendsModal(false)}
|
onClose={() => setShowAddFriendsModal(false)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
import * as styles from "./user.css";
|
import * as styles from "./user.css";
|
||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
|
|
||||||
export interface UserFriendPendingRequestProps {
|
export interface UserFriendRequestProps {
|
||||||
userId: string;
|
userId: string;
|
||||||
profileImageUrl: string | null;
|
profileImageUrl: string | null;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
@ -17,7 +17,7 @@ export interface UserFriendPendingRequestProps {
|
||||||
onClickRequest: (userId: string) => void;
|
onClickRequest: (userId: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UserFriendPendingRequest = ({
|
export const UserFriendRequest = ({
|
||||||
userId,
|
userId,
|
||||||
profileImageUrl,
|
profileImageUrl,
|
||||||
displayName,
|
displayName,
|
||||||
|
@ -26,7 +26,7 @@ export const UserFriendPendingRequest = ({
|
||||||
onClickAcceptRequest,
|
onClickAcceptRequest,
|
||||||
onClickRefuseRequest,
|
onClickRefuseRequest,
|
||||||
onClickRequest,
|
onClickRequest,
|
||||||
}: UserFriendPendingRequestProps) => {
|
}: UserFriendRequestProps) => {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
|
@ -10,6 +10,8 @@ export type GameStatus =
|
||||||
|
|
||||||
export type GameShop = "steam" | "epic";
|
export type GameShop = "steam" | "epic";
|
||||||
|
|
||||||
|
export type FriendRequestAction = "ACCEPTED" | "REFUSED" | "CANCEL";
|
||||||
|
|
||||||
export interface SteamGenre {
|
export interface SteamGenre {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -275,7 +277,7 @@ export interface UserFriend {
|
||||||
profileImageUrl: string | null;
|
profileImageUrl: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PendingFriendRequest {
|
export interface FriendRequest {
|
||||||
userId: string;
|
userId: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
profileImageUrl: string | null;
|
profileImageUrl: string | null;
|
||||||
|
|
Loading…
Reference in a new issue