-
+ return (
+
{
+ if (!open) {
+ handleClose();
+ }
+ }}
+ onBackdropClick={handleClose}
+ >
+

- {(currentData?.userId || currentData?.isOwnProfile) && (
+ {(currentData?.userId || currentData?.isOwnProfile) && !currentData.deleted && (
)}
- {/* Verify button for owner */}
- {!currentData.isOwnProfile && currentData.userId && (
+ {/* Admin Actions Section - Hide for deleted users */}
+ {!currentData.isOwnProfile && user.currentUser?.id === 1 && !currentData.deleted && (
+
+
Admin Actions
+
+
+ {currentData.suspended ? "Unsuspend Account" : "Suspend Account"}
+
+
+ Delete Account
+
+ {
+ setCurrentData({ ...currentData, verified });
+ }}
+ />
+
+
+ )}
+
+ {/* Verify button for non-admin owner */}
+ {!currentData.isOwnProfile && currentData.userId && user.currentUser?.id !== 1 && (
)}
-
-
-
- {currentData.bio !== undefined && (
+ {/* Hide profile sections for deleted users */}
+ {!currentData.deleted && (
+
- )}
+ placeholder="username" />
- {currentData.memberSince && (
-
- )}
+ {currentData.bio !== undefined && (
+
+ )}
- {currentData.verified && (
-
- )}
-
-
+ {currentData.memberSince && (
+
+ )}
+
+ {currentData.verified && (
+
+ )}
+
+ )}
{currentData.isOwnProfile && (
-
- ,
- document.getElementById("root")!
+
);
}
diff --git a/frontend/src/pages/chat/ui/SuspensionDialog.tsx b/frontend/src/pages/chat/ui/SuspensionDialog.tsx
new file mode 100644
index 0000000..b9d1e22
--- /dev/null
+++ b/frontend/src/pages/chat/ui/SuspensionDialog.tsx
@@ -0,0 +1,42 @@
+import { StyledDialog } from "@/core/components/StyledDialog";
+
+interface SuspensionDialogProps {
+ reason: string;
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+}
+
+export function SuspensionDialog({ reason, open, onOpenChange }: SuspensionDialogProps) {
+ return (
+
+
+
+
+
+
+
+
Аккаунт заблокирован
+
+ Ваш аккаунт был заблокирован за нарушение правил сообщества.
+ Вы не можете отправлять сообщения или взаимодействовать с другими пользователями.
+
+ {reason && reason !== "No reason provided" && (
+
+
Причина блокировки:
+
+ {reason}
+
+
+ )}
+
+ Если вы считаете, что блокировка была применена по ошибке,
+ обратитесь к администратору для рассмотрения вашего случая.
+
+
+
+
+ );
+}
diff --git a/frontend/src/pages/chat/ui/right/Message.tsx b/frontend/src/pages/chat/ui/right/Message.tsx
index f3767b4..4411f49 100644
--- a/frontend/src/pages/chat/ui/right/Message.tsx
+++ b/frontend/src/pages/chat/ui/right/Message.tsx
@@ -487,7 +487,7 @@ export function Message({ message, isAuthor, onContextMenu, onReactionClick, isD
{!isAuthor && !isDm && (

{
const target = e.target as HTMLImageElement;
diff --git a/frontend/src/pages/chat/ui/right/MessageContextMenu.tsx b/frontend/src/pages/chat/ui/right/MessageContextMenu.tsx
index 3ac3022..a999063 100644
--- a/frontend/src/pages/chat/ui/right/MessageContextMenu.tsx
+++ b/frontend/src/pages/chat/ui/right/MessageContextMenu.tsx
@@ -1,6 +1,7 @@
import { useState, useEffect, useRef } from "react";
import type { Message, Size2D } from "@/core/types";
import { EmojiMenu } from "./EmojiMenu";
+import { useAppState } from "@/pages/chat/state";
interface MessageContextMenuProps {
message: Message;
@@ -33,6 +34,7 @@ export function MessageContextMenu({
isOpen,
onOpenChange
}: MessageContextMenuProps) {
+ const { user } = useAppState();
// Internal state for closing animation
const [isClosing, setIsClosing] = useState(false);
const [calculatedPosition, setCalculatedPosition] = useState(position);
@@ -209,7 +211,7 @@ export function MessageContextMenu({
onDelete(message);
handleClose();
},
- show: isAuthor
+ show: isAuthor || user.currentUser?.id === 1
},
];
diff --git a/package.json b/package.json
index 0949b79..f4b9d31 100644
--- a/package.json
+++ b/package.json
@@ -68,6 +68,7 @@
"escape-string-regexp": "^5.0.0",
"marked": "^16.3.0",
"mdui": "^2.1.4",
+ "motion": "^12.23.24",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-router-dom": "^7.9.3",