131 lines
4.6 KiB
TypeScript
131 lines
4.6 KiB
TypeScript
import * as React from "react";
|
|
import { Check, ChevronsUpDown, Search } from "lucide-react";
|
|
import { cn } from "@/components/ui/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 { getAllHsnSacCodes, HsnSacCode } from "@/services/hsnSacCodeApi";
|
|
|
|
interface HsnSacSelectorProps {
|
|
value: string;
|
|
onChange: (value: string) => void;
|
|
type: "HSN" | "SAC";
|
|
placeholder?: string;
|
|
disabled?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
export function HsnSacSelector({
|
|
value,
|
|
onChange,
|
|
type,
|
|
placeholder,
|
|
disabled,
|
|
className,
|
|
}: HsnSacSelectorProps) {
|
|
const [open, setOpen] = React.useState(false);
|
|
const [allCodes, setAllCodes] = React.useState<HsnSacCode[]>([]);
|
|
|
|
React.useEffect(() => {
|
|
const fetchCodes = async () => {
|
|
try {
|
|
const response = await getAllHsnSacCodes(true, 1, 1000);
|
|
setAllCodes(response.codes);
|
|
} catch (error) {
|
|
console.error("Failed to fetch HSN/SAC codes for selector:", error);
|
|
}
|
|
};
|
|
|
|
if (open && allCodes.length === 0) {
|
|
fetchCodes();
|
|
}
|
|
}, [open, allCodes.length]);
|
|
|
|
const filteredCodes = React.useMemo(() => {
|
|
return allCodes.filter((c) => c.type === type);
|
|
}, [allCodes, type]);
|
|
|
|
return (
|
|
<Popover open={open} onOpenChange={setOpen}>
|
|
<PopoverTrigger asChild>
|
|
<Button
|
|
variant="outline"
|
|
role="combobox"
|
|
aria-expanded={open}
|
|
disabled={disabled}
|
|
className={cn("w-full justify-between bg-white font-normal h-9 px-3 text-xs sm:text-sm border-slate-200 hover:bg-slate-50", className)}
|
|
>
|
|
<span className="font-medium text-slate-900">
|
|
{value
|
|
? allCodes.find((code) => code.code === value)?.code || value
|
|
: placeholder || `Select ${type}...`}
|
|
</span>
|
|
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-[320px] p-0 shadow-2xl border-slate-200" align="start">
|
|
<Command className="rounded-lg border-0">
|
|
<div className="bg-slate-50/80 p-2.5 flex items-center gap-2">
|
|
<Search className="w-4 h-4 text-slate-400" />
|
|
<CommandInput
|
|
placeholder={`Search ${type} code...`}
|
|
wrapperClassName="border-none p-0 h-auto flex-1"
|
|
className="h-8 border-none bg-transparent shadow-none ring-0 focus-visible:ring-0 placeholder:text-slate-400 text-sm"
|
|
/>
|
|
</div>
|
|
<CommandList className="max-h-[350px] scrollbar-thin scrollbar-thumb-slate-200">
|
|
<CommandEmpty className="py-8 text-center">
|
|
<div className="flex flex-col items-center gap-2">
|
|
<Search className="h-8 w-8 text-slate-200" />
|
|
<p className="text-sm font-medium text-slate-500">No {type} code found</p>
|
|
<p className="text-xs text-slate-400">Try a different search term</p>
|
|
</div>
|
|
</CommandEmpty>
|
|
<CommandGroup className="p-1.5">
|
|
{filteredCodes.map((code) => (
|
|
<CommandItem
|
|
key={code.id}
|
|
value={code.code}
|
|
onSelect={(currentValue) => {
|
|
onChange(currentValue);
|
|
setOpen(false);
|
|
}}
|
|
className="flex flex-col items-start gap-1 p-2.5 rounded-md aria-selected:bg-slate-100 transition-colors cursor-pointer mb-1 last:mb-0"
|
|
>
|
|
<div className="flex items-center w-full justify-between">
|
|
<span className="font-bold text-sm text-slate-900 leading-none">{code.code}</span>
|
|
<div className="flex items-center gap-2">
|
|
<Check
|
|
className={cn(
|
|
"h-4 w-4 text-re-green transition-all",
|
|
value === code.code ? "opacity-100 scale-100" : "opacity-0 scale-75"
|
|
)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
{code.description && (
|
|
<span className="text-[11px] text-slate-500 line-clamp-2 leading-tight pr-4">
|
|
{code.description}
|
|
</span>
|
|
)}
|
|
</CommandItem>
|
|
))}
|
|
</CommandGroup>
|
|
</CommandList>
|
|
</Command>
|
|
</PopoverContent>
|
|
</Popover>
|
|
);
|
|
}
|