Improve admin ban UX, add product cloning, and enhance auth handling
Refines the admin ban page with better dialog state management and feedback during ban/unban actions. Adds a product cloning feature to the products dashboard and updates the product table to support cloning. Improves error handling in ChatDetail for authentication errors, and enhances middleware to handle auth check timeouts and network errors more gracefully. Also updates BanUserCard to validate user ID and ensure correct request formatting.
This commit is contained in:
@@ -32,6 +32,7 @@ export default function AdminBanPage() {
|
||||
const [unbanning, setUnbanning] = useState<string | null>(null);
|
||||
const [blockedUsers, setBlockedUsers] = useState<BlockedUser[]>([]);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [banDialogOpen, setBanDialogOpen] = useState(false);
|
||||
const [banData, setBanData] = useState({
|
||||
telegramUserId: "",
|
||||
reason: "",
|
||||
@@ -59,7 +60,10 @@ export default function AdminBanPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleBanUser = async () => {
|
||||
const handleBanUser = async (e?: React.MouseEvent) => {
|
||||
e?.preventDefault();
|
||||
e?.stopPropagation();
|
||||
|
||||
if (!banData.telegramUserId) {
|
||||
toast({
|
||||
title: "Error",
|
||||
@@ -71,15 +75,12 @@ export default function AdminBanPage() {
|
||||
|
||||
try {
|
||||
setBanning(true);
|
||||
await fetchClient("/admin/ban", {
|
||||
const response = await fetchClient("/admin/ban", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
body: {
|
||||
telegramUserId: parseInt(banData.telegramUserId),
|
||||
reason: banData.additionalDetails || banData.reason || undefined,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
toast({
|
||||
@@ -88,7 +89,8 @@ export default function AdminBanPage() {
|
||||
});
|
||||
|
||||
setBanData({ telegramUserId: "", reason: "", additionalDetails: "" });
|
||||
fetchBlockedUsers();
|
||||
setBanDialogOpen(false);
|
||||
await fetchBlockedUsers();
|
||||
} catch (error: any) {
|
||||
console.error("Failed to ban user:", error);
|
||||
toast({
|
||||
@@ -101,7 +103,10 @@ export default function AdminBanPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleUnbanUser = async (telegramUserId: number) => {
|
||||
const handleUnbanUser = async (telegramUserId: number, e?: React.MouseEvent) => {
|
||||
e?.preventDefault();
|
||||
e?.stopPropagation();
|
||||
|
||||
try {
|
||||
setUnbanning(telegramUserId.toString());
|
||||
await fetchClient(`/admin/ban/${telegramUserId}`, {
|
||||
@@ -113,7 +118,7 @@ export default function AdminBanPage() {
|
||||
description: "User has been unbanned",
|
||||
});
|
||||
|
||||
fetchBlockedUsers();
|
||||
await fetchBlockedUsers();
|
||||
} catch (error: any) {
|
||||
console.error("Failed to unban user:", error);
|
||||
toast({
|
||||
@@ -235,20 +240,18 @@ export default function AdminBanPage() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<AlertDialog>
|
||||
<AlertDialog
|
||||
open={banDialogOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (!banning) {
|
||||
setBanDialogOpen(open);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="destructive" disabled={banning}>
|
||||
{banning ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||
Banning...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Ban className="h-4 w-4 mr-2" />
|
||||
Ban User
|
||||
</>
|
||||
)}
|
||||
<Ban className="h-4 w-4 mr-2" />
|
||||
Ban User
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
@@ -259,9 +262,23 @@ export default function AdminBanPage() {
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={handleBanUser}>
|
||||
Confirm Ban
|
||||
<AlertDialogCancel disabled={banning}>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleBanUser(e);
|
||||
}}
|
||||
disabled={banning}
|
||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{banning ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||
Banning...
|
||||
</>
|
||||
) : (
|
||||
"Confirm Ban"
|
||||
)}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
@@ -354,9 +371,19 @@ export default function AdminBanPage() {
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={() => handleUnbanUser(user.telegramUserId)}>
|
||||
Confirm Unban
|
||||
<AlertDialogCancel disabled={unbanning === user.telegramUserId.toString()}>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={(e) => handleUnbanUser(user.telegramUserId, e)}
|
||||
disabled={unbanning === user.telegramUserId.toString()}
|
||||
>
|
||||
{unbanning === user.telegramUserId.toString() ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||
Unbanning...
|
||||
</>
|
||||
) : (
|
||||
"Confirm Unban"
|
||||
)}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
|
||||
Reference in New Issue
Block a user