diff --git a/concord-client/bun.lock b/concord-client/bun.lock index 89b916f..101ef0e 100644 --- a/concord-client/bun.lock +++ b/concord-client/bun.lock @@ -18,7 +18,6 @@ "@tailwindcss/vite": "^4.1.13", "@tanstack/react-query": "^5.90.2", "@tanstack/react-query-devtools": "^5.90.2", - "bcrypt": "^6.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", @@ -501,8 +500,6 @@ "baseline-browser-mapping": ["baseline-browser-mapping@2.8.7", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-bxxN2M3a4d1CRoQC//IqsR5XrLh0IJ8TCv2x6Y9N0nckNz/rTjZB3//GGscZziZOxmjP55rzxg/ze7usFI9FqQ=="], - "bcrypt": ["bcrypt@6.0.0", "", { "dependencies": { "node-addon-api": "^8.3.0", "node-gyp-build": "^4.8.4" } }, "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg=="], - "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="], @@ -1051,9 +1048,7 @@ "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], - "node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="], - - "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], + "node-addon-api": ["node-addon-api@1.7.2", "", {}, "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="], "node-releases": ["node-releases@2.0.21", "", {}, "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw=="], @@ -1431,8 +1426,6 @@ "hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], - "iconv-corefoundation/node-addon-api": ["node-addon-api@1.7.2", "", {}, "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="], - "lazystream/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], diff --git a/concord-client/package.json b/concord-client/package.json index 0c74498..d97c2a2 100644 --- a/concord-client/package.json +++ b/concord-client/package.json @@ -24,7 +24,6 @@ "@tailwindcss/vite": "^4.1.13", "@tanstack/react-query": "^5.90.2", "@tanstack/react-query-devtools": "^5.90.2", - "bcrypt": "^6.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", diff --git a/concord-client/src/App.tsx b/concord-client/src/App.tsx index 4c5a7db..9001049 100644 --- a/concord-client/src/App.tsx +++ b/concord-client/src/App.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect } from "react"; import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router"; import { QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; diff --git a/concord-client/src/components/channel/ChannelList.tsx b/concord-client/src/components/channel/ChannelList.tsx index caec7c6..89a6a96 100644 --- a/concord-client/src/components/channel/ChannelList.tsx +++ b/concord-client/src/components/channel/ChannelList.tsx @@ -1,5 +1,4 @@ import React, { useState } from "react"; -import { useNavigate, useParams } from "react-router"; import { ChevronDown, ChevronRight, Plus, Edit } from "lucide-react"; import { Button } from "@/components/ui/button"; import { @@ -10,7 +9,6 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { CategoryWithChannels } from "@/types/api"; -import { Channel } from "@/types/database"; import ChannelItem from "@/components/channel/ChannelItem"; interface CategoryHeaderProps { diff --git a/concord-client/src/components/common/Avatar.tsx b/concord-client/src/components/common/Avatar.tsx index d446ac7..c75e9f7 100644 --- a/concord-client/src/components/common/Avatar.tsx +++ b/concord-client/src/components/common/Avatar.tsx @@ -60,7 +60,7 @@ const Avatar: React.FC = ({ } }; - const getUserInitials = (username: string, nickname?: string) => { + const getUserInitials = (username: string, nickname: string | null) => { const name = nickname || username; return name .split(" ") @@ -116,7 +116,7 @@ const Avatar: React.FC = ({ size === "xl" && "text-lg", )} > - {getUserInitials(user.username, user.nickname)} + {getUserInitials(user.username, user.nickname ? user.nickname : null)} diff --git a/concord-client/src/components/direct-dropdown.tsx b/concord-client/src/components/direct-dropdown.tsx deleted file mode 100644 index 5a08725..0000000 --- a/concord-client/src/components/direct-dropdown.tsx +++ /dev/null @@ -1,276 +0,0 @@ -import * as React from "react"; -import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; -import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; - -// Basic dropdown styles -const dropdownStyles = { - content: ` - min-w-[220px] - bg-white dark:bg-gray-800 - border border-gray-200 dark:border-gray-700 - rounded-md - p-1 - shadow-lg - z-50 - animate-in - fade-in-80 - data-[state=open]:animate-in - data-[state=closed]:animate-out - data-[state=closed]:fade-out-0 - data-[state=open]:fade-in-0 - data-[state=closed]:zoom-out-95 - data-[state=open]:zoom-in-95 - data-[side=bottom]:slide-in-from-top-2 - data-[side=left]:slide-in-from-right-2 - data-[side=right]:slide-in-from-left-2 - data-[side=top]:slide-in-from-bottom-2 - `, - item: ` - relative - flex - cursor-pointer - select-none - items-center - rounded-sm - px-2 - py-1.5 - text-sm - outline-none - transition-colors - hover:bg-gray-100 dark:hover:bg-gray-700 - focus:bg-gray-100 dark:focus:bg-gray-700 - data-[disabled]:pointer-events-none - data-[disabled]:opacity-50 - `, - separator: ` - -mx-1 - my-1 - h-px - bg-gray-200 dark:bg-gray-700 - `, - label: ` - px-2 - py-1.5 - text-sm - font-semibold - text-gray-500 dark:text-gray-400 - `, - destructive: ` - text-red-600 dark:text-red-400 - hover:bg-red-50 dark:hover:bg-red-900/20 - focus:bg-red-50 dark:focus:bg-red-900/20 - `, -}; - -// Utility to combine class names -const cn = (...classes: (string | undefined | false)[]) => { - return classes.filter(Boolean).join(" "); -}; - -// Root dropdown menu -export const DirectDropdownMenu = DropdownMenu.Root; -export const DirectDropdownMenuTrigger = DropdownMenu.Trigger; - -// Content component with styling -interface DirectDropdownMenuContentProps - extends React.ComponentProps { - className?: string; - sideOffset?: number; -} - -export const DirectDropdownMenuContent = React.forwardRef< - React.ElementRef, - DirectDropdownMenuContentProps ->(({ className, sideOffset = 4, ...props }, ref) => ( - - - -)); -DirectDropdownMenuContent.displayName = "DirectDropdownMenuContent"; - -// Menu item component -interface DirectDropdownMenuItemProps - extends React.ComponentProps { - className?: string; - destructive?: boolean; -} - -export const DirectDropdownMenuItem = React.forwardRef< - React.ElementRef, - DirectDropdownMenuItemProps ->(({ className, destructive, ...props }, ref) => ( - -)); -DirectDropdownMenuItem.displayName = "DirectDropdownMenuItem"; - -// Separator component -interface DirectDropdownMenuSeparatorProps - extends React.ComponentProps { - className?: string; -} - -export const DirectDropdownMenuSeparator = React.forwardRef< - React.ElementRef, - DirectDropdownMenuSeparatorProps ->(({ className, ...props }, ref) => ( - -)); -DirectDropdownMenuSeparator.displayName = "DirectDropdownMenuSeparator"; - -// Label component -interface DirectDropdownMenuLabelProps - extends React.ComponentProps { - className?: string; -} - -export const DirectDropdownMenuLabel = React.forwardRef< - React.ElementRef, - DirectDropdownMenuLabelProps ->(({ className, ...props }, ref) => ( - -)); -DirectDropdownMenuLabel.displayName = "DirectDropdownMenuLabel"; - -// Checkbox item component -interface DirectDropdownMenuCheckboxItemProps - extends React.ComponentProps { - className?: string; - children: React.ReactNode; -} - -export const DirectDropdownMenuCheckboxItem = React.forwardRef< - React.ElementRef, - DirectDropdownMenuCheckboxItemProps ->(({ className, children, ...props }, ref) => ( - - - - - - - {children} - -)); -DirectDropdownMenuCheckboxItem.displayName = "DirectDropdownMenuCheckboxItem"; - -// Sub menu components -export const DirectDropdownMenuSub = DropdownMenu.Sub; - -interface DirectDropdownMenuSubTriggerProps - extends React.ComponentProps { - className?: string; - children: React.ReactNode; -} - -export const DirectDropdownMenuSubTrigger = React.forwardRef< - React.ElementRef, - DirectDropdownMenuSubTriggerProps ->(({ className, children, ...props }, ref) => ( - - {children} - - -)); -DirectDropdownMenuSubTrigger.displayName = "DirectDropdownMenuSubTrigger"; - -interface DirectDropdownMenuSubContentProps - extends React.ComponentProps { - className?: string; -} - -export const DirectDropdownMenuSubContent = React.forwardRef< - React.ElementRef, - DirectDropdownMenuSubContentProps ->(({ className, ...props }, ref) => ( - -)); -DirectDropdownMenuSubContent.displayName = "DirectDropdownMenuSubContent"; - -// Example usage component to test the dropdown -export const DirectDropdownExample: React.FC = () => { - const [isOpen, setIsOpen] = React.useState(false); - - return ( -
- - - - - - - My Account - - - console.log("Profile clicked")} - > - Profile - - - console.log("Settings clicked")} - > - Settings - - - - - console.log("Logout clicked")} - > - Log out - - - -
- ); -}; diff --git a/concord-client/src/components/layout/MemberList.tsx b/concord-client/src/components/layout/MemberList.tsx index efa426d..5181cdb 100644 --- a/concord-client/src/components/layout/MemberList.tsx +++ b/concord-client/src/components/layout/MemberList.tsx @@ -1,5 +1,4 @@ -// src/components/layout/MemberList.tsx - Enhanced with role management -import React, { useState } from "react"; +import React from "react"; import { useParams } from "react-router"; import { Crown, Shield, UserIcon } from "lucide-react"; import { ScrollArea } from "@/components/ui/scroll-area"; @@ -28,6 +27,7 @@ interface MemberItemProps { member: User; instanceId: string; isOwner?: boolean; + currentUserRole: "member" | "mod" | "admin"; } // Get the user's role for this specific instance @@ -155,7 +155,7 @@ const MemberList: React.FC = () => { if (!acc[roleInfo.name]) { acc[roleInfo.name] = []; } - acc[roleInfo.name].push(member); + acc[roleInfo.name].push(member as User); return acc; }, {} as Record, diff --git a/concord-client/src/components/layout/ServerSidebar.tsx b/concord-client/src/components/layout/ServerSidebar.tsx index 35a342d..58b8f67 100644 --- a/concord-client/src/components/layout/ServerSidebar.tsx +++ b/concord-client/src/components/layout/ServerSidebar.tsx @@ -13,7 +13,6 @@ 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(); diff --git a/concord-client/src/components/layout/UserPanel.tsx b/concord-client/src/components/layout/UserPanel.tsx index bce22c8..9c718f9 100644 --- a/concord-client/src/components/layout/UserPanel.tsx +++ b/concord-client/src/components/layout/UserPanel.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React from "react"; import { Settings, Mic, MicOff, Headphones } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; diff --git a/concord-client/src/components/modals/CreateChannelModal.tsx b/concord-client/src/components/modals/CreateChannelModal.tsx index dc2ab42..ee46cd7 100644 --- a/concord-client/src/components/modals/CreateChannelModal.tsx +++ b/concord-client/src/components/modals/CreateChannelModal.tsx @@ -9,17 +9,8 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; 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; @@ -31,7 +22,6 @@ interface CreateChannelModalProps { export const CreateChannelModal: React.FC = ({ isOpen, onClose, - instanceId, defaultCategoryId, }) => { const [name, setName] = useState(""); @@ -39,25 +29,8 @@ 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) { @@ -98,12 +71,6 @@ export const CreateChannelModal: React.FC = ({ Create Channel - {categoriesError && ( -
- Failed to load categories. Please try again. -
- )} -
@@ -151,46 +118,6 @@ export const CreateChannelModal: React.FC = ({ />
-
- - -
-