From fb49fb596a56955ca70eac9da47d2826299469e1 Mon Sep 17 00:00:00 2001
From: Mert Demir <mertd@users.noreply.github.com>
Date: Mon, 5 Feb 2024 02:23:11 +0900
Subject: 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
---
 src/components/expense-form.tsx | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

(limited to 'src/components/expense-form.tsx')

diff --git a/src/components/expense-form.tsx b/src/components/expense-form.tsx
index 3d6c2da..431afc0 100644
--- a/src/components/expense-form.tsx
+++ b/src/components/expense-form.tsx
@@ -40,8 +40,10 @@ import { cn } from '@/lib/utils'
 import { zodResolver } from '@hookform/resolvers/zod'
 import { Save, Trash2 } from 'lucide-react'
 import { useSearchParams } from 'next/navigation'
+import { useState } from 'react'
 import { useForm } from 'react-hook-form'
 import { match } from 'ts-pattern'
+import { extractCategoryFromTitle } from './expense-form-actions'
 
 export type Props = {
   group: NonNullable<Awaited<ReturnType<typeof getGroup>>>
@@ -133,6 +135,7 @@ export function ExpenseForm({
             : [],
         },
   })
+  const [isCategoryLoading, setCategoryLoading] = useState(false)
 
   return (
     <Form {...form}>
@@ -155,6 +158,17 @@ export function ExpenseForm({
                       placeholder="Monday evening restaurant"
                       className="text-base"
                       {...field}
+                      onBlur={async () => {
+                        field.onBlur() // avoid skipping other blur event listeners since we overwrite `field`
+                        if (process.env.NEXT_PUBLIC_ENABLE_CATEGORY_EXTRACT) {
+                          setCategoryLoading(true)
+                          const { categoryId } = await extractCategoryFromTitle(
+                            field.value,
+                          )
+                          form.setValue('category', categoryId)
+                          setCategoryLoading(false)
+                        }
+                      }}
                     />
                   </FormControl>
                   <FormDescription>
@@ -239,8 +253,11 @@ export function ExpenseForm({
                   <FormLabel>Category</FormLabel>
                   <CategorySelector
                     categories={categories}
-                    defaultValue={field.value}
+                    defaultValue={
+                      form.watch(field.name) // may be overwritten externally
+                    }
                     onValueChange={field.onChange}
+                    isLoading={isCategoryLoading}
                   />
                   <FormDescription>
                     Select the expense category.
-- 
cgit v1.3

