Skip to content

Commit 1044494

Browse files
authored
Merge pull request #578 from trycompai/main
[comp] Production Deploy
2 parents c901d7a + e757633 commit 1044494

File tree

1 file changed

+71
-80
lines changed

1 file changed

+71
-80
lines changed

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/create-vendor-form.tsx

Lines changed: 71 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ import {
2424
FormMessage,
2525
} from "@comp/ui/form";
2626
import { Input } from "@comp/ui/input";
27-
import {
28-
Popover,
29-
PopoverContent,
30-
PopoverPrimitive,
31-
PopoverTrigger,
32-
} from "@comp/ui/popover";
3327
import {
3428
Select,
3529
SelectContent,
@@ -97,14 +91,13 @@ export function CreateVendorForm({
9791
},
9892
});
9993

100-
// Debounced search function using the custom hook
10194
const debouncedSearch = useDebouncedCallback((query: string) => {
102-
if (query.trim().length > 1) { // Only search if query is longer than 1 char
95+
if (query.trim().length > 1) {
10396
searchVendors.execute({ name: query });
10497
} else {
105-
setSearchResults([]); // Clear results if query is too short
98+
setSearchResults([]);
10699
}
107-
}, 300); // 300ms debounce delay
100+
}, 300);
108101

109102
const form = useForm<z.infer<typeof createVendorSchema>>({
110103
resolver: zodResolver(createVendorSchema),
@@ -115,6 +108,7 @@ export function CreateVendorForm({
115108
category: VendorCategory.cloud,
116109
status: VendorStatus.not_assessed,
117110
},
111+
mode: "onChange",
118112
});
119113

120114
const onSubmit = async (data: z.infer<typeof createVendorSchema>) => {
@@ -131,9 +125,9 @@ export function CreateVendorForm({
131125
form.setValue("name", vendor.company_name ?? vendor.legal_name ?? "");
132126
form.setValue("website", vendor.website ?? "");
133127
form.setValue("description", vendor.company_description ?? "");
134-
setSearchQuery(vendor.company_name ?? vendor.legal_name ?? ""); // Update search query display
135-
setSearchResults([]); // Clear results
136-
setPopoverOpen(false); // Close popover
128+
setSearchQuery(vendor.company_name ?? vendor.legal_name ?? "");
129+
setSearchResults([]);
130+
setPopoverOpen(false);
137131
};
138132

139133
return (
@@ -152,82 +146,79 @@ export function CreateVendorForm({
152146
control={form.control}
153147
name="name"
154148
render={({ field }) => (
155-
<FormItem className="flex flex-col">
149+
<FormItem className="flex flex-col relative">
156150
<FormLabel>
157151
{t(
158152
"vendors.form.vendor_name",
159153
)}
160154
</FormLabel>
161-
<Popover open={popoverOpen} onOpenChange={setPopoverOpen}>
162-
<PopoverTrigger asChild>
163-
<FormControl>
164-
<Button
165-
variant="outline"
166-
role="combobox"
167-
aria-expanded={popoverOpen}
168-
className={cn("w-full justify-between", !field.value && "text-muted-foreground")}
169-
>
170-
{field.value || t("vendors.form.vendor_name_placeholder")}
171-
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
172-
</Button>
173-
</FormControl>
174-
</PopoverTrigger>
175-
<PopoverContent className="w-[--radix-popover-trigger-width] p-0">
176-
<Command shouldFilter={false}> {/* Disable default filtering */}
177-
<CommandInput
178-
placeholder={t("vendors.form.search_vendor_placeholder")} // Add a new translation key
179-
value={searchQuery}
180-
onValueChange={(value) => {
181-
setSearchQuery(value);
182-
// Also update the form field in real-time if user types without selecting
183-
// This allows creating a custom vendor
184-
field.onChange(value);
185-
// Trigger debounced search
186-
debouncedSearch(value);
187-
}}
188-
autoFocus
189-
/>
190-
<CommandList>
191-
<CommandEmpty>
192-
{isSearching ? t("common.loading") : t("vendors.form.no_vendor_found")} {/* Add new translation keys */}
193-
</CommandEmpty>
194-
<CommandGroup heading={t("vendors.form.suggestions")}> {/* Add new translation key */}
195-
{searchResults.map((vendor) => (
196-
<CommandItem
197-
key={vendor.website}
198-
value={vendor.company_name ?? vendor.website} // Use a unique value for CommandItem
199-
onSelect={() => handleSelectVendor(vendor)}
200-
className="cursor-pointer"
201-
>
202-
{/* Check icon can be used if needed, but maybe confusing here */}
203-
{/* <Check
204-
className={cn(
205-
"mr-2 h-4 w-4",
206-
(form.getValues("name") === vendor.company_name || form.getValues("name") === vendor.legal_name) ? "opacity-100" : "opacity-0",
207-
)}
208-
/> */}
209-
{vendor.company_name ?? vendor.legal_name ?? vendor.website}
210-
</CommandItem>
211-
))}
212-
{/* Option to explicitly create the custom vendor typed */}
213-
{searchQuery && !isSearching && searchResults.length === 0 && (
214-
<CommandItem
215-
key="custom"
216-
value={searchQuery}
217-
onSelect={() => {
218-
field.onChange(searchQuery); // Ensure form field has the typed value
155+
<FormControl>
156+
<div className="relative">
157+
<Input
158+
placeholder={t("vendors.form.search_vendor_placeholder")}
159+
value={searchQuery}
160+
onChange={(e) => {
161+
const val = e.target.value;
162+
setSearchQuery(val);
163+
field.onChange(val);
164+
debouncedSearch(val);
165+
if (val.trim().length > 1) {
166+
setPopoverOpen(true);
167+
} else {
168+
setPopoverOpen(false);
169+
setSearchResults([]);
170+
}
171+
}}
172+
onBlur={() => {
173+
setTimeout(() => setPopoverOpen(false), 150);
174+
}}
175+
onFocus={() => {
176+
if (searchQuery.trim().length > 1 && (isSearching || searchResults.length > 0 || (!isSearching && searchResults.length === 0))) {
177+
setPopoverOpen(true);
178+
}
179+
}}
180+
autoFocus
181+
/>
182+
{popoverOpen && (
183+
<div className="absolute top-full z-10 w-full mt-1 bg-background border rounded-md shadow-lg">
184+
<div className="max-h-[300px] overflow-y-auto p-1">
185+
{isSearching && (
186+
<div className="p-2 text-sm text-muted-foreground">{t("common.loading")}...</div>
187+
)}
188+
{!isSearching && searchResults.length > 0 && (
189+
<>
190+
<p className="px-2 py-1.5 text-xs font-medium text-muted-foreground">{t("vendors.form.suggestions")}</p>
191+
{searchResults.map((vendor) => (
192+
<div
193+
key={vendor.website ?? vendor.company_name ?? vendor.legal_name ?? Math.random().toString()}
194+
className="cursor-pointer p-2 hover:bg-accent rounded-sm text-sm"
195+
onMouseDown={() => {
196+
handleSelectVendor(vendor);
197+
setPopoverOpen(false);
198+
}}
199+
>
200+
{vendor.company_name ?? vendor.legal_name ?? vendor.website}
201+
</div>
202+
))}
203+
</>
204+
)}
205+
{!isSearching && searchQuery.trim().length > 1 && searchResults.length === 0 && (
206+
<div
207+
className="cursor-pointer p-2 hover:bg-accent rounded-sm text-sm italic"
208+
onMouseDown={() => {
209+
field.onChange(searchQuery);
210+
setSearchResults([]);
219211
setPopoverOpen(false);
220212
}}
221-
className="cursor-pointer italic"
222213
>
223-
{t("vendors.form.create_custom_vendor", { name: searchQuery })} {/* Add new translation key */}
224-
</CommandItem>
214+
{t("vendors.form.create_custom_vendor", { name: searchQuery })}
215+
</div>
225216
)}
226-
</CommandGroup>
227-
</CommandList>
228-
</Command>
229-
</PopoverContent>
230-
</Popover>
217+
</div>
218+
</div>
219+
)}
220+
</div>
221+
</FormControl>
231222
<FormMessage />
232223
</FormItem>
233224
)}

0 commit comments

Comments
 (0)