1 import { Check, ChevronsUpDown, Eye, File, FileUp } from "lucide-react";
2 import { useEffect, useRef, useState } from "react";
3 import { Textarea } from "../ui/textarea";
4 import {
5 Select,
6 SelectContent,
7 SelectItem,
8 SelectTrigger,
9 SelectValue,
10 } from "../ui/select";
11 import {
12 Popover,
13 PopoverContent,
14 PopoverTrigger,
15 } from "@/components/ui/popover";
16 import { Button } from "../ui/button";
17 import { UploadedFileInformationProps } from "@/lib/types";
18 import {
19 Command,
20 CommandEmpty,
21 CommandGroup,
22 CommandInput,
23 CommandItem,
24 CommandList,
25 } from "@/components/ui/command";
26
27 import { cn } from "@/lib/utils";
28 import useDebounce from "@/lib/hooks/use-debounce";
29 import searchClients from "@/lib/actions/application";
30 import { toast } from "sonner";
31
32 interface ClientList {
33 label: string;
34 value: string;
35 }
36
37 export const ClientInformation = () => {
38 const [open, setOpen] = useState<boolean>(false);
39 const [value, setValue] = useState("");
40 const [searchTerm, setSearchTerm] = useState("");
41 const [clients, setClients] = useState<ClientList[]>([]);
42
43 const debouncedValue = useDebounce(searchTerm, 1500);
44
45 useEffect(() => {
46 const fetchClients = async (search: string) => {
47 try {
48 if (!search.trim()) {
49 setClients([]);
50 return;
51 }
52
53 const response = await searchClients(search);
54 setClients(response);
55 } catch (error: any) {
56 toast.error(error.message);
57 }
58 };
59
60 fetchClients(debouncedValue);
61 }, [debouncedValue]);
62
63 return (
64 <Popover open={open} onOpenChange={setOpen}>
65 <PopoverTrigger asChild>
66 <Button
67 variant="outline"
68 role="combobox"
69 aria-expanded={open}
70 className="w-[600px] justify-between"
71 >
72 {value
73 ? clients.find((client) => client.value === value)?.label
74 : "Select framework..."}
75 <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
76 </Button>
77 </PopoverTrigger>
78 <PopoverContent className="w-[600px] p-0">
79 <Command>
80 <CommandInput
81 value={searchTerm}
82 onValueChange={(event) => setSearchTerm(event)}
83 placeholder="Search framework..."
84 />
85
86 <CommandList>
87 {clients.length === 0 ? (
88 <CommandEmpty>No client found.</CommandEmpty>
89 ) : (
90 <CommandGroup>
91 {clients.map((client) => (
92 <CommandItem
93 key={client.value}
94 value={client.value}
95 onSelect={(currentValue) => {
96 setValue(currentValue === value ? "" : currentValue);
97 setOpen(false);
98 }}
99 >
100 <Check
101 className={cn(
102 "mr-2 h-4 w-4",
103 value === client.value ? "opacity-100" : "opacity-0"
104 )}
105 />
106 {client.label}
107 </CommandItem>
108 ))}
109 </CommandGroup>
110 )}
111 </CommandList>
112 </Command>
113 </PopoverContent>
114 </Popover>
115 );
116 };
117
118
119 "use server";
120
121 export default async function searchClients(searchValue: string) {
122 try {
123 const response = await prisma?.client.findMany({
124 where: {
125 businessName: {
126 contains: searchValue,
127 },
128 },
129 select: {
130 id: true,
131 businessName: true,
132 },
133 });
134
135 if (!response) {
136 throw new Error("No clients found with the given search value.");
137 }
138
139 const clients = response.map((res) => ({
140 label: res.businessName,
141 value: res.id.toString(),
142 }));
143
144 return clients;
145 } catch (error) {
146 if (error instanceof Error) {
147 throw new Error(error.message);
148 } else {
149 throw new Error("something went wrong.");
150 }
151 }
152 }
What I have tried:
Duplicate 152 line unexplained code-dump removed.