perf(web): improve dialog sizing and footer layout

- migrate frontend dialogs to the shared footer API so actions stay separated from scrollable body content.
- tune dialog dimensions for model analytics, prefill groups, billing history, channel model sync, and related workflows.
- update channel terminology and dialog action translations across supported locales.
This commit is contained in:
QuentinHsu
2026-06-06 21:49:33 +08:00
parent 7a5348caa3
commit 2eaa943d9f
80 changed files with 8137 additions and 8517 deletions
@@ -23,14 +23,6 @@ import { zodResolver } from '@hookform/resolvers/zod'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { Combobox } from '@/components/ui/combobox'
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog'
import {
Form,
FormControl,
@@ -41,6 +33,7 @@ import {
FormMessage,
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { Dialog } from '@/components/dialog'
const createPaymentMethodDialogSchema = (t: (key: string) => string) =>
z.object({
@@ -54,6 +47,8 @@ type PaymentMethodDialogFormValues = z.infer<
ReturnType<typeof createPaymentMethodDialogSchema>
>
const PAYMENT_METHOD_FORM_ID = 'payment-method-form'
export type PaymentMethodData = {
name: string
type: string
@@ -169,134 +164,133 @@ export function PaymentMethodDialog({
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className='sm:max-w-[500px]'>
<DialogHeader>
<DialogTitle>
{isEditMode ? t('Edit payment method') : t('Add payment method')}
</DialogTitle>
<DialogDescription>
{t('Configure a payment method for user recharge options.')}
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form
onSubmit={form.handleSubmit(handleSubmit)}
className='space-y-4'
<Dialog
open={open}
onOpenChange={onOpenChange}
title={isEditMode ? t('Edit payment method') : t('Add payment method')}
description={t('Configure a payment method for user recharge options.')}
contentClassName='sm:max-w-[500px]'
contentHeight='auto'
bodyClassName='space-y-4'
footer={
<>
<Button
type='button'
variant='outline'
onClick={() => onOpenChange(false)}
>
<FormField
control={form.control}
name='name'
render={({ field }) => (
<FormItem>
<FormLabel>{t('Name')}</FormLabel>
<FormControl>
<Input placeholder={t('e.g., Alipay, WeChat')} {...field} />
</FormControl>
<FormDescription>
{t('Display name for this payment method.')}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
{t('Cancel')}
</Button>
<Button type='submit' form={PAYMENT_METHOD_FORM_ID}>
{isEditMode ? t('Update') : t('Add')}
</Button>
</>
}
>
<Form {...form}>
<form
id={PAYMENT_METHOD_FORM_ID}
onSubmit={form.handleSubmit(handleSubmit)}
className='space-y-4'
>
<FormField
control={form.control}
name='name'
render={({ field }) => (
<FormItem>
<FormLabel>{t('Name')}</FormLabel>
<FormControl>
<Input placeholder={t('e.g., Alipay, WeChat')} {...field} />
</FormControl>
<FormDescription>
{t('Display name for this payment method.')}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='type'
render={({ field }) => (
<FormItem>
<FormLabel>{t('Type')}</FormLabel>
<FormControl>
<FormField
control={form.control}
name='type'
render={({ field }) => (
<FormItem>
<FormLabel>{t('Type')}</FormLabel>
<FormControl>
<Combobox
options={PAYMENT_TYPES}
value={field.value}
onValueChange={field.onChange}
placeholder={t('Select or enter payment type')}
searchPlaceholder={t('Search payment types...')}
allowCustomValue
/>
</FormControl>
<FormDescription>
{t('Select from presets or type custom identifier.')}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='color'
render={({ field }) => (
<FormItem>
<FormLabel>{t('Color')}</FormLabel>
<FormControl>
<div className='flex items-center gap-2'>
<Combobox
options={PAYMENT_TYPES}
options={COLOR_PRESETS}
value={field.value}
onValueChange={field.onChange}
placeholder={t('Select or enter payment type')}
searchPlaceholder={t('Search payment types...')}
placeholder={t('Select or enter color value')}
searchPlaceholder={t('Search colors...')}
allowCustomValue
className='flex-1'
/>
</FormControl>
<FormDescription>
{t('Select from presets or type custom identifier.')}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='color'
render={({ field }) => (
<FormItem>
<FormLabel>{t('Color')}</FormLabel>
<FormControl>
<div className='flex items-center gap-2'>
<Combobox
options={COLOR_PRESETS}
value={field.value}
onValueChange={field.onChange}
placeholder={t('Select or enter color value')}
searchPlaceholder={t('Search colors...')}
allowCustomValue
className='flex-1'
{colorPreview && (
<div
className='size-9 shrink-0 rounded border'
style={{ backgroundColor: colorPreview }}
title={colorPreview}
/>
{colorPreview && (
<div
className='size-9 shrink-0 rounded border'
style={{ backgroundColor: colorPreview }}
title={colorPreview}
/>
)}
</div>
</FormControl>
<FormDescription>
{t('Select preset or enter custom CSS color value.')}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
)}
</div>
</FormControl>
<FormDescription>
{t('Select preset or enter custom CSS color value.')}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='min_topup'
render={({ field }) => (
<FormItem>
<FormLabel>{t('Minimum top-up (optional)')}</FormLabel>
<FormControl>
<Input
type='number'
step='0.01'
placeholder={t('e.g., 50')}
{...field}
/>
</FormControl>
<FormDescription>
{t('Optional minimum recharge amount for this method.')}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<DialogFooter>
<Button
type='button'
variant='outline'
onClick={() => onOpenChange(false)}
>
{t('Cancel')}
</Button>
<Button type='submit'>
{isEditMode ? t('Update') : t('Add')}
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
<FormField
control={form.control}
name='min_topup'
render={({ field }) => (
<FormItem>
<FormLabel>{t('Minimum top-up (optional)')}</FormLabel>
<FormControl>
<Input
type='number'
step='0.01'
placeholder={t('e.g., 50')}
{...field}
/>
</FormControl>
<FormDescription>
{t('Optional minimum recharge amount for this method.')}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</form>
</Form>
</Dialog>
)
}