diff --git a/frontend/src/hooks/groups.ts b/frontend/src/hooks/groups.ts index 869291b..eeaa183 100644 --- a/frontend/src/hooks/groups.ts +++ b/frontend/src/hooks/groups.ts @@ -92,10 +92,11 @@ export function useSetGroupExpansions(groupId: number) { }); } -// Приглашение игрока в группу по нику (вместо прямого добавления). -export function useInviteMember(groupId: number) { +// Приглашение игрока в группу по нику (вместо прямого добавления). groupId передаётся +// при вызове — чтобы можно было приглашать в выбранную группу (со страницы чужого профиля). +export function useInviteMember() { return useMutation({ - mutationFn: async (nickname: string) => + mutationFn: async ({ groupId, nickname }: { groupId: number; nickname: string }) => unwrap( await api.POST("/api/groups/{group_id}/invitations", { params: { path: { group_id: groupId } }, diff --git a/frontend/src/pages/GroupSettingsPage.tsx b/frontend/src/pages/GroupSettingsPage.tsx index acee949..ea05dfc 100644 --- a/frontend/src/pages/GroupSettingsPage.tsx +++ b/frontend/src/pages/GroupSettingsPage.tsx @@ -16,7 +16,7 @@ export function GroupSettingsPage() { const { data: expansions } = useExpansions(); const { data: members } = useGroupMembers(groupId); const setExpansions = useSetGroupExpansions(groupId ?? 0); - const inviteMember = useInviteMember(groupId ?? 0); + const inviteMember = useInviteMember(); const removeMember = useRemoveMember(groupId ?? 0); const toast = useToast(); @@ -51,7 +51,7 @@ export function GroupSettingsPage() { const nick = newNick.trim(); if (!nick) return; try { - await inviteMember.mutateAsync(nick); + await inviteMember.mutateAsync({ groupId: group.id, nickname: nick }); setNewNick(""); toast.show("Приглашение отправлено"); } catch (e) { diff --git a/frontend/src/pages/PublicProfilePage.tsx b/frontend/src/pages/PublicProfilePage.tsx index ed986fb..44098c4 100644 --- a/frontend/src/pages/PublicProfilePage.tsx +++ b/frontend/src/pages/PublicProfilePage.tsx @@ -1,8 +1,13 @@ +import { useState } from "react"; import { useParams } from "react-router-dom"; +import { ApiError } from "../api/client"; import { Avatar } from "../components/Avatar"; import { ProfileStatsCard } from "../components/ProfileStatsCard"; import { Spinner } from "../components/Spinner"; +import { useToast } from "../context/ToastContext"; +import { useMe } from "../hooks/auth"; +import { useInviteMember } from "../hooks/groups"; import { usePublicProfile } from "../hooks/stats"; /** @@ -13,10 +18,27 @@ export function PublicProfilePage() { const { userId } = useParams(); const id = Number(userId); const { data, isLoading, isError } = usePublicProfile(id); + const { data: me } = useMe(); + const invite = useInviteMember(); + const toast = useToast(); + const [pickOpen, setPickOpen] = useState(false); if (isLoading) return ; if (isError || !data) return
Профиль не найден.
; + const groups = me?.groups ?? []; + const isSelf = me?.id === data.user_id; + + const doInvite = async (groupId: number) => { + setPickOpen(false); + try { + await invite.mutateAsync({ groupId, nickname: data.nickname }); + toast.show("Приглашение отправлено"); + } catch (e) { + toast.show(e instanceof ApiError ? e.message : "Не удалось пригласить"); + } + }; + return (
@@ -37,6 +59,46 @@ export function PublicProfilePage() {
+ {/* Пригласить в группу (только чужой профиль и если у меня есть группы). */} + {!isSelf && groups.length > 0 && ( +
+ {groups.length === 1 ? ( + + ) : ( + <> + + {pickOpen && ( +
+ {groups.map((g) => ( + + ))} +
+ )} + + )} +
+ )} + );