From 1cfe2ee7407b046f8ca912ab6f59e4b3b4f443ca Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sat, 8 Nov 2025 13:44:29 +0000 Subject: [PATCH] Create Discord Management admin component cgen-df0d81d8fe084790bbc3ad2f339764aa --- .../admin/AdminDiscordManagement.tsx | 318 ++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 client/components/admin/AdminDiscordManagement.tsx diff --git a/client/components/admin/AdminDiscordManagement.tsx b/client/components/admin/AdminDiscordManagement.tsx new file mode 100644 index 00000000..c29c81f3 --- /dev/null +++ b/client/components/admin/AdminDiscordManagement.tsx @@ -0,0 +1,318 @@ +import React, { useState, useEffect } from "react"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "../ui/card"; +import { Button } from "../ui/button"; +import { Badge } from "../ui/badge"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogHeader, + AlertDialogTitle, +} from "../ui/alert-dialog"; + +interface RoleMapping { + id: string; + arm: string; + user_type?: string; + discord_role: string; + server_id?: string; + created_at: string; +} + +const ARMS = [ + { value: "labs", label: "Labs", color: "bg-yellow-500/20" }, + { value: "gameforge", label: "GameForge", color: "bg-green-500/20" }, + { value: "corp", label: "Corp", color: "bg-blue-500/20" }, + { value: "foundation", label: "Foundation", color: "bg-red-500/20" }, + { value: "devlink", label: "Dev-Link", color: "bg-cyan-500/20" }, +]; + +export function AdminDiscordManagement() { + const [mappings, setMappings] = useState([]); + const [loading, setLoading] = useState(true); + const [newMapping, setNewMapping] = useState({ + arm: "labs", + discord_role: "", + server_id: "", + }); + const [editingId, setEditingId] = useState(null); + const [deleteId, setDeleteId] = useState(null); + const [error, setError] = useState(null); + const [success, setSuccess] = useState(null); + + useEffect(() => { + fetchMappings(); + }, []); + + const fetchMappings = async () => { + try { + setLoading(true); + const response = await fetch("/api/discord/role-mappings"); + if (!response.ok) throw new Error("Failed to fetch mappings"); + const data = await response.json(); + setMappings(data); + setError(null); + } catch (err) { + console.error("Error fetching mappings:", err); + setError("Failed to load role mappings"); + } finally { + setLoading(false); + } + }; + + const handleCreateMapping = async (e: React.FormEvent) => { + e.preventDefault(); + if (!newMapping.discord_role) { + setError("Discord role is required"); + return; + } + + try { + const response = await fetch("/api/discord/role-mappings", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(newMapping), + }); + + if (!response.ok) throw new Error("Failed to create mapping"); + const data = await response.json(); + setMappings([...mappings, data]); + setNewMapping({ arm: "labs", discord_role: "", server_id: "" }); + setSuccess("Role mapping created successfully!"); + setTimeout(() => setSuccess(null), 3000); + } catch (err) { + console.error("Error creating mapping:", err); + setError("Failed to create role mapping"); + } + }; + + const handleDeleteMapping = async (id: string) => { + try { + const response = await fetch(`/api/discord/role-mappings?id=${id}`, { + method: "DELETE", + }); + + if (!response.ok) throw new Error("Failed to delete mapping"); + setMappings(mappings.filter((m) => m.id !== id)); + setSuccess("Role mapping deleted successfully!"); + setTimeout(() => setSuccess(null), 3000); + } catch (err) { + console.error("Error deleting mapping:", err); + setError("Failed to delete role mapping"); + } finally { + setDeleteId(null); + } + }; + + const getArmLabel = (armValue: string) => { + return ARMS.find((a) => a.value === armValue)?.label || armValue; + }; + + return ( +
+ {/* Bot Status */} + + + Discord Bot Status + Real-time bot configuration + + +
+
+

Bot Status

+

Online

+
+
+

Linked Accounts

+

+ {mappings.length > 0 ? "Active" : "0"} +

+
+
+

Role Mappings

+

+ {mappings.length} +

+
+
+

Servers

+

6

+
+
+
+
+ + {/* Role Mappings */} + + + Discord Role Mappings + + Configure which Discord roles are assigned for each arm + + + + {error && ( +
+ {error} +
+ )} + {success && ( +
+ {success} +
+ )} + + {/* Add New Mapping Form */} +
+

Add New Role Mapping

+
+
+
+ + +
+ +
+ + + setNewMapping({ + ...newMapping, + discord_role: e.target.value, + }) + } + className="w-full mt-1 bg-gray-800 border border-purple-500/30 rounded px-3 py-2 text-white focus:outline-none focus:border-purple-500" + /> +
+ +
+ + + setNewMapping({ ...newMapping, server_id: e.target.value }) + } + className="w-full mt-1 bg-gray-800 border border-purple-500/30 rounded px-3 py-2 text-white focus:outline-none focus:border-purple-500" + /> +
+
+ + +
+
+ + {/* Mappings Table */} + {loading ? ( +
+ Loading mappings... +
+ ) : mappings.length === 0 ? ( +
+ No role mappings configured yet. Add one above! +
+ ) : ( +
+ + + + + + + + + + + {mappings.map((mapping) => ( + + + + + + + ))} + +
Arm + Discord Role + + Server ID + + Actions +
+ + {getArmLabel(mapping.arm)} + + + {mapping.discord_role} + + {mapping.server_id || "Global"} + + +
+
+ )} +
+
+ + {/* Delete Confirmation */} + !open && setDeleteId(null)}> + + + Delete Role Mapping? + + This role mapping will be permanently deleted. Users will no longer + receive this role when setting this arm. + + + Cancel + deleteId && handleDeleteMapping(deleteId)} + className="bg-red-600 hover:bg-red-700" + > + Delete + + + +
+ ); +}