113 lines
3.3 KiB
TypeScript
113 lines
3.3 KiB
TypeScript
import { Check, Loader } from "lucide-react";
|
||
|
||
import { cn } from "../lib/utils";
|
||
import { Button } from "../components/ui/button";
|
||
import {
|
||
Command,
|
||
CommandEmpty,
|
||
CommandGroup,
|
||
CommandInput,
|
||
CommandItem,
|
||
CommandList,
|
||
} from "../components/ui/command";
|
||
import {
|
||
Popover,
|
||
PopoverContent,
|
||
PopoverTrigger,
|
||
} from "../components/ui/popover";
|
||
import { useState } from "react";
|
||
|
||
interface Item {
|
||
value: string | number;
|
||
label: string;
|
||
}
|
||
|
||
interface AppSelectBoxProps {
|
||
items: Item[];
|
||
placeholder?: string;
|
||
haveSearchbar?: boolean;
|
||
value: string;
|
||
setValue: React.Dispatch<React.SetStateAction<string>>;
|
||
loading?: boolean; // New loading prop
|
||
width?: string; // New width prop
|
||
disabled?: boolean;
|
||
title?: string; // Add title prop
|
||
}
|
||
|
||
export default function AppSelectBox({
|
||
haveSearchbar,
|
||
items,
|
||
placeholder,
|
||
value,
|
||
setValue,
|
||
loading = false, // Default to false
|
||
width = "w-[105px]", // Default width
|
||
disabled = false,
|
||
title,
|
||
}: AppSelectBoxProps) {
|
||
const [open, setOpen] = useState(false);
|
||
|
||
return (
|
||
<div className={`w-full flex flex-col ${title ? "gap-2" : "gap-0"}`}>
|
||
{title && (
|
||
<p className="text-R14 text-foreground dark:text-gray-200">{title}</p>
|
||
)}
|
||
<Popover open={open} onOpenChange={setOpen}>
|
||
<PopoverTrigger asChild>
|
||
<Button
|
||
variant="outline"
|
||
size={"lg"}
|
||
aria-expanded={open}
|
||
className={`${width} ${value ? "text-BLACK dark:text-gray-200" : "text-GRAY dark:text-gray-400"} rounded-[12px] border border-input bg-inputBg dark:bg-gray-800 dark:border-gray-600`}
|
||
disabled={disabled || loading} // Disable button when loading
|
||
>
|
||
{loading ? (
|
||
<Loader className="animate-spin" size={16} /> // Show loading spinner
|
||
) : value ? (
|
||
items.find((item: Item) => item.value.toString() === value)?.label
|
||
) : (
|
||
placeholder
|
||
)}
|
||
</Button>
|
||
</PopoverTrigger>
|
||
{!loading && ( // Only show dropdown content when not loading
|
||
<PopoverContent className={`${width} p-0`}>
|
||
<Command>
|
||
{haveSearchbar && (
|
||
<CommandInput placeholder="جستجو" className="h-9" />
|
||
)}
|
||
<CommandList>
|
||
<CommandEmpty>آیتمی وجود نداره</CommandEmpty>
|
||
<CommandGroup>
|
||
{items.map((item: Item) => (
|
||
<CommandItem
|
||
key={item.value}
|
||
value={item.value.toString()}
|
||
onSelect={() => {
|
||
setValue(
|
||
item.value === value ? "" : item.value.toString()
|
||
);
|
||
setOpen(false);
|
||
}}
|
||
>
|
||
{item.label}
|
||
<Check
|
||
className={cn(
|
||
"ml-auto",
|
||
value === item.value.toString()
|
||
? "opacity-100"
|
||
: "opacity-0"
|
||
)}
|
||
/>
|
||
</CommandItem>
|
||
))}
|
||
</CommandGroup>
|
||
</CommandList>
|
||
</Command>
|
||
</PopoverContent>
|
||
)}
|
||
</Popover>
|
||
</div>
|
||
);
|
||
}
|