feat: vollständiges Dashboard-Redesign mit HeroUI - monolithische App.tsx aufgelöst, 16 Seiten, Context-API, collapsible Sidebar, neues Dashboard-Layout
Some checks failed
Deploy Discord Bot / deploy (push) Has been cancelled
Some checks failed
Deploy Discord Bot / deploy (push) Has been cancelled
This commit is contained in:
94
frontend/src/pages/ServerStats.tsx
Normal file
94
frontend/src/pages/ServerStats.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import { Card, CardContent, CardHeader, Input, Button, Chip, Switch, Separator } 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} onValueChange={(v) => setStatsDraft((s) => ({ ...(s || {}), enabled: v }))}>
|
||||
<div className="flex items-center gap-2"><BarChart3 size={16} /> Server Stats aktiv</div>
|
||||
</Switch>
|
||||
|
||||
<Input
|
||||
label="Kategorie-Name"
|
||||
placeholder="?? Server Stats"
|
||||
value={statsDraft?.categoryName || ''}
|
||||
onValueChange={(v) => setStatsDraft((s) => ({ ...(s || {}), categoryName: v }))}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Refresh (Minuten)"
|
||||
type="number"
|
||||
value={String(statsDraft?.refreshMinutes || 10)}
|
||||
onValueChange={(v) => setStatsDraft((s) => ({ ...(s || {}), refreshMinutes: Number(v || 10) }))}
|
||||
/>
|
||||
|
||||
<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} onValueChange={(v) => setStatsItemDraft((s) => ({ ...s, label: v }))} />
|
||||
<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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user