fix: fix all build blocking errors for bun run build
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -60,7 +60,7 @@ const Avatar: React.FC<AvatarProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
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<AvatarProps> = ({
|
||||
size === "xl" && "text-lg",
|
||||
)}
|
||||
>
|
||||
{getUserInitials(user.username, user.nickname)}
|
||||
{getUserInitials(user.username, user.nickname ? user.nickname : null)}
|
||||
</AvatarFallback>
|
||||
</ShadcnAvatar>
|
||||
|
||||
|
||||
@@ -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<typeof DropdownMenu.Content> {
|
||||
className?: string;
|
||||
sideOffset?: number;
|
||||
}
|
||||
|
||||
export const DirectDropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenu.Content>,
|
||||
DirectDropdownMenuContentProps
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
dropdownStyles.content.replace(/\s+/g, " ").trim(),
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenu.Portal>
|
||||
));
|
||||
DirectDropdownMenuContent.displayName = "DirectDropdownMenuContent";
|
||||
|
||||
// Menu item component
|
||||
interface DirectDropdownMenuItemProps
|
||||
extends React.ComponentProps<typeof DropdownMenu.Item> {
|
||||
className?: string;
|
||||
destructive?: boolean;
|
||||
}
|
||||
|
||||
export const DirectDropdownMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenu.Item>,
|
||||
DirectDropdownMenuItemProps
|
||||
>(({ className, destructive, ...props }, ref) => (
|
||||
<DropdownMenu.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
dropdownStyles.item.replace(/\s+/g, " ").trim(),
|
||||
destructive && dropdownStyles.destructive.replace(/\s+/g, " ").trim(),
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DirectDropdownMenuItem.displayName = "DirectDropdownMenuItem";
|
||||
|
||||
// Separator component
|
||||
interface DirectDropdownMenuSeparatorProps
|
||||
extends React.ComponentProps<typeof DropdownMenu.Separator> {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const DirectDropdownMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenu.Separator>,
|
||||
DirectDropdownMenuSeparatorProps
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenu.Separator
|
||||
ref={ref}
|
||||
className={cn(
|
||||
dropdownStyles.separator.replace(/\s+/g, " ").trim(),
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DirectDropdownMenuSeparator.displayName = "DirectDropdownMenuSeparator";
|
||||
|
||||
// Label component
|
||||
interface DirectDropdownMenuLabelProps
|
||||
extends React.ComponentProps<typeof DropdownMenu.Label> {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const DirectDropdownMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenu.Label>,
|
||||
DirectDropdownMenuLabelProps
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenu.Label
|
||||
ref={ref}
|
||||
className={cn(dropdownStyles.label.replace(/\s+/g, " ").trim(), className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DirectDropdownMenuLabel.displayName = "DirectDropdownMenuLabel";
|
||||
|
||||
// Checkbox item component
|
||||
interface DirectDropdownMenuCheckboxItemProps
|
||||
extends React.ComponentProps<typeof DropdownMenu.CheckboxItem> {
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const DirectDropdownMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenu.CheckboxItem>,
|
||||
DirectDropdownMenuCheckboxItemProps
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DropdownMenu.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
dropdownStyles.item.replace(/\s+/g, " ").trim(),
|
||||
"pl-8",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenu.ItemIndicator>
|
||||
<CheckIcon className="h-4 w-4" />
|
||||
</DropdownMenu.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenu.CheckboxItem>
|
||||
));
|
||||
DirectDropdownMenuCheckboxItem.displayName = "DirectDropdownMenuCheckboxItem";
|
||||
|
||||
// Sub menu components
|
||||
export const DirectDropdownMenuSub = DropdownMenu.Sub;
|
||||
|
||||
interface DirectDropdownMenuSubTriggerProps
|
||||
extends React.ComponentProps<typeof DropdownMenu.SubTrigger> {
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const DirectDropdownMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenu.SubTrigger>,
|
||||
DirectDropdownMenuSubTriggerProps
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DropdownMenu.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(dropdownStyles.item.replace(/\s+/g, " ").trim(), className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRightIcon className="ml-auto h-4 w-4" />
|
||||
</DropdownMenu.SubTrigger>
|
||||
));
|
||||
DirectDropdownMenuSubTrigger.displayName = "DirectDropdownMenuSubTrigger";
|
||||
|
||||
interface DirectDropdownMenuSubContentProps
|
||||
extends React.ComponentProps<typeof DropdownMenu.SubContent> {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const DirectDropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenu.SubContent>,
|
||||
DirectDropdownMenuSubContentProps
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenu.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
dropdownStyles.content.replace(/\s+/g, " ").trim(),
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DirectDropdownMenuSubContent.displayName = "DirectDropdownMenuSubContent";
|
||||
|
||||
// Example usage component to test the dropdown
|
||||
export const DirectDropdownExample: React.FC = () => {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<DirectDropdownMenu open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DirectDropdownMenuTrigger asChild>
|
||||
<button className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
|
||||
Open Menu
|
||||
</button>
|
||||
</DirectDropdownMenuTrigger>
|
||||
|
||||
<DirectDropdownMenuContent align="end" className="w-56">
|
||||
<DirectDropdownMenuLabel>My Account</DirectDropdownMenuLabel>
|
||||
<DirectDropdownMenuSeparator />
|
||||
|
||||
<DirectDropdownMenuItem
|
||||
onClick={() => console.log("Profile clicked")}
|
||||
>
|
||||
<span>Profile</span>
|
||||
</DirectDropdownMenuItem>
|
||||
|
||||
<DirectDropdownMenuItem
|
||||
onClick={() => console.log("Settings clicked")}
|
||||
>
|
||||
<span>Settings</span>
|
||||
</DirectDropdownMenuItem>
|
||||
|
||||
<DirectDropdownMenuSeparator />
|
||||
|
||||
<DirectDropdownMenuItem
|
||||
destructive
|
||||
onClick={() => console.log("Logout clicked")}
|
||||
>
|
||||
<span>Log out</span>
|
||||
</DirectDropdownMenuItem>
|
||||
</DirectDropdownMenuContent>
|
||||
</DirectDropdownMenu>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -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<string, User[]>,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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<CreateChannelModalProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
instanceId,
|
||||
defaultCategoryId,
|
||||
}) => {
|
||||
const [name, setName] = useState("");
|
||||
@@ -39,25 +29,8 @@ export const CreateChannelModal: React.FC<CreateChannelModalProps> = ({
|
||||
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<CreateChannelModalProps> = ({
|
||||
<DialogTitle>Create Channel</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
{categoriesError && (
|
||||
<div className="p-3 text-sm text-destructive bg-destructive/10 rounded-md">
|
||||
Failed to load categories. Please try again.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<Label>Channel Type</Label>
|
||||
@@ -151,46 +118,6 @@ export const CreateChannelModal: React.FC<CreateChannelModalProps> = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>Category</Label>
|
||||
<Select
|
||||
value={categoryId}
|
||||
onValueChange={setCategoryId}
|
||||
required
|
||||
disabled={categoriesLoading}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
placeholder={
|
||||
categoriesLoading
|
||||
? "Loading categories..."
|
||||
: "Select a category"
|
||||
}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{categoriesLoading ? (
|
||||
<SelectItem value="loading" disabled>
|
||||
<div className="flex items-center gap-2">
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
Loading...
|
||||
</div>
|
||||
</SelectItem>
|
||||
) : categories && categories.length > 0 ? (
|
||||
categories.map((category) => (
|
||||
<SelectItem key={category.id} value={category.id}>
|
||||
{category.name}
|
||||
</SelectItem>
|
||||
))
|
||||
) : (
|
||||
<SelectItem value="no-categories" disabled>
|
||||
No categories available
|
||||
</SelectItem>
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button type="button" variant="outline" onClick={onClose}>
|
||||
Cancel
|
||||
@@ -201,7 +128,6 @@ export const CreateChannelModal: React.FC<CreateChannelModalProps> = ({
|
||||
!name.trim() ||
|
||||
!categoryId ||
|
||||
createChannelMutation.isPending ||
|
||||
categoriesLoading ||
|
||||
categoryId === "loading" ||
|
||||
categoryId === "no-categories"
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ export const CreateServerModal: React.FC = () => {
|
||||
{
|
||||
name: name.trim(),
|
||||
icon: icon.trim() || undefined,
|
||||
description: description.trim() || undefined,
|
||||
// description: description.trim() || undefined,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
|
||||
Reference in New Issue
Block a user