sync: phase 1 backend + frontend from server
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import { useState } from "react";
|
||||
|
||||
interface MemberContextMenuProps {
|
||||
memberId: string;
|
||||
username: string;
|
||||
canKick: boolean;
|
||||
canBan: boolean;
|
||||
canMute: boolean;
|
||||
onMessage?: () => void;
|
||||
onKick?: (reason: string) => void;
|
||||
onBan?: (reason: string) => void;
|
||||
onMute?: (duration: string, reason: string) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function MemberContextMenu({
|
||||
username,
|
||||
canKick,
|
||||
canBan,
|
||||
canMute,
|
||||
onMessage,
|
||||
onKick,
|
||||
onBan,
|
||||
onMute,
|
||||
onClose,
|
||||
}: MemberContextMenuProps) {
|
||||
const [mode, setMode] = useState<"menu" | "kick" | "ban" | "mute">("menu");
|
||||
const [reason, setReason] = useState("");
|
||||
const [duration, setDuration] = useState("1h");
|
||||
|
||||
if (mode === "kick") {
|
||||
return (
|
||||
<div className="absolute z-50 bg-gb-bg border border-gb-bg-t p-3 font-mono text-xs shadow-lg min-w-[200px]">
|
||||
<div className="text-gb-orange mb-2">KICK {username.toUpperCase()}</div>
|
||||
<input
|
||||
type="text"
|
||||
value={reason}
|
||||
onChange={(e) => setReason(e.target.value)}
|
||||
placeholder="reason (optional)"
|
||||
className="terminal-input w-full mb-2"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => onKick?.(reason)} className="flex-1 bg-gb-red text-gb-bg py-1 hover:bg-gb-orange">
|
||||
[KICK]
|
||||
</button>
|
||||
<button onClick={() => setMode("menu")} className="flex-1 bg-gb-bg-t text-gb-fg py-1 hover:bg-gb-bg-s">
|
||||
[BACK]
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (mode === "ban") {
|
||||
return (
|
||||
<div className="absolute z-50 bg-gb-bg border border-gb-bg-t p-3 font-mono text-xs shadow-lg min-w-[200px]">
|
||||
<div className="text-gb-orange mb-2">BAN {username.toUpperCase()}</div>
|
||||
<input
|
||||
type="text"
|
||||
value={reason}
|
||||
onChange={(e) => setReason(e.target.value)}
|
||||
placeholder="reason (optional)"
|
||||
className="terminal-input w-full mb-2"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => onBan?.(reason)} className="flex-1 bg-gb-red text-gb-bg py-1 hover:bg-gb-orange">
|
||||
[BAN]
|
||||
</button>
|
||||
<button onClick={() => setMode("menu")} className="flex-1 bg-gb-bg-t text-gb-fg py-1 hover:bg-gb-bg-s">
|
||||
[BACK]
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (mode === "mute") {
|
||||
return (
|
||||
<div className="absolute z-50 bg-gb-bg border border-gb-bg-t p-3 font-mono text-xs shadow-lg min-w-[200px]">
|
||||
<div className="text-gb-orange mb-2">MUTE {username.toUpperCase()}</div>
|
||||
<select
|
||||
value={duration}
|
||||
onChange={(e) => setDuration(e.target.value)}
|
||||
className="w-full mb-2 bg-gb-bg-s text-gb-fg text-xs border-none outline-none"
|
||||
>
|
||||
<option value="15m">15 minutes</option>
|
||||
<option value="1h">1 hour</option>
|
||||
<option value="6h">6 hours</option>
|
||||
<option value="1d">1 day</option>
|
||||
<option value="7d">7 days</option>
|
||||
<option value="">permanent</option>
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
value={reason}
|
||||
onChange={(e) => setReason(e.target.value)}
|
||||
placeholder="reason (optional)"
|
||||
className="terminal-input w-full mb-2"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => onMute?.(duration, reason)} className="flex-1 bg-gb-yellow text-gb-bg py-1 hover:bg-gb-orange">
|
||||
[MUTE]
|
||||
</button>
|
||||
<button onClick={() => setMode("menu")} className="flex-1 bg-gb-bg-t text-gb-fg py-1 hover:bg-gb-bg-s">
|
||||
[BACK]
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="absolute z-50 bg-gb-bg border border-gb-bg-t py-1 font-mono text-xs shadow-lg min-w-[140px]">
|
||||
<button onClick={onMessage} className="w-full text-left px-3 py-1 hover:bg-gb-bg-t text-gb-fg">
|
||||
Message
|
||||
</button>
|
||||
{canKick && (
|
||||
<button onClick={() => setMode("kick")} className="w-full text-left px-3 py-1 hover:bg-gb-bg-t text-gb-yellow">
|
||||
Kick
|
||||
</button>
|
||||
)}
|
||||
{canMute && (
|
||||
<button onClick={() => setMode("mute")} className="w-full text-left px-3 py-1 hover:bg-gb-bg-t text-gb-orange">
|
||||
Mute
|
||||
</button>
|
||||
)}
|
||||
{canBan && (
|
||||
<button onClick={() => setMode("ban")} className="w-full text-left px-3 py-1 hover:bg-gb-bg-t text-gb-red">
|
||||
Ban
|
||||
</button>
|
||||
)}
|
||||
<div className="border-t border-gb-bg-t my-1" />
|
||||
<button onClick={onClose} className="w-full text-left px-3 py-1 hover:bg-gb-bg-t text-gb-fg-f">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user