339 lines
21 KiB
TypeScript
339 lines
21 KiB
TypeScript
import React from "react";
|
|
import { useSettingsForm } from "./SettingsLayout";
|
|
import { FormField, FormItem, FormLabel, FormControl, FormDescription } from "@/components/ui/form";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Switch } from "@/components/ui/switch";
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
|
|
import { CreditCard, Shield } from "lucide-react";
|
|
import { fromSelectValue, toSelectValue, NONE_VALUE } from "@/hooks/use-settings";
|
|
|
|
export function SystemsSettings() {
|
|
const { form, meta } = useSettingsForm();
|
|
|
|
return (
|
|
<div className="space-y-6 animate-in fade-in slide-up duration-500">
|
|
<Accordion type="multiple" className="w-full space-y-4" defaultValue={["lootdrop", "moderation"]}>
|
|
<AccordionItem value="lootdrop" className="border border-border/40 rounded-xl bg-card/30 px-4 transition-all data-[state=open]:border-primary/20 data-[state=open]:bg-card/50">
|
|
<AccordionTrigger className="hover:no-underline py-4">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-8 h-8 rounded-full bg-indigo-500/10 flex items-center justify-center text-indigo-500">
|
|
<CreditCard className="w-4 h-4" />
|
|
</div>
|
|
<span className="font-bold">Loot Drops</span>
|
|
</div>
|
|
</AccordionTrigger>
|
|
<AccordionContent className="space-y-4 pb-4">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<FormField
|
|
control={form.control}
|
|
name="lootdrop.spawnChance"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Spawn Chance (0-1)</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" step="0.01" min="0" max="1" className="bg-background/50" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="lootdrop.minMessages"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Min Messages</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="bg-background/50" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="bg-muted/30 p-4 rounded-lg space-y-3">
|
|
<h4 className="text-xs font-bold text-muted-foreground uppercase tracking-wider">Rewards</h4>
|
|
<div className="grid grid-cols-3 gap-4">
|
|
<FormField
|
|
control={form.control}
|
|
name="lootdrop.reward.min"
|
|
render={({ field }) => (
|
|
<FormItem className="space-y-1">
|
|
<FormLabel className="text-xs">Min</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="h-9 text-sm" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="lootdrop.reward.max"
|
|
render={({ field }) => (
|
|
<FormItem className="space-y-1">
|
|
<FormLabel className="text-xs">Max</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="h-9 text-sm" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="lootdrop.reward.currency"
|
|
render={({ field }) => (
|
|
<FormItem className="space-y-1">
|
|
<FormLabel className="text-xs">Currency</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} placeholder="AU" className="h-9 text-sm" />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<FormField
|
|
control={form.control}
|
|
name="lootdrop.cooldownMs"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Cooldown (ms)</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="bg-background/50" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="lootdrop.activityWindowMs"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Activity Window (ms)</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="bg-background/50" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
|
|
<AccordionItem value="trivia" className="border border-border/40 rounded-xl bg-card/30 px-4 transition-all data-[state=open]:border-primary/20 data-[state=open]:bg-card/50">
|
|
<AccordionTrigger className="hover:no-underline py-4">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-8 h-8 rounded-full bg-purple-500/10 flex items-center justify-center text-purple-500 text-sm">
|
|
🎯
|
|
</div>
|
|
<span className="font-bold">Trivia</span>
|
|
</div>
|
|
</AccordionTrigger>
|
|
<AccordionContent className="space-y-4 pb-4">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<FormField
|
|
control={form.control}
|
|
name="trivia.entryFee"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Entry Fee (AU)</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="text" className="bg-background/50" placeholder="50" />
|
|
</FormControl>
|
|
<FormDescription className="text-xs">Cost to play</FormDescription>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="trivia.rewardMultiplier"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Reward Multiplier</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" step="0.1" className="bg-background/50" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
<FormDescription className="text-xs">multiplier</FormDescription>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<FormField
|
|
control={form.control}
|
|
name="trivia.timeoutSeconds"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Timeout (seconds)</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="bg-background/50" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="trivia.cooldownMs"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Cooldown (ms)</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="bg-background/50" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
<FormField
|
|
control={form.control}
|
|
name="trivia.difficulty"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Difficulty</FormLabel>
|
|
<Select onValueChange={field.onChange} value={field.value}>
|
|
<FormControl>
|
|
<SelectTrigger className="bg-background/50">
|
|
<SelectValue placeholder="Select difficulty" />
|
|
</SelectTrigger>
|
|
</FormControl>
|
|
<SelectContent>
|
|
<SelectItem value="easy">Easy</SelectItem>
|
|
<SelectItem value="medium">Medium</SelectItem>
|
|
<SelectItem value="hard">Hard</SelectItem>
|
|
<SelectItem value="random">Random</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
|
|
<AccordionItem value="moderation" className="border border-border/40 rounded-xl bg-card/30 px-4 transition-all data-[state=open]:border-primary/20 data-[state=open]:bg-card/50">
|
|
<AccordionTrigger className="hover:no-underline py-4">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-8 h-8 rounded-full bg-red-500/10 flex items-center justify-center text-red-500">
|
|
<Shield className="w-4 h-4" />
|
|
</div>
|
|
<span className="font-bold">Moderation</span>
|
|
</div>
|
|
</AccordionTrigger>
|
|
<AccordionContent className="space-y-6 pb-4">
|
|
<div className="space-y-4">
|
|
<h4 className="font-bold text-sm text-foreground/80 uppercase tracking-wider">Case Management</h4>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<FormField
|
|
control={form.control}
|
|
name="moderation.cases.dmOnWarn"
|
|
render={({ field }) => (
|
|
<FormItem className="flex flex-row items-center justify-between rounded-lg border border-border/50 bg-background/50 p-4">
|
|
<div className="space-y-0.5">
|
|
<FormLabel className="text-sm font-medium">DM on Warm</FormLabel>
|
|
<FormDescription className="text-xs">Notify via DM</FormDescription>
|
|
</div>
|
|
<FormControl>
|
|
<Switch checked={field.value} onCheckedChange={field.onChange} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="moderation.cases.logChannelId"
|
|
render={({ field }) => (
|
|
<FormItem className="glass-card p-4 rounded-xl border border-border/50">
|
|
<FormLabel className="text-sm">Log Channel</FormLabel>
|
|
<Select onValueChange={v => field.onChange(fromSelectValue(v))} value={toSelectValue(field.value || null)}>
|
|
<FormControl>
|
|
<SelectTrigger className="bg-background/50 h-9">
|
|
<SelectValue placeholder="Select a channel" />
|
|
</SelectTrigger>
|
|
</FormControl>
|
|
<SelectContent>
|
|
<SelectItem value={NONE_VALUE}>None</SelectItem>
|
|
{meta?.channels.filter(c => c.type === 0).map(c => (
|
|
<SelectItem key={c.id} value={c.id}>#{c.name}</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
<FormField
|
|
control={form.control}
|
|
name="moderation.cases.autoTimeoutThreshold"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Auto Timeout Threshold</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" min="0" className="bg-background/50" onChange={e => field.onChange(e.target.value ? Number(e.target.value) : undefined)} />
|
|
</FormControl>
|
|
<FormDescription className="text-xs">Warnings before auto-timeout.</FormDescription>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
<h4 className="font-bold text-sm text-foreground/80 uppercase tracking-wider">Message Pruning</h4>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<FormField
|
|
control={form.control}
|
|
name="moderation.prune.maxAmount"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-xs">Max Amount</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="bg-background/50 h-9" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="moderation.prune.confirmThreshold"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-xs">Confirm Threshold</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="bg-background/50 h-9" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="moderation.prune.batchSize"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-xs">Batch Size</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="bg-background/50 h-9" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="moderation.prune.batchDelayMs"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel className="text-xs">Batch Delay (ms)</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} type="number" className="bg-background/50 h-9" onChange={e => field.onChange(Number(e.target.value))} />
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
</Accordion>
|
|
</div>
|
|
);
|
|
}
|