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:
+121
-127
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user