mirror of
https://github.com/rustmailer/bichon.git
synced 2026-08-03 07:48:34 +02:00
feat(i18n): add language switcher in top-right corner for multi-language support #9
This commit is contained in:
@@ -33,6 +33,7 @@ import { useQuery } from '@tanstack/react-query'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
import { TableSkeleton } from '@/components/table-skeleton'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FileIcon } from 'lucide-react'
|
||||
import { format, formatDistanceToNow } from 'date-fns'
|
||||
import LongText from '@/components/long-text'
|
||||
@@ -49,6 +50,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export function OAuth2TokensDialog({ currentRow, open, onOpenChange }: Props) {
|
||||
const { t } = useTranslation()
|
||||
const navigate = useNavigate()
|
||||
const { data: oauth2Tokens, isLoading } = useQuery({
|
||||
queryKey: ['oauth2-tokens', currentRow.id],
|
||||
@@ -65,21 +67,21 @@ export function OAuth2TokensDialog({ currentRow, open, onOpenChange }: Props) {
|
||||
await navigator.clipboard.writeText(token);
|
||||
if (access) {
|
||||
toast({
|
||||
title: "Success",
|
||||
description: "Access token copied to clipboard",
|
||||
title: t('common.ok'),
|
||||
description: t('accounts.accessTokenCopiedToClipboard'),
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: "Success",
|
||||
description: "Refresh token copied to clipboard",
|
||||
title: t('common.ok'),
|
||||
description: t('accounts.refreshTokenCopiedToClipboard'),
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to copy text",
|
||||
title: t('settings.failedToCopyText'),
|
||||
description: (err as Error).message,
|
||||
action: <ToastAction altText="Try again">Try again</ToastAction>,
|
||||
action: <ToastAction altText={t('common.tryAgain')}>{t('common.tryAgain')}</ToastAction>,
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
@@ -93,9 +95,9 @@ export function OAuth2TokensDialog({ currentRow, open, onOpenChange }: Props) {
|
||||
>
|
||||
<DialogContent className='sm:max-w-3xl'>
|
||||
<DialogHeader className='text-left'>
|
||||
<DialogTitle>OAuth2 Tokens</DialogTitle>
|
||||
<DialogTitle>{t('accounts.oauth2Tokens')}</DialogTitle>
|
||||
<DialogDescription>
|
||||
Details of the OAuth2 tokens for the account.
|
||||
{t('accounts.detailsOfTheOAuth2TokensForTheAccount')}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Card>
|
||||
@@ -106,20 +108,20 @@ export function OAuth2TokensDialog({ currentRow, open, onOpenChange }: Props) {
|
||||
<Table className='w-full'>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Field</TableHead>
|
||||
<TableHead>Value</TableHead>
|
||||
<TableHead>Action</TableHead>
|
||||
<TableHead>{t('accounts.field')}</TableHead>
|
||||
<TableHead>{t('accounts.value')}</TableHead>
|
||||
<TableHead>{t('common.actions')}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className='max-w-80'>OAuth2 Name</TableCell>
|
||||
<TableCell className='max-w-80'>{t('oauth2.id')}</TableCell>
|
||||
<TableCell>
|
||||
<LongText className='max-w-[240px] sm:max-w-[430px]'>{oauth2Tokens.oauth2_name}</LongText>
|
||||
<LongText className='max-w-[240px] sm:max-w-[430px]'>{oauth2Tokens.oauth2_id}</LongText>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className='max-w-80'>Access Token</TableCell>
|
||||
<TableCell className='max-w-80'>{t('accessTokens.token')}</TableCell>
|
||||
<TableCell>
|
||||
<LongText className='max-w-[240px] sm:max-w-[430px]'>{oauth2Tokens.access_token}</LongText>
|
||||
</TableCell>
|
||||
@@ -130,7 +132,7 @@ export function OAuth2TokensDialog({ currentRow, open, onOpenChange }: Props) {
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className='max-w-80'>Refresh Token</TableCell>
|
||||
<TableCell className='max-w-80'>{t('accounts.refreshToken')}</TableCell>
|
||||
<TableCell>
|
||||
<LongText className='max-w-[240px] sm:max-w-[430px]'>{oauth2Tokens.refresh_token}</LongText>
|
||||
</TableCell>
|
||||
@@ -141,13 +143,13 @@ export function OAuth2TokensDialog({ currentRow, open, onOpenChange }: Props) {
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className='max-w-80'>Created At</TableCell>
|
||||
<TableCell className='max-w-80'>{t('settings.createdAt')}</TableCell>
|
||||
<TableCell>
|
||||
{format(new Date(oauth2Tokens.created_at), 'yyyy-MM-dd HH:mm:ss')}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className='max-w-80'>Updated At</TableCell>
|
||||
<TableCell className='max-w-80'>{t('settings.updatedAt')}</TableCell>
|
||||
<TableCell>
|
||||
{formatDistanceToNow(new Date(oauth2Tokens.updated_at), { addSuffix: true })}
|
||||
</TableCell>
|
||||
@@ -158,10 +160,11 @@ export function OAuth2TokensDialog({ currentRow, open, onOpenChange }: Props) {
|
||||
<div className="flex h-[250px] mt-4 shrink-0 items-center justify-center rounded-md border border-dashed">
|
||||
<div className="mx-auto flex max-w-[420px] flex-col items-center justify-center text-center">
|
||||
<FileIcon className="h-10 w-10 text-muted-foreground" />
|
||||
<h3 className="mt-4 text-lg font-semibold">No OAuth2 Tokens</h3>
|
||||
<h3 className="mt-4 text-lg font-semibold">{t('accounts.noOAuth2Tokens')}</h3>
|
||||
<p className="mb-4 mt-2 text-sm text-muted-foreground">
|
||||
The account has not completed the authorization process. Please
|
||||
<a onClick={() => navigate({ to: '/oauth2' })} className="ml-1 text-blue-500 underline cursor-pointer">click here</a> to authorize the account.
|
||||
{t('accounts.theAccountHasNotCompletedTheAuthorizationProcess')}
|
||||
<a onClick={() => navigate({ to: '/oauth2' })} className="ml-1 text-blue-500 underline cursor-pointer">{t('accounts.clickHere')}</a>
|
||||
{t('accounts.toAuthorizeTheAccount')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -170,7 +173,7 @@ export function OAuth2TokensDialog({ currentRow, open, onOpenChange }: Props) {
|
||||
</Card>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant='outline' className="px-2 py-1 text-sm h-auto">Close</Button>
|
||||
<Button variant='outline' className="px-2 py-1 text-sm h-auto">{t('common.close')}</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
Reference in New Issue
Block a user