feat(user): Add User Detail

This commit is contained in:
web@ppanel 2025-02-02 14:40:29 +07:00
parent 6733fc211c
commit fdaf11b654
66 changed files with 1977 additions and 704 deletions

View File

@ -1,79 +1,76 @@
<a name="readme-top"></a>
# Changelog
# [1.0.0-beta.7](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2025-01-28)
### ♻ Code Refactoring
* **sbscribe**: Rename and reorganize components for better structure and clarity ([5e5e4ed](https://github.com/perfect-panel/ppanel-web/commit/5e5e4ed))
- **sbscribe**: Rename and reorganize components for better structure and clarity ([5e5e4ed](https://github.com/perfect-panel/ppanel-web/commit/5e5e4ed))
### ✨ Features
* **auth**: Add email and SMS code sending functionality with localization updates ([57eaa55](https://github.com/perfect-panel/ppanel-web/commit/57eaa55))
* **auth**: Add Oauth configuration for Telegram, Facebook, Google, Github, and Apple ([18ee600](https://github.com/perfect-panel/ppanel-web/commit/18ee600))
* **auth**: Add SMS and email configuration options to global store and update localization ([4acf7b1](https://github.com/perfect-panel/ppanel-web/commit/4acf7b1))
* **auth**: Enhance user registration with invite handling and logo display ([207bc24](https://github.com/perfect-panel/ppanel-web/commit/207bc24))
* **auth**: Redirect user after OAuth login and add logos icon collection ([aa6dda8](https://github.com/perfect-panel/ppanel-web/commit/aa6dda8))
* **config**: Add application selection and encryption settings to configuration form ([88b3504](https://github.com/perfect-panel/ppanel-web/commit/88b3504))
* **config**: Update encryption fields in configuration form and refactor OAuth callback parameters ([652e032](https://github.com/perfect-panel/ppanel-web/commit/652e032))
* **global**: Add SMS configuration options to global store ([39a9ce6](https://github.com/perfect-panel/ppanel-web/commit/39a9ce6))
* **locales**: Add area code and telephone fields to user forms in multiple languages ([9b8258c](https://github.com/perfect-panel/ppanel-web/commit/9b8258c))
* **locales**: Add description information of communication keys and encryption methods to enhance client configuration capabilities ([d1f5a9b](https://github.com/perfect-panel/ppanel-web/commit/d1f5a9b))
* **node**: Add tags ([f408fdf](https://github.com/perfect-panel/ppanel-web/commit/f408fdf))
* **node**: Move the node configuration to the server module ([7f0f5ce](https://github.com/perfect-panel/ppanel-web/commit/7f0f5ce))
* **oauth**: Add certification component for handling OAuth login callbacks and improve user authentication flow ([5ed04c0](https://github.com/perfect-panel/ppanel-web/commit/5ed04c0))
* **oauth**: Implement OAuth token retrieval and refactor login callback handling ([40a6f7c](https://github.com/perfect-panel/ppanel-web/commit/40a6f7c))
* **oauth**: Refactor platform parameter handling and improve logout redirection logic ([8346c85](https://github.com/perfect-panel/ppanel-web/commit/8346c85))
* **oauth**: Update OAuth login handling to use callback parameter and improve URL parameter retrieval ([9227411](https://github.com/perfect-panel/ppanel-web/commit/9227411))
* **sms**: Update locales ([938363b](https://github.com/perfect-panel/ppanel-web/commit/938363b))
* **subscribe**: Add 'sold' column to SubscribeTable and update inventory terminology ([19619fd](https://github.com/perfect-panel/ppanel-web/commit/19619fd))
* **subscribe**: Move subscription configuration and application to subscription module ([f90d4d2](https://github.com/perfect-panel/ppanel-web/commit/f90d4d2))
* **subscribe**: Update SubscribeTable component to use API.SubscribeItem type and ensure proper type casting ([f26f1c2](https://github.com/perfect-panel/ppanel-web/commit/f26f1c2))
* **tutorial**: Fetch the latest tutorial version from GitHub API for dynamic URL generation ([28f8c78](https://github.com/perfect-panel/ppanel-web/commit/28f8c78))
* **user**: Add telephone input with area code selection and update localization ([585b99c](https://github.com/perfect-panel/ppanel-web/commit/585b99c))
* Update Auth Control ([c59742a](https://github.com/perfect-panel/ppanel-web/commit/c59742a))
- **auth**: Add email and SMS code sending functionality with localization updates ([57eaa55](https://github.com/perfect-panel/ppanel-web/commit/57eaa55))
- **auth**: Add Oauth configuration for Telegram, Facebook, Google, Github, and Apple ([18ee600](https://github.com/perfect-panel/ppanel-web/commit/18ee600))
- **auth**: Add SMS and email configuration options to global store and update localization ([4acf7b1](https://github.com/perfect-panel/ppanel-web/commit/4acf7b1))
- **auth**: Enhance user registration with invite handling and logo display ([207bc24](https://github.com/perfect-panel/ppanel-web/commit/207bc24))
- **auth**: Redirect user after OAuth login and add logos icon collection ([aa6dda8](https://github.com/perfect-panel/ppanel-web/commit/aa6dda8))
- **config**: Add application selection and encryption settings to configuration form ([88b3504](https://github.com/perfect-panel/ppanel-web/commit/88b3504))
- **config**: Update encryption fields in configuration form and refactor OAuth callback parameters ([652e032](https://github.com/perfect-panel/ppanel-web/commit/652e032))
- **global**: Add SMS configuration options to global store ([39a9ce6](https://github.com/perfect-panel/ppanel-web/commit/39a9ce6))
- **locales**: Add area code and telephone fields to user forms in multiple languages ([9b8258c](https://github.com/perfect-panel/ppanel-web/commit/9b8258c))
- **locales**: Add description information of communication keys and encryption methods to enhance client configuration capabilities ([d1f5a9b](https://github.com/perfect-panel/ppanel-web/commit/d1f5a9b))
- **node**: Add tags ([f408fdf](https://github.com/perfect-panel/ppanel-web/commit/f408fdf))
- **node**: Move the node configuration to the server module ([7f0f5ce](https://github.com/perfect-panel/ppanel-web/commit/7f0f5ce))
- **oauth**: Add certification component for handling OAuth login callbacks and improve user authentication flow ([5ed04c0](https://github.com/perfect-panel/ppanel-web/commit/5ed04c0))
- **oauth**: Implement OAuth token retrieval and refactor login callback handling ([40a6f7c](https://github.com/perfect-panel/ppanel-web/commit/40a6f7c))
- **oauth**: Refactor platform parameter handling and improve logout redirection logic ([8346c85](https://github.com/perfect-panel/ppanel-web/commit/8346c85))
- **oauth**: Update OAuth login handling to use callback parameter and improve URL parameter retrieval ([9227411](https://github.com/perfect-panel/ppanel-web/commit/9227411))
- **sms**: Update locales ([938363b](https://github.com/perfect-panel/ppanel-web/commit/938363b))
- **subscribe**: Add 'sold' column to SubscribeTable and update inventory terminology ([19619fd](https://github.com/perfect-panel/ppanel-web/commit/19619fd))
- **subscribe**: Move subscription configuration and application to subscription module ([f90d4d2](https://github.com/perfect-panel/ppanel-web/commit/f90d4d2))
- **subscribe**: Update SubscribeTable component to use API.SubscribeItem type and ensure proper type casting ([f26f1c2](https://github.com/perfect-panel/ppanel-web/commit/f26f1c2))
- **tutorial**: Fetch the latest tutorial version from GitHub API for dynamic URL generation ([28f8c78](https://github.com/perfect-panel/ppanel-web/commit/28f8c78))
- **user**: Add telephone input with area code selection and update localization ([585b99c](https://github.com/perfect-panel/ppanel-web/commit/585b99c))
- Update Auth Control ([c59742a](https://github.com/perfect-panel/ppanel-web/commit/c59742a))
### 🐛 Bug Fixes
* **api**: Remove redundant requestType parameter in appleLoginCallback ([0aa5d5b](https://github.com/perfect-panel/ppanel-web/commit/0aa5d5b))
* **api**: Rename app-related functions and types to application for consistency ([9d8b814](https://github.com/perfect-panel/ppanel-web/commit/9d8b814))
* **api**: Update subscription_protocol to subscribe_type for consistency across services ([b6da51b](https://github.com/perfect-panel/ppanel-web/commit/b6da51b))
* **auth**: Change Textarea value to defaultValue for client_secret in Apple auth page ([69fc670](https://github.com/perfect-panel/ppanel-web/commit/69fc670))
* **auth**: Remove unused telephone code login function and update typings for telephone login requests ([7239685](https://github.com/perfect-panel/ppanel-web/commit/7239685))
* **auth**: Require minimum length for invite string when forced invite is enabled ([a604f28](https://github.com/perfect-panel/ppanel-web/commit/a604f28))
* **auth**: Update user authentication flow to include email and phone code verification ([5d078fd](https://github.com/perfect-panel/ppanel-web/commit/5d078fd))
* **dashboard**: Improve URL encoding for subscription links and enhance success message handling ([4983c33](https://github.com/perfect-panel/ppanel-web/commit/4983c33))
* **dashboard**: Update icon imports for platform consistency and adjust icon size ([3e8912e](https://github.com/perfect-panel/ppanel-web/commit/3e8912e))
* **dashboard**: Update platform detection logic and improve layout responsiveness ([b0aa364](https://github.com/perfect-panel/ppanel-web/commit/b0aa364))
* **deps**: Remove outdated @iconify/react dependency and add iconify-json packages ([d6fbc38](https://github.com/perfect-panel/ppanel-web/commit/d6fbc38))
* **locales**: Add error message for incorrect user information ([52c1d1f](https://github.com/perfect-panel/ppanel-web/commit/52c1d1f))
* **locales**: Add error message for incorrect user information ([3d92902](https://github.com/perfect-panel/ppanel-web/commit/3d92902))
* **locales**: Add logout message to authentication localization files ([1d0d911](https://github.com/perfect-panel/ppanel-web/commit/1d0d911))
* **nav**: Comment out unused social login options to simplify navigation configuration ([cefcb31](https://github.com/perfect-panel/ppanel-web/commit/cefcb31))
* **node-config**: Add null checks for time slots and ensure proper handling of undefined values ([1cdb7e7](https://github.com/perfect-panel/ppanel-web/commit/1cdb7e7))
* **node**: Add country and city fields to the form schema and localization files ([8775fb6](https://github.com/perfect-panel/ppanel-web/commit/8775fb6))
* **oauth**: Refactor OAuth configuration types and update related API methods ([6227ba9](https://github.com/perfect-panel/ppanel-web/commit/6227ba9))
* **oauth**: Remove redundant checks when updating configuration to simplify logic ([9140b8a](https://github.com/perfect-panel/ppanel-web/commit/9140b8a))
* **payment**: Replace window.open with window.location.href for checkout links ([1d8c765](https://github.com/perfect-panel/ppanel-web/commit/1d8c765))
* **phone**: Update SMS expiration time field to use 'sms_expire_time' with default value of 300 ([18b07c7](https://github.com/perfect-panel/ppanel-web/commit/18b07c7))
* **redirect**: Simplify redirect URL logic by removing unnecessary condition for sessionStorage ([c53ac61](https://github.com/perfect-panel/ppanel-web/commit/c53ac61))
* **redirect**: Update redirect URL logic to ensure proper handling of OAuth and auth paths ([7954762](https://github.com/perfect-panel/ppanel-web/commit/7954762))
* **site**: Add image upload functionality for site logo configuration ([4ea6e4a](https://github.com/perfect-panel/ppanel-web/commit/4ea6e4a))
* **sort**: Refactor sorting logic in NodeTable and SubscribeTable components for improved clarity and performance ([331bbea](https://github.com/perfect-panel/ppanel-web/commit/331bbea))
* **subscription**: Add reset functionality for user subscription token ([39e89bf](https://github.com/perfect-panel/ppanel-web/commit/39e89bf))
* **type**: Fix ts type check error ([3cb0629](https://github.com/perfect-panel/ppanel-web/commit/3cb0629))
* **user-nav**: Update user avatar and label to display telephone if email is not available ([7b6bb7b](https://github.com/perfect-panel/ppanel-web/commit/7b6bb7b))
* **user**: Update user identifier field and localizations ([1b6befa](https://github.com/perfect-panel/ppanel-web/commit/1b6befa))
- **api**: Remove redundant requestType parameter in appleLoginCallback ([0aa5d5b](https://github.com/perfect-panel/ppanel-web/commit/0aa5d5b))
- **api**: Rename app-related functions and types to application for consistency ([9d8b814](https://github.com/perfect-panel/ppanel-web/commit/9d8b814))
- **api**: Update subscription_protocol to subscribe_type for consistency across services ([b6da51b](https://github.com/perfect-panel/ppanel-web/commit/b6da51b))
- **auth**: Change Textarea value to defaultValue for client_secret in Apple auth page ([69fc670](https://github.com/perfect-panel/ppanel-web/commit/69fc670))
- **auth**: Remove unused telephone code login function and update typings for telephone login requests ([7239685](https://github.com/perfect-panel/ppanel-web/commit/7239685))
- **auth**: Require minimum length for invite string when forced invite is enabled ([a604f28](https://github.com/perfect-panel/ppanel-web/commit/a604f28))
- **auth**: Update user authentication flow to include email and phone code verification ([5d078fd](https://github.com/perfect-panel/ppanel-web/commit/5d078fd))
- **dashboard**: Improve URL encoding for subscription links and enhance success message handling ([4983c33](https://github.com/perfect-panel/ppanel-web/commit/4983c33))
- **dashboard**: Update icon imports for platform consistency and adjust icon size ([3e8912e](https://github.com/perfect-panel/ppanel-web/commit/3e8912e))
- **dashboard**: Update platform detection logic and improve layout responsiveness ([b0aa364](https://github.com/perfect-panel/ppanel-web/commit/b0aa364))
- **deps**: Remove outdated @iconify/react dependency and add iconify-json packages ([d6fbc38](https://github.com/perfect-panel/ppanel-web/commit/d6fbc38))
- **locales**: Add error message for incorrect user information ([52c1d1f](https://github.com/perfect-panel/ppanel-web/commit/52c1d1f))
- **locales**: Add error message for incorrect user information ([3d92902](https://github.com/perfect-panel/ppanel-web/commit/3d92902))
- **locales**: Add logout message to authentication localization files ([1d0d911](https://github.com/perfect-panel/ppanel-web/commit/1d0d911))
- **nav**: Comment out unused social login options to simplify navigation configuration ([cefcb31](https://github.com/perfect-panel/ppanel-web/commit/cefcb31))
- **node-config**: Add null checks for time slots and ensure proper handling of undefined values ([1cdb7e7](https://github.com/perfect-panel/ppanel-web/commit/1cdb7e7))
- **node**: Add country and city fields to the form schema and localization files ([8775fb6](https://github.com/perfect-panel/ppanel-web/commit/8775fb6))
- **oauth**: Refactor OAuth configuration types and update related API methods ([6227ba9](https://github.com/perfect-panel/ppanel-web/commit/6227ba9))
- **oauth**: Remove redundant checks when updating configuration to simplify logic ([9140b8a](https://github.com/perfect-panel/ppanel-web/commit/9140b8a))
- **payment**: Replace window.open with window.location.href for checkout links ([1d8c765](https://github.com/perfect-panel/ppanel-web/commit/1d8c765))
- **phone**: Update SMS expiration time field to use 'sms_expire_time' with default value of 300 ([18b07c7](https://github.com/perfect-panel/ppanel-web/commit/18b07c7))
- **redirect**: Simplify redirect URL logic by removing unnecessary condition for sessionStorage ([c53ac61](https://github.com/perfect-panel/ppanel-web/commit/c53ac61))
- **redirect**: Update redirect URL logic to ensure proper handling of OAuth and auth paths ([7954762](https://github.com/perfect-panel/ppanel-web/commit/7954762))
- **site**: Add image upload functionality for site logo configuration ([4ea6e4a](https://github.com/perfect-panel/ppanel-web/commit/4ea6e4a))
- **sort**: Refactor sorting logic in NodeTable and SubscribeTable components for improved clarity and performance ([331bbea](https://github.com/perfect-panel/ppanel-web/commit/331bbea))
- **subscription**: Add reset functionality for user subscription token ([39e89bf](https://github.com/perfect-panel/ppanel-web/commit/39e89bf))
- **type**: Fix ts type check error ([3cb0629](https://github.com/perfect-panel/ppanel-web/commit/3cb0629))
- **user-nav**: Update user avatar and label to display telephone if email is not available ([7b6bb7b](https://github.com/perfect-panel/ppanel-web/commit/7b6bb7b))
- **user**: Update user identifier field and localizations ([1b6befa](https://github.com/perfect-panel/ppanel-web/commit/1b6befa))
### 💄 Styles
* **dashboard**: Adjust grid layout and update image dimensions in application display ([f3204b7](https://github.com/perfect-panel/ppanel-web/commit/f3204b7))
* **globals**: Refactor delete confirmation button and update badge styles in node and subscribe tables ([30ae781](https://github.com/perfect-panel/ppanel-web/commit/30ae781))
* Update node secret UI and add telephone code field to authentication form ([770932e](https://github.com/perfect-panel/ppanel-web/commit/770932e))
- **dashboard**: Adjust grid layout and update image dimensions in application display ([f3204b7](https://github.com/perfect-panel/ppanel-web/commit/f3204b7))
- **globals**: Refactor delete confirmation button and update badge styles in node and subscribe tables ([30ae781](https://github.com/perfect-panel/ppanel-web/commit/30ae781))
- Update node secret UI and add telephone code field to authentication form ([770932e](https://github.com/perfect-panel/ppanel-web/commit/770932e))
<a name="readme-top"></a>

View File

@ -17,7 +17,7 @@ import { cn } from '@workspace/ui/lib/utils';
import { formatDate } from '@workspace/ui/utils';
import { UserDetail } from '../user/user-detail';
export default function Page() {
export default function Page(props: { userId?: string }) {
const t = useTranslations('order');
const statusOptions = [
@ -115,7 +115,7 @@ export default function Page() {
<Separator className='my-4' />
<ul className='grid gap-3'>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'></span>
<span className='text-muted-foreground'>{t('method')}</span>
<span>{t(`methods.${row.original.method}`)}</span>
</li>
</ul>
@ -177,10 +177,19 @@ export default function Page() {
value: String(item.id),
})),
},
{ key: 'user_id', placeholder: `${t('user')}ID` },
]}
].concat(
props.userId
? []
: [
{
key: 'user_id',
placeholder: `${t('user')} ID`,
options: undefined,
},
],
)}
request={async (pagination, filter) => {
const { data } = await getOrderList({ ...pagination, ...filter });
const { data } = await getOrderList({ ...pagination, ...filter, user_id: props.userId });
return {
list: data.data?.list || [],
total: data.data?.total || 0,

View File

@ -0,0 +1,33 @@
import UserOrderList from '@/app/dashboard/order/page';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { getTranslations } from 'next-intl/server';
import UserLoginHistory from './user-login-history';
import { UserProfileForm } from './user-profile';
import UserSubscription from './user-subscription';
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const t = await getTranslations('user');
const { id } = await params;
return (
<Tabs defaultValue='profile'>
<TabsList>
<TabsTrigger value='profile'>{t('userProfile')}</TabsTrigger>
<TabsTrigger value='subscriptions'>{t('userSubscriptions')}</TabsTrigger>
<TabsTrigger value='orders'>{t('userOrders')}</TabsTrigger>
<TabsTrigger value='logs'>{t('userLogs')}</TabsTrigger>
</TabsList>
<TabsContent value='profile'>
<UserProfileForm />
</TabsContent>
<TabsContent value='subscriptions'>
<UserSubscription userId={id} />
</TabsContent>
<TabsContent value='orders'>
<UserOrderList userId={id} />
</TabsContent>
<TabsContent value='logs'>
<UserLoginHistory />
</TabsContent>
</Tabs>
);
}

View File

@ -0,0 +1,50 @@
'use client';
import { ProTable } from '@/components/pro-table';
import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { useParams } from 'next/navigation';
export default function UserLoginHistory() {
const t = useTranslations('user');
const { id } = useParams<{ id: string }>();
return (
<ProTable<
{
ip: string;
user_agent: string;
created_at: string;
},
Record<string, unknown>
>
columns={[
{
accessorKey: 'ip',
header: t('loginIp'),
},
{
accessorKey: 'user_agent',
header: t('userAgent'),
},
{
accessorKey: 'created_at',
header: t('loginTime'),
cell: ({ row }) => formatDate(row.getValue('created_at')),
},
]}
params={[
{
key: 'search',
placeholder: t('searchIp'),
},
]}
request={async (pagination, filter) => {
return {
list: [],
total: 0,
};
}}
/>
);
}

View File

@ -0,0 +1,107 @@
'use client';
import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useState } from 'react';
export function AuthMethodsForm({ user }: { user: API.User }) {
const [emailChanges, setEmailChanges] = useState<Record<string, string>>({});
const handleRemoveAuth = async (authType: string) => {};
const handleUpdateEmail = async (authType: string) => {};
const handleCreateEmail = async (email: string) => {};
const handleEmailChange = (authType: string, value: string) => {
setEmailChanges((prev) => ({
...prev,
[authType]: value,
}));
};
const emailMethod = user.auth_methods.find((method) => method.auth_type === 'email');
const otherMethods = user.auth_methods.filter((method) => method.auth_type !== 'email');
const defaultEmailMethod = {
auth_type: 'email',
auth_identifier: '',
verified: false,
...emailMethod,
};
const isEmailExists = !!emailMethod;
const handleEmailAction = () => {
const email = emailChanges['email'];
if (isEmailExists) {
handleUpdateEmail('email');
} else {
handleCreateEmail(email as string);
}
};
return (
<Card>
<CardHeader>
<CardTitle>Authentication Settings</CardTitle>
</CardHeader>
<CardContent className='space-y-6'>
<div className='space-y-6'>
<Card className='border-none shadow-none'>
<CardContent className='space-y-3 p-0'>
<div className='flex items-center justify-between'>
<div className='font-medium uppercase'>email</div>
<Badge variant={defaultEmailMethod.verified ? 'default' : 'destructive'}>
{defaultEmailMethod.verified ? 'Verified' : 'Unverified'}
</Badge>
</div>
<div className='flex items-center gap-2'>
<div className='flex-1'>
<EnhancedInput
value={defaultEmailMethod.auth_identifier}
placeholder='Please enter email'
onValueChange={(value) => handleEmailChange('email', value as string)}
/>
</div>
<Button
onClick={handleEmailAction}
disabled={
!emailChanges['email'] ||
(isEmailExists && emailChanges['email'] === defaultEmailMethod.auth_identifier)
}
>
{isEmailExists ? 'Update' : 'Add'}
</Button>
</div>
</CardContent>
</Card>
{otherMethods.map((method) => (
<Card key={method.auth_type} className='border-none shadow-none'>
<CardContent className='space-y-3 p-0'>
<div className='flex items-center justify-between'>
<div className='font-medium uppercase'>{method.auth_type}</div>
<Badge variant={method.verified ? 'default' : 'destructive'}>
{method.verified ? 'Verified' : 'Unverified'}
</Badge>
</div>
<div className='flex items-center gap-4'>
<div className='flex-1'>
<div className='text-muted-foreground text-sm'>{method.auth_identifier}</div>
</div>
<Button
variant='destructive'
size='sm'
onClick={() => handleRemoveAuth(method.auth_type)}
>
Remove
</Button>
</div>
</CardContent>
</Card>
))}
</div>
</CardContent>
</Card>
);
}

View File

@ -0,0 +1,254 @@
'use client';
import useGlobalStore from '@/config/use-global';
import { updateUser } from '@/services/admin/user';
import { zodResolver } from '@hookform/resolvers/zod';
import { Button } from '@workspace/ui/components/button';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@workspace/ui/components/form';
import { Input } from '@workspace/ui/components/input';
import { Switch } from '@workspace/ui/components/switch';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { UploadImage } from '@workspace/ui/custom-components/upload-image';
import { unitConversion } from '@workspace/ui/utils';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import * as z from 'zod';
const basicInfoSchema = z.object({
avatar: z.string().optional(),
balance: z.number().optional(),
commission: z.number().optional(),
gift_amount: z.number().optional(),
refer_code: z.string().optional(),
referer_id: z.number().optional(),
is_admin: z.boolean().optional(),
password: z.string().optional(),
enable: z.boolean(),
});
type BasicInfoValues = z.infer<typeof basicInfoSchema>;
export function BasicInfoForm({ user }: { user: API.User }) {
const { common } = useGlobalStore();
const { currency } = common;
const form = useForm<BasicInfoValues>({
resolver: zodResolver(basicInfoSchema),
defaultValues: {
avatar: user.avatar,
balance: user.balance,
commission: user.commission,
gift_amount: user.gift_amount,
refer_code: user.refer_code,
referer_id: user.referer_id,
is_admin: user.is_admin,
enable: user.enable,
},
});
async function onSubmit(data: BasicInfoValues) {
await updateUser({
id: user.id,
...data,
} as API.UpdateUserRequest);
toast.success('Saved successfully');
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<Card>
<CardHeader className='flex flex-row items-center justify-between'>
<CardTitle>Basic Information</CardTitle>
<Button type='submit' size='sm'>
Save
</Button>
</CardHeader>
<CardContent className='space-y-4'>
<FormField
control={form.control}
name='enable'
render={({ field }) => (
<FormItem className='flex items-center justify-between space-x-2'>
<FormLabel>Account Enable</FormLabel>
<FormControl>
<Switch checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name='is_admin'
render={({ field }) => (
<FormItem className='flex items-center justify-between space-x-2'>
<FormLabel>Administrator</FormLabel>
<FormControl>
<Switch checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
</FormItem>
)}
/>
<div className='grid grid-cols-3 gap-4'>
<FormField
control={form.control}
name='balance'
render={({ field }) => (
<FormItem>
<FormLabel>Balance</FormLabel>
<FormControl>
<EnhancedInput
type='number'
value={field.value}
prefix={currency?.currency_symbol ?? '$'}
formatInput={(value) => unitConversion('centsToDollars', value)}
formatOutput={(value) => unitConversion('dollarsToCents', value)}
onValueChange={(value) => {
form.setValue(field.name, value as number);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='commission'
render={({ field }) => (
<FormItem>
<FormLabel>Commission</FormLabel>
<FormControl>
<EnhancedInput
type='number'
value={field.value}
prefix={currency?.currency_symbol ?? '$'}
formatInput={(value) => unitConversion('centsToDollars', value)}
formatOutput={(value) => unitConversion('dollarsToCents', value)}
onValueChange={(value) => {
form.setValue(field.name, value as number);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='gift_amount'
render={({ field }) => (
<FormItem>
<FormLabel>Gift Amount</FormLabel>
<FormControl>
<EnhancedInput
type='number'
value={field.value}
prefix={currency?.currency_symbol ?? '$'}
formatInput={(value) => unitConversion('centsToDollars', value)}
formatOutput={(value) => unitConversion('dollarsToCents', value)}
onValueChange={(value) => {
form.setValue(field.name, value as number);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<div className='grid grid-cols-2 gap-4'>
<FormField
control={form.control}
name='refer_code'
render={({ field }) => (
<FormItem>
<FormLabel>Referral Code</FormLabel>
<FormControl>
<EnhancedInput
value={field.value}
onValueChange={(value) => {
form.setValue(field.name, value as string);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='referer_id'
render={({ field }) => (
<FormItem>
<FormLabel>Referrer (User ID)</FormLabel>
<FormControl>
<EnhancedInput
type='number'
value={field.value}
onValueChange={(value) => {
form.setValue(field.name, value as number);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<FormField
control={form.control}
name='avatar'
render={({ field }) => (
<FormItem>
<FormLabel>Avatar</FormLabel>
<FormControl>
<EnhancedInput
value={field.value}
onValueChange={(value) => {
form.setValue(field.name, value as string);
}}
suffix={
<UploadImage
className='bg-muted h-9 rounded-none border-none px-2'
returnType='base64'
onChange={(value) => form.setValue('avatar', value as string)}
/>
}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='password'
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input type='password' placeholder='Leave empty to keep unchanged' {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</CardContent>
</Card>
</form>
</Form>
);
}

View File

@ -0,0 +1,38 @@
'use client';
import { getUserDetail } from '@/services/admin/user';
import { useQuery } from '@tanstack/react-query';
import { useParams } from 'next/navigation';
import { AuthMethodsForm } from './auth-methods-form';
import { BasicInfoForm } from './basic-info-form';
import { NotifySettingsForm } from './notify-settings-form';
export function UserProfileForm() {
const { id } = useParams<{ id: string }>();
const { data: user } = useQuery({
queryKey: ['user', id],
queryFn: async () => {
const { data } = await getUserDetail({
id: Number(id),
});
return data.data;
},
});
if (!user) return null;
return (
<div className='grid gap-4 md:grid-cols-2 xl:grid-cols-3'>
<div className='md:col-span-2 xl:col-span-1'>
<BasicInfoForm user={user} />
</div>
<div>
<NotifySettingsForm user={user} />
</div>
<div>
<AuthMethodsForm user={user} />
</div>
</div>
);
}

View File

@ -0,0 +1,135 @@
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { Button } from '@workspace/ui/components/button';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
import { Form, FormControl, FormField, FormItem, FormLabel } from '@workspace/ui/components/form';
import { Switch } from '@workspace/ui/components/switch';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import * as z from 'zod';
const notifySettingsSchema = z.object({
enable_email_notify: z.boolean(),
enable_telegram_notify: z.boolean(),
enable_balance_notify: z.boolean(),
enable_login_notify: z.boolean(),
enable_subscribe_notify: z.boolean(),
enable_trade_notify: z.boolean(),
});
type NotifySettingsValues = z.infer<typeof notifySettingsSchema>;
export function NotifySettingsForm({ user }: { user: API.User }) {
const form = useForm<NotifySettingsValues>({
resolver: zodResolver(notifySettingsSchema),
defaultValues: {
enable_email_notify: user.enable_email_notify,
enable_telegram_notify: user.enable_telegram_notify,
enable_balance_notify: user.enable_balance_notify,
enable_login_notify: user.enable_login_notify,
enable_subscribe_notify: user.enable_subscribe_notify,
enable_trade_notify: user.enable_trade_notify,
},
});
async function onSubmit(data: NotifySettingsValues) {
toast.warning('In Development...');
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<Card>
<CardHeader className='flex flex-row items-center justify-between'>
<CardTitle>Notification Settings</CardTitle>
<Button type='submit' size='sm'>
Save
</Button>
</CardHeader>
<CardContent className='space-y-4'>
<div className='grid grid-cols-1 gap-4'>
<FormField
control={form.control}
name='enable_email_notify'
render={({ field }) => (
<FormItem className='flex items-center justify-between space-x-2'>
<FormLabel>Email Notifications</FormLabel>
<FormControl>
<Switch checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name='enable_telegram_notify'
render={({ field }) => (
<FormItem className='flex items-center justify-between space-x-2'>
<FormLabel>Telegram Notifications</FormLabel>
<FormControl>
<Switch checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name='enable_balance_notify'
render={({ field }) => (
<FormItem className='flex items-center justify-between space-x-2'>
<FormLabel>Balance Change Notifications</FormLabel>
<FormControl>
<Switch checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name='enable_login_notify'
render={({ field }) => (
<FormItem className='flex items-center justify-between space-x-2'>
<FormLabel>Login Notifications</FormLabel>
<FormControl>
<Switch checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name='enable_subscribe_notify'
render={({ field }) => (
<FormItem className='flex items-center justify-between space-x-2'>
<FormLabel>Subscription Notifications</FormLabel>
<FormControl>
<Switch checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name='enable_trade_notify'
render={({ field }) => (
<FormItem className='flex items-center justify-between space-x-2'>
<FormLabel>Trade Notifications</FormLabel>
<FormControl>
<Switch checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
</FormItem>
)}
/>
</div>
</CardContent>
</Card>
</form>
</Form>
);
}

View File

@ -0,0 +1,143 @@
'use client';
import { Display } from '@/components/display';
import { ProTable, ProTableActions } from '@/components/pro-table';
import { Button } from '@workspace/ui/components/button';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { formatDate } from '@workspace/ui/utils';
import { useRef, useState } from 'react';
import { SubscriptionDetail } from './subscription-detail';
import { SubscriptionForm } from './subscription-form';
// 模拟数据
const mockData: API.Subscribe[] = [
{
id: 1,
name: 'Basic Package',
description: 'Basic Traffic Package',
unit_price: 9.9,
unit_time: '30d',
discount: [],
replacement: 0,
inventory: 100,
traffic: 1073741824, // 1GB
speed_limit: 10,
device_limit: 3,
quota: 0,
group_id: 1,
server_group: [1],
server: [1, 2],
show: true,
sell: true,
sort: 1,
deduction_ratio: 0,
allow_deduction: false,
reset_cycle: 30,
renewal_reset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
// 可以添加更多模拟数据...
];
interface Props {
userId: string;
}
export default function UserSubscription({ userId }: Props) {
const [loading, setLoading] = useState(false);
const ref = useRef<ProTableActions>(null);
return (
<ProTable<API.Subscribe, Record<string, unknown>>
action={ref}
header={{
title: 'Subscription List',
toolbar: (
<SubscriptionForm
key='create'
trigger={<Button>Create</Button>}
title='Create Subscription'
loading={loading}
userId={userId}
onSubmit={async (values) => {
console.log('创建订阅:', values);
return true;
}}
/>
),
}}
columns={[
{
accessorKey: 'id',
header: 'ID',
},
{
accessorKey: 'name',
header: '名称',
},
{
accessorKey: 'traffic',
header: '流量',
cell: ({ row }) => <Display type='traffic' value={row.getValue('traffic')} />,
},
{
accessorKey: 'speed_limit',
header: '限速',
cell: ({ row }) => `${row.getValue('speed_limit')} Mbps`,
},
{
accessorKey: 'device_limit',
header: '设备限制',
},
{
accessorKey: 'created_at',
header: '创建时间',
cell: ({ row }) => formatDate(row.getValue('created_at')),
},
]}
request={async () => {
// 模拟异步请求
await new Promise((resolve) => setTimeout(resolve, 1000));
return {
list: mockData,
total: mockData.length,
};
}}
actions={{
render: (row) => {
return [
<SubscriptionForm
key='edit'
trigger={<Button>Edit</Button>}
title='Edit Subscription'
loading={loading}
userId={userId}
initialData={row}
onSubmit={async (values) => {
console.log('编辑订阅:', values);
return true;
}}
/>,
<SubscriptionDetail
key='detail'
trigger={<Button variant='secondary'>Details</Button>}
subscriptionId={row.id.toString()}
/>,
<ConfirmButton
key='delete'
trigger={<Button variant='destructive'>Delete</Button>}
title='Confirm Delete'
description='Are you sure to delete this subscription?'
onConfirm={async () => {
console.log('删除订阅:', row.id);
}}
cancelText='Cancel'
confirmText='Confirm'
/>,
];
},
}}
/>
);
}

View File

@ -0,0 +1,152 @@
'use client';
import { Display } from '@/components/display';
import { ProTable } from '@/components/pro-table';
import { Button } from '@workspace/ui/components/button';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@workspace/ui/components/dialog';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { formatDate } from '@workspace/ui/utils';
import { ReactNode, useState } from 'react';
import { toast } from 'sonner';
// 模拟数据
const mockLogs = [
{ id: 1, action: 'Create Subscription', created_at: Date.now() - 86400000 },
{ id: 2, action: 'Update Traffic', created_at: Date.now() - 3600000 },
];
const mockTrafficLogs = [
{ id: 1, traffic: 104857600, created_at: Date.now() - 86400000 },
{ id: 2, traffic: 52428800, created_at: Date.now() - 3600000 },
];
const mockDevices = [
{ id: 1, ip: '192.168.1.1', last_seen_at: Date.now() - 300000 },
{ id: 2, ip: '192.168.1.2', last_seen_at: Date.now() - 600000 },
];
interface Props {
trigger: ReactNode;
subscriptionId: string;
}
export function SubscriptionDetail({ trigger }: Props) {
const [open, setOpen] = useState(false);
// 模拟下线设备的函数
const handleOfflineDevice = async (deviceId: number) => {
// TODO: 调用实际的API
console.log('下线设备:', deviceId);
toast.success('设备已下线');
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>{trigger}</DialogTrigger>
<DialogContent className='max-w-5xl'>
<DialogHeader>
<DialogTitle>Subscription Details</DialogTitle>
</DialogHeader>
<div className='mt-4'>
<Tabs defaultValue='logs'>
<TabsList className='w-full'>
<TabsTrigger value='logs' className='flex-1'>
Subscription Logs
</TabsTrigger>
<TabsTrigger value='traffic' className='flex-1'>
Traffic Logs
</TabsTrigger>
<TabsTrigger value='devices' className='flex-1'>
Online Devices
</TabsTrigger>
</TabsList>
<TabsContent value='logs'>
<ProTable
columns={[
{
accessorKey: 'action',
header: 'Action',
},
{
accessorKey: 'created_at',
header: 'Time',
cell: ({ row }) => formatDate(row.getValue('created_at')),
},
]}
request={async () => ({
list: mockLogs,
total: mockLogs.length,
})}
/>
</TabsContent>
<TabsContent value='traffic'>
<ProTable
columns={[
{
accessorKey: 'traffic',
header: 'Traffic',
cell: ({ row }) => <Display type='traffic' value={row.getValue('traffic')} />,
},
{
accessorKey: 'created_at',
header: 'Time',
cell: ({ row }) => formatDate(row.getValue('created_at')),
},
]}
request={async () => ({
list: mockTrafficLogs,
total: mockTrafficLogs.length,
})}
/>
</TabsContent>
<TabsContent value='devices'>
<ProTable
columns={[
{
accessorKey: 'ip',
header: 'IP',
},
{
accessorKey: 'last_seen_at',
header: 'Last Seen',
cell: ({ row }) => formatDate(row.getValue('last_seen_at')),
},
]}
request={async () => ({
list: mockDevices,
total: mockDevices.length,
})}
actions={{
render: (row) => {
return [
<ConfirmButton
key='offline'
trigger={
<Button variant='destructive' size='sm'>
线
</Button>
}
title='Confirm Offline'
description={`Are you sure to offline IP ${row.ip}?`}
onConfirm={() => handleOfflineDevice(row.id)}
cancelText='Cancel'
confirmText='Confirm'
/>,
];
},
}}
/>
</TabsContent>
</Tabs>
</div>
</DialogContent>
</Dialog>
);
}

View File

@ -0,0 +1,127 @@
'use client';
import { Button } from '@workspace/ui/components/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@workspace/ui/components/form';
import { Input } from '@workspace/ui/components/input';
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@workspace/ui/components/sheet';
import { ReactNode, useState } from 'react';
import { useForm } from 'react-hook-form';
interface Props {
trigger: ReactNode;
title: string;
loading?: boolean;
userId: string;
initialData?: API.Subscribe;
onSubmit: (values: any) => Promise<boolean>;
}
export function SubscriptionForm({
trigger,
title,
loading,
userId,
initialData,
onSubmit,
}: Props) {
const [open, setOpen] = useState(false);
const form = useForm({
defaultValues: {
user_id: userId,
name: initialData?.name || '',
traffic: initialData?.traffic || 0,
speed_limit: initialData?.speed_limit || 0,
device_limit: initialData?.device_limit || 0,
...(initialData && { id: initialData.id }),
},
});
const handleSubmit = async (values: any) => {
const success = await onSubmit(values);
if (success) {
setOpen(false);
form.reset();
}
};
return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>{trigger}</SheetTrigger>
<SheetContent side='right'>
<SheetHeader>
<SheetTitle>{title}</SheetTitle>
</SheetHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(handleSubmit)} className='mt-4 space-y-4'>
<FormField
control={form.control}
name='name'
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='traffic'
render={({ field }) => (
<FormItem>
<FormLabel>Traffic (Bytes)</FormLabel>
<FormControl>
<Input type='number' {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='speed_limit'
render={({ field }) => (
<FormItem>
<FormLabel>Speed Limit (Mbps)</FormLabel>
<FormControl>
<Input type='number' {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='device_limit'
render={({ field }) => (
<FormItem>
<FormLabel>Device Limit</FormLabel>
<FormControl>
<Input type='number' {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type='submit'>Submit</Button>
</form>
</Form>
</SheetContent>
</Sheet>
);
}

View File

@ -3,11 +3,13 @@
import { Display } from '@/components/display';
import { ProTable, ProTableActions } from '@/components/pro-table';
import { createUser, deleteUser, getUserList, updateUser } from '@/services/admin/user';
import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button';
import { Switch } from '@workspace/ui/components/switch';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import Link from 'next/link';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import { UserDetail } from './user-detail';
@ -74,7 +76,21 @@ export default function Page() {
{
accessorKey: 'auth_methods',
header: t('userName'),
cell: ({ row }) => row.original.auth_methods?.[0]?.auth_identifier || '--',
cell: ({ row }) => {
const method = row.original.auth_methods?.[0];
return (
<div>
<Badge
variant={method?.verified ? 'default' : 'destructive'}
className='mr-1 uppercase'
title={method?.verified ? t('verified') : ''}
>
{method?.auth_type}
</Badge>
{method?.auth_identifier}
</div>
);
},
},
{
accessorKey: 'balance',
@ -117,31 +133,9 @@ export default function Page() {
actions={{
render: (row) => {
return [
<UserForm<API.UpdateUserRequest>
key='edit'
trigger={t('edit')}
title={t('editUser')}
loading={loading}
initialValues={row as unknown as API.UpdateUserRequest}
onSubmit={async (values) => {
setLoading(true);
try {
await updateUser({
...row,
...values,
});
toast.success(t('updateSuccess'));
ref.current?.refresh();
setLoading(false);
return true;
} catch (error) {
setLoading(false);
return false;
}
}}
/>,
<Button key='detail' asChild>
<Link href={`/dashboard/user/${row.id}`}>{t('edit')}</Link>
</Button>,
<ConfirmButton
key='edit'
trigger={<Button variant='destructive'>{t('delete')}</Button>}

View File

@ -7,6 +7,7 @@ import { Button } from '@workspace/ui/components/button';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@workspace/ui/components/hover-card';
import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import Link from 'next/link';
import { useState } from 'react';
export function UserDetail({ id }: { id: number }) {
@ -27,8 +28,10 @@ export function UserDetail({ id }: { id: number }) {
return (
<HoverCard>
<HoverCardTrigger asChild onMouseEnter={() => setShouldFetch(true)}>
<Button variant='link' className='p-0'>
@{data?.email?.split('@')[0] || 'Loading...'}
<Button variant='link' className='p-0' asChild>
<Link href={`/dashboard/user/${id}`}>
{data?.auth_methods[0]?.auth_identifier || t('loading')}
</Link>
</Button>
</HoverCardTrigger>
<HoverCardContent>
@ -38,10 +41,6 @@ export function UserDetail({ id }: { id: number }) {
<span className='text-muted-foreground'>ID</span>
<span>{data?.id}</span>
</li>
<li className='flex items-center justify-between font-semibold'>
<span className='text-muted-foreground'>{t('email')}</span>
<span>{data?.email}</span>
</li>
<li className='flex items-center justify-between font-semibold'>
<span className='text-muted-foreground'>{t('balance')}</span>
<span>

View File

@ -21,6 +21,7 @@ import {
SheetTrigger,
} from '@workspace/ui/components/sheet';
import { Switch } from '@workspace/ui/components/switch';
import { AreaCodeSelect } from '@workspace/ui/custom-components/area-code-select';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { Icon } from '@workspace/ui/custom-components/icon';
import { unitConversion } from '@workspace/ui/utils';
@ -51,9 +52,9 @@ export default function UserForm<T extends Record<string, any>>({
const [open, setOpen] = useState(false);
const formSchema = z.object({
// email: z.string().email(t('form.invalidEmailFormat')),
// telephone_area_code: z.string().optional(),
// telephone: z.string().optional(),
email: z.string().email(t('invalidEmailFormat')),
telephone_area_code: z.string().optional(),
telephone: z.string().optional(),
password: z.string().optional(),
referer_id: z.number().optional(),
refer_code: z.string().optional(),
@ -98,15 +99,15 @@ export default function UserForm<T extends Record<string, any>>({
<ScrollArea className='-mx-6 h-[calc(100dvh-48px-36px-36px-env(safe-area-inset-top))]'>
<Form {...form}>
<form onSubmit={form.handleSubmit(handleSubmit)} className='space-y-4 px-6 pt-4'>
{/* <FormField
<FormField
control={form.control}
name='email'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.userEmail')}</FormLabel>
<FormLabel>{t('userEmail')}</FormLabel>
<FormControl>
<EnhancedInput
placeholder={t('form.userEmailPlaceholder')}
placeholder={t('userEmailPlaceholder')}
{...field}
onValueChange={(value) => {
form.setValue(field.name, value);
@ -123,7 +124,7 @@ export default function UserForm<T extends Record<string, any>>({
name='telephone'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.telephone')}</FormLabel>
<FormLabel>{t('telephone')}</FormLabel>
<FormControl>
<EnhancedInput
prefix={
@ -136,7 +137,7 @@ export default function UserForm<T extends Record<string, any>>({
<AreaCodeSelect
className='w-32 rounded-none border-y-0 border-l-0'
simple
placeholder={t('form.areaCodePlaceholder')}
placeholder={t('areaCodePlaceholder')}
value={field.value}
onChange={(value) => {
form.setValue(field.name, value.phone);
@ -148,7 +149,7 @@ export default function UserForm<T extends Record<string, any>>({
)}
/>
}
placeholder={t('form.telephonePlaceholder')}
placeholder={t('telephonePlaceholder')}
{...field}
onValueChange={(value) => {
form.setValue(field.name, value);
@ -158,16 +159,16 @@ export default function UserForm<T extends Record<string, any>>({
<FormMessage />
</FormItem>
)}
/> */}
/>
<FormField
control={form.control}
name='password'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.password')}</FormLabel>
<FormLabel>{t('password')}</FormLabel>
<FormControl>
<EnhancedInput
placeholder={t('form.passwordPlaceholder')}
placeholder={t('passwordPlaceholder')}
{...field}
onValueChange={(value) => {
form.setValue(field.name, value);
@ -183,10 +184,10 @@ export default function UserForm<T extends Record<string, any>>({
name='referer_id'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.refererId')}</FormLabel>
<FormLabel>{t('refererId')}</FormLabel>
<FormControl>
<EnhancedInput
placeholder={t('form.refererIdPlaceholder')}
placeholder={t('refererIdPlaceholder')}
{...field}
type='number'
onValueChange={(value) => {
@ -203,10 +204,10 @@ export default function UserForm<T extends Record<string, any>>({
name='refer_code'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.inviteCode')}</FormLabel>
<FormLabel>{t('inviteCode')}</FormLabel>
<FormControl>
<EnhancedInput
placeholder={t('form.inviteCodePlaceholder')}
placeholder={t('inviteCodePlaceholder')}
{...field}
onValueChange={(value) => {
form.setValue(field.name, value);
@ -222,11 +223,11 @@ export default function UserForm<T extends Record<string, any>>({
name='balance'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.balance')}</FormLabel>
<FormLabel>{t('balance')}</FormLabel>
<FormControl>
<EnhancedInput
prefix={currency?.currency_symbol ?? '$'}
placeholder={t('form.balancePlaceholder')}
placeholder={t('balancePlaceholder')}
type='number'
{...field}
formatInput={(value) => unitConversion('centsToDollars', value)}
@ -246,11 +247,11 @@ export default function UserForm<T extends Record<string, any>>({
name='gift_amount'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.giftAmount')}</FormLabel>
<FormLabel>{t('giftAmount')}</FormLabel>
<FormControl>
<EnhancedInput
prefix={currency?.currency_symbol ?? '$'}
placeholder={t('form.giftAmountPlaceholder')}
placeholder={t('giftAmountPlaceholder')}
type='number'
{...field}
formatInput={(value) => unitConversion('centsToDollars', value)}
@ -270,11 +271,11 @@ export default function UserForm<T extends Record<string, any>>({
name='commission'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.commission')}</FormLabel>
<FormLabel>{t('commission')}</FormLabel>
<FormControl>
<EnhancedInput
prefix={currency?.currency_symbol ?? '$'}
placeholder={t('form.commissionPlaceholder')}
placeholder={t('commissionPlaceholder')}
type='number'
{...field}
formatInput={(value) => unitConversion('centsToDollars', value)}
@ -294,7 +295,7 @@ export default function UserForm<T extends Record<string, any>>({
name='is_admin'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.manager')}</FormLabel>
<FormLabel>{t('manager')}</FormLabel>
<FormControl>
<div className='pt-2'>
<Switch checked={!!field.value} onCheckedChange={field.onChange} />
@ -315,11 +316,10 @@ export default function UserForm<T extends Record<string, any>>({
setOpen(false);
}}
>
{t('form.cancel')}
{t('cancel')}
</Button>
<Button disabled={loading} onClick={form.handleSubmit(handleSubmit)}>
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />}{' '}
{t('form.confirm')}
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />} {t('confirm')}
</Button>
</SheetFooter>
</SheetContent>

View File

@ -2,6 +2,7 @@
import { ProTable as _ProTable, ProTableProps } from '@workspace/ui/custom-components/pro-table';
import { useTranslations } from 'next-intl';
import { Empty } from './empty';
export { type ProTableActions } from '@workspace/ui/custom-components/pro-table';
export function ProTable<
@ -25,6 +26,7 @@ export function ProTable<
},
textRowsPerPage: t('rowsPerPage'),
}}
empty={<Empty />}
/>
);
}

View File

@ -101,6 +101,12 @@ export const navs = [
title: 'User Management',
url: '/dashboard/user',
icon: 'flat-color-icons:conference-call',
items: [
{
title: 'User Detail',
url: '/dashboard/user/:id',
},
],
},
{
title: 'Announcement Management',
@ -127,9 +133,15 @@ export const navs = [
];
export function findNavByUrl(url: string) {
function matchDynamicRoute(pattern: string, path: string): boolean {
const regexPattern = pattern.replace(/:[^/]+/g, '[^/]+').replace(/\//g, '\\/');
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(path);
}
function findNav(items: any[], url: string, path: any[] = []): any[] {
for (const item of items) {
if (item.url === url) {
if (item.url === url || (item.url && matchDynamicRoute(item.url, url))) {
return [...path, item];
}
if (item.items) {

View File

@ -24,5 +24,6 @@
"Ticket Management": "Správa lístků",
"Twitter": "Twitter",
"User": "Uživatel",
"User Detail": "Podrobnosti o uživateli",
"User Management": "Správa uživatelů"
}

View File

@ -1,8 +1,17 @@
{
"actions": "akce",
"areaCode": "Směrový kód",
"areaCodePlaceholder": "Kód oblasti",
"auth": "Autentizace",
"authIdentifier": "Identifikátor ověření",
"authIdentifierPlaceholder": "Zadejte identifikátor ověření",
"authType": "Typ ověření",
"authUser": "Autentizovaný uživatel",
"balance": "Zůstatek",
"balancePlaceholder": "Zůstatek",
"cancel": "zrušit",
"commission": "Provize",
"commissionPlaceholder": "Zadejte provizi",
"confirm": "Potvrdit",
"confirmDelete": "Opravdu chcete smazat?",
"create": "Vytvořit",
@ -12,39 +21,38 @@
"delete": "smazat",
"deleteDescription": "Po odstranění nelze data obnovit, prosím, postupujte opatrně.",
"deleteSuccess": "Úspěšně odstraněno",
"detail": "Detail",
"edit": "Upravit",
"editUser": "Upravit uživatele",
"email": "e-mail",
"enable": "Povolit",
"form": {
"areaCode": "Směrové číslo",
"areaCodePlaceholder": "Směrové číslo",
"balance": "Zůstatek",
"balancePlaceholder": "Zůstatek",
"cancel": "Zrušit",
"commission": "Provize",
"commissionPlaceholder": "Zadejte provizi",
"confirm": "Potvrdit",
"giftAmount": "Částka daru",
"giftAmountPlaceholder": "Zadejte částku daru",
"invalidEmailFormat": "Neplatný formát e-mailu",
"inviteCode": "Pozvánkový kód",
"inviteCodePlaceholder": "Zadejte pozvánkový kód (ponechte prázdné pro automatické generování)",
"manager": "Správce",
"password": "Heslo",
"passwordPlaceholder": "Zadejte nové heslo (může zůstat prázdné)",
"refererId": "ID doporučitele",
"refererIdPlaceholder": "Zadejte ID doporučitele",
"telephone": "Telefonní číslo",
"telephonePlaceholder": "Zadejte telefonní číslo",
"userEmail": "E-mail uživatele",
"userEmailPlaceholder": "Zadejte e-mail uživatele"
},
"giftAmount": "Částka dárku",
"giftAmountPlaceholder": "Zadejte částku dárku",
"invalidEmailFormat": "Neplatný formát e-mailu",
"inviteCode": "Pozvánkový kód",
"inviteCodePlaceholder": "Zadejte kód pozvánky (ponechte prázdné pro vygenerování)",
"loading": "Načítání...",
"loginIp": "Přihlašovací IP",
"loginTime": "Čas přihlášení",
"manager": "Manažer",
"password": "Heslo",
"passwordPlaceholder": "Zadejte nové heslo (volitelné)",
"referer": "Doporučitel",
"refererId": "ID doporučitele",
"refererIdPlaceholder": "Zadejte ID doporučitele",
"searchIp": "Vyhledat IP adresu",
"selectAuthType": "Vyberte typ ověření",
"telephone": "Telefonní číslo",
"telephonePlaceholder": "Zadejte telefonní číslo",
"updateSuccess": "Aktualizace byla úspěšná",
"userAgent": "Uživatelský agent",
"userEmail": "Uživatelský e-mail",
"userEmailPlaceholder": "Zadejte e-mail uživatele",
"userList": "Seznam uživatelů",
"userName": "Identifikátor uživatele"
"userLogs": "Historie přihlášení",
"userName": "Identifikátor uživatele",
"userOrders": "Objednávky",
"userProfile": "Profil",
"userSubscriptions": "Předplatné",
"verified": "Ověřeno"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Ticketverwaltung",
"Twitter": "Twitter",
"User": "Benutzer",
"User Detail": "Benutzerdetails",
"User Management": "Benutzerverwaltung"
}

View File

@ -1,8 +1,17 @@
{
"actions": "Aktionen",
"areaCode": "Vorwahl",
"areaCodePlaceholder": "Vorwahl",
"auth": "Authentifizierung",
"authIdentifier": "Authentifizierungskennung",
"authIdentifierPlaceholder": "Geben Sie die Authentifizierungskennung ein",
"authType": "Authentifizierungstyp",
"authUser": "Authentifizierter Benutzer",
"balance": "Kontostand",
"balancePlaceholder": "Kontostand",
"cancel": "Abbrechen",
"commission": "Provision",
"commissionPlaceholder": "Provision eingeben",
"confirm": "Bestätigen",
"confirmDelete": "Sind Sie sicher, dass Sie löschen möchten?",
"create": "Erstellen",
@ -12,39 +21,38 @@
"delete": "Löschen",
"deleteDescription": "Nach dem Löschen können die Daten nicht wiederhergestellt werden. Bitte gehen Sie vorsichtig vor.",
"deleteSuccess": "Erfolgreich gelöscht",
"detail": "Detail",
"edit": "Bearbeiten",
"editUser": "Benutzer bearbeiten",
"email": "E-Mail",
"enable": "Aktivieren",
"form": {
"areaCode": "Vorwahl",
"areaCodePlaceholder": "Vorwahl eingeben",
"balance": "Kontostand",
"balancePlaceholder": "Kontostand",
"cancel": "Abbrechen",
"commission": "Provision",
"commissionPlaceholder": "Geben Sie die Provision ein",
"confirm": "Bestätigen",
"giftAmount": "Geschenkbetrag",
"giftAmountPlaceholder": "Geben Sie den Geschenkbetrag ein",
"invalidEmailFormat": "Ungültiges E-Mail-Format",
"inviteCode": "Einladungscode",
"inviteCodePlaceholder": "Bitte Einladungscode eingeben (leer lassen für automatische Generierung)",
"manager": "Administrator",
"password": "Passwort",
"passwordPlaceholder": "Bitte neues Passwort eingeben (kann leer bleiben)",
"refererId": "Empfehler-ID",
"refererIdPlaceholder": "Bitte Empfehler-ID eingeben",
"telephone": "Telefonnummer",
"telephonePlaceholder": "Telefonnummer eingeben",
"userEmail": "Benutzer-E-Mail",
"userEmailPlaceholder": "Bitte Benutzer-E-Mail eingeben"
},
"giftAmount": "Geschenkbetrag",
"giftAmountPlaceholder": "Geben Sie den Geschenkbetrag ein",
"invalidEmailFormat": "Ungültiges E-Mail-Format",
"inviteCode": "Einladungscode",
"inviteCodePlaceholder": "Einladungscode eingeben (leer lassen, um zu generieren)",
"loading": "Laden...",
"loginIp": "Login-IP",
"loginTime": "Anmeldezeit",
"manager": "Manager",
"password": "Passwort",
"passwordPlaceholder": "Neues Passwort eingeben (optional)",
"referer": "Empfehler",
"refererId": "Referenz-ID",
"refererIdPlaceholder": "Geben Sie die Referenz-ID ein",
"searchIp": "IP-Adresse suchen",
"selectAuthType": "Authentifizierungstyp auswählen",
"telephone": "Telefonnummer",
"telephonePlaceholder": "Telefonnummer eingeben",
"updateSuccess": "Aktualisierung erfolgreich",
"userAgent": "Benutzeragent",
"userEmail": "Benutzer-E-Mail",
"userEmailPlaceholder": "Benutzer-E-Mail eingeben",
"userList": "Benutzerliste",
"userName": "Benutzerkennung"
"userLogs": "Anmeldeverlauf",
"userName": "Benutzerkennung",
"userOrders": "Bestellungen",
"userProfile": "Profil",
"userSubscriptions": "Abonnements",
"verified": "Verifiziert"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Ticket Management",
"Twitter": "Twitter",
"User": "User",
"User Detail": "User Detail",
"User Management": "User Management"
}

View File

@ -13,7 +13,14 @@
"stripe_wechat_pay": "Stripe (WeChat)"
},
"orderNumber": "Order Number",
"status": "Order Status",
"status": {
"0": "Status",
"1": "Pending",
"2": "Paid",
"3": "Cancelled",
"4": "Closed",
"5": "Completed"
},
"subscribe": "Subscribe",
"subscribePrice": "Subscription Price",
"total": "Total",

View File

@ -1,8 +1,17 @@
{
"actions": "Actions",
"areaCode": "Area Code",
"areaCodePlaceholder": "Area code",
"auth": "Auth",
"authIdentifier": "Auth Identifier",
"authIdentifierPlaceholder": "Enter auth identifier",
"authType": "Auth Type",
"authUser": "Auth User",
"balance": "Balance",
"balancePlaceholder": "Balance",
"cancel": "Cancel",
"commission": "Commission",
"commissionPlaceholder": "Enter commission",
"confirm": "Confirm",
"confirmDelete": "Are you sure you want to delete?",
"create": "Create",
@ -12,39 +21,38 @@
"delete": "Delete",
"deleteDescription": "Data cannot be recovered after deletion, please proceed with caution.",
"deleteSuccess": "Delete successful",
"detail": "Detail",
"edit": "Edit",
"editUser": "Edit User",
"email": "Email",
"enable": "Enable",
"form": {
"areaCode": "Area Code",
"areaCodePlaceholder": "Area code",
"balance": "Balance",
"balancePlaceholder": "Balance",
"cancel": "Cancel",
"commission": "Commission",
"commissionPlaceholder": "Enter commission",
"confirm": "Confirm",
"giftAmount": "Gift Amount",
"giftAmountPlaceholder": "Enter gift amount",
"invalidEmailFormat": "Invalid email format",
"inviteCode": "Invite Code",
"inviteCodePlaceholder": "Enter invite code (leave blank to generate)",
"manager": "Manager",
"password": "Password",
"passwordPlaceholder": "Enter new password (optional)",
"refererId": "Referer ID",
"refererIdPlaceholder": "Enter referer ID",
"telephone": "Phone Number",
"telephonePlaceholder": "Enter phone number",
"userEmail": "User Email",
"userEmailPlaceholder": "Enter user email"
},
"giftAmount": "Gift Amount",
"giftAmountPlaceholder": "Enter gift amount",
"invalidEmailFormat": "Invalid email format",
"inviteCode": "Invite Code",
"inviteCodePlaceholder": "Enter invite code (leave blank to generate)",
"loading": "Loading...",
"loginIp": "Login IP",
"loginTime": "Login Time",
"manager": "Manager",
"password": "Password",
"passwordPlaceholder": "Enter new password (optional)",
"referer": "Referer",
"refererId": "Referer ID",
"refererIdPlaceholder": "Enter referer ID",
"searchIp": "Search IP address",
"selectAuthType": "Select auth type",
"telephone": "Phone Number",
"telephonePlaceholder": "Enter phone number",
"updateSuccess": "Update successful",
"userAgent": "User Agent",
"userEmail": "User Email",
"userEmailPlaceholder": "Enter user email",
"userList": "User List",
"userName": "User Identifier"
"userLogs": "Login History",
"userName": "User Identifier",
"userOrders": "Orders",
"userProfile": "Profile",
"userSubscriptions": "Subscriptions",
"verified": "Verified"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Gestión de Tickets",
"Twitter": "Twitter",
"User": "Usuario",
"User Detail": "Detalle del Usuario",
"User Management": "Gestión de Usuarios"
}

View File

@ -1,8 +1,17 @@
{
"actions": "acciones",
"areaCode": "Código de Área",
"areaCodePlaceholder": "Código de área",
"auth": "Autenticación",
"authIdentifier": "Identificador de Autenticación",
"authIdentifierPlaceholder": "Ingrese el identificador de autenticación",
"authType": "Tipo de Autenticación",
"authUser": "Usuario Autenticado",
"balance": "Saldo",
"balancePlaceholder": "Saldo",
"cancel": "Cancelar",
"commission": "Comisión",
"commissionPlaceholder": "Ingrese comisión",
"confirm": "Confirmar",
"confirmDelete": "¿Está seguro de que desea eliminar?",
"create": "Crear",
@ -12,39 +21,38 @@
"delete": "eliminar",
"deleteDescription": "Después de eliminar, los datos no se podrán recuperar. Proceda con precaución.",
"deleteSuccess": "Eliminación exitosa",
"detail": "Detalle",
"edit": "editar",
"editUser": "Editar usuario",
"email": "correo electrónico",
"enable": "Habilitar",
"form": {
"areaCode": "Código de Área",
"areaCodePlaceholder": "Código de área",
"balance": "Saldo",
"balancePlaceholder": "Saldo",
"cancel": "Cancelar",
"commission": "Comisión",
"commissionPlaceholder": "Ingrese la comisión",
"confirm": "Confirmar",
"giftAmount": "Monto del Regalo",
"giftAmountPlaceholder": "Ingrese el monto del regalo",
"invalidEmailFormat": "Formato de correo electrónico no válido",
"inviteCode": "Código de invitación",
"inviteCodePlaceholder": "Por favor, introduzca el código de invitación (déjelo en blanco para generar automáticamente)",
"manager": "Administrador",
"password": "Contraseña",
"passwordPlaceholder": "Por favor, introduzca una nueva contraseña (puede dejarlo en blanco)",
"refererId": "ID del referente",
"refererIdPlaceholder": "Por favor, introduzca el ID del referente",
"telephone": "Número de Teléfono",
"telephonePlaceholder": "Ingrese número de teléfono",
"userEmail": "Correo electrónico del usuario",
"userEmailPlaceholder": "Por favor, introduzca el correo electrónico del usuario"
},
"giftAmount": "Monto del Regalo",
"giftAmountPlaceholder": "Ingrese el monto del regalo",
"invalidEmailFormat": "Formato de correo electrónico no válido",
"inviteCode": "Código de invitación",
"inviteCodePlaceholder": "Introduce el código de invitación (déjalo en blanco para generar uno)",
"loading": "Cargando...",
"loginIp": "IP de inicio de sesión",
"loginTime": "Hora de inicio de sesión",
"manager": "Gerente",
"password": "Contraseña",
"passwordPlaceholder": "Ingrese nueva contraseña (opcional)",
"referer": "Recomendador",
"refererId": "ID del Referente",
"refererIdPlaceholder": "Ingrese el ID del referente",
"searchIp": "Buscar dirección IP",
"selectAuthType": "Seleccionar tipo de autenticación",
"telephone": "Número de Teléfono",
"telephonePlaceholder": "Ingrese número de teléfono",
"updateSuccess": "Actualización exitosa",
"userAgent": "Agente de Usuario",
"userEmail": "Correo Electrónico del Usuario",
"userEmailPlaceholder": "Introduce el correo electrónico del usuario",
"userList": "Lista de usuarios",
"userName": "Identificador de Usuario"
"userLogs": "Historial de inicio de sesión",
"userName": "Identificador de Usuario",
"userOrders": "Pedidos",
"userProfile": "Perfil",
"userSubscriptions": "Suscripciones",
"verified": "Verificado"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Gestión de Tickets",
"Twitter": "Twitter",
"User": "Usuario",
"User Detail": "Detalle del Usuario",
"User Management": "Gestión de Usuarios"
}

View File

@ -1,8 +1,17 @@
{
"actions": "acciones",
"areaCode": "Código de Área",
"areaCodePlaceholder": "Código de área",
"auth": "Autenticación",
"authIdentifier": "Identificador de Autenticación",
"authIdentifierPlaceholder": "Ingrese identificador de autenticación",
"authType": "Tipo de Autenticación",
"authUser": "Usuario Autenticado",
"balance": "Saldo",
"balancePlaceholder": "Saldo",
"cancel": "Cancelar",
"commission": "Comisión",
"commissionPlaceholder": "Ingrese comisión",
"confirm": "Confirmar",
"confirmDelete": "¿Está seguro de que desea eliminar?",
"create": "Crear",
@ -12,39 +21,38 @@
"delete": "Eliminar",
"deleteDescription": "Después de eliminar, los datos no se pueden recuperar. Proceda con precaución.",
"deleteSuccess": "Eliminación exitosa",
"detail": "Detalle",
"edit": "editar",
"editUser": "Editar usuario",
"email": "correo electrónico",
"enable": "Habilitar",
"form": {
"areaCode": "Código de Área",
"areaCodePlaceholder": "Código de área",
"balance": "Saldo",
"balancePlaceholder": "Saldo",
"cancel": "Cancelar",
"commission": "Comisión",
"commissionPlaceholder": "Ingrese la comisión",
"confirm": "Confirmar",
"giftAmount": "Monto del Regalo",
"giftAmountPlaceholder": "Ingrese el monto del regalo",
"invalidEmailFormat": "Formato de correo electrónico no válido",
"inviteCode": "Código de invitación",
"inviteCodePlaceholder": "Ingrese el código de invitación (déjelo en blanco para generar automáticamente)",
"manager": "Administrador",
"password": "Contraseña",
"passwordPlaceholder": "Ingrese nueva contraseña (opcional)",
"refererId": "ID del referente",
"refererIdPlaceholder": "Ingrese ID del referente",
"telephone": "Número de Teléfono",
"telephonePlaceholder": "Ingrese número de teléfono",
"userEmail": "Correo electrónico del usuario",
"userEmailPlaceholder": "Ingrese el correo electrónico del usuario"
},
"giftAmount": "Monto del Regalo",
"giftAmountPlaceholder": "Ingrese el monto del regalo",
"invalidEmailFormat": "Formato de correo electrónico no válido",
"inviteCode": "Código de Invitación",
"inviteCodePlaceholder": "Ingresa el código de invitación (déjalo en blanco para generar uno)",
"loading": "Cargando...",
"loginIp": "IP de inicio de sesión",
"loginTime": "Hora de Inicio de Sesión",
"manager": "Gerente",
"password": "Contraseña",
"passwordPlaceholder": "Ingresa nueva contraseña (opcional)",
"referer": "Recomendador",
"refererId": "ID del Referente",
"refererIdPlaceholder": "Ingrese ID del referente",
"searchIp": "Buscar dirección IP",
"selectAuthType": "Seleccionar tipo de autenticación",
"telephone": "Número de Teléfono",
"telephonePlaceholder": "Ingrese número de teléfono",
"updateSuccess": "Actualización exitosa",
"userAgent": "Agente de Usuario",
"userEmail": "Correo Electrónico del Usuario",
"userEmailPlaceholder": "Ingresa el correo electrónico del usuario",
"userList": "Lista de usuarios",
"userName": "Identificador de Usuario"
"userLogs": "Historial de Inicio de Sesión",
"userName": "Identificador de Usuario",
"userOrders": "Pedidos",
"userProfile": "Perfil",
"userSubscriptions": "Suscripciones",
"verified": "Verificado"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "مدیریت بلیط",
"Twitter": "توییتر",
"User": "کاربر",
"User Detail": "جزئیات کاربر",
"User Management": "مدیریت کاربران"
}

View File

@ -1,8 +1,17 @@
{
"actions": "اقدامات",
"areaCode": "کد منطقه",
"areaCodePlaceholder": "کد منطقه",
"auth": "احراز هویت",
"authIdentifier": "شناسه احراز هویت",
"authIdentifierPlaceholder": "شناسه احراز هویت را وارد کنید",
"authType": "نوع احراز هویت",
"authUser": "کاربر تأیید شده",
"balance": "تعادل",
"balancePlaceholder": "موجودی",
"cancel": "لغو",
"commission": "کمیسیون",
"commissionPlaceholder": "کمیسیون را وارد کنید",
"confirm": "تأیید",
"confirmDelete": "آیا مطمئن هستید که می‌خواهید حذف کنید؟",
"create": "ایجاد",
@ -12,39 +21,38 @@
"delete": "حذف",
"deleteDescription": "پس از حذف، داده‌ها قابل بازیابی نیستند، لطفاً با احتیاط ادامه دهید.",
"deleteSuccess": "حذف با موفقیت انجام شد",
"detail": "جزئیات",
"edit": "ویرایش",
"editUser": "ویرایش کاربر",
"email": "ایمیل",
"enable": "فعال کردن",
"form": {
"areaCode": "کد منطقه",
"areaCodePlaceholder": "کد منطقه",
"balance": "موجودی",
"balancePlaceholder": "موجودی",
"cancel": "لغو",
"commission": "کمیسیون",
"commissionPlaceholder": "کمیسیون را وارد کنید",
"confirm": "تأیید",
"giftAmount": "مبلغ هدیه",
"giftAmountPlaceholder": "مبلغ هدیه را وارد کنید",
"invalidEmailFormat": "فرمت ایمیل نامعتبر است",
"inviteCode": "کد دعوت",
"inviteCodePlaceholder": "کد دعوت را وارد کنید (برای تولید خالی بگذارید)",
"manager": "مدیر",
"password": "رمز عبور",
"passwordPlaceholder": "رمز عبور جدید را وارد کنید (اختیاری)",
"refererId": "شناسه معرف",
"refererIdPlaceholder": "شناسه معرف را وارد کنید",
"telephone": "شماره تلفن",
"telephonePlaceholder": "شماره تلفن را وارد کنید",
"userEmail": "ایمیل کاربر",
"userEmailPlaceholder": "ایمیل کاربر را وارد کنید"
},
"giftAmount": "مقدار هدیه",
"giftAmountPlaceholder": "مبلغ هدیه را وارد کنید",
"invalidEmailFormat": "فرمت ایمیل نامعتبر است",
"inviteCode": "کد دعوت",
"inviteCodePlaceholder": "کد دعوت را وارد کنید (برای تولید خالی بگذارید)",
"loading": "در حال بارگذاری...",
"loginIp": "آی‌پی ورود",
"loginTime": "زمان ورود",
"manager": "مدیر",
"password": "رمز عبور",
"passwordPlaceholder": "رمز عبور جدید را وارد کنید (اختیاری)",
"referer": "ارجاع‌دهنده",
"refererId": "شناسه معرف",
"refererIdPlaceholder": "شناسه معرف را وارد کنید",
"searchIp": "جستجوی آدرس IP",
"selectAuthType": "نوع احراز هویت را انتخاب کنید",
"telephone": "شماره تلفن",
"telephonePlaceholder": "شماره تلفن را وارد کنید",
"updateSuccess": "به‌روزرسانی با موفقیت انجام شد",
"userAgent": "عامل کاربر",
"userEmail": "ایمیل کاربر",
"userEmailPlaceholder": "ایمیل کاربر را وارد کنید",
"userList": "فهرست کاربران",
"userName": "شناسه کاربر"
"userLogs": "تاریخچه ورود",
"userName": "شناسه کاربر",
"userOrders": "سفارش‌ها",
"userProfile": "پروفایل",
"userSubscriptions": "اشتراک‌ها",
"verified": "تأیید شده"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Lipputoiminta",
"Twitter": "Twitter",
"User": "Käyttäjä",
"User Detail": "Käyttäjän tiedot",
"User Management": "Käyttäjien hallinta"
}

View File

@ -1,8 +1,17 @@
{
"actions": "toiminnot",
"areaCode": "Alueen koodi",
"areaCodePlaceholder": "Alueen koodi",
"auth": "Tunnistus",
"authIdentifier": "Tunnistautumistunnus",
"authIdentifierPlaceholder": "Syötä tunnistautumistunnus",
"authType": "Todennustyyppi",
"authUser": "Todennus Käyttäjä",
"balance": "Saldo",
"balancePlaceholder": "Saldo",
"cancel": "Peruuta",
"commission": "Komissio",
"commissionPlaceholder": "Syötä komissio",
"confirm": "Vahvista",
"confirmDelete": "Oletko varma, että haluat poistaa?",
"create": "Luo",
@ -12,39 +21,38 @@
"delete": "poista",
"deleteDescription": "Poistamisen jälkeen tietoja ei voi palauttaa, ole varovainen.",
"deleteSuccess": "Poisto onnistui",
"detail": "Yksityiskohta",
"edit": "muokkaa",
"editUser": "Muokkaa käyttäjää",
"email": "sähköposti",
"enable": "Ota käyttöön",
"form": {
"areaCode": "Aluekoodi",
"areaCodePlaceholder": "Aluekoodi",
"balance": "Saldo",
"balancePlaceholder": "Saldo",
"cancel": "Peruuta",
"commission": "Komissio",
"commissionPlaceholder": "Syötä komissio",
"confirm": "Vahvista",
"giftAmount": "Lahjan määrä",
"giftAmountPlaceholder": "Syötä lahjan määrä",
"invalidEmailFormat": "Virheellinen sähköpostimuoto",
"inviteCode": "Kutsukoodi",
"inviteCodePlaceholder": "Syötä kutsukoodi (jätä tyhjäksi, jos haluat luoda automaattisesti)",
"manager": "Ylläpitäjä",
"password": "Salasana",
"passwordPlaceholder": "Syötä uusi salasana (voi jättää tyhjäksi)",
"refererId": "Suosittelijan ID",
"refererIdPlaceholder": "Syötä suosittelijan ID",
"telephone": "Puhelinnumero",
"telephonePlaceholder": "Syötä puhelinnumero",
"userEmail": "Käyttäjän sähköposti",
"userEmailPlaceholder": "Syötä käyttäjän sähköposti"
},
"giftAmount": "Lahjan määrä",
"giftAmountPlaceholder": "Syötä lahjan määrä",
"invalidEmailFormat": "Virheellinen sähköpostimuoto",
"inviteCode": "Kutsukoodi",
"inviteCodePlaceholder": "Syötä kutsukoodi (jätä tyhjäksi luodaksesi uuden)",
"loading": "Ladataan...",
"loginIp": "Kirjautumis-IP",
"loginTime": "Kirjautumisaika",
"manager": "Johtaja",
"password": "Salasana",
"passwordPlaceholder": "Syötä uusi salasana (valinnainen)",
"referer": "Suosittelija",
"refererId": "Viittaajan ID",
"refererIdPlaceholder": "Syötä suosittelijan ID",
"searchIp": "Etsi IP-osoite",
"selectAuthType": "Valitse todennustyyppi",
"telephone": "Puhelinnumero",
"telephonePlaceholder": "Syötä puhelinnumero",
"updateSuccess": "Päivitys onnistui",
"userAgent": "Käyttäjäagentti",
"userEmail": "Käyttäjän sähköposti",
"userEmailPlaceholder": "Syötä käyttäjän sähköpostiosoite",
"userList": "Käyttäjälista",
"userName": "Käyttäjän tunniste"
"userLogs": "Kirjautumishistoria",
"userName": "Käyttäjän tunniste",
"userOrders": "Tilaukset",
"userProfile": "Profiili",
"userSubscriptions": "Tilaukset",
"verified": "Vahvistettu"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Gestion des billets",
"Twitter": "Twitter",
"User": "Utilisateur",
"User Detail": "Détail de l'utilisateur",
"User Management": "Gestion des utilisateurs"
}

View File

@ -1,8 +1,17 @@
{
"actions": "actions",
"areaCode": "Indicatif régional",
"areaCodePlaceholder": "Indicatif régional",
"auth": "Auth",
"authIdentifier": "Identifiant d'authentification",
"authIdentifierPlaceholder": "Entrez l'identifiant d'authentification",
"authType": "Type d'authentification",
"authUser": "Utilisateur Auth",
"balance": "Solde",
"balancePlaceholder": "Solde",
"cancel": "Annuler",
"commission": "Commission",
"commissionPlaceholder": "Entrez la commission",
"confirm": "Confirmer",
"confirmDelete": "Êtes-vous sûr de vouloir supprimer ?",
"create": "Créer",
@ -12,39 +21,38 @@
"delete": "Supprimer",
"deleteDescription": "Une fois supprimées, les données ne peuvent pas être récupérées. Veuillez procéder avec prudence.",
"deleteSuccess": "Suppression réussie",
"detail": "Détail",
"edit": "Éditer",
"editUser": "Modifier l'utilisateur",
"email": "e-mail",
"enable": "Activer",
"form": {
"areaCode": "Indicatif régional",
"areaCodePlaceholder": "Indicatif régional",
"balance": "Solde",
"balancePlaceholder": "Solde",
"cancel": "Annuler",
"commission": "Commission",
"commissionPlaceholder": "Entrez la commission",
"confirm": "Confirmer",
"giftAmount": "Montant du cadeau",
"giftAmountPlaceholder": "Entrez le montant du cadeau",
"invalidEmailFormat": "Format d'e-mail invalide",
"inviteCode": "Code d'invitation",
"inviteCodePlaceholder": "Veuillez entrer le code d'invitation (laissez vide pour générer automatiquement)",
"manager": "Administrateur",
"password": "Mot de passe",
"passwordPlaceholder": "Veuillez entrer un nouveau mot de passe (peut être laissé vide)",
"refererId": "ID du parrain",
"refererIdPlaceholder": "Veuillez entrer l'ID du parrain",
"telephone": "Numéro de téléphone",
"telephonePlaceholder": "Entrez le numéro de téléphone",
"userEmail": "E-mail de l'utilisateur",
"userEmailPlaceholder": "Veuillez entrer l'e-mail de l'utilisateur"
},
"giftAmount": "Montant du cadeau",
"giftAmountPlaceholder": "Entrez le montant du cadeau",
"invalidEmailFormat": "Format d'email invalide",
"inviteCode": "Code d'invitation",
"inviteCodePlaceholder": "Entrez le code d'invitation (laissez vide pour générer)",
"loading": "Chargement...",
"loginIp": "IP de connexion",
"loginTime": "Heure de connexion",
"manager": "Gestionnaire",
"password": "Mot de passe",
"passwordPlaceholder": "Entrez un nouveau mot de passe (facultatif)",
"referer": "Référent",
"refererId": "ID du référent",
"refererIdPlaceholder": "Entrez l'ID du référent",
"searchIp": "Rechercher une adresse IP",
"selectAuthType": "Sélectionner le type d'authentification",
"telephone": "Numéro de téléphone",
"telephonePlaceholder": "Entrez le numéro de téléphone",
"updateSuccess": "Mise à jour réussie",
"userAgent": "Agent utilisateur",
"userEmail": "E-mail de l'utilisateur",
"userEmailPlaceholder": "Entrez l'email de l'utilisateur",
"userList": "Liste des utilisateurs",
"userName": "Identifiant Utilisateur"
"userLogs": "Historique des connexions",
"userName": "Identifiant Utilisateur",
"userOrders": "Commandes",
"userProfile": "Profil",
"userSubscriptions": "Abonnements",
"verified": "Vérifié"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "टिकट प्रबंधन",
"Twitter": "ट्विटर",
"User": "उपयोगकर्ता",
"User Detail": "उपयोगकर्ता विवरण",
"User Management": "उपयोगकर्ता प्रबंधन"
}

View File

@ -1,8 +1,17 @@
{
"actions": "क्रियाएँ",
"areaCode": "क्षेत्र कोड",
"areaCodePlaceholder": "क्षेत्र कोड",
"auth": "प्रमाणीकरण",
"authIdentifier": "प्रमाणीकरण पहचानकर्ता",
"authIdentifierPlaceholder": "प्रमाणिक पहचानकर्ता दर्ज करें",
"authType": "प्रमाणीकरण प्रकार",
"authUser": "प्रमाणित उपयोगकर्ता",
"balance": "शेष",
"balancePlaceholder": "शेष",
"cancel": "रद्द करें",
"commission": "आयोग",
"commissionPlaceholder": "कमीशन दर्ज करें",
"confirm": "पुष्टि करें",
"confirmDelete": "क्या आप वाकई हटाना चाहते हैं?",
"create": "सृजन",
@ -12,39 +21,38 @@
"delete": "हटाएं",
"deleteDescription": "हटाने के बाद डेटा पुनर्प्राप्त नहीं किया जा सकता है, कृपया सावधानीपूर्वक कार्य करें।",
"deleteSuccess": "हटाने में सफलता",
"detail": "विवरण",
"edit": "संपादित करें",
"editUser": "उपयोगकर्ता संपादित करें",
"email": "ईमेल",
"enable": "सक्षम करें",
"form": {
"areaCode": "क्षेत्र कोड",
"areaCodePlaceholder": "क्षेत्र कोड",
"balance": "शेष राशि",
"balancePlaceholder": "शेष राशि",
"cancel": "रद्द करें",
"commission": "कमीशन",
"commissionPlaceholder": "कमीशन दर्ज करें",
"confirm": "पुष्टि करें",
"giftAmount": "उपहार राशि",
"giftAmountPlaceholder": "उपहार राशि दर्ज करें",
"invalidEmailFormat": "अमान्य ईमेल प्रारूप",
"inviteCode": "आमंत्रण कोड",
"inviteCodePlaceholder": "कृपया आमंत्रण कोड दर्ज करें (खाली छोड़ने पर स्वचालित रूप से उत्पन्न होगा)",
"manager": "प्रबंधक",
"password": "पासवर्ड",
"passwordPlaceholder": "कृपया नया पासवर्ड दर्ज करें (खाली छोड़ सकते हैं)",
"refererId": "रेफरर आईडी",
"refererIdPlaceholder": "कृपया रेफरर आईडी दर्ज करें",
"telephone": "फ़ोन नंबर",
"telephonePlaceholder": "फ़ोन नंबर दर्ज करें",
"userEmail": "उपयोगकर्ता ईमेल",
"userEmailPlaceholder": "कृपया उपयोगकर्ता ईमेल दर्ज करें"
},
"giftAmount": "उपहार राशि",
"giftAmountPlaceholder": "उपहार राशि दर्ज करें",
"invalidEmailFormat": "अमान्य ईमेल प्रारूप",
"inviteCode": "आमंत्रण कोड",
"inviteCodePlaceholder": "आमंत्रण कोड दर्ज करें (उत्पन्न करने के लिए खाली छोड़ें)",
"loading": "लोड हो रहा है...",
"loginIp": "लॉगिन आईपी",
"loginTime": "लॉगिन समय",
"manager": "प्रबंधक",
"password": "पासवर्ड",
"passwordPlaceholder": "नया पासवर्ड दर्ज करें (वैकल्पिक)",
"referer": "सिफारिशकर्ता",
"refererId": "रेफरर आईडी",
"refererIdPlaceholder": "रेफरर आईडी दर्ज करें",
"searchIp": "आईपी पता खोजें",
"selectAuthType": "प्रमाणीकरण प्रकार चुनें",
"telephone": "फ़ोन नंबर",
"telephonePlaceholder": "फ़ोन नंबर दर्ज करें",
"updateSuccess": "अपडेट सफल",
"userAgent": "उपयोगकर्ता एजेंट",
"userEmail": "उपयोगकर्ता ईमेल",
"userEmailPlaceholder": "उपयोगकर्ता ईमेल दर्ज करें",
"userList": "उपयोगकर्ता सूची",
"userName": "उपयोगकर्ता पहचानकर्ता"
"userLogs": "लॉगिन इतिहास",
"userName": "उपयोगकर्ता पहचानकर्ता",
"userOrders": "ऑर्डर",
"userProfile": "प्रोफ़ाइल",
"userSubscriptions": "सदस्यताएँ",
"verified": "सत्यापित"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Jegykezelés",
"Twitter": "Twitter",
"User": "Felhasználó",
"User Detail": "Felhasználói részletek",
"User Management": "Felhasználókezelés"
}

View File

@ -1,8 +1,17 @@
{
"actions": "műveletek",
"areaCode": "Körzetszám",
"areaCodePlaceholder": "Körzetszám",
"auth": "Hitelesítés",
"authIdentifier": "Hitelesítési azonosító",
"authIdentifierPlaceholder": "Adja meg az azonosítót",
"authType": "Hitelesítési típus",
"authUser": "Hitelesített felhasználó",
"balance": "Egyenleg",
"balancePlaceholder": "Egyenleg",
"cancel": "Mégse",
"commission": "Jutalék",
"commissionPlaceholder": "Adja meg a jutalékot",
"confirm": "Megerősítés",
"confirmDelete": "Biztosan törölni szeretné?",
"create": "Létrehozás",
@ -12,39 +21,38 @@
"delete": "törlés",
"deleteDescription": "A törlés után az adatok nem állíthatók vissza, kérjük, járjon el körültekintően.",
"deleteSuccess": "Sikeres törlés",
"detail": "Részlet",
"edit": "szerkesztés",
"editUser": "Felhasználó szerkesztése",
"email": "e-mail",
"enable": "Engedélyezés",
"form": {
"areaCode": "Körzetszám",
"areaCodePlaceholder": "Körzetszám",
"balance": "Egyenleg",
"balancePlaceholder": "Egyenleg",
"cancel": "Mégse",
"commission": "Jutalék",
"commissionPlaceholder": "Adja meg a jutalékot",
"confirm": "Megerősít",
"giftAmount": "Ajándék összege",
"giftAmountPlaceholder": "Adja meg az ajándék összegét",
"invalidEmailFormat": "Érvénytelen e-mail formátum",
"inviteCode": "Meghívókód",
"inviteCodePlaceholder": "Kérjük, adja meg a meghívókódot (ha üres, automatikusan generálódik)",
"manager": "Adminisztrátor",
"password": "Jelszó",
"passwordPlaceholder": "Kérjük, adjon meg egy új jelszót (hagyja üresen, ha nem kívánja megváltoztatni)",
"refererId": "Ajánló ID",
"refererIdPlaceholder": "Kérjük, adja meg az ajánló ID-t",
"telephone": "Telefonszám",
"telephonePlaceholder": "Adja meg a telefonszámot",
"userEmail": "Felhasználói e-mail",
"userEmailPlaceholder": "Kérjük, adja meg a felhasználói e-mail címet"
},
"giftAmount": "Ajándék Összeg",
"giftAmountPlaceholder": "Adja meg az ajándék összegét",
"invalidEmailFormat": "Érvénytelen e-mail formátum",
"inviteCode": "Meghívókód",
"inviteCodePlaceholder": "Adja meg a meghívó kódot (hagyja üresen a generáláshoz)",
"loading": "Betöltés...",
"loginIp": "Bejelentkezési IP",
"loginTime": "Bejelentkezési idő",
"manager": "Menedzser",
"password": "Jelszó",
"passwordPlaceholder": "Adjon meg új jelszót (opcionális)",
"referer": "Ajánló",
"refererId": "Hivatkozó azonosító",
"refererIdPlaceholder": "Adja meg az ajánló azonosítóját",
"searchIp": "IP-cím keresése",
"selectAuthType": "Válassza ki az azonosítás típusát",
"telephone": "Telefonszám",
"telephonePlaceholder": "Adja meg a telefonszámot",
"updateSuccess": "Sikeres frissítés",
"userAgent": "Felhasználói ügynök",
"userEmail": "Felhasználó e-mail",
"userEmailPlaceholder": "Adja meg a felhasználó e-mail címét",
"userList": "Felhasználói lista",
"userName": "Felhasználói azonosító"
"userLogs": "Bejelentkezési előzmények",
"userName": "Felhasználói azonosító",
"userOrders": "Rendelések",
"userProfile": "Profil",
"userSubscriptions": "Előfizetések",
"verified": "Ellenőrzött"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "チケット管理",
"Twitter": "Twitter",
"User": "ユーザー",
"User Detail": "ユーザー詳細",
"User Management": "ユーザー管理"
}

View File

@ -1,8 +1,17 @@
{
"actions": "アクション",
"areaCode": "市外局番",
"areaCodePlaceholder": "市外局番",
"auth": "認証",
"authIdentifier": "認証識別子",
"authIdentifierPlaceholder": "認証IDを入力してください",
"authType": "認証タイプ",
"authUser": "認証ユーザー",
"balance": "残高",
"balancePlaceholder": "残高",
"cancel": "キャンセル",
"commission": "手数料",
"commissionPlaceholder": "手数料を入力してください",
"confirm": "確認",
"confirmDelete": "削除してもよろしいですか?",
"create": "作成",
@ -12,39 +21,38 @@
"delete": "削除",
"deleteDescription": "削除後はデータを復元できませんので、慎重に操作してください。",
"deleteSuccess": "削除に成功しました",
"detail": "詳細",
"edit": "編集",
"editUser": "ユーザー編集",
"email": "メールアドレス",
"enable": "有効",
"form": {
"areaCode": "市外局番",
"areaCodePlaceholder": "市外局番",
"balance": "残高",
"balancePlaceholder": "残高",
"cancel": "キャンセル",
"commission": "手数料",
"commissionPlaceholder": "手数料を入力してください",
"confirm": "確認",
"giftAmount": "ギフト金額",
"giftAmountPlaceholder": "ギフト金額を入力してください",
"invalidEmailFormat": "無効なメール形式",
"inviteCode": "招待コード",
"inviteCodePlaceholder": "招待コードを入力してください(空白の場合は自動生成されます)",
"manager": "管理者",
"password": "パスワード",
"passwordPlaceholder": "新しいパスワードを入力してください(空白可)",
"refererId": "紹介者ID",
"refererIdPlaceholder": "紹介者IDを入力してください",
"telephone": "電話番号",
"telephonePlaceholder": "電話番号を入力",
"userEmail": "ユーザーのメール",
"userEmailPlaceholder": "ユーザーのメールを入力してください"
},
"giftAmount": "ギフト金額",
"giftAmountPlaceholder": "ギフト金額を入力してください",
"invalidEmailFormat": "無効なメール形式です",
"inviteCode": "招待コード",
"inviteCodePlaceholder": "招待コードを入力してください(生成するには空白のままにしてください)",
"loading": "読み込み中...",
"loginIp": "ログインIP",
"loginTime": "ログイン時間",
"manager": "マネージャー",
"password": "パスワード",
"passwordPlaceholder": "新しいパスワードを入力してください(任意)",
"referer": "推薦者",
"refererId": "リファラーID",
"refererIdPlaceholder": "紹介者IDを入力してください",
"searchIp": "IPアドレスを検索",
"selectAuthType": "認証タイプを選択",
"telephone": "電話番号",
"telephonePlaceholder": "電話番号を入力してください",
"updateSuccess": "更新が成功しました",
"userAgent": "ユーザーエージェント",
"userEmail": "ユーザーのメール",
"userEmailPlaceholder": "ユーザーのメールアドレスを入力してください",
"userList": "ユーザーリスト",
"userName": "ユーザー識別子"
"userLogs": "ログイン履歴",
"userName": "ユーザー識別子",
"userOrders": "注文",
"userProfile": "プロフィール",
"userSubscriptions": "サブスクリプション",
"verified": "確認済み"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "티켓 관리",
"Twitter": "트위터",
"User": "사용자",
"User Detail": "사용자 세부 정보",
"User Management": "사용자 관리"
}

View File

@ -1,8 +1,17 @@
{
"actions": "작업",
"areaCode": "지역 코드",
"areaCodePlaceholder": "지역 코드",
"auth": "인증",
"authIdentifier": "인증 식별자",
"authIdentifierPlaceholder": "인증 식별자를 입력하세요",
"authType": "인증 유형",
"authUser": "인증 사용자",
"balance": "잔액",
"balancePlaceholder": "잔액",
"cancel": "취소",
"commission": "커미션",
"commissionPlaceholder": "수수료 입력",
"confirm": "확인",
"confirmDelete": "삭제하시겠습니까?",
"create": "생성",
@ -12,39 +21,38 @@
"delete": "삭제",
"deleteDescription": "삭제 후 데이터는 복구할 수 없으니 신중하게 진행하세요.",
"deleteSuccess": "삭제 성공",
"detail": "세부사항",
"edit": "편집",
"editUser": "사용자 편집",
"email": "이메일",
"enable": "사용",
"form": {
"areaCode": "지역 코드",
"areaCodePlaceholder": "지역 코드 입력",
"balance": "잔액",
"balancePlaceholder": "잔액",
"cancel": "취소",
"commission": "수수료",
"commissionPlaceholder": "수수료 입력",
"confirm": "확인",
"giftAmount": "선물 금액",
"giftAmountPlaceholder": "선물 금액 입력",
"invalidEmailFormat": "유효하지 않은 이메일 형식",
"inviteCode": "초대 코드",
"inviteCodePlaceholder": "초대 코드를 입력하세요 (비워두면 자동 생성)",
"manager": "관리자",
"password": "비밀번호",
"passwordPlaceholder": "새 비밀번호를 입력하세요 (비워둘 수 있음)",
"refererId": "추천인 ID",
"refererIdPlaceholder": "추천인 ID를 입력하세요",
"telephone": "전화번호",
"telephonePlaceholder": "전화번호 입력",
"userEmail": "사용자 이메일",
"userEmailPlaceholder": "사용자 이메일을 입력하세요"
},
"giftAmount": "선물 금액",
"giftAmountPlaceholder": "선물 금액 입력",
"invalidEmailFormat": "잘못된 이메일 형식입니다",
"inviteCode": "초대 코드",
"inviteCodePlaceholder": "초대 코드를 입력하세요 (생성을 원하시면 비워두세요)",
"loading": "로딩 중...",
"loginIp": "로그인 IP",
"loginTime": "로그인 시간",
"manager": "매니저",
"password": "비밀번호",
"passwordPlaceholder": "새 비밀번호 입력 (선택 사항)",
"referer": "추천인",
"refererId": "추천인 ID",
"refererIdPlaceholder": "추천인 ID를 입력하세요",
"searchIp": "IP 주소 검색",
"selectAuthType": "인증 유형 선택",
"telephone": "전화번호",
"telephonePlaceholder": "전화번호 입력",
"updateSuccess": "업데이트 성공",
"userAgent": "사용자 에이전트",
"userEmail": "사용자 이메일",
"userEmailPlaceholder": "사용자 이메일 입력",
"userList": "사용자 목록",
"userName": "사용자 식별자"
"userLogs": "로그인 기록",
"userName": "사용자 식별자",
"userOrders": "주문",
"userProfile": "프로필",
"userSubscriptions": "구독",
"verified": "검증됨"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Billettadministrasjon",
"Twitter": "Twitter",
"User": "Bruker",
"User Detail": "Brukerdetaljer",
"User Management": "Brukeradministrasjon"
}

View File

@ -1,8 +1,17 @@
{
"actions": "handlinger",
"areaCode": "Retningsnummer",
"areaCodePlaceholder": "Retningsnummer",
"auth": "Autentisering",
"authIdentifier": "Autentiseringsidentifikator",
"authIdentifierPlaceholder": "Skriv inn autentiseringsidentifikator",
"authType": "Autentiseringstype",
"authUser": "Autentisert Bruker",
"balance": "Balanse",
"balancePlaceholder": "Balanse",
"cancel": "Avbryt",
"commission": "Kommisjon",
"commissionPlaceholder": "Skriv inn provisjon",
"confirm": "bekreft",
"confirmDelete": "Er du sikker på at du vil slette?",
"create": "opprett",
@ -12,39 +21,38 @@
"delete": "slett",
"deleteDescription": "Data kan ikke gjenopprettes etter sletting, vær forsiktig.",
"deleteSuccess": "Sletting vellykket",
"detail": "Detalj",
"edit": "rediger",
"editUser": "Rediger bruker",
"email": "e-post",
"enable": "Aktiver",
"form": {
"areaCode": "Retningsnummer",
"areaCodePlaceholder": "Retningsnummer",
"balance": "Balanse",
"balancePlaceholder": "Balanse",
"cancel": "Avbryt",
"commission": "Provisjon",
"commissionPlaceholder": "Skriv inn provisjon",
"confirm": "Bekreft",
"giftAmount": "Gavebeløp",
"giftAmountPlaceholder": "Skriv inn gavebeløp",
"invalidEmailFormat": "Ugyldig e-postformat",
"inviteCode": "Invitasjonskode",
"inviteCodePlaceholder": "Vennligst skriv inn invitasjonskode (la stå tom for automatisk generering)",
"manager": "Administrator",
"password": "Passord",
"passwordPlaceholder": "Vennligst skriv inn nytt passord (kan stå tomt)",
"refererId": "Henvisnings-ID",
"refererIdPlaceholder": "Vennligst skriv inn henvisnings-ID",
"telephone": "Telefonnummer",
"telephonePlaceholder": "Skriv inn telefonnummer",
"userEmail": "Brukerens e-post",
"userEmailPlaceholder": "Vennligst skriv inn brukerens e-post"
},
"giftAmount": "Gavebeløp",
"giftAmountPlaceholder": "Skriv inn gavebeløp",
"invalidEmailFormat": "Ugyldig e-postformat",
"inviteCode": "Invitasjonskode",
"inviteCodePlaceholder": "Skriv inn invitasjonskode (la stå tom for å generere)",
"loading": "Laster inn...",
"loginIp": "Innloggings-IP",
"loginTime": "Innloggingstid",
"manager": "Leder",
"password": "Passord",
"passwordPlaceholder": "Skriv inn nytt passord (valgfritt)",
"referer": "Henviser",
"refererId": "Henvisnings-ID",
"refererIdPlaceholder": "Skriv inn referanse-ID",
"searchIp": "Søk IP-adresse",
"selectAuthType": "Velg autentiseringstype",
"telephone": "Telefonnummer",
"telephonePlaceholder": "Skriv inn telefonnummer",
"updateSuccess": "Oppdatering vellykket",
"userAgent": "Brukeragent",
"userEmail": "Brukerens e-post",
"userEmailPlaceholder": "Skriv inn brukers e-post",
"userList": "Brukerliste",
"userName": "Brukeridentifikator"
"userLogs": "Innloggingshistorikk",
"userName": "Brukeridentifikator",
"userOrders": "Bestillinger",
"userProfile": "Profil",
"userSubscriptions": "Abonnementer",
"verified": "Verifisert"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Zarządzanie zgłoszeniami",
"Twitter": "Twitter",
"User": "Użytkownik",
"User Detail": "Szczegóły użytkownika",
"User Management": "Zarządzanie użytkownikami"
}

View File

@ -1,8 +1,17 @@
{
"actions": "działania",
"areaCode": "Kod obszaru",
"areaCodePlaceholder": "Kod obszaru",
"auth": "Autoryzacja",
"authIdentifier": "Identyfikator uwierzytelniania",
"authIdentifierPlaceholder": "Wprowadź identyfikator uwierzytelniający",
"authType": "Typ uwierzytelniania",
"authUser": "Użytkownik uwierzytelniony",
"balance": "saldo",
"balancePlaceholder": "Saldo",
"cancel": "Anuluj",
"commission": "Prowizja",
"commissionPlaceholder": "Wprowadź prowizję",
"confirm": "Potwierdź",
"confirmDelete": "Czy na pewno chcesz usunąć?",
"create": "Utwórz",
@ -12,39 +21,38 @@
"delete": "usuń",
"deleteDescription": "Po usunięciu danych nie można ich odzyskać, prosimy o ostrożność.",
"deleteSuccess": "Usunięto pomyślnie",
"detail": "Szczegóły",
"edit": "edytuj",
"editUser": "Edytuj użytkownika",
"email": "e-mail",
"enable": "Włącz",
"form": {
"areaCode": "Kod kierunkowy",
"areaCodePlaceholder": "Kod kierunkowy",
"balance": "Saldo",
"balancePlaceholder": "Saldo",
"cancel": "Anuluj",
"commission": "Prowizja",
"commissionPlaceholder": "Wprowadź prowizję",
"confirm": "Potwierdź",
"giftAmount": "Kwota prezentu",
"giftAmountPlaceholder": "Wprowadź kwotę prezentu",
"invalidEmailFormat": "Nieprawidłowy format e-maila",
"inviteCode": "Kod zaproszenia",
"inviteCodePlaceholder": "Wprowadź kod zaproszenia (pozostaw puste, aby wygenerować automatycznie)",
"manager": "Administrator",
"password": "Hasło",
"passwordPlaceholder": "Wprowadź nowe hasło (można pozostawić puste)",
"refererId": "ID polecającego",
"refererIdPlaceholder": "Wprowadź ID polecającego",
"telephone": "Numer telefonu",
"telephonePlaceholder": "Wprowadź numer telefonu",
"userEmail": "E-mail użytkownika",
"userEmailPlaceholder": "Wprowadź e-mail użytkownika"
},
"giftAmount": "Kwota Prezentu",
"giftAmountPlaceholder": "Wprowadź kwotę prezentu",
"invalidEmailFormat": "Nieprawidłowy format adresu e-mail",
"inviteCode": "Kod zaproszenia",
"inviteCodePlaceholder": "Wprowadź kod zaproszenia (pozostaw puste, aby wygenerować)",
"loading": "Ładowanie...",
"loginIp": "IP logowania",
"loginTime": "Czas logowania",
"manager": "Menedżer",
"password": "Hasło",
"passwordPlaceholder": "Wprowadź nowe hasło (opcjonalnie)",
"referer": "Polecający",
"refererId": "Identyfikator polecającego",
"refererIdPlaceholder": "Wprowadź identyfikator polecającego",
"searchIp": "Wyszukaj adres IP",
"selectAuthType": "Wybierz typ uwierzytelniania",
"telephone": "Numer telefonu",
"telephonePlaceholder": "Wprowadź numer telefonu",
"updateSuccess": "Aktualizacja zakończona pomyślnie",
"userAgent": "Agent użytkownika",
"userEmail": "Email użytkownika",
"userEmailPlaceholder": "Wprowadź adres e-mail użytkownika",
"userList": "Lista użytkowników",
"userName": "Identyfikator użytkownika"
"userLogs": "Historia logowania",
"userName": "Identyfikator użytkownika",
"userOrders": "Zamówienia",
"userProfile": "Profil",
"userSubscriptions": "Subskrypcje",
"verified": "Zweryfikowano"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Gerenciamento de Chamados",
"Twitter": "Twitter",
"User": "Usuário",
"User Detail": "Detalhes do Usuário",
"User Management": "Gerenciamento de Usuários"
}

View File

@ -1,8 +1,17 @@
{
"actions": "ações",
"areaCode": "Código de Área",
"areaCodePlaceholder": "Código de área",
"auth": "Autenticação",
"authIdentifier": "Identificador de Autenticação",
"authIdentifierPlaceholder": "Digite o identificador de autenticação",
"authType": "Tipo de Autenticação",
"authUser": "Usuário Autenticado",
"balance": "Saldo",
"balancePlaceholder": "Saldo",
"cancel": "Cancelar",
"commission": "Comissão",
"commissionPlaceholder": "Insira a comissão",
"confirm": "confirmar",
"confirmDelete": "Você tem certeza de que deseja excluir?",
"create": "Criar",
@ -12,39 +21,38 @@
"delete": "Excluir",
"deleteDescription": "Após a exclusão, os dados não poderão ser recuperados. Proceda com cautela.",
"deleteSuccess": "Exclusão bem-sucedida",
"detail": "Detalhe",
"edit": "editar",
"editUser": "Editar Usuário",
"email": "e-mail",
"enable": "Habilitar",
"form": {
"areaCode": "Código de Área",
"areaCodePlaceholder": "Código de área",
"balance": "Saldo",
"balancePlaceholder": "Saldo",
"cancel": "Cancelar",
"commission": "Comissão",
"commissionPlaceholder": "Insira a comissão",
"confirm": "Confirmar",
"giftAmount": "Valor do Presente",
"giftAmountPlaceholder": "Insira o valor do presente",
"invalidEmailFormat": "Formato de e-mail inválido",
"inviteCode": "Código de Convite",
"inviteCodePlaceholder": "Insira o código de convite (deixe em branco para gerar automaticamente)",
"manager": "Administrador",
"password": "Senha",
"passwordPlaceholder": "Insira a nova senha (pode deixar em branco)",
"refererId": "ID do Referente",
"refererIdPlaceholder": "Insira o ID do referente",
"telephone": "Número de Telefone",
"telephonePlaceholder": "Digite o número de telefone",
"userEmail": "E-mail do Usuário",
"userEmailPlaceholder": "Insira o e-mail do usuário"
},
"giftAmount": "Valor do Presente",
"giftAmountPlaceholder": "Insira o valor do presente",
"invalidEmailFormat": "Formato de e-mail inválido",
"inviteCode": "Código de Convite",
"inviteCodePlaceholder": "Digite o código de convite (deixe em branco para gerar)",
"loading": "Carregando...",
"loginIp": "IP de Login",
"loginTime": "Hora de Login",
"manager": "Gerente",
"password": "Senha",
"passwordPlaceholder": "Digite a nova senha (opcional)",
"referer": "Referente",
"refererId": "ID do Referente",
"refererIdPlaceholder": "Digite o ID do referenciador",
"searchIp": "Pesquisar endereço IP",
"selectAuthType": "Selecione o tipo de autenticação",
"telephone": "Número de Telefone",
"telephonePlaceholder": "Digite o número de telefone",
"updateSuccess": "Atualização bem-sucedida",
"userAgent": "Agente do Usuário",
"userEmail": "E-mail do Usuário",
"userEmailPlaceholder": "Digite o e-mail do usuário",
"userList": "Lista de Usuários",
"userName": "Identificador do Usuário"
"userLogs": "Histórico de Login",
"userName": "Identificador do Usuário",
"userOrders": "Pedidos",
"userProfile": "Perfil",
"userSubscriptions": "Assinaturas",
"verified": "Verificado"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Gestionarea Biletelor",
"Twitter": "Twitter",
"User": "Utilizator",
"User Detail": "Detalii Utilizator",
"User Management": "Gestionarea Utilizatorilor"
}

View File

@ -1,8 +1,17 @@
{
"actions": "acțiuni",
"areaCode": "Prefix telefonic",
"areaCodePlaceholder": "Prefix telefonic",
"auth": "Autentificare",
"authIdentifier": "Identificator de autentificare",
"authIdentifierPlaceholder": "Introduceți identificatorul de autentificare",
"authType": "Tip de autentificare",
"authUser": "Utilizator Autentificat",
"balance": "Sold",
"balancePlaceholder": "Sold",
"cancel": "Anulare",
"commission": "Comision",
"commissionPlaceholder": "Introduceți comisionul",
"confirm": "Confirmare",
"confirmDelete": "Sunteți sigur că doriți să ștergeți?",
"create": "crea",
@ -12,39 +21,38 @@
"delete": "șterge",
"deleteDescription": "După ștergere, datele nu pot fi recuperate, vă rugăm să acționați cu prudență.",
"deleteSuccess": "Ștergere reușită",
"detail": "Detaliu",
"edit": "editează",
"editUser": "Editare utilizator",
"email": "e-mail",
"enable": "Activare",
"form": {
"areaCode": "Prefix",
"areaCodePlaceholder": "Introduceți prefixul",
"balance": "Sold",
"balancePlaceholder": "Sold",
"cancel": "Anulează",
"commission": "Comision",
"commissionPlaceholder": "Introduceți comisionul",
"confirm": "Confirmă",
"giftAmount": "Sumă Cadou",
"giftAmountPlaceholder": "Introduceți suma cadou",
"invalidEmailFormat": "Format de e-mail invalid",
"inviteCode": "Cod de invitație",
"inviteCodePlaceholder": "Introduceți codul de invitație (lăsați gol pentru generare automată)",
"manager": "Administrator",
"password": "Parolă",
"passwordPlaceholder": "Introduceți o parolă nouă (poate fi lăsată goală)",
"refererId": "ID recomandant",
"refererIdPlaceholder": "Introduceți ID-ul recomandantului",
"telephone": "Număr de telefon",
"telephonePlaceholder": "Introduceți numărul de telefon",
"userEmail": "E-mail utilizator",
"userEmailPlaceholder": "Introduceți e-mailul utilizatorului"
},
"giftAmount": "Sumă Cadou",
"giftAmountPlaceholder": "Introduceți suma cadoului",
"invalidEmailFormat": "Format de email invalid",
"inviteCode": "Cod de invitație",
"inviteCodePlaceholder": "Introduceți codul de invitație (lăsați necompletat pentru a genera)",
"loading": "Se încarcă...",
"loginIp": "IP de autentificare",
"loginTime": "Ora de autentificare",
"manager": "Manager",
"password": "Parolă",
"passwordPlaceholder": "Introduceți o parolă nouă (opțional)",
"referer": "Referent",
"refererId": "ID Referent",
"refererIdPlaceholder": "Introduceți ID-ul referentului",
"searchIp": "Caută adresa IP",
"selectAuthType": "Selectați tipul de autentificare",
"telephone": "Număr de telefon",
"telephonePlaceholder": "Introduceți numărul de telefon",
"updateSuccess": "Actualizare reușită",
"userAgent": "Agent Utilizator",
"userEmail": "Email utilizator",
"userEmailPlaceholder": "Introduceți emailul utilizatorului",
"userList": "Lista utilizatorilor",
"userName": "Identificator Utilizator"
"userLogs": "Istoricul autentificărilor",
"userName": "Identificator Utilizator",
"userOrders": "Comenzi",
"userProfile": "Profil",
"userSubscriptions": "Abonamente",
"verified": "Verificat"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Управление заявками",
"Twitter": "Твиттер",
"User": "Пользователь",
"User Detail": "Детали пользователя",
"User Management": "Управление пользователями"
}

View File

@ -1,8 +1,17 @@
{
"actions": "действия",
"areaCode": "Код региона",
"areaCodePlaceholder": "Код региона",
"auth": "Авторизация",
"authIdentifier": "Идентификатор аутентификации",
"authIdentifierPlaceholder": "Введите идентификатор аутентификации",
"authType": "Тип аутентификации",
"authUser": "Авторизованный пользователь",
"balance": "Баланс",
"balancePlaceholder": "Баланс",
"cancel": "Отмена",
"commission": "Комиссия",
"commissionPlaceholder": "Введите комиссию",
"confirm": "Подтвердить",
"confirmDelete": "Вы уверены, что хотите удалить?",
"create": "Создать",
@ -12,39 +21,38 @@
"delete": "Удалить",
"deleteDescription": "После удаления данные не могут быть восстановлены, пожалуйста, действуйте осторожно.",
"deleteSuccess": "Удаление успешно",
"detail": "Детали",
"edit": "редактировать",
"editUser": "Редактировать пользователя",
"email": "Электронная почта",
"enable": "Включить",
"form": {
"areaCode": "Код региона",
"areaCodePlaceholder": "Код региона",
"balance": "Баланс",
"balancePlaceholder": "Баланс",
"cancel": "Отмена",
"commission": "Комиссия",
"commissionPlaceholder": "Введите комиссию",
"confirm": "Подтвердить",
"giftAmount": "Сумма подарка",
"giftAmountPlaceholder": "Введите сумму подарка",
"invalidEmailFormat": "Недопустимый формат электронной почты",
"inviteCode": "Код приглашения",
"inviteCodePlaceholder": "Введите код приглашения (оставьте пустым для автоматической генерации)",
"manager": "Администратор",
"password": "Пароль",
"passwordPlaceholder": "Введите новый пароль (можно оставить пустым)",
"refererId": "ID рекомендателя",
"refererIdPlaceholder": "Введите ID рекомендателя",
"telephone": "Номер телефона",
"telephonePlaceholder": "Введите номер телефона",
"userEmail": "Электронная почта пользователя",
"userEmailPlaceholder": "Введите электронную почту пользователя"
},
"giftAmount": "Сумма подарка",
"giftAmountPlaceholder": "Введите сумму подарка",
"invalidEmailFormat": "Неверный формат электронной почты",
"inviteCode": "Код приглашения",
"inviteCodePlaceholder": "Введите код приглашения (оставьте пустым для генерации)",
"loading": "Загрузка...",
"loginIp": "IP-адрес входа",
"loginTime": "Время входа",
"manager": "Менеджер",
"password": "Пароль",
"passwordPlaceholder": "Введите новый пароль (необязательно)",
"referer": "Реферер",
"refererId": "ID реферера",
"refererIdPlaceholder": "Введите ID реферера",
"searchIp": "Поиск IP-адреса",
"selectAuthType": "Выберите тип аутентификации",
"telephone": "Номер телефона",
"telephonePlaceholder": "Введите номер телефона",
"updateSuccess": "Обновление успешно",
"userAgent": "Пользовательский агент",
"userEmail": "Электронная почта пользователя",
"userEmailPlaceholder": "Введите электронную почту пользователя",
"userList": "Список пользователей",
"userName": "Идентификатор пользователя"
"userLogs": "История входов",
"userName": "Идентификатор пользователя",
"userOrders": "Заказы",
"userProfile": "Профиль",
"userSubscriptions": "Подписки",
"verified": "Проверено"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "การจัดการตั๋ว",
"Twitter": "ทวิตเตอร์",
"User": "ผู้ใช้",
"User Detail": "รายละเอียดผู้ใช้",
"User Management": "การจัดการผู้ใช้"
}

View File

@ -1,8 +1,17 @@
{
"actions": "การดำเนินการ",
"areaCode": "รหัสพื้นที่",
"areaCodePlaceholder": "รหัสพื้นที่",
"auth": "การยืนยันตัวตน",
"authIdentifier": "ตัวระบุการยืนยันตัวตน",
"authIdentifierPlaceholder": "กรอกตัวระบุการยืนยันตัวตน",
"authType": "ประเภทการยืนยันตัวตน",
"authUser": "ผู้ใช้ที่ได้รับอนุญาต",
"balance": "ยอดคงเหลือ",
"balancePlaceholder": "ยอดคงเหลือ",
"cancel": "ยกเลิก",
"commission": "คอมมิชชั่น",
"commissionPlaceholder": "กรอกค่าคอมมิชชั่น",
"confirm": "ยืนยัน",
"confirmDelete": "คุณแน่ใจหรือว่าต้องการลบ?",
"create": "สร้าง",
@ -12,39 +21,38 @@
"delete": "ลบ",
"deleteDescription": "หลังจากลบแล้วจะไม่สามารถกู้คืนข้อมูลได้ โปรดดำเนินการด้วยความระมัดระวัง",
"deleteSuccess": "ลบสำเร็จ",
"detail": "รายละเอียด",
"edit": "แก้ไข",
"editUser": "แก้ไขผู้ใช้",
"email": "อีเมล",
"enable": "เปิดใช้งาน",
"form": {
"areaCode": "รหัสพื้นที่",
"areaCodePlaceholder": "รหัสพื้นที่",
"balance": "ยอดคงเหลือ",
"balancePlaceholder": "ยอดคงเหลือ",
"cancel": "ยกเลิก",
"commission": "ค่าคอมมิชชั่น",
"commissionPlaceholder": "กรอกค่าคอมมิชชั่น",
"confirm": "ยืนยัน",
"giftAmount": "จำนวนของขวัญ",
"giftAmountPlaceholder": "กรอกจำนวนของขวัญ",
"invalidEmailFormat": "รูปแบบอีเมลไม่ถูกต้อง",
"inviteCode": "รหัสเชิญ",
"inviteCodePlaceholder": "กรุณาใส่รหัสเชิญ (เว้นว่างเพื่อสร้างอัตโนมัติ)",
"manager": "ผู้ดูแลระบบ",
"password": "รหัสผ่าน",
"passwordPlaceholder": "กรุณาใส่รหัสผ่านใหม่ (สามารถเว้นว่างได้)",
"refererId": "รหัสผู้แนะนำ",
"refererIdPlaceholder": "กรุณาใส่รหัสผู้แนะนำ",
"telephone": "หมายเลขโทรศัพท์",
"telephonePlaceholder": "กรอกหมายเลขโทรศัพท์",
"userEmail": "อีเมลผู้ใช้",
"userEmailPlaceholder": "กรุณาใส่อีเมลผู้ใช้"
},
"giftAmount": "จำนวนเงินของขวัญ",
"giftAmountPlaceholder": "กรอกจำนวนเงินของขวัญ",
"invalidEmailFormat": "รูปแบบอีเมลไม่ถูกต้อง",
"inviteCode": "รหัสเชิญ",
"inviteCodePlaceholder": "กรอกรหัสเชิญ (เว้นว่างไว้เพื่อสร้างใหม่)",
"loading": "กำลังโหลด...",
"loginIp": "ไอพีที่เข้าสู่ระบบ",
"loginTime": "เวลาเข้าสู่ระบบ",
"manager": "ผู้จัดการ",
"password": "รหัสผ่าน",
"passwordPlaceholder": "กรุณาใส่รหัสผ่านใหม่ (ไม่บังคับ)",
"referer": "ผู้แนะนำ",
"refererId": "รหัสผู้แนะนำ",
"refererIdPlaceholder": "กรอก ID ผู้แนะนำ",
"searchIp": "ค้นหาที่อยู่ IP",
"selectAuthType": "เลือกประเภทการยืนยันตัวตน",
"telephone": "หมายเลขโทรศัพท์",
"telephonePlaceholder": "กรอกหมายเลขโทรศัพท์",
"updateSuccess": "อัปเดตสำเร็จ",
"userAgent": "ตัวแทนผู้ใช้",
"userEmail": "อีเมลผู้ใช้",
"userEmailPlaceholder": "กรอกอีเมลผู้ใช้",
"userList": "รายชื่อผู้ใช้",
"userName": "ตัวระบุผู้ใช้"
"userLogs": "ประวัติการเข้าสู่ระบบ",
"userName": "ตัวระบุผู้ใช้",
"userOrders": "คำสั่งซื้อ",
"userProfile": "โปรไฟล์",
"userSubscriptions": "การสมัครสมาชิก",
"verified": "ยืนยันแล้ว"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Bilet Yönetimi",
"Twitter": "Twitter",
"User": "Kullanıcı",
"User Detail": "Kullanıcı Detayı",
"User Management": "Kullanıcı Yönetimi"
}

View File

@ -1,8 +1,17 @@
{
"actions": "eylemler",
"areaCode": "Alan Kodu",
"areaCodePlaceholder": "Alan kodu",
"auth": "Kimlik Doğrulama",
"authIdentifier": "Kimlik Doğrulama Tanımlayıcısı",
"authIdentifierPlaceholder": "Kimlik doğrulama tanımlayıcısını girin",
"authType": "Kimlik Doğrulama Türü",
"authUser": "Yetkili Kullanıcı",
"balance": "Bakiye",
"balancePlaceholder": "Bakiye",
"cancel": "İptal",
"commission": "Komisyon",
"commissionPlaceholder": "Komisyonu girin",
"confirm": "Onayla",
"confirmDelete": "Silmek istediğinizden emin misiniz?",
"create": "oluştur",
@ -12,39 +21,38 @@
"delete": "sil",
"deleteDescription": "Silindikten sonra veriler kurtarılamaz, lütfen dikkatli olun.",
"deleteSuccess": "Başarıyla silindi",
"detail": "Detay",
"edit": "düzenle",
"editUser": "Kullanıcıyı Düzenle",
"email": "e-posta",
"enable": "etkinleştir",
"form": {
"areaCode": "Alan Kodu",
"areaCodePlaceholder": "Alan kodu",
"balance": "Bakiye",
"balancePlaceholder": "Bakiye",
"cancel": "İptal",
"commission": "Komisyon",
"commissionPlaceholder": "Komisyonu girin",
"confirm": "Onayla",
"giftAmount": "Hediye Tutarı",
"giftAmountPlaceholder": "Hediye tutarını girin",
"invalidEmailFormat": "Geçersiz e-posta formatı",
"inviteCode": "Davet Kodu",
"inviteCodePlaceholder": "Lütfen davet kodunu girin (boş bırakılırsa otomatik oluşturulur)",
"manager": "Yönetici",
"password": "Şifre",
"passwordPlaceholder": "Lütfen yeni şifreyi girin (boş bırakılabilir)",
"refererId": "Referans ID",
"refererIdPlaceholder": "Lütfen referans ID'yi girin",
"telephone": "Telefon Numarası",
"telephonePlaceholder": "Telefon numarasını girin",
"userEmail": "Kullanıcı E-postası",
"userEmailPlaceholder": "Lütfen kullanıcı e-postasını girin"
},
"giftAmount": "Hediye Miktarı",
"giftAmountPlaceholder": "Hediye tutarını girin",
"invalidEmailFormat": "Geçersiz e-posta formatı",
"inviteCode": "Davet Kodu",
"inviteCodePlaceholder": "Davet kodunu girin (oluşturmak için boş bırakın)",
"loading": "Yükleniyor...",
"loginIp": "Giriş IP'si",
"loginTime": "Giriş Zamanı",
"manager": "Yönetici",
"password": "Şifre",
"passwordPlaceholder": "Yeni şifreyi girin (isteğe bağlı)",
"referer": "Referans",
"refererId": "Referans Kimliği",
"refererIdPlaceholder": "Referans kimliğini girin",
"searchIp": "IP adresi ara",
"selectAuthType": "Kimlik doğrulama türünü seçin",
"telephone": "Telefon Numarası",
"telephonePlaceholder": "Telefon numarasını girin",
"updateSuccess": "Güncelleme başarılı",
"userAgent": "Kullanıcı Aracısı",
"userEmail": "Kullanıcı E-postası",
"userEmailPlaceholder": "Kullanıcı e-postasını girin",
"userList": "Kullanıcı Listesi",
"userName": "Kullanıcı Tanımlayıcı"
"userLogs": "Giriş Geçmişi",
"userName": "Kullanıcı Tanımlayıcı",
"userOrders": "Siparişler",
"userProfile": "Profil",
"userSubscriptions": "Abonelikler",
"verified": "Doğrulandı"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Управління заявками",
"Twitter": "Твіттер",
"User": "Користувач",
"User Detail": "Деталі користувача",
"User Management": "Управління користувачами"
}

View File

@ -1,8 +1,17 @@
{
"actions": "дії",
"areaCode": "Код регіону",
"areaCodePlaceholder": "Код області",
"auth": "Авторизація",
"authIdentifier": "Ідентифікатор автентифікації",
"authIdentifierPlaceholder": "Введіть ідентифікатор авторизації",
"authType": "Тип автентифікації",
"authUser": "Авторизований користувач",
"balance": "Баланс",
"balancePlaceholder": "Баланс",
"cancel": "Скасувати",
"commission": "Комісія",
"commissionPlaceholder": "Введіть комісію",
"confirm": "Підтвердити",
"confirmDelete": "Ви впевнені, що хочете видалити?",
"create": "створити",
@ -12,39 +21,38 @@
"delete": "Видалити",
"deleteDescription": "Після видалення дані не можна буде відновити, будь ласка, дійте обережно.",
"deleteSuccess": "Видалення успішне",
"detail": "Деталі",
"edit": "редагувати",
"editUser": "Редагувати користувача",
"email": "електронна пошта",
"enable": "Увімкнути",
"form": {
"areaCode": "Код області",
"areaCodePlaceholder": "Код області",
"balance": "Баланс",
"balancePlaceholder": "Баланс",
"cancel": "Скасувати",
"commission": "Комісія",
"commissionPlaceholder": "Введіть комісію",
"confirm": "Підтвердити",
"giftAmount": "Сума подарунка",
"giftAmountPlaceholder": "Введіть суму подарунка",
"invalidEmailFormat": "Недійсний формат електронної пошти",
"inviteCode": "Код запрошення",
"inviteCodePlaceholder": "Введіть код запрошення (залиште порожнім для автоматичної генерації)",
"manager": "Адміністратор",
"password": "Пароль",
"passwordPlaceholder": "Введіть новий пароль (можна залишити порожнім)",
"refererId": "ID реферера",
"refererIdPlaceholder": "Введіть ID реферера",
"telephone": "Номер телефону",
"telephonePlaceholder": "Введіть номер телефону",
"userEmail": "Електронна пошта користувача",
"userEmailPlaceholder": "Введіть електронну пошту користувача"
},
"giftAmount": "Сума подарунка",
"giftAmountPlaceholder": "Введіть суму подарунка",
"invalidEmailFormat": "Неправильний формат електронної пошти",
"inviteCode": "Код запрошення",
"inviteCodePlaceholder": "Введіть код запрошення (залиште порожнім для генерації)",
"loading": "Завантаження...",
"loginIp": "IP-адреса входу",
"loginTime": "Час входу",
"manager": "Менеджер",
"password": "Пароль",
"passwordPlaceholder": "Введіть новий пароль (необов'язково)",
"referer": "Реферер",
"refererId": "Ідентифікатор реферера",
"refererIdPlaceholder": "Введіть ID реферера",
"searchIp": "Пошук IP-адреси",
"selectAuthType": "Виберіть тип автентифікації",
"telephone": "Номер телефону",
"telephonePlaceholder": "Введіть номер телефону",
"updateSuccess": "Оновлення успішне",
"userAgent": "Агент користувача",
"userEmail": "Електронна пошта користувача",
"userEmailPlaceholder": "Введіть електронну адресу користувача",
"userList": "Список користувачів",
"userName": "Ідентифікатор користувача"
"userLogs": "Історія входів",
"userName": "Ідентифікатор користувача",
"userOrders": "Замовлення",
"userProfile": "Профіль",
"userSubscriptions": "Підписки",
"verified": "Перевірено"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "Quản lý phiếu hỗ trợ",
"Twitter": "Twitter",
"User": "Người dùng",
"User Detail": "Chi Tiết Người Dùng",
"User Management": "Quản lý người dùng"
}

View File

@ -1,8 +1,17 @@
{
"actions": "Hành động",
"areaCode": "Mã Vùng",
"areaCodePlaceholder": "Mã vùng",
"auth": "Xác thực",
"authIdentifier": "Định danh Xác thực",
"authIdentifierPlaceholder": "Nhập mã xác thực",
"authType": "Loại xác thực",
"authUser": "Người Dùng Xác Thực",
"balance": "Số dư",
"balancePlaceholder": "Số dư",
"cancel": "Hủy",
"commission": "Hoa hồng",
"commissionPlaceholder": "Nhập hoa hồng",
"confirm": "Xác nhận",
"confirmDelete": "Bạn có chắc chắn muốn xóa không?",
"create": "Tạo",
@ -12,39 +21,38 @@
"delete": "Xóa",
"deleteDescription": "Sau khi xóa, dữ liệu không thể khôi phục, hãy thao tác cẩn thận.",
"deleteSuccess": "Xóa thành công",
"detail": "Chi tiết",
"edit": "Chỉnh sửa",
"editUser": "Chỉnh sửa người dùng",
"email": "Email",
"enable": "Kích hoạt",
"form": {
"areaCode": "Mã vùng",
"areaCodePlaceholder": "Mã vùng",
"balance": "Số dư",
"balancePlaceholder": "Số dư",
"cancel": "Hủy",
"commission": "Hoa hồng",
"commissionPlaceholder": "Nhập hoa hồng",
"confirm": "Xác nhận",
"giftAmount": "Số tiền quà tặng",
"giftAmountPlaceholder": "Nhập số tiền quà tặng",
"invalidEmailFormat": "Định dạng email không hợp lệ",
"inviteCode": "Mã mời",
"inviteCodePlaceholder": "Vui lòng nhập mã mời (để trống sẽ tự động tạo)",
"manager": "Quản trị viên",
"password": "Mật khẩu",
"passwordPlaceholder": "Vui lòng nhập mật khẩu mới (có thể để trống)",
"refererId": "ID người giới thiệu",
"refererIdPlaceholder": "Vui lòng nhập ID người giới thiệu",
"telephone": "Số điện thoại",
"telephonePlaceholder": "Nhập số điện thoại",
"userEmail": "Email người dùng",
"userEmailPlaceholder": "Vui lòng nhập email người dùng"
},
"giftAmount": "Số tiền quà tặng",
"giftAmountPlaceholder": "Nhập số tiền quà tặng",
"invalidEmailFormat": "Định dạng email không hợp lệ",
"inviteCode": "Mã Mời",
"inviteCodePlaceholder": "Nhập mã mời (để trống để tạo mới)",
"loading": "Đang tải...",
"loginIp": "Địa chỉ IP đăng nhập",
"loginTime": "Thời gian đăng nhập",
"manager": "Quản lý",
"password": "Mật khẩu",
"passwordPlaceholder": "Nhập mật khẩu mới (không bắt buộc)",
"referer": "Người giới thiệu",
"refererId": "ID người giới thiệu",
"refererIdPlaceholder": "Nhập mã người giới thiệu",
"searchIp": "Tìm kiếm địa chỉ IP",
"selectAuthType": "Chọn loại xác thực",
"telephone": "Số điện thoại",
"telephonePlaceholder": "Nhập số điện thoại",
"updateSuccess": "Cập nhật thành công",
"userAgent": "Tác nhân người dùng",
"userEmail": "Email Người Dùng",
"userEmailPlaceholder": "Nhập email người dùng",
"userList": "Danh sách người dùng",
"userName": "Định danh Người dùng"
"userLogs": "Lịch sử đăng nhập",
"userName": "Định danh Người dùng",
"userOrders": "Đơn hàng",
"userProfile": "Hồ sơ",
"userSubscriptions": "Đăng ký",
"verified": "Đã xác minh"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "工单管理",
"Twitter": "Twitter",
"User": "用户",
"User Detail": "用户详情",
"User Management": "用户管理"
}

View File

@ -1,8 +1,17 @@
{
"actions": "操作",
"areaCode": "区号",
"areaCodePlaceholder": "区号",
"auth": "认证",
"authIdentifier": "认证标识符",
"authIdentifierPlaceholder": "输入认证标识符",
"authType": "认证类型",
"authUser": "授权用户",
"balance": "余额",
"balancePlaceholder": "余额",
"cancel": "取消",
"commission": "佣金",
"commissionPlaceholder": "输入佣金",
"confirm": "确认",
"confirmDelete": "您确定要删除吗?",
"create": "创建",
@ -12,39 +21,38 @@
"delete": "删除",
"deleteDescription": "删除后无法恢复数据,请谨慎操作。",
"deleteSuccess": "删除成功",
"detail": "详情",
"edit": "编辑",
"editUser": "编辑用户",
"email": "邮箱",
"enable": "启用",
"form": {
"areaCode": "区号",
"areaCodePlaceholder": "输入区号",
"balance": "余额",
"balancePlaceholder": "余额",
"cancel": "取消",
"commission": "佣金",
"commissionPlaceholder": "输入佣金",
"confirm": "确认",
"giftAmount": "礼品金额",
"giftAmountPlaceholder": "输入礼品金额",
"invalidEmailFormat": "无效的电子邮件格式",
"inviteCode": "邀请码",
"inviteCodePlaceholder": "请输入邀请码(留空则自动生成)",
"manager": "管理员",
"password": "密码",
"passwordPlaceholder": "请输入新密码(可留空)",
"refererId": "推荐人 ID",
"refererIdPlaceholder": "请输入推荐人 ID",
"telephone": "电话号码",
"telephonePlaceholder": "输入电话号码",
"userEmail": "用户邮箱",
"userEmailPlaceholder": "请输入用户邮箱"
},
"giftAmount": "礼物金额",
"giftAmountPlaceholder": "输入礼品金额",
"invalidEmailFormat": "电子邮件格式无效",
"inviteCode": "邀请码",
"inviteCodePlaceholder": "输入邀请码(留空以生成)",
"loading": "加载中...",
"loginIp": "登录IP",
"loginTime": "登录时间",
"manager": "经理",
"password": "密码",
"passwordPlaceholder": "输入新密码(可选)",
"referer": "推荐人",
"refererId": "推荐人ID",
"refererIdPlaceholder": "输入推荐人ID",
"searchIp": "搜索IP地址",
"selectAuthType": "选择认证类型",
"telephone": "电话号码",
"telephonePlaceholder": "输入电话号码",
"updateSuccess": "更新成功",
"userAgent": "用户代理",
"userEmail": "用户邮箱",
"userEmailPlaceholder": "输入用户邮箱",
"userList": "用户列表",
"userName": "用户标识符"
"userLogs": "登录历史",
"userName": "用户标识符",
"userOrders": "订单",
"userProfile": "个人资料",
"userSubscriptions": "订阅",
"verified": "已验证"
}

View File

@ -24,5 +24,6 @@
"Ticket Management": "工單管理",
"Twitter": "Twitter",
"User": "使用者",
"User Detail": "用戶詳情",
"User Management": "使用者管理"
}

View File

@ -1,8 +1,17 @@
{
"actions": "操作",
"areaCode": "地區代碼",
"areaCodePlaceholder": "區號",
"auth": "認證",
"authIdentifier": "認證識別碼",
"authIdentifierPlaceholder": "輸入認證識別碼",
"authType": "認證類型",
"authUser": "授權用戶",
"balance": "餘額",
"balancePlaceholder": "結餘",
"cancel": "取消",
"commission": "佣金",
"commissionPlaceholder": "輸入佣金",
"confirm": "確認",
"confirmDelete": "您確定要刪除嗎?",
"create": "建立",
@ -12,39 +21,38 @@
"delete": "刪除",
"deleteDescription": "刪除後無法恢復資料,請謹慎操作。",
"deleteSuccess": "刪除成功",
"detail": "詳情",
"edit": "編輯",
"editUser": "編輯使用者",
"email": "電子郵件",
"enable": "啟用",
"form": {
"areaCode": "區號",
"areaCodePlaceholder": "輸入區號",
"balance": "餘額",
"balancePlaceholder": "餘額",
"cancel": "取消",
"commission": "佣金",
"commissionPlaceholder": "輸入佣金",
"confirm": "確認",
"giftAmount": "禮物金額",
"giftAmountPlaceholder": "輸入禮物金額",
"invalidEmailFormat": "無效的電子郵件格式",
"inviteCode": "邀請碼",
"inviteCodePlaceholder": "請輸入邀請碼(留空則自動生成)",
"manager": "管理員",
"password": "密碼",
"passwordPlaceholder": "請輸入新密碼(可留空)",
"refererId": "推薦人 ID",
"refererIdPlaceholder": "請輸入推薦人 ID",
"telephone": "電話號碼",
"telephonePlaceholder": "輸入電話號碼",
"userEmail": "用戶信箱",
"userEmailPlaceholder": "請輸入用戶信箱"
},
"giftAmount": "禮物金額",
"giftAmountPlaceholder": "輸入禮物金額",
"invalidEmailFormat": "電郵格式無效",
"inviteCode": "邀請碼",
"inviteCodePlaceholder": "輸入邀請碼(留空以生成)",
"loading": "載入中...",
"loginIp": "登入 IP",
"loginTime": "登入時間",
"manager": "經理",
"password": "密碼",
"passwordPlaceholder": "輸入新密碼(可選)",
"referer": "推薦人",
"refererId": "推薦人 ID",
"refererIdPlaceholder": "輸入推薦人 ID",
"searchIp": "搜尋IP地址",
"selectAuthType": "選擇認證類型",
"telephone": "電話號碼",
"telephonePlaceholder": "輸入電話號碼",
"updateSuccess": "更新成功",
"userAgent": "用戶代理",
"userEmail": "用戶電郵",
"userEmailPlaceholder": "輸入用戶電郵",
"userList": "使用者列表",
"userName": "用戶識別碼"
"userLogs": "登入歷史",
"userName": "用戶識別碼",
"userOrders": "訂單",
"userProfile": "個人資料",
"userSubscriptions": "訂閱",
"verified": "已驗證"
}

View File

@ -32,6 +32,7 @@ export async function appleLoginCallback(
return request<API.Response & { data?: any }>('/v1/auth/oauth/callback/apple', {
method: 'POST',
data: formData,
requestType: 'form',
...(options || {}),
});
}

View File

@ -24,8 +24,14 @@ export async function generateStaticParams() {
];
}
export default async function Page({ params }: any) {
const { platform } = params;
export default async function Page({
params,
}: {
params: Promise<{
platform: string;
}>;
}) {
const { platform } = await params;
const t = await getTranslations('auth');
return (
<Certification platform={platform}>

View File

@ -35,7 +35,7 @@ export function ColumnFilter<TData>({ table, params, filters }: ColumnFilterProp
return (
<Combobox
key={param.key}
className='w-32'
className='min-w-32'
placeholder={param.placeholder || 'Choose...'}
value={filters[param.key] || ''}
onChange={(value) => {
@ -48,7 +48,7 @@ export function ColumnFilter<TData>({ table, params, filters }: ColumnFilterProp
return (
<Input
key={param.key}
className='w-32'
className='min-w-32'
placeholder={param.placeholder || 'Search...'}
value={filters[param.key] || ''}
onChange={(event) => updateFilter(param.key, event.target.value)}