refactor: replace EditDialog with DashboardCrudFormDialog for companies and quick replies

- Removed the EditDialog component from companies and quick replies.
- Integrated DashboardCrudFormDialog to handle form submissions and editing for both entities.
- Updated the CompanyPicker to utilize the new form dialog for creating companies.
- Introduced DashboardCrudFieldControl for rendering form fields dynamically.
- Added utility functions for building form values and normalizing submit values.
- Updated tests to cover new form utilities and ensure correct behavior for form submissions.
This commit is contained in:
mlogclub
2026-05-28 08:45:15 +08:00
parent fe480ff131
commit e8d7565caf
11 changed files with 637 additions and 576 deletions
@@ -0,0 +1,79 @@
"use client"
import type { FieldError as HookFormFieldError } from "react-hook-form"
import { Controller, type Control, type UseFormRegister } from "react-hook-form"
import { OptionCombobox } from "@/components/option-combobox"
import {
Field,
FieldContent,
FieldError,
FieldLabel,
} from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { cn } from "@/lib/utils"
import type { DashboardCrudFormField } from "./dashboard-crud-utils"
export function DashboardCrudFieldControl<TItem>({
field,
control,
register,
error,
}: {
field: DashboardCrudFormField<TItem>
control: Control<Record<string, string>>
register: UseFormRegister<Record<string, string>>
error?: HookFormFieldError
}) {
const inputId = `dashboard-crud-field-${field.name}`
return (
<Field
data-invalid={!!error}
className={cn(
(field.colSpan === 2 || field.type === "textarea") && "md:col-span-2"
)}
>
<FieldLabel htmlFor={field.type === "select" ? undefined : inputId}>
{field.label}
</FieldLabel>
<FieldContent>
{field.type === "select" ? (
<Controller
control={control}
name={field.name}
render={({ field: controllerField }) => (
<OptionCombobox
value={controllerField.value}
options={[...(field.options ?? [])]}
placeholder={field.placeholder ?? field.label}
onChange={controllerField.onChange}
/>
)}
/>
) : field.type === "textarea" ? (
<Textarea
id={inputId}
rows={field.rows ?? 4}
placeholder={field.placeholder}
aria-invalid={!!error}
{...register(field.name)}
/>
) : (
<Input
id={inputId}
type={field.type === "number" ? "number" : "text"}
min={field.type === "number" ? field.min : undefined}
max={field.type === "number" ? field.max : undefined}
step={field.type === "number" ? field.step : undefined}
placeholder={field.placeholder}
aria-invalid={!!error}
{...register(field.name)}
/>
)}
<FieldError errors={error ? [error] : []} />
</FieldContent>
</Field>
)
}