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
@@ -16,6 +16,34 @@ export type DashboardCrudPageResult<T> = {
}
}
export type DashboardCrudFormValue = string | number | undefined
export type DashboardCrudFormOption = {
value: string
label: string
}
export type DashboardCrudFormField<TItem = unknown> = {
name: string
label: string
type?: "text" | "textarea" | "number" | "select"
placeholder?: string
defaultValue?: DashboardCrudFormValue
required?: boolean
requiredMessage?: string
trim?: boolean
valueType?: "string" | "number"
min?: number
max?: number
step?: number
pattern?: RegExp
patternMessage?: string
options?: ReadonlyArray<DashboardCrudFormOption>
colSpan?: 1 | 2
rows?: number
valueFromItem?: (item: TItem) => DashboardCrudFormValue
}
export function buildDashboardCrudQuery({
values,
filters,
@@ -72,3 +100,42 @@ export function normalizeDashboardCrudPageResult<T>(
},
}
}
export function buildDashboardCrudFormValues<TItem>(
fields: ReadonlyArray<DashboardCrudFormField<TItem>>,
item?: TItem | null
): Record<string, string> {
return Object.fromEntries(
fields.map((field) => {
let value: unknown = field.defaultValue ?? ""
if (item) {
if (field.valueFromItem) {
value = field.valueFromItem(item)
} else if (typeof item === "object" && item && field.name in item) {
value = (item as Record<string, unknown>)[field.name]
}
}
return [field.name, value === undefined || value === null ? "" : String(value)]
})
)
}
export function normalizeDashboardCrudSubmitValues<TItem>(
fields: ReadonlyArray<DashboardCrudFormField<TItem>>,
values: Record<string, string>
): Record<string, string | number> {
const output: Record<string, string | number> = {}
fields.forEach((field) => {
const rawValue = values[field.name] ?? ""
const text = field.trim ? rawValue.trim() : rawValue
if (field.type === "number" || field.valueType === "number") {
const numberValue = Number(text)
output[field.name] = Number.isFinite(numberValue) ? numberValue : 0
return
}
output[field.name] = text
})
return output
}