Revert "Add missing admin action files and navigation links"

This reverts commit 41be6835bf.
This commit is contained in:
Simo committed 2026-07-11 20:37:56 +02:00
1 parent 4a1e1115b3
commit 4d515bc400
338 files changed
+5949 -28144

No files matched your search

@@ -1,219 +0,0 @@
'use client'
import { Check, Coins, Copy, KeyRound, MessageCircle, Unplug, Volume2, VolumeX } from 'lucide-react'
import { useState } from 'react'
import {
alertUser,
disconnectUser,
muteUser,
resetPassword,
sendCredits,
unmuteUser,
} from '@/actions/users'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { useServerAction } from '@/hooks/use-server-action'
interface UserQuickActionsProps {
userId: number
username: string
isOnline: boolean
}
export function UserQuickActions({ userId, username, isOnline }: UserQuickActionsProps) {
const { run, isPending } = useServerAction()
// Reset password state
const [newPassword, setNewPassword] = useState<string | null>(null)
const [copied, setCopied] = useState(false)
// Alert state
const [alertMessage, setAlertMessage] = useState('')
// Mute state
const [muteDuration, setMuteDuration] = useState('10')
// Credits state
const [creditAmount, setCreditAmount] = useState('1000')
function handleResetPassword() {
if (!confirm(`Reset password for ${username}? A new random password will be generated.`)) return
run(() => resetPassword({ userId }), {
successMessage: 'Password reset successfully.',
onSuccess: (data) => {
setNewPassword(data.newPassword as string)
},
})
}
function handleDisconnect() {
run(() => disconnectUser({ userId }), {
successMessage: `${username} disconnected.`,
})
}
function handleAlert() {
if (!alertMessage.trim()) return
run(() => alertUser({ userId, message: alertMessage.trim() }), {
successMessage: 'Alert sent.',
onSuccess: () => setAlertMessage(''),
})
}
function handleMute() {
const duration = Number(muteDuration)
if (Number.isNaN(duration) || duration < 0) return
run(() => muteUser({ userId, duration }), {
successMessage: `${username} muted.`,
})
}
function handleUnmute() {
run(() => unmuteUser({ userId }), {
successMessage: `${username} unmuted.`,
})
}
function handleSendCredits() {
const amount = parseInt(creditAmount, 10)
if (!amount || amount <= 0) return
run(() => sendCredits({ userId, amount }), {
successMessage: `${amount.toLocaleString()} credits sent to ${username}.`,
})
}
function copyPassword() {
if (newPassword) {
navigator.clipboard.writeText(newPassword)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
}
return (
<>
<Card>
<CardHeader>
<CardTitle>Quick Actions</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{/* Row 1: Password + Disconnect */}
<div className="grid grid-cols-2 gap-3">
<Button
variant="outline"
onClick={handleResetPassword}
disabled={isPending}
className="justify-start"
>
<KeyRound className="mr-2 h-4 w-4" />
Reset Password
</Button>
<Button
variant="outline"
onClick={handleDisconnect}
disabled={isPending || !isOnline}
className="justify-start"
>
<Unplug className="mr-2 h-4 w-4" />
Disconnect
{isOnline && (
<Badge variant="default" className="ml-auto text-[10px] bg-green-600">
Online
</Badge>
)}
</Button>
</div>
{/* Send Alert */}
<div className="space-y-2">
<Label className="text-xs text-muted-foreground">Send In-Game Alert</Label>
<div className="flex gap-2">
<Input
placeholder="Message to send..."
value={alertMessage}
onChange={(e) => setAlertMessage(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleAlert()}
className="flex-1"
/>
<Button
onClick={handleAlert}
disabled={isPending || !alertMessage.trim()}
size="icon"
>
<MessageCircle className="h-4 w-4" />
</Button>
</div>
</div>
{/* Mute */}
<div className="space-y-2">
<Label className="text-xs text-muted-foreground">Mute / Unmute</Label>
<div className="flex gap-2">
<Input
type="number"
placeholder="Minutes (0 = permanent)"
value={muteDuration}
onChange={(e) => setMuteDuration(e.target.value)}
className="w-32"
/>
<Button variant="outline" onClick={handleMute} disabled={isPending} size="sm">
<VolumeX className="mr-1.5 h-3.5 w-3.5" /> Mute
</Button>
<Button variant="outline" onClick={handleUnmute} disabled={isPending} size="sm">
<Volume2 className="mr-1.5 h-3.5 w-3.5" /> Unmute
</Button>
</div>
</div>
{/* Send Credits */}
<div className="space-y-2">
<Label className="text-xs text-muted-foreground">Send Credits (RCON)</Label>
<div className="flex gap-2">
<Input
type="number"
value={creditAmount}
onChange={(e) => setCreditAmount(e.target.value)}
className="w-32"
min={1}
/>
<Button variant="outline" onClick={handleSendCredits} disabled={isPending} size="sm">
<Coins className="mr-1.5 h-3.5 w-3.5" /> Send Credits
</Button>
</div>
</div>
</CardContent>
</Card>
{/* Password Reset Dialog */}
<Dialog open={!!newPassword} onOpenChange={() => setNewPassword(null)}>
<DialogContent className="max-w-sm">
<DialogHeader>
<DialogTitle>Password Reset</DialogTitle>
<DialogDescription>
New password generated for <strong>{username}</strong>. Copy it now — it won&apos;t be
shown again.
</DialogDescription>
</DialogHeader>
<div className="flex items-center gap-2 rounded-lg border bg-muted p-3">
<code className="flex-1 text-lg font-mono font-bold tracking-wider select-all">
{newPassword}
</code>
<Button variant="ghost" size="icon" onClick={copyPassword}>
{copied ? <Check className="h-4 w-4 text-green-500" /> : <Copy className="h-4 w-4" />}
</Button>
</div>
</DialogContent>
</Dialog>
</>
)
}