aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/category-selector.tsx
diff options
context:
space:
mode:
authorMert Demir <mertd@users.noreply.github.com>2024-02-05 02:23:11 +0900
committerGitHub <noreply@github.com>2024-02-04 12:23:11 -0500
commitfb49fb596a56955ca70eac9da47d2826299469e1 (patch)
tree71dd092faf01d37b35a8015e3cfda494ddc7b99e /src/components/category-selector.tsx
parent10fd69404a69b15d5c0888d9382663f324455ec0 (diff)
Automatic category from expense title (#80)
* environment variable * random category draft * get category from ai * input limit and documentation * use watch * use field.name * prettier * presigned upload, readme warning, category to string util * prettier * check whether feature is enabled * use process.env * improved prompt to return id only * remove console.debug * show loader * share class name * prettier * use template literals * rename format util * prettier
Diffstat (limited to 'src/components/category-selector.tsx')
-rw-r--r--src/components/category-selector.tsx38
1 files changed, 32 insertions, 6 deletions
diff --git a/src/components/category-selector.tsx b/src/components/category-selector.tsx
index 8e6c5a6..05c3be0 100644
--- a/src/components/category-selector.tsx
+++ b/src/components/category-selector.tsx
@@ -1,4 +1,4 @@
-import { ChevronDown } from 'lucide-react'
+import { ChevronDown, Loader2 } from 'lucide-react'
import { CategoryIcon } from '@/app/groups/[groupId]/expenses/category-icon'
import { Button, ButtonProps } from '@/components/ui/button'
@@ -17,23 +17,32 @@ import {
} from '@/components/ui/popover'
import { useMediaQuery } from '@/lib/hooks'
import { Category } from '@prisma/client'
-import { forwardRef, useState } from 'react'
+import { forwardRef, useEffect, useState } from 'react'
type Props = {
categories: Category[]
onValueChange: (categoryId: Category['id']) => void
+ /** Category ID to be selected by default. Overwriting this value will update current selection, too. */
defaultValue: Category['id']
+ isLoading: boolean
}
export function CategorySelector({
categories,
onValueChange,
defaultValue,
+ isLoading,
}: Props) {
const [open, setOpen] = useState(false)
const [value, setValue] = useState<number>(defaultValue)
const isDesktop = useMediaQuery('(min-width: 768px)')
+ // allow overwriting currently selected category from outside
+ useEffect(() => {
+ setValue(defaultValue)
+ onValueChange(defaultValue)
+ }, [defaultValue])
+
const selectedCategory =
categories.find((category) => category.id === value) ?? categories[0]
@@ -41,7 +50,11 @@ export function CategorySelector({
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
- <CategoryButton category={selectedCategory} open={open} />
+ <CategoryButton
+ category={selectedCategory}
+ open={open}
+ isLoading={isLoading}
+ />
</PopoverTrigger>
<PopoverContent className="p-0" align="start">
<CategoryCommand
@@ -60,7 +73,11 @@ export function CategorySelector({
return (
<Drawer open={open} onOpenChange={setOpen}>
<DrawerTrigger asChild>
- <CategoryButton category={selectedCategory} open={open} />
+ <CategoryButton
+ category={selectedCategory}
+ open={open}
+ isLoading={isLoading}
+ />
</DrawerTrigger>
<DrawerContent className="p-0">
<CategoryCommand
@@ -122,9 +139,14 @@ function CategoryCommand({
type CategoryButtonProps = {
category: Category
open: boolean
+ isLoading: boolean
}
const CategoryButton = forwardRef<HTMLButtonElement, CategoryButtonProps>(
- ({ category, open, ...props }: ButtonProps & CategoryButtonProps, ref) => {
+ (
+ { category, open, isLoading, ...props }: ButtonProps & CategoryButtonProps,
+ ref,
+ ) => {
+ const iconClassName = 'ml-2 h-4 w-4 shrink-0 opacity-50'
return (
<Button
variant="outline"
@@ -135,7 +157,11 @@ const CategoryButton = forwardRef<HTMLButtonElement, CategoryButtonProps>(
{...props}
>
<CategoryLabel category={category} />
- <ChevronDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
+ {isLoading ? (
+ <Loader2 className={`animate-spin ${iconClassName}`} />
+ ) : (
+ <ChevronDown className={iconClassName} />
+ )}
</Button>
)
},