This commit is contained in:
1 parent
8efd032cc6
commit
df38dccbf1
735 files changed
+128321
-120870
No files matched your search
@@ -1,14 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { DoorOpen, Loader2, Megaphone, MessageSquare, Shield, Volume2, VolumeX, Zap } from "lucide-react";
|
||||
import {
|
||||
DoorOpen,
|
||||
Loader2,
|
||||
Megaphone,
|
||||
MessageSquare,
|
||||
Shield,
|
||||
Volume2,
|
||||
VolumeX,
|
||||
Zap,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
broadcastAlert,
|
||||
quickAlert,
|
||||
quickKick,
|
||||
quickMute,
|
||||
quickRoomKick,
|
||||
quickUnmute,
|
||||
broadcastAlert,
|
||||
quickAlert,
|
||||
quickKick,
|
||||
quickMute,
|
||||
quickRoomKick,
|
||||
quickUnmute,
|
||||
} from "@/actions/moderation";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
@@ -17,199 +26,236 @@ import { Textarea } from "@/components/ui/textarea";
|
||||
import { useServerAction } from "@/hooks/use-server-action";
|
||||
|
||||
export function ModActionsClient() {
|
||||
const { run, isPending } = useServerAction();
|
||||
const { run, isPending } = useServerAction();
|
||||
|
||||
// User actions
|
||||
const [userId, setUserId] = useState("");
|
||||
const [muteDuration, setMuteDuration] = useState("10");
|
||||
const [alertMessage, setAlertMessage] = useState("");
|
||||
// User actions
|
||||
const [userId, setUserId] = useState("");
|
||||
const [muteDuration, setMuteDuration] = useState("10");
|
||||
const [alertMessage, setAlertMessage] = useState("");
|
||||
|
||||
// Room actions
|
||||
const [roomId, setRoomId] = useState("");
|
||||
// Room actions
|
||||
const [roomId, setRoomId] = useState("");
|
||||
|
||||
// Broadcast
|
||||
const [broadcastMsg, setBroadcastMsg] = useState("");
|
||||
// Broadcast
|
||||
const [broadcastMsg, setBroadcastMsg] = useState("");
|
||||
|
||||
const uid = parseInt(userId, 10);
|
||||
const rid = parseInt(roomId, 10);
|
||||
const uid = parseInt(userId, 10);
|
||||
const rid = parseInt(roomId, 10);
|
||||
|
||||
return (
|
||||
<div className="grid gap-6 lg:grid-cols-2">
|
||||
{/* User Actions */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm flex items-center gap-2">
|
||||
<Zap className="h-4 w-4 text-[var(--admin-warning)]" />
|
||||
User Actions
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div>
|
||||
<span className="text-xs text-muted-foreground mb-1 block">User ID</span>
|
||||
<Input
|
||||
type="number"
|
||||
value={userId}
|
||||
onChange={(e) => setUserId(e.target.value)}
|
||||
placeholder="Enter user ID"
|
||||
/>
|
||||
</div>
|
||||
return (
|
||||
<div className="grid gap-6 lg:grid-cols-2">
|
||||
{/* User Actions */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm flex items-center gap-2">
|
||||
<Zap className="h-4 w-4 text-[var(--admin-warning)]" />
|
||||
User Actions
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div>
|
||||
<span className="text-xs text-muted-foreground mb-1 block">
|
||||
User ID
|
||||
</span>
|
||||
<Input
|
||||
type="number"
|
||||
value={userId}
|
||||
onChange={(e) => setUserId(e.target.value)}
|
||||
placeholder="Enter user ID"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
disabled={isPending || !uid}
|
||||
onClick={() => run(() => quickKick({ userId: uid }), { successMessage: "User disconnected" })}
|
||||
>
|
||||
{isPending ? (
|
||||
<Loader2 className="mr-1 h-3 w-3 animate-spin" />
|
||||
) : (
|
||||
<Zap className="mr-1 h-3 w-3" />
|
||||
)}
|
||||
Kick / Disconnect
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={isPending || !uid}
|
||||
onClick={() => run(() => quickUnmute({ userId: uid }), { successMessage: "User unmuted" })}
|
||||
>
|
||||
<Volume2 className="mr-1 h-3 w-3" /> Unmute
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
disabled={isPending || !uid}
|
||||
onClick={() =>
|
||||
run(() => quickKick({ userId: uid }), {
|
||||
successMessage: "User disconnected",
|
||||
})
|
||||
}
|
||||
>
|
||||
{isPending ? (
|
||||
<Loader2 className="mr-1 h-3 w-3 animate-spin" />
|
||||
) : (
|
||||
<Zap className="mr-1 h-3 w-3" />
|
||||
)}
|
||||
Kick / Disconnect
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={isPending || !uid}
|
||||
onClick={() =>
|
||||
run(() => quickUnmute({ userId: uid }), {
|
||||
successMessage: "User unmuted",
|
||||
})
|
||||
}
|
||||
>
|
||||
<Volume2 className="mr-1 h-3 w-3" /> Unmute
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
min={1}
|
||||
max={1440}
|
||||
value={muteDuration}
|
||||
onChange={(e) => setMuteDuration(e.target.value)}
|
||||
className="w-24"
|
||||
placeholder="Min"
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex-1"
|
||||
disabled={isPending || !uid || !parseInt(muteDuration, 10)}
|
||||
onClick={() =>
|
||||
run(() => quickMute({ userId: uid, duration: parseInt(muteDuration, 10) }), {
|
||||
successMessage: `Muted for ${muteDuration} min`,
|
||||
})
|
||||
}
|
||||
>
|
||||
<VolumeX className="mr-1 h-3 w-3" /> Mute
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
min={1}
|
||||
max={1440}
|
||||
value={muteDuration}
|
||||
onChange={(e) => setMuteDuration(e.target.value)}
|
||||
className="w-24"
|
||||
placeholder="Min"
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex-1"
|
||||
disabled={isPending || !uid || !parseInt(muteDuration, 10)}
|
||||
onClick={() =>
|
||||
run(
|
||||
() =>
|
||||
quickMute({
|
||||
userId: uid,
|
||||
duration: parseInt(muteDuration, 10),
|
||||
}),
|
||||
{
|
||||
successMessage: `Muted for ${muteDuration} min`,
|
||||
},
|
||||
)
|
||||
}
|
||||
>
|
||||
<VolumeX className="mr-1 h-3 w-3" /> Mute
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Textarea
|
||||
value={alertMessage}
|
||||
onChange={(e) => setAlertMessage(e.target.value)}
|
||||
placeholder="Alert message to user..."
|
||||
rows={2}
|
||||
className="resize-none text-xs"
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="shrink-0 h-auto"
|
||||
disabled={isPending || !uid || !alertMessage.trim()}
|
||||
onClick={() => {
|
||||
run(() => quickAlert({ userId: uid, message: alertMessage.trim() }), {
|
||||
successMessage: "Alert sent",
|
||||
onSuccess: () => setAlertMessage(""),
|
||||
});
|
||||
}}
|
||||
>
|
||||
<MessageSquare className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<div className="flex gap-2">
|
||||
<Textarea
|
||||
value={alertMessage}
|
||||
onChange={(e) => setAlertMessage(e.target.value)}
|
||||
placeholder="Alert message to user..."
|
||||
rows={2}
|
||||
className="resize-none text-xs"
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="shrink-0 h-auto"
|
||||
disabled={isPending || !uid || !alertMessage.trim()}
|
||||
onClick={() => {
|
||||
run(
|
||||
() =>
|
||||
quickAlert({ userId: uid, message: alertMessage.trim() }),
|
||||
{
|
||||
successMessage: "Alert sent",
|
||||
onSuccess: () => setAlertMessage(""),
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
<MessageSquare className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Room Actions */}
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm flex items-center gap-2">
|
||||
<DoorOpen className="h-4 w-4 text-[var(--admin-warning)]" />
|
||||
Room Actions
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<div>
|
||||
<span className="text-xs text-muted-foreground mb-1 block">Room ID</span>
|
||||
<Input
|
||||
type="number"
|
||||
value={roomId}
|
||||
onChange={(e) => setRoomId(e.target.value)}
|
||||
placeholder="Enter room ID"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
className="w-full"
|
||||
disabled={isPending || !rid}
|
||||
onClick={() =>
|
||||
run(() => quickRoomKick({ roomId: rid }), {
|
||||
successMessage: "All users kicked from room",
|
||||
})
|
||||
}
|
||||
>
|
||||
<Zap className="mr-1 h-3 w-3" /> Kick All From Room
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{/* Room Actions */}
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm flex items-center gap-2">
|
||||
<DoorOpen className="h-4 w-4 text-[var(--admin-warning)]" />
|
||||
Room Actions
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<div>
|
||||
<span className="text-xs text-muted-foreground mb-1 block">
|
||||
Room ID
|
||||
</span>
|
||||
<Input
|
||||
type="number"
|
||||
value={roomId}
|
||||
onChange={(e) => setRoomId(e.target.value)}
|
||||
placeholder="Enter room ID"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
className="w-full"
|
||||
disabled={isPending || !rid}
|
||||
onClick={() =>
|
||||
run(() => quickRoomKick({ roomId: rid }), {
|
||||
successMessage: "All users kicked from room",
|
||||
})
|
||||
}
|
||||
>
|
||||
<Zap className="mr-1 h-3 w-3" /> Kick All From Room
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Broadcast */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm flex items-center gap-2">
|
||||
<Megaphone className="h-4 w-4 text-primary" />
|
||||
Broadcast Alert
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<Textarea
|
||||
value={broadcastMsg}
|
||||
onChange={(e) => setBroadcastMsg(e.target.value)}
|
||||
placeholder="Type broadcast message..."
|
||||
rows={3}
|
||||
className="resize-none"
|
||||
/>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
disabled={isPending || !broadcastMsg.trim()}
|
||||
onClick={() => {
|
||||
run(() => broadcastAlert({ message: broadcastMsg.trim(), type: "hotel" }), {
|
||||
successMessage: "Hotel alert sent!",
|
||||
onSuccess: () => setBroadcastMsg(""),
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Megaphone className="mr-1 h-3 w-3" /> Hotel Alert
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
disabled={isPending || !broadcastMsg.trim()}
|
||||
onClick={() => {
|
||||
run(() => broadcastAlert({ message: broadcastMsg.trim(), type: "staff" }), {
|
||||
successMessage: "Staff alert sent!",
|
||||
onSuccess: () => setBroadcastMsg(""),
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Shield className="mr-1 h-3 w-3" /> Staff Alert
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
{/* Broadcast */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm flex items-center gap-2">
|
||||
<Megaphone className="h-4 w-4 text-primary" />
|
||||
Broadcast Alert
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<Textarea
|
||||
value={broadcastMsg}
|
||||
onChange={(e) => setBroadcastMsg(e.target.value)}
|
||||
placeholder="Type broadcast message..."
|
||||
rows={3}
|
||||
className="resize-none"
|
||||
/>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
disabled={isPending || !broadcastMsg.trim()}
|
||||
onClick={() => {
|
||||
run(
|
||||
() =>
|
||||
broadcastAlert({
|
||||
message: broadcastMsg.trim(),
|
||||
type: "hotel",
|
||||
}),
|
||||
{
|
||||
successMessage: "Hotel alert sent!",
|
||||
onSuccess: () => setBroadcastMsg(""),
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Megaphone className="mr-1 h-3 w-3" /> Hotel Alert
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
disabled={isPending || !broadcastMsg.trim()}
|
||||
onClick={() => {
|
||||
run(
|
||||
() =>
|
||||
broadcastAlert({
|
||||
message: broadcastMsg.trim(),
|
||||
type: "staff",
|
||||
}),
|
||||
{
|
||||
successMessage: "Staff alert sent!",
|
||||
onSuccess: () => setBroadcastMsg(""),
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Shield className="mr-1 h-3 w-3" /> Staff Alert
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user