From a5e7fa4bc69239bcc8bc43e5e31a016813d87a6d Mon Sep 17 00:00:00 2001 From: Gabriel Garcia Date: Sun, 28 Sep 2025 07:46:11 -0400 Subject: [PATCH] sad --- .../src/components/layout/ChannelSidebar.tsx | 3 + .../src/components/layout/MemberList.tsx | 49 +- .../src/components/layout/ServerSidebar.tsx | 3 +- .../components/modals/CreateChannelModal.tsx | 97 +++- .../components/modals/EditMessageModal.tsx | 121 ---- .../components/modals/MessageActionsModal.tsx | 42 +- .../components/modals/PinnedMessagesModal.tsx | 155 ------ .../src/components/modals/UserRoleModal.tsx | 262 --------- .../src/components/modals/UserStatusModal.tsx | 83 --- .../src/components/theme-selector.tsx | 526 ++++++++++-------- concord-client/src/hooks/useCategories.ts | 139 +++++ concord-client/src/lib/api-client.ts | 8 +- concord-client/src/pages/ChatPage.tsx | 179 ++---- concord-client/src/pages/LoginPage.tsx | 2 +- concord-client/src/pages/NotFoundPage.tsx | 2 +- concord-client/src/pages/SettingsPage.tsx | 105 +++- concord-server/src/services/messageService.ts | 7 +- 17 files changed, 687 insertions(+), 1096 deletions(-) delete mode 100644 concord-client/src/components/modals/EditMessageModal.tsx delete mode 100644 concord-client/src/components/modals/PinnedMessagesModal.tsx delete mode 100644 concord-client/src/components/modals/UserRoleModal.tsx delete mode 100644 concord-client/src/components/modals/UserStatusModal.tsx create mode 100644 concord-client/src/hooks/useCategories.ts diff --git a/concord-client/src/components/layout/ChannelSidebar.tsx b/concord-client/src/components/layout/ChannelSidebar.tsx index e16d933..3968960 100644 --- a/concord-client/src/components/layout/ChannelSidebar.tsx +++ b/concord-client/src/components/layout/ChannelSidebar.tsx @@ -6,6 +6,7 @@ import { ScrollArea } from "@/components/ui/scroll-area"; import { useInstanceDetails } from "@/hooks/useServers"; import { useUiStore } from "@/stores/uiStore"; import ChannelList from "@/components/channel/ChannelList"; +import { CreateCategoryModal, CreateChannelModal } from "../server/ServerIcon"; const ChannelSidebar: React.FC = () => { const { instanceId } = useParams(); @@ -94,6 +95,8 @@ const ChannelSidebar: React.FC = () => { + + ); }; diff --git a/concord-client/src/components/layout/MemberList.tsx b/concord-client/src/components/layout/MemberList.tsx index cfd5422..efa426d 100644 --- a/concord-client/src/components/layout/MemberList.tsx +++ b/concord-client/src/components/layout/MemberList.tsx @@ -9,7 +9,6 @@ import { Role } from "@/types/database"; import { useInstanceMembers } from "@/hooks/useServers"; import { useAuthStore } from "@/stores/authStore"; import { User } from "@/types/database"; -import { UserRoleModal } from "@/components/modals/UserRoleModal"; // Status color utility const getStatusColor = (status: string) => { @@ -28,8 +27,6 @@ const getStatusColor = (status: string) => { interface MemberItemProps { member: User; instanceId: string; - currentUserRole: string; - canManageRoles: boolean; isOwner?: boolean; } @@ -53,27 +50,17 @@ const getRoleInfo = (role: string) => { const MemberItem: React.FC = ({ member, instanceId, - currentUserRole, - canManageRoles, isOwner = false, }) => { - const [showUserModal, setShowUserModal] = useState(false); const userRole = getUserRoleForInstance(member.roles, instanceId || ""); const roleInfo = getRoleInfo(userRole); - const handleMemberClick = () => { - if (canManageRoles && !member.admin) { - setShowUserModal(true); - } - }; - return ( <> - - {/* User Role Modal */} - setShowUserModal(false)} - user={member} - instanceId={instanceId} - currentUserRole={currentUserRole} - canManageRoles={canManageRoles} - /> ); }; @@ -138,20 +115,6 @@ const MemberList: React.FC = () => { const { data: members, isLoading } = useInstanceMembers(instanceId); const { user: currentUser } = useAuthStore(); - // Check if current user can manage roles - const canManageRoles = React.useMemo(() => { - if (!currentUser || !instanceId) return false; - - // Global admins can manage roles - if (currentUser.admin) return true; - - // Check if user is admin or mod in this instance - const userRole = currentUser.roles.find( - (role) => role.instanceId === instanceId, - ); - return userRole && (userRole.role === "admin" || userRole.role === "mod"); - }, [currentUser, instanceId]); - const currentUserRole = React.useMemo(() => { if (!currentUser || !instanceId) return "member"; if (currentUser.admin) return "admin"; @@ -212,12 +175,9 @@ const MemberList: React.FC = () => { {/* Header */}
-
-

- Members: {members.length} Online:{" "} - {members.filter((m) => m.status === "online").length} -

-
+

+ {members.length} Members +

{/* Member List */} @@ -242,7 +202,6 @@ const MemberList: React.FC = () => { member={member} instanceId={instanceId} currentUserRole={currentUserRole} - canManageRoles={canManageRoles} isOwner={false} /> ))} diff --git a/concord-client/src/components/layout/ServerSidebar.tsx b/concord-client/src/components/layout/ServerSidebar.tsx index 650a3d2..35a342d 100644 --- a/concord-client/src/components/layout/ServerSidebar.tsx +++ b/concord-client/src/components/layout/ServerSidebar.tsx @@ -13,6 +13,7 @@ import { useUiStore } from "@/stores/uiStore"; import { useAuthStore } from "@/stores/authStore"; import ServerIcon from "@/components/server/ServerIcon"; import { getAccessibleInstances, isGlobalAdmin } from "@/utils/permissions"; +import { CreateServerModal } from "../modals/CreateServerModal"; const ServerSidebar: React.FC = () => { const navigate = useNavigate(); @@ -40,7 +41,7 @@ const ServerSidebar: React.FC = () => { const handleHomeClick = () => { setActiveInstance(null); - navigate("/channels/@me"); + navigate("/"); }; const handleCreateServer = () => { diff --git a/concord-client/src/components/modals/CreateChannelModal.tsx b/concord-client/src/components/modals/CreateChannelModal.tsx index 177d318..dc2ab42 100644 --- a/concord-client/src/components/modals/CreateChannelModal.tsx +++ b/concord-client/src/components/modals/CreateChannelModal.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { Dialog, DialogContent, @@ -16,21 +16,22 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { Hash, Volume2 } from "lucide-react"; +import { Hash, Volume2, Loader2 } from "lucide-react"; import { useCreateChannel } from "@/hooks/useServers"; +import { useCategoriesByInstance } from "@/hooks/useCategories"; // New hook import { CategoryWithChannels } from "@/types/api"; interface CreateChannelModalProps { isOpen: boolean; onClose: () => void; - categories: CategoryWithChannels[]; + instanceId: string; // Changed to use instanceId instead of categories prop defaultCategoryId?: string; } export const CreateChannelModal: React.FC = ({ isOpen, onClose, - categories, + instanceId, defaultCategoryId, }) => { const [name, setName] = useState(""); @@ -38,8 +39,35 @@ export const CreateChannelModal: React.FC = ({ const [type, setType] = useState<"text" | "voice">("text"); const [categoryId, setCategoryId] = useState(defaultCategoryId || ""); + // Fetch categories using the new API + const { + data: categories, + isLoading: categoriesLoading, + error: categoriesError, + } = useCategoriesByInstance(instanceId); + const createChannelMutation = useCreateChannel(); + // Update categoryId when defaultCategoryId changes or categories load + useEffect(() => { + if (defaultCategoryId) { + setCategoryId(defaultCategoryId); + } else if (categories && categories.length > 0 && !categoryId) { + // Auto-select first category if none selected + setCategoryId(categories[0].id); + } + }, [defaultCategoryId, categories, categoryId]); + + // Reset form when modal opens/closes + useEffect(() => { + if (!isOpen) { + setName(""); + setDescription(""); + setType("text"); + setCategoryId(defaultCategoryId || ""); + } + }, [isOpen, defaultCategoryId]); + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!name.trim() || !categoryId) return; @@ -69,6 +97,13 @@ export const CreateChannelModal: React.FC = ({ Create Channel + + {categoriesError && ( +
+ Failed to load categories. Please try again. +
+ )} +
@@ -118,16 +153,40 @@ export const CreateChannelModal: React.FC = ({
- - + - {categories.map((category) => ( - - {category.name} + {categoriesLoading ? ( + +
+ + Loading... +
- ))} + ) : categories && categories.length > 0 ? ( + categories.map((category) => ( + + {category.name} + + )) + ) : ( + + No categories available + + )}
@@ -139,12 +198,22 @@ export const CreateChannelModal: React.FC = ({
diff --git a/concord-client/src/components/modals/EditMessageModal.tsx b/concord-client/src/components/modals/EditMessageModal.tsx deleted file mode 100644 index 9045bce..0000000 --- a/concord-client/src/components/modals/EditMessageModal.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import React, { useState, useRef, useEffect } from "react"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; -import { Label } from "@/components/ui/label"; -import { Message } from "@/lib/api-client"; -import { useEditMessage } from "@/hooks/useMessages"; - -interface EditMessageModalProps { - isOpen: boolean; - onClose: () => void; - message: Message; - channelId: string; -} - -export const EditMessageModal: React.FC = ({ - isOpen, - onClose, - message, - channelId, -}) => { - const [content, setContent] = useState(message.text); - const textareaRef = useRef(null); - const editMessageMutation = useEditMessage(); - - // Auto-resize textarea - useEffect(() => { - if (textareaRef.current && isOpen) { - textareaRef.current.style.height = "auto"; - textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; - textareaRef.current.focus(); - } - }, [content, isOpen]); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if (content.trim() && content.trim() !== message.text) { - try { - await editMessageMutation.mutateAsync({ - messageId: message.id, - content: content.trim(), - channelId, - }); - onClose(); - } catch (error) { - console.error("Failed to edit message:", error); - } - } - }; - - const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === "Enter" && !e.shiftKey) { - e.preventDefault(); - handleSubmit(e); - } else if (e.key === "Escape") { - onClose(); - } - }; - - const handleCancel = () => { - setContent(message.text); - onClose(); - }; - - return ( - - - - Edit Message - -
-
- -