feat(auth-control): Update general

This commit is contained in:
web@ppanel
2025-02-09 20:14:27 +07:00
parent e3a31eb709
commit 3883646566
55 changed files with 1331 additions and 1677 deletions
@@ -0,0 +1,103 @@
'use client';
import { getInviteConfig, updateInviteConfig } from '@/services/admin/system';
import { useQuery } from '@tanstack/react-query';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export function Invite() {
const t = useTranslations('auth-control.invite');
const { data, refetch } = useQuery({
queryKey: ['getInviteConfig'],
queryFn: async () => {
const { data } = await getInviteConfig();
return data.data;
},
});
async function updateConfig(key: string, value: unknown) {
if (data?.[key] === value) return;
try {
await updateInviteConfig({
...data,
[key]: value,
} as API.InviteConfig);
toast.success(t('saveSuccess'));
refetch();
} catch (error) {
/* empty */
}
}
return (
<Card>
<CardHeader>
<CardTitle>{t('inviteSettings')}</CardTitle>
</CardHeader>
<CardContent>
<Table>
<TableBody>
<TableRow>
<TableCell>
<Label>{t('enableForcedInvite')}</Label>
<p className='text-muted-foreground text-xs'>
{t('enableForcedInviteDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.forced_invite}
onCheckedChange={(checked) => {
updateConfig('forced_invite', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('inviteCommissionPercentage')}</Label>
<p className='text-muted-foreground text-xs'>
{t('inviteCommissionPercentageDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
placeholder={t('inputPlaceholder')}
value={data?.referral_percentage}
type='number'
min={0}
max={100}
suffix='%'
onValueBlur={(value) => updateConfig('referral_percentage', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('commissionFirstTimeOnly')}</Label>
<p className='text-muted-foreground text-xs'>
{t('commissionFirstTimeOnlyDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.only_first_purchase}
onCheckedChange={(checked) => {
updateConfig('only_first_purchase', checked);
}}
/>
</TableCell>
</TableRow>
</TableBody>
</Table>
</CardContent>
</Card>
);
}
@@ -1,118 +1,15 @@
'use client';
import { getRegisterConfig, updateRegisterConfig } from '@/services/admin/system';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
import { Invite } from './invite';
import { Register } from './register';
import { Verify } from './verify';
export default function Page() {
const t = useTranslations('auth-control');
const { data, refetch } = useQuery({
queryKey: ['getRegisterConfig'],
queryFn: async () => {
const { data } = await getRegisterConfig();
return data.data;
},
});
async function updateConfig(key: string, value: unknown) {
if (data?.[key] === value) return;
try {
await updateRegisterConfig({
...data,
[key]: value,
} as API.RegisterConfig);
toast.success(t('saveSuccess'));
refetch();
} catch (error) {
/* empty */
}
}
return (
<Table>
<TableBody>
<TableRow>
<TableCell>
<Label>{t('stopNewUserRegistration')}</Label>
<p className='text-muted-foreground text-xs'>
{t('stopNewUserRegistrationDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.stop_register}
onCheckedChange={(checked) => {
updateConfig('stop_register', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('ipRegistrationLimit')}</Label>
<p className='text-muted-foreground text-xs'>{t('ipRegistrationLimitDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.enable_ip_register_limit}
onCheckedChange={(checked) => {
updateConfig('enable_ip_register_limit', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('registrationLimitCount')}</Label>
<p className='text-muted-foreground text-xs'>
{t('registrationLimitCountDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
type='number'
min={0}
value={data?.ip_register_limit}
onValueBlur={(value) => updateConfig('ip_register_limit', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('penaltyTime')}</Label>
<p className='text-muted-foreground text-xs'>{t('penaltyTimeDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
type='number'
min={0}
value={data?.ip_register_limit_duration}
onValueBlur={(value) => updateConfig('ip_register_limit_duration', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('trialRegistration')}</Label>
<p className='text-muted-foreground text-xs'>{t('trialRegistrationDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.enable_trial}
onCheckedChange={(checked) => {
updateConfig('enable_trial', checked);
}}
/>
</TableCell>
</TableRow>
</TableBody>
</Table>
<div className='space-y-3'>
<Register />
<Verify />
<Invite />
</div>
);
}
@@ -0,0 +1,124 @@
'use client';
import { getRegisterConfig, updateRegisterConfig } from '@/services/admin/system';
import { useQuery } from '@tanstack/react-query';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export function Register() {
const t = useTranslations('auth-control.register');
const { data, refetch } = useQuery({
queryKey: ['getRegisterConfig'],
queryFn: async () => {
const { data } = await getRegisterConfig();
return data.data;
},
});
async function updateConfig(key: string, value: unknown) {
if (data?.[key] === value) return;
await updateRegisterConfig({
...data,
[key]: value,
} as API.RegisterConfig);
toast.success(t('saveSuccess'));
refetch();
}
return (
<Card>
<CardHeader>
<CardTitle>{t('registerSettings')}</CardTitle>
</CardHeader>
<CardContent>
<Table>
<TableBody>
<TableRow>
<TableCell>
<Label>{t('stopNewUserRegistration')}</Label>
<p className='text-muted-foreground text-xs'>
{t('stopNewUserRegistrationDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.stop_register}
onCheckedChange={(checked) => {
updateConfig('stop_register', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('ipRegistrationLimit')}</Label>
<p className='text-muted-foreground text-xs'>
{t('ipRegistrationLimitDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.enable_ip_register_limit}
onCheckedChange={(checked) => {
updateConfig('enable_ip_register_limit', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('registrationLimitCount')}</Label>
<p className='text-muted-foreground text-xs'>
{t('registrationLimitCountDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
type='number'
min={0}
value={data?.ip_register_limit}
onValueBlur={(value) => updateConfig('ip_register_limit', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('penaltyTime')}</Label>
<p className='text-muted-foreground text-xs'>{t('penaltyTimeDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
type='number'
min={0}
value={data?.ip_register_limit_duration}
onValueBlur={(value) => updateConfig('ip_register_limit_duration', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('trialRegistration')}</Label>
<p className='text-muted-foreground text-xs'>{t('trialRegistrationDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.enable_trial}
onCheckedChange={(checked) => {
updateConfig('enable_trial', checked);
}}
/>
</TableCell>
</TableRow>
</TableBody>
</Table>
</CardContent>
</Card>
);
}
@@ -0,0 +1,125 @@
'use client';
import { getVerifyConfig, updateVerifyConfig } from '@/services/admin/system';
import { useQuery } from '@tanstack/react-query';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export function Verify() {
const t = useTranslations('auth-control.verify');
const { data, refetch } = useQuery({
queryKey: ['getVerifyConfig'],
queryFn: async () => {
const { data } = await getVerifyConfig();
return data.data;
},
});
async function updateConfig(key: string, value: unknown) {
if (data?.[key] === value) return;
try {
await updateVerifyConfig({
...data,
[key]: value,
} as API.VerifyConfig);
toast.success(t('saveSuccess'));
refetch();
} catch (error) {
/* empty */
}
}
return (
<Card className='mb-6'>
<CardHeader>
<CardTitle>{t('verifySettings')}</CardTitle>
</CardHeader>
<CardContent>
<Table>
<TableBody>
<TableRow>
<TableCell>
<Label>{t('turnstileSiteKey')}</Label>
<p className='text-muted-foreground text-xs'>{t('turnstileSiteKeyDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
placeholder={t('inputPlaceholder')}
defaultValue={data?.turnstile_site_key}
onValueBlur={(value) => updateConfig('turnstile_site_key', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('turnstileSecret')}</Label>
<p className='text-muted-foreground text-xs'>{t('turnstileSecretDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
placeholder={t('inputPlaceholder')}
defaultValue={data?.turnstile_secret}
onValueBlur={(value) => updateConfig('turnstile_secret', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('registrationVerificationCode')}</Label>
<p className='text-muted-foreground text-xs'>
{t('registrationVerificationCodeDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.enable_register_verify}
onCheckedChange={(checked) => {
updateConfig('enable_register_verify', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('loginVerificationCode')}</Label>
<p className='text-muted-foreground text-xs'>
{t('loginVerificationCodeDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.enable_login_verify}
onCheckedChange={(checked) => {
updateConfig('enable_login_verify', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('resetPasswordVerificationCode')}</Label>
<p className='text-muted-foreground text-xs'>
{t('resetPasswordVerificationCodeDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.enable_reset_password_verify}
onCheckedChange={(checked) => {
updateConfig('enable_reset_password_verify', checked);
}}
/>
</TableCell>
</TableRow>
</TableBody>
</Table>
</CardContent>
</Card>
);
}
@@ -358,30 +358,34 @@ export default function Page() {
</TableCell>
</TableRow>
)}
<TableRow>
<TableCell>
<Label>{t('template')}</Label>
<p className='text-muted-foreground text-xs'>
{t('templateTip', { code: platformConfig?.code_variable })}
</p>
</TableCell>
<TableCell className='text-right'>
<Textarea
defaultValue={data?.platform_config?.template ?? ''}
onBlur={(e) =>
updateConfig('config', {
...data?.config,
platform_config: {
...data?.config?.platform_config,
template: e.target.value,
},
})
}
disabled={isFetching}
placeholder={t('placeholders.template', { code: platformConfig?.code_variable })}
/>
</TableCell>
</TableRow>
{platformConfig?.code_variable && (
<TableRow>
<TableCell>
<Label>{t('template')}</Label>
<p className='text-muted-foreground text-xs'>
{t('templateTip', { code: platformConfig?.code_variable })}
</p>
</TableCell>
<TableCell className='text-right'>
<Textarea
defaultValue={data?.platform_config?.template ?? ''}
onBlur={(e) =>
updateConfig('config', {
...data?.config,
platform_config: {
...data?.config?.platform_config,
template: e.target.value,
},
})
}
disabled={isFetching}
placeholder={t('placeholders.template', {
code: platformConfig?.code_variable,
})}
/>
</TableCell>
</TableRow>
)}
<TableRow>
<TableCell>
<Label>{t('testSms')}</Label>
@@ -1,93 +0,0 @@
'use client';
import { getInviteConfig, updateInviteConfig } from '@/services/admin/system';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Invite() {
const t = useTranslations('system.invite');
const { data, refetch } = useQuery({
queryKey: ['getInviteConfig'],
queryFn: async () => {
const { data } = await getInviteConfig();
return data.data;
},
});
async function updateConfig(key: string, value: unknown) {
if (data?.[key] === value) return;
try {
await updateInviteConfig({
...data,
[key]: value,
} as API.InviteConfig);
toast.success(t('saveSuccess'));
refetch();
} catch (error) {
/* empty */
}
}
return (
<Table>
<TableBody>
<TableRow>
<TableCell>
<Label>{t('enableForcedInvite')}</Label>
<p className='text-muted-foreground text-xs'>{t('enableForcedInviteDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.forced_invite}
onCheckedChange={(checked) => {
updateConfig('forced_invite', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('inviteCommissionPercentage')}</Label>
<p className='text-muted-foreground text-xs'>
{t('inviteCommissionPercentageDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
placeholder={t('inputPlaceholder')}
value={data?.referral_percentage}
type='number'
min={0}
max={100}
suffix='%'
onValueBlur={(value) => updateConfig('referral_percentage', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('commissionFirstTimeOnly')}</Label>
<p className='text-muted-foreground text-xs'>
{t('commissionFirstTimeOnlyDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.only_first_purchase}
onCheckedChange={(checked) => {
updateConfig('only_first_purchase', checked);
}}
/>
</TableCell>
</TableRow>
</TableBody>
</Table>
);
}
-16
View File
@@ -1,12 +1,8 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { getTranslations } from 'next-intl/server';
import Currency from './currency';
import Invite from './invite';
import Site from './site';
import Telegram from './telegram';
import Tos from './tos';
import Verify from './verify';
export default async function Page() {
const t = await getTranslations('system');
@@ -16,9 +12,6 @@ export default async function Page() {
<TabsList className='h-full flex-wrap'>
<TabsTrigger value='site'>{t('tabs.site')}</TabsTrigger>
<TabsTrigger value='currency'>{t('tabs.currency')}</TabsTrigger>
<TabsTrigger value='verify'>{t('tabs.verify')}</TabsTrigger>
<TabsTrigger value='invite'>{t('tabs.invite')}</TabsTrigger>
<TabsTrigger value='telegram'>{t('tabs.telegram')}</TabsTrigger>
<TabsTrigger value='tos'>{t('tabs.tos')}</TabsTrigger>
</TabsList>
<TabsContent value='site'>
@@ -27,15 +20,6 @@ export default async function Page() {
<TabsContent value='currency'>
<Currency />
</TabsContent>
<TabsContent value='verify'>
<Verify />
</TabsContent>
<TabsContent value='invite'>
<Invite />
</TabsContent>
<TabsContent value='telegram'>
<Telegram />
</TabsContent>
<TabsContent value='tos'>
<Tos />
</TabsContent>
@@ -1,99 +0,0 @@
'use client';
import { getTelegramConfig, updateTelegramConfig } from '@/services/admin/system';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Telegram() {
const t = useTranslations('system.telegram');
const { data, refetch } = useQuery({
queryKey: ['getTelegramConfig'],
queryFn: async () => {
const { data } = await getTelegramConfig();
return data.data;
},
});
async function updateConfig(key: string, value: unknown) {
if (data?.[key] === value) return;
try {
await updateTelegramConfig({
...data,
[key]: value,
} as API.TelegramConfig);
toast.success(t('saveSuccess'));
refetch();
} catch (error) {
/* empty */
}
}
return (
<Table>
<TableBody>
<TableRow>
<TableCell>
<Label>{t('webhookDomain')}</Label>
<p className='text-muted-foreground text-xs'>{t('webhookDomainDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
placeholder={t('inputPlaceholderWebhookDomain')}
value={data?.telegram_web_hook_domain}
onValueBlur={(value) => updateConfig('telegram_web_hook_domain', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('botToken')}</Label>
<p className='text-muted-foreground text-xs'>{t('botTokenDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
placeholder={t('inputPlaceholderBotToken')}
value={data?.telegram_bot_token}
onValueBlur={(value) => updateConfig('telegram_bot_token', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('enableBotNotifications')}</Label>
<p className='text-muted-foreground text-xs'>
{t('enableBotNotificationsDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.telegram_notify}
onCheckedChange={(checked) => {
updateConfig('telegram_notify', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('groupURL')}</Label>
<p className='text-muted-foreground text-xs'>{t('groupURLDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
placeholder={t('inputPlaceholderGroupURL')}
value={data?.telegram_group_url}
onValueBlur={(value) => updateConfig('telegram_group_url', value)}
/>
</TableCell>
</TableRow>
</TableBody>
</Table>
);
}
-115
View File
@@ -1,115 +0,0 @@
'use client';
import { getVerifyConfig, updateVerifyConfig } from '@/services/admin/system';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Verify() {
const t = useTranslations('system.verify');
const { data, refetch } = useQuery({
queryKey: ['getVerifyConfig'],
queryFn: async () => {
const { data } = await getVerifyConfig();
return data.data;
},
});
async function updateConfig(key: string, value: unknown) {
if (data?.[key] === value) return;
try {
await updateVerifyConfig({
...data,
[key]: value,
} as API.VerifyConfig);
toast.success(t('saveSuccess'));
refetch();
} catch (error) {
/* empty */
}
}
return (
<Table>
<TableBody>
<TableRow>
<TableCell>
<Label>{t('turnstileSiteKey')}</Label>
<p className='text-muted-foreground text-xs'>{t('turnstileSiteKeyDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
placeholder={t('inputPlaceholder')}
defaultValue={data?.turnstile_site_key}
onValueBlur={(value) => updateConfig('turnstile_site_key', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('turnstileSecret')}</Label>
<p className='text-muted-foreground text-xs'>{t('turnstileSecretDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<EnhancedInput
placeholder={t('inputPlaceholder')}
defaultValue={data?.turnstile_secret}
onValueBlur={(value) => updateConfig('turnstile_secret', value)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('registrationVerificationCode')}</Label>
<p className='text-muted-foreground text-xs'>
{t('registrationVerificationCodeDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.enable_register_verify}
onCheckedChange={(checked) => {
updateConfig('enable_register_verify', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('loginVerificationCode')}</Label>
<p className='text-muted-foreground text-xs'>{t('loginVerificationCodeDescription')}</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.enable_login_verify}
onCheckedChange={(checked) => {
updateConfig('enable_login_verify', checked);
}}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Label>{t('resetPasswordVerificationCode')}</Label>
<p className='text-muted-foreground text-xs'>
{t('resetPasswordVerificationCodeDescription')}
</p>
</TableCell>
<TableCell className='text-right'>
<Switch
checked={data?.enable_reset_password_verify}
onCheckedChange={(checked) => {
updateConfig('enable_reset_password_verify', checked);
}}
/>
</TableCell>
</TableRow>
</TableBody>
</Table>
);
}