garage-erp/apps/dashboard/shared/components/form/fields/rhf-auto-generate-field.tsx
2026-04-07 06:32:40 +03:00

101 lines
3.0 KiB
TypeScript

"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>
)
}