99 lines
4.5 KiB
TypeScript
99 lines
4.5 KiB
TypeScript
import { Card, CardContent, CardHeader, Input, Button, Chip, Switch, Separator, TextField, Label } from '@heroui/react';
|
||
import { Activity, Save, Trash2, Plus, BarChart3 } from 'lucide-react';
|
||
import { useApp } from '../context/AppContext';
|
||
import { SectionCard } from '../components/shared/SectionCard';
|
||
|
||
export function ServerStats() {
|
||
const { statsDraft, setStatsDraft, saveServerStats, statsItemDraft, setStatsItemDraft, addStatsItem, deleteStatsItem } = useApp();
|
||
|
||
const items = (statsDraft?.items || []);
|
||
|
||
return (
|
||
<SectionCard title="Server Stats" subtitle="Counter und Refresh-Intervall steuern">
|
||
<div className="grid gap-5 xl:grid-cols-[420px_1fr]">
|
||
<Card className="border border-default-100 bg-default-50/20">
|
||
<CardHeader className="px-5 pt-5 pb-0">
|
||
<h3 className="text-base font-semibold">Konfiguration</h3>
|
||
</CardHeader>
|
||
<CardContent className="flex flex-col gap-4 p-5">
|
||
<Switch isSelected={statsDraft?.enabled === true} onChange={(v) => setStatsDraft((s) => ({ ...(s || {}), enabled: v }))}>
|
||
<div className="flex items-center gap-2"><BarChart3 size={16} /> Server Stats aktiv</div>
|
||
</Switch>
|
||
|
||
<TextField>
|
||
<Label>Kategorie-Name</Label>
|
||
<Input
|
||
placeholder="?? Server Stats"
|
||
value={statsDraft?.categoryName || ''}
|
||
onChange={(e) => setStatsDraft((s) => ({ ...(s || {}), categoryName: e.target.value }))}
|
||
/>
|
||
</TextField>
|
||
|
||
<TextField>
|
||
<Label>Refresh (Minuten)</Label>
|
||
<Input
|
||
type="number"
|
||
value={String(statsDraft?.refreshMinutes || 10)}
|
||
onChange={(e) => setStatsDraft((s) => ({ ...(s || {}), refreshMinutes: Number(e.target.value || 10) }))}
|
||
/>
|
||
</TextField>
|
||
|
||
<Button color="primary" startContent={<Save size={16} />} onPress={saveServerStats}>
|
||
Server Stats speichern
|
||
</Button>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card className="border border-default-100 bg-default-50/20">
|
||
<CardHeader className="px-5 pt-5 pb-0">
|
||
<h3 className="text-base font-semibold">Items ({items.length})</h3>
|
||
</CardHeader>
|
||
<CardContent className="flex flex-col gap-3 p-5">
|
||
{items.length ? items.map((item, i) => (
|
||
<div key={i} className="flex items-center justify-between rounded-xl border border-default-100 bg-default-50/30 px-4 py-3 text-small">
|
||
<div className="flex items-center gap-2">
|
||
<Activity size={14} className="text-primary-400" />
|
||
<span className="font-medium">{item.label || item.key}</span>
|
||
<Chip size="sm" variant="flat">{item.type || '-'}</Chip>
|
||
</div>
|
||
<Button isIconOnly size="sm" variant="light" color="danger" onPress={() => deleteStatsItem(i)}>
|
||
<Trash2 size={14} />
|
||
</Button>
|
||
</div>
|
||
)) : (
|
||
<div className="flex flex-col items-center gap-2 py-4 text-center text-tiny text-default-400">
|
||
<BarChart3 size={20} />
|
||
Keine Items
|
||
</div>
|
||
)}
|
||
|
||
<Separator />
|
||
|
||
<div>
|
||
<h4 className="text-small font-semibold mb-2">Item hinzuf<EFBFBD>gen</h4>
|
||
<div className="flex flex-col gap-2">
|
||
<Input placeholder="Label" value={statsItemDraft.label} onChange={(e) => setStatsItemDraft((s) => ({ ...s, label: e.target.value }))} />
|
||
<select
|
||
className="w-full rounded-xl border border-default-200 bg-default-50 px-3 py-2 text-sm outline-none"
|
||
value={statsItemDraft.type}
|
||
onChange={(e) => setStatsItemDraft((s) => ({ ...s, type: e.target.value }))}
|
||
>
|
||
<option value="members">Mitglieder</option>
|
||
<option value="channels">Channels</option>
|
||
<option value="roles">Rollen</option>
|
||
<option value="boosts">Boosts</option>
|
||
<option value="online">Online</option>
|
||
<option value="custom">Custom</option>
|
||
</select>
|
||
<Button size="sm" color="primary" startContent={<Plus size={14} />} onPress={addStatsItem}>
|
||
Hinzuf<EFBFBD>gen
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</SectionCard>
|
||
);
|
||
}
|