updates
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { useFormContext, type FieldValues, type FieldPath } from "react-hook-form"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { RefreshCw } from "lucide-react"
|
||||
|
||||
import { useAuthApi } from "@/shared/useApi"
|
||||
import { AUTO_GENERATE_ROUTES } from "@garage/api"
|
||||
import { FieldShell } from "../field-shell"
|
||||
import { Input } from "@/shared/components/ui/input"
|
||||
import { Button } from "@/shared/components/ui/button"
|
||||
|
||||
type RhfAutoGenerateFieldProps<
|
||||
TValues extends FieldValues,
|
||||
TName extends FieldPath<TValues>,
|
||||
> = {
|
||||
name: TName
|
||||
label?: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
disabled?: boolean
|
||||
placeholder?: string
|
||||
table: string
|
||||
/** When true, fetches the next code immediately on mount */
|
||||
autoFetch?: boolean
|
||||
}
|
||||
|
||||
export function RhfAutoGenerateField<
|
||||
TValues extends FieldValues,
|
||||
TName extends FieldPath<TValues>,
|
||||
>({
|
||||
name,
|
||||
label,
|
||||
description,
|
||||
required,
|
||||
disabled,
|
||||
placeholder,
|
||||
table,
|
||||
autoFetch = false,
|
||||
}: RhfAutoGenerateFieldProps<TValues, TName>) {
|
||||
const api = useAuthApi()
|
||||
const { setValue, watch, formState: { errors } } = useFormContext<TValues>()
|
||||
const value = watch(name)
|
||||
const error = errors[name]
|
||||
|
||||
const [enabled, setEnabled] = useState(autoFetch)
|
||||
|
||||
const { isFetching } = useQuery({
|
||||
queryKey: [AUTO_GENERATE_ROUTES.BY_TABLE, table],
|
||||
queryFn: async () => {
|
||||
const res = await api.autoGenerate.generate(table)
|
||||
const generated = (res as any)?.data
|
||||
if (generated) {
|
||||
setValue(name, generated as any, { shouldValidate: true })
|
||||
}
|
||||
return res
|
||||
},
|
||||
enabled,
|
||||
refetchOnWindowFocus: false,
|
||||
staleTime: 0,
|
||||
gcTime: 0,
|
||||
})
|
||||
|
||||
const handleGenerate = () => {
|
||||
setEnabled(false)
|
||||
// Reset and re-enable to trigger a fresh fetch
|
||||
setTimeout(() => setEnabled(true), 0)
|
||||
}
|
||||
|
||||
return (
|
||||
<FieldShell
|
||||
label={label}
|
||||
error={error?.message as string | undefined}
|
||||
description={description}
|
||||
required={required}
|
||||
>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
value={value ?? ""}
|
||||
onChange={(e) => setValue(name, e.target.value as any, { shouldValidate: true })}
|
||||
name={name}
|
||||
disabled={disabled}
|
||||
aria-invalid={!!error || undefined}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
disabled={disabled || isFetching}
|
||||
onClick={handleGenerate}
|
||||
title="Auto-generate"
|
||||
>
|
||||
<RefreshCw className={isFetching ? "animate-spin" : ""} />
|
||||
</Button>
|
||||
</div>
|
||||
</FieldShell>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user