refactor: improve PeopleFilters and Autocomplete components

- Refactored PeopleFilters to utilize a single context object for better readability.
- Enhanced the Autocomplete component's keyboard navigation and selection logic.
- Updated the handling of the "Create New" option to improve user experience and maintain consistent selection behavior.
This commit is contained in:
Varun Raj
2025-03-25 22:11:54 +05:30
parent 997246d937
commit eab7cc7a8f
2 changed files with 43 additions and 29 deletions
+10 -3
View File
@@ -20,7 +20,8 @@ import { ParsedUrlQueryInput } from "querystring";
export function PeopleFilters() {
const router = useRouter();
const { updateContext, page, maximumAssetCount, type = "all", query = "", visibility = "all" } = usePeopleFilterContext();
const filters = usePeopleFilterContext();
const { updateContext, page, maximumAssetCount, type = "all", query = "", visibility = "all" } = filters;
const handleChange = (data: Partial<IPersonListFilters>) => {
updateContext(data);
@@ -69,7 +70,10 @@ export function PeopleFilters() {
}}
/>
<Select value={type} onValueChange={(value) => handleChange({ type: value })}>
<Select value={type} onValueChange={(value) => handleChange({
...removeNullOrUndefinedProperties(filters),
type: value as "all" | "nameless" | "named"
})}>
<SelectTrigger>
<SelectValue placeholder="Person Type" />
</SelectTrigger>
@@ -80,7 +84,10 @@ export function PeopleFilters() {
</SelectContent>
</Select>
<Select value={visibility} onValueChange={(value) => handleChange({ visibility: value as "all" | "visible" | "hidden" })}>
<Select value={visibility} onValueChange={(value) => handleChange({
...removeNullOrUndefinedProperties(filters),
visibility: value as "all" | "visible" | "hidden"
})}>
<SelectTrigger>
<SelectValue placeholder="Visibility" />
</SelectTrigger>
+33 -26
View File
@@ -118,7 +118,7 @@ const Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>(
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
e.preventDefault()
setOpen(true)
setSelectedIndex(0)
setSelectedIndex(showCreateNew ? 0 : -1)
}
return
}
@@ -126,22 +126,28 @@ const Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>(
switch (e.key) {
case 'ArrowDown':
e.preventDefault()
setSelectedIndex((prev) => (prev + 1) % totalOptions)
setSelectedIndex((prev) => {
const next = prev + 1
return next >= totalOptions ? 0 : next
})
break
case 'ArrowUp':
e.preventDefault()
setSelectedIndex((prev) => (prev - 1 + totalOptions) % totalOptions)
setSelectedIndex((prev) => {
const next = prev - 1
return next < 0 ? totalOptions - 1 : next
})
break
case 'Enter':
e.preventDefault()
if (selectedIndex >= 0 && selectedIndex < filteredOptions.length) {
const option = filteredOptions[selectedIndex]
setInputValue(option.label)
onOptionSelect(option)
if (showCreateNew && selectedIndex === 0) {
onCreateNew(inputValue.trim())
setOpen(false)
setSelectedIndex(-1)
} else if (showCreateNew && selectedIndex === filteredOptions.length) {
onCreateNew(inputValue.trim())
} else if (selectedIndex >= (showCreateNew ? 1 : 0) && selectedIndex < totalOptions) {
const option = filteredOptions[selectedIndex - (showCreateNew ? 1 : 0)]
setInputValue(option.label)
onOptionSelect(option)
setOpen(false)
setSelectedIndex(-1)
}
@@ -174,6 +180,7 @@ const Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>(
value={inputValue}
onFocus={() => {
setOpen(true)
setSelectedIndex(showCreateNew ? 0 : -1)
}}
onKeyDown={handleKeyDown}
placeholder={placeholder}
@@ -181,7 +188,7 @@ const Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>(
{...props}
onChange={(e) => {
setInputValue(e.target.value)
setSelectedIndex(-1)
setSelectedIndex(showCreateNew ? 0 : -1)
props.onChange?.(e)
}}
/>
@@ -193,12 +200,27 @@ const Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>(
</div>
) : (
<>
{showCreateNew && (
<button
className={cn(
"w-full px-3 py-2 text-left text-sm text-primary hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none",
selectedIndex === 0 && "bg-accent text-accent-foreground"
)}
onClick={() => {
onCreateNew(inputValue.trim())
setOpen(false)
setSelectedIndex(-1)
}}
>
{createNewLabel} &quot;{inputValue.trim()}&quot;
</button>
)}
{filteredOptions.map((option, index) => (
<button
key={option.value}
className={cn(
"w-full px-3 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none flex items-center gap-2",
index === selectedIndex && "bg-accent text-accent-foreground"
(showCreateNew ? index + 1 : index) === selectedIndex && "bg-accent text-accent-foreground"
)}
onClick={() => {
setInputValue(option.label)
@@ -215,21 +237,6 @@ const Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>(
</span>
</button>
))}
{showCreateNew && (
<button
className={cn(
"w-full border-t px-3 py-2 text-left text-sm text-primary hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none",
selectedIndex === filteredOptions.length && "bg-accent text-accent-foreground"
)}
onClick={() => {
onCreateNew(inputValue.trim())
setOpen(false)
setSelectedIndex(-1)
}}
>
{createNewLabel} &quot;{inputValue.trim()}&quot;
</button>
)}
</>
)}
</div>