♻️ refactor: Update component imports and improve code consistency

- Refactored sidebar component to include additional sheet elements and improved accessibility with SheetHeader, SheetTitle, and SheetDescription.
- Updated skeleton component for better readability and consistency in class names.
- Refined slider component by standardizing import statements and enhancing class name formatting.
- Enhanced sonner component with consistent import statements and improved class name formatting.
- Standardized switch component imports and class names for better readability.
- Improved table component structure and class name consistency across various elements.
- Refactored tabs component for better readability and consistent class name formatting.
- Updated textarea component for improved readability and consistency in class names.
- Fixed timeline component to safely access getBoundingClientRect.
- Refactored toggle group and toggle components for improved readability and consistency in class names.
- Updated tooltip component for better readability and consistent class name formatting.
- Enhanced enhanced-input component to support generic types for better type safety.
- Refactored use-mobile hook for improved readability and consistency.
- Updated countries utility to make certain properties optional for better flexibility.
- Refined tailwind configuration for improved readability and consistency in theme settings.
This commit is contained in:
web
2025-09-02 06:00:28 -07:00
parent 6ccf9b8bdc
commit 59faeab34a
34 changed files with 366 additions and 252 deletions
@@ -34,8 +34,8 @@ import { z } from 'zod';
const deviceSchema = z.object({
id: z.number(),
method: z.string().default('device'),
enabled: z.boolean().default(false),
method: z.string(),
enabled: z.boolean(),
config: z
.object({
show_ads: z.boolean().optional(),
@@ -40,23 +40,23 @@ import { z } from 'zod';
const emailSettingsSchema = z.object({
id: z.number(),
method: z.string().default('email'),
enabled: z.boolean().default(false),
method: z.string(),
enabled: z.boolean(),
config: z
.object({
enable_verify: z.boolean().default(false),
enable_domain_suffix: z.boolean().default(false),
enable_verify: z.boolean(),
enable_domain_suffix: z.boolean(),
domain_suffix_list: z.string().optional(),
verify_email_template: z.string().optional(),
expiration_email_template: z.string().optional(),
maintenance_email_template: z.string().optional(),
traffic_exceed_email_template: z.string().optional(),
platform: z.string().default('smtp'),
platform: z.string(),
platform_config: z
.object({
host: z.string().optional(),
port: z.coerce.number().optional(),
ssl: z.boolean().default(false),
port: z.number().optional(),
ssl: z.boolean(),
user: z.string().optional(),
pass: z.string().optional(),
from: z.string().optional(),
@@ -33,8 +33,8 @@ import { z } from 'zod';
const googleSchema = z.object({
id: z.number(),
method: z.string().default('google'),
enabled: z.boolean().default(false),
method: z.string().default('google').optional(),
enabled: z.boolean().default(false).optional(),
config: z
.object({
client_id: z.string().optional(),
@@ -49,8 +49,8 @@ import { z } from 'zod';
const phoneSettingsSchema = z.object({
id: z.number(),
method: z.string().default('mobile'),
enabled: z.boolean().default(false),
method: z.string(),
enabled: z.boolean(),
config: z
.object({
enable_whitelist: z.boolean().optional(),
@@ -267,7 +267,7 @@ export default function CouponForm<T extends Record<string, any>>({
<DatePicker
placeholder={t('form.enterValue')}
value={field.value}
disabled={(date) => date < new Date(Date.now() - 24 * 60 * 60 * 1000)}
disabled={(date: Date) => date < new Date(Date.now() - 24 * 60 * 60 * 1000)}
onChange={(value) => {
form.setValue(field.name, value);
}}
@@ -1,5 +1,6 @@
'use client';
import { UserDetail } from '@/app/dashboard/user/user-detail';
import { ProTable } from '@/components/pro-table';
import { filterTrafficLogDetails } from '@/services/admin/log';
import { formatBytes, formatDate } from '@workspace/ui/utils';
@@ -22,7 +23,11 @@ export default function TrafficDetailsPage() {
initialFilters={initialFilters}
columns={[
{ accessorKey: 'server_id', header: t('column.serverId') },
{ accessorKey: 'user_id', header: t('column.userId') },
{
accessorKey: 'user_id',
header: t('column.userId'),
cell: ({ row }) => <UserDetail id={Number(row.original.user_id)} />,
},
{ accessorKey: 'subscribe_id', header: t('column.subscribeId') },
{
accessorKey: 'upload',
@@ -47,7 +47,7 @@ export default function EmailBroadcastForm() {
const emailBroadcastSchema = z.object({
subject: z.string().min(1, t('subject') + ' ' + t('cannotBeEmpty')),
content: z.string().min(1, t('content') + ' ' + t('cannotBeEmpty')),
scope: z.string().default('all'),
scope: z.string(),
register_start_time: z.string().optional(),
register_end_time: z.string().optional(),
additional: z
+19 -27
View File
@@ -42,39 +42,31 @@ export type ProtocolName =
type ServerRow = API.Server;
export type NodeFormValues = {
name: string;
server_id?: number;
protocol: ProtocolName | '';
address: string;
port: number;
tags: string[];
};
const buildSchema = (t: ReturnType<typeof useTranslations>) =>
z.object({
name: z.string().trim().min(1, t('errors.nameRequired')),
server_id: z
.number({ message: t('errors.serverRequired') })
.int()
.gt(0, t('errors.serverRequired'))
.optional(),
protocol: z.string().min(1, t('errors.protocolRequired')),
address: z.string().trim().min(1, t('errors.serverAddrRequired')),
port: z
.number({ message: t('errors.portRange') })
.int()
.min(1, t('errors.portRange'))
.max(65535, t('errors.portRange')),
tags: z.array(z.string()),
});
export type NodeFormValues = z.infer<ReturnType<typeof buildSchema>>;
async function getServers(): Promise<ServerRow[]> {
const { data } = await filterServerList({ page: 1, size: 1000 });
return (data?.data?.list || []) as ServerRow[];
}
const buildSchema = (t: ReturnType<typeof useTranslations>) =>
z.object({
name: z.string().trim().min(1, t('errors.nameRequired')),
server_id: z.coerce
.number({ invalid_type_error: t('errors.serverRequired') })
.int()
.gt(0, t('errors.serverRequired')),
protocol: z.custom<ProtocolName>((v) => typeof v === 'string' && v.length > 0, {
message: t('errors.protocolRequired'),
}),
address: z.string().trim().min(1, t('errors.serverAddrRequired')),
port: z.coerce
.number({ invalid_type_error: t('errors.portRange') })
.int()
.min(1, t('errors.portRange'))
.max(65535, t('errors.portRange')),
tags: z.array(z.string()).default([]),
});
export default function NodeForm(props: {
trigger: string;
title: string;
@@ -75,9 +75,9 @@ export default function PaymentForm<T>({
icon: z.string().optional(),
domain: z.string().optional(),
config: z.any(),
fee_mode: z.coerce.number().min(0).max(2),
fee_percent: z.coerce.number().optional(),
fee_amount: z.coerce.number().optional(),
fee_mode: z.number().min(0).max(2),
fee_percent: z.number().optional(),
fee_amount: z.number().optional(),
description: z.string().optional(),
});
@@ -319,7 +319,7 @@ export default function PaymentForm<T>({
}}
defaultValue={field.value}
value={field.value}
// @ts-expect-error
// @ts-expect-error - disabled prop type mismatch with SelectTrigger component
disabled={isEdit && Boolean(initialValues?.platform)}
>
<FormControl>
@@ -87,7 +87,7 @@ export default function SubscribeForm<T extends Record<string, any>>({
name: z.string(),
description: z.string().optional(),
unit_price: z.number(),
unit_time: z.string().default('Month'),
unit_time: z.string(),
replacement: z.number().optional(),
discount: z
.array(
@@ -97,22 +97,22 @@ export default function SubscribeForm<T extends Record<string, any>>({
}),
)
.optional(),
inventory: z.number().optional().default(-1),
speed_limit: z.number().optional().default(0),
device_limit: z.number().optional().default(0),
traffic: z.number().optional().default(0),
quota: z.number().optional().default(0),
inventory: z.number().optional(),
speed_limit: z.number().optional(),
device_limit: z.number().optional(),
traffic: z.number().optional(),
quota: z.number().optional(),
group_id: z.number().optional().nullish(),
// Use tags as group identifiers; accept string (tag) or number (legacy id)
node_tags: z.array(z.string()).optional().default([]),
nodes: z.array(z.number()).optional().default([]),
deduction_ratio: z.number().optional().default(0),
allow_deduction: z.boolean().optional().default(false),
reset_cycle: z.number().optional().default(0),
renewal_reset: z.boolean().optional().default(false),
node_tags: z.array(z.string()).optional(),
nodes: z.array(z.number()).optional(),
deduction_ratio: z.number().optional(),
allow_deduction: z.boolean().optional(),
reset_cycle: z.number().optional(),
renewal_reset: z.boolean().optional(),
});
const form = useForm({
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: assign(
defaultValues,
@@ -204,7 +204,7 @@ export default function SubscribeForm<T extends Record<string, any>>({
});
if (hasChanges) {
form.setValue(fieldName, calculatedValues, { shouldDirty: true });
form.setValue(fieldName as any, calculatedValues, { shouldDirty: true });
}
}, 300);
},
@@ -321,6 +321,7 @@ export default function SubscribeForm<T extends Record<string, any>>({
<Combobox<number, false>
placeholder={t('form.selectSubscribeGroup')}
{...field}
value={field.value ?? undefined}
onChange={(value) => {
form.setValue(field.name, value || 0);
}}
@@ -665,7 +666,8 @@ export default function SubscribeForm<T extends Record<string, any>>({
min: 0,
step: 0.01,
formatInput: (value) => unitConversion('centsToDollars', value),
formatOutput: (value) => unitConversion('dollarsToCents', value),
formatOutput: (value) =>
unitConversion('dollarsToCents', value).toString(),
},
]}
value={field.value}
@@ -911,7 +913,8 @@ export default function SubscribeForm<T extends Record<string, any>>({
const keys = Object.keys(errors);
for (const key of keys) {
const formattedKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
toast.error(`${t(`form.${formattedKey}`)} is ${errors[key]?.message}`);
const error = (errors as any)[key];
toast.error(`${t(`form.${formattedKey}`)} is ${error?.message}`);
return false;
}
})}
@@ -96,8 +96,8 @@ function getTimeRangeData(slots: API.TimePeriod[]) {
const nodeConfigSchema = z.object({
node_secret: z.string().optional(),
node_pull_interval: z.number().or(z.string().pipe(z.coerce.number())).optional(),
node_push_interval: z.number().or(z.string().pipe(z.coerce.number())).optional(),
node_pull_interval: z.number().optional(),
node_push_interval: z.number().optional(),
});
type NodeConfigFormData = z.infer<typeof nodeConfigSchema>;
@@ -64,9 +64,9 @@ const createClientFormSchema = (t: any) =>
description: z.string().optional(),
icon: z.string().optional(),
user_agent: z.string().min(1, `User-Agent ${t('form.validation.userAgentRequiredSuffix')}`),
scheme: z.string().default(''),
template: z.string().default(''),
output_format: z.string().default(''),
scheme: z.string(),
template: z.string(),
output_format: z.string(),
download_link: z.object({
windows: z.string().optional(),
mac: z.string().optional(),
+1 -1
View File
@@ -142,7 +142,7 @@ export default function UserForm<T extends Record<string, any>>({
placeholder={t('areaCodePlaceholder')}
value={field.value}
onChange={(value) => {
form.setValue(field.name, value.phone);
form.setValue(field.name, value.phone as string);
}}
/>
</FormControl>
@@ -205,7 +205,7 @@ export function SubscriptionForm({ trigger, title, loading, initialData, onSubmi
<FormControl>
<DatePicker
placeholder={t('permanent')}
value={field.value}
value={field.value ?? undefined}
onChange={(value) => {
if (value === field.value) {
form.setValue(field.name, 0);