Add translations

This commit is contained in:
Nicola Benaglia 2025-05-09 21:20:38 +02:00
parent d838fe483a
commit 7cd3d10d67
25 changed files with 229 additions and 136 deletions

View File

@ -12,6 +12,7 @@
"continue": "continue", "continue": "continue",
"continue_logout": "continue to logout", "continue_logout": "continue to logout",
"decline": "decline", "decline": "decline",
"decrypt": "decrypt",
"edit": "edit", "edit": "edit",
"export": "export", "export": "export",
"import": "import", "import": "import",
@ -38,6 +39,7 @@
"payment": "payment fee", "payment": "payment fee",
"publish": "publish fee" "publish": "publish fee"
}, },
"general_settings": "general settings",
"page": { "page": {
"last": "last", "last": "last",
"first": "first", "first": "first",
@ -45,6 +47,7 @@
"previous": "previous" "previous": "previous"
}, },
"downloading_qdn": "downloading from QDN", "downloading_qdn": "downloading from QDN",
"invite_list": "invite list",
"last_height": "last height", "last_height": "last height",
"loading": "loading...", "loading": "loading...",
"loading_posts": "loading posts... please wait.", "loading_posts": "loading posts... please wait.",

View File

@ -1,7 +1,12 @@
{ {
"action": { "action": {
"cancel_ban": "cancel ban", "cancel_ban": "cancel ban",
"copy_private_key": "copy private key",
"create_group": "create group", "create_group": "create group",
"disable_push_notifications": "disable all push notifications",
"enable_dev_mode": "enable dev mode",
"export_password": "export password",
"export_private_key": "export private key",
"find_group": "find group", "find_group": "find group",
"join_group": "join group", "join_group": "join group",
"invite_member": "invite member", "invite_member": "invite member",
@ -35,16 +40,20 @@
}, },
"message": { "message": {
"generic": { "generic": {
"descrypt_wallet": "decrypting wallet...",
"encryption_key": "the group's first common encryption key is in the process of creation. Please wait a few minutes for it to be retrieved by the network. Checking every 2 minutes...", "encryption_key": "the group's first common encryption key is in the process of creation. Please wait a few minutes for it to be retrieved by the network. Checking every 2 minutes...",
"group_invited_you": "{{group}} has invited you", "group_invited_you": "{{group}} has invited you",
"no_display": "nothing to display", "no_display": "nothing to display",
"no_selection": "no group selected", "no_selection": "no group selected",
"not_part_group": "you are not part of the encrypted group of members. Wait until an admin re-encrypts the keys.", "not_part_group": "you are not part of the encrypted group of members. Wait until an admin re-encrypts the keys.",
"only_encrypted": "only unencrypted messages will be displayed.", "only_encrypted": "only unencrypted messages will be displayed.",
"private_key_copied": "private key copied",
"secure_place": "keep your private key in a secure place. Do not share!",
"setting_group": "setting up group... please wait." "setting_group": "setting up group... please wait."
}, },
"error": { "error": {
"access_name": "cannot send a message without a access to your name", "access_name": "cannot send a message without a access to your name",
"descrypt_wallet": "error decrypting wallet {{ :errorMessage }}",
"description_required": "please provide a description", "description_required": "please provide a description",
"group_info": "cannot access group information", "group_info": "cannot access group information",
"name_required": "please provide a name", "name_required": "please provide a name",
@ -55,7 +64,7 @@
"group_creation_name": "created group {{group_name}}: awaiting confirmation", "group_creation_name": "created group {{group_name}}: awaiting confirmation",
"group_creation_label": "created group {{name}}: success!", "group_creation_label": "created group {{name}}: success!",
"group_invite": "successfully invited {{value}}. It may take a couple of minutes for the changes to propagate", "group_invite": "successfully invited {{value}}. It may take a couple of minutes for the changes to propagate",
"join_creation": "successfully requested to join group. It may take a couple of minutes for the changes to propagate", "group_join": "successfully requested to join group. It may take a couple of minutes for the changes to propagate",
"group_join_name": "joined group {{group_name}}: awaiting confirmation", "group_join_name": "joined group {{group_name}}: awaiting confirmation",
"group_join_label": "joined group {{name}}: success!", "group_join_label": "joined group {{name}}: success!",
"loading_threads": "loading threads... please wait.", "loading_threads": "loading threads... please wait.",

View File

@ -2,6 +2,8 @@
"action": { "action": {
"cancel_ban": "annulla ban", "cancel_ban": "annulla ban",
"create_group": "crea gruppo", "create_group": "crea gruppo",
"disable_push_notifications": "disabilita tutte le notifiche push",
"enable_dev_mode": "enable dev mode",
"find_group": "trova gruppo", "find_group": "trova gruppo",
"join_group": "unisciti al gruppo", "join_group": "unisciti al gruppo",
"invite_member": "invita membro", "invite_member": "invita membro",
@ -35,6 +37,7 @@
}, },
"message": { "message": {
"generic": { "generic": {
"descrypt_wallet": "decriptazione del wallet...",
"encryption_key": "la prima chiave di cifratura comune del gruppo è in fase di creazione. Attendere alcuni minuti affinché venga recuperata dalla rete. Controllo ogni 2 minuti...", "encryption_key": "la prima chiave di cifratura comune del gruppo è in fase di creazione. Attendere alcuni minuti affinché venga recuperata dalla rete. Controllo ogni 2 minuti...",
"group_invited_you": "{{group}} ti ha invitato", "group_invited_you": "{{group}} ti ha invitato",
"no_display": "niente da visualizzare", "no_display": "niente da visualizzare",
@ -45,6 +48,7 @@
}, },
"error": { "error": {
"access_name": "impossibile inviare un messaggio senza accesso al tuo nome", "access_name": "impossibile inviare un messaggio senza accesso al tuo nome",
"descrypt_wallet": "errore di decriptazione del wallet {{: errorMessage }}",
"description_required": "per favore fornisci una descrizione", "description_required": "per favore fornisci una descrizione",
"group_info": "impossibile accedere alle informazioni del gruppo", "group_info": "impossibile accedere alle informazioni del gruppo",
"name_required": "per favore fornisci un nome", "name_required": "per favore fornisci un nome",
@ -55,11 +59,11 @@
"group_creation_name": "gruppo {{group_name}} creato: in attesa di conferma", "group_creation_name": "gruppo {{group_name}} creato: in attesa di conferma",
"group_creation_label": "gruppo {{name}} creato: successo!", "group_creation_label": "gruppo {{name}} creato: successo!",
"group_invite": "invito inviato con successo a {{value}}. Potrebbero volerci alcuni minuti affinché le modifiche si propaghino", "group_invite": "invito inviato con successo a {{value}}. Potrebbero volerci alcuni minuti affinché le modifiche si propaghino",
"join_creation": "richiesta di adesione al gruppo inviata con successo. Potrebbero volerci alcuni minuti affinché le modifiche si propaghino", "group_join": "richiesta di adesione al gruppo inviata con successo. Potrebbero volerci alcuni minuti affinché le modifiche si propaghino",
"group_join_name": "entrato nel gruppo {{group_name}}: in attesa di conferma", "group_join_name": "entrato nel gruppo {{group_name}}: in attesa di conferma",
"group_join_label": "entrato nel gruppo {{name}}: successo!", "group_join_label": "entrato nel gruppo {{name}}: successo!",
"loading_threads": "caricamento thread... attendere prego.", "loading_threads": "caricamento thread... attendere prego.",
"unbanned_user": "utente sbannato con successo. Potrebbero volerci alcuni minuti affinché le modifiche si propaghino" "unbanned_user": "utente riammesso con successo. Potrebbero volerci alcuni minuti affinché le modifiche si propaghino"
} }
} }
} }

View File

@ -1,6 +1,6 @@
import React from 'react';
import './customloader.css'; import './customloader.css';
import { Box, useTheme } from '@mui/material'; import { Box, useTheme } from '@mui/material';
export const CustomLoader = () => { export const CustomLoader = () => {
const theme = useTheme(); const theme = useTheme();
return ( return (

View File

@ -1,5 +1,3 @@
import React from 'react';
export const CustomSvg = ({ src, color = 'black', size = 24 }) => { export const CustomSvg = ({ src, color = 'black', size = 24 }) => {
return ( return (
<svg <svg
@ -14,4 +12,3 @@ export const CustomSvg = ({ src, color = 'black', size = 24 }) => {
</svg> </svg>
); );
}; };

View File

@ -36,6 +36,7 @@
left: 56px; left: 56px;
animation: lds-ellipsis3 0.6s infinite; animation: lds-ellipsis3 0.6s infinite;
} }
@keyframes lds-ellipsis1 { @keyframes lds-ellipsis1 {
0% { 0% {
transform: scale(0); transform: scale(0);

View File

@ -1,4 +1,4 @@
import React, { useCallback, useRef } from 'react'; import { useCallback } from 'react';
import { resourceDownloadControllerAtom } from '../atoms/global'; import { resourceDownloadControllerAtom } from '../atoms/global';
import { getBaseApiReact } from '../App'; import { getBaseApiReact } from '../App';
import { useSetAtom } from 'jotai'; import { useSetAtom } from 'jotai';

View File

@ -165,13 +165,13 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
> >
<Box <Box
sx={{ sx={{
width: '325px', alignItems: 'center',
height: '250px',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center',
gap: '10px', gap: '10px',
height: '250px',
padding: '10px', padding: '10px',
width: '325px',
}} }}
> >
<LoadingButton <LoadingButton
@ -214,12 +214,12 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
<p>{t('group:ban_list', { postProcess: 'capitalize' })}</p> <p>{t('group:ban_list', { postProcess: 'capitalize' })}</p>
<div <div
style={{ style={{
position: 'relative',
height: '500px',
width: '100%',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
flexShrink: 1, flexShrink: 1,
height: '500px',
position: 'relative',
width: '100%',
}} }}
> >
<AutoSizer> <AutoSizer>

View File

@ -331,6 +331,7 @@ export const ListOfGroupPromotions = () => {
}); });
setIsLoadingJoinGroup(false); setIsLoadingJoinGroup(false);
} catch (error) { } catch (error) {
console.log(error);
} finally { } finally {
setIsLoadingJoinGroup(false); setIsLoadingJoinGroup(false);
} }
@ -339,30 +340,30 @@ export const ListOfGroupPromotions = () => {
return ( return (
<Box <Box
sx={{ sx={{
width: '100%',
display: 'flex',
marginTop: '20px',
flexDirection: 'column',
alignItems: 'center', alignItems: 'center',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center', justifyContent: 'center',
marginTop: '20px',
width: '100%',
}} }}
> >
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
gap: '20px', gap: '20px',
width: '100%',
justifyContent: 'space-between', justifyContent: 'space-between',
width: '100%',
}} }}
> >
<ButtonBase <ButtonBase
sx={{ sx={{
alignSelf: isExpanded && 'flex-start',
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
padding: `0px ${isExpanded ? '24px' : '20px'}`,
gap: '10px', gap: '10px',
justifyContent: 'flex-start', justifyContent: 'flex-start',
alignSelf: isExpanded && 'flex-start', padding: `0px ${isExpanded ? '24px' : '20px'}`,
}} }}
onClick={() => setIsExpanded((prev) => !prev)} onClick={() => setIsExpanded((prev) => !prev)}
> >
@ -374,6 +375,7 @@ export const ListOfGroupPromotions = () => {
Group promotions{' '} Group promotions{' '}
{promotions.length > 0 && ` (${promotions.length})`} {promotions.length > 0 && ` (${promotions.length})`}
</Typography> </Typography>
{isExpanded ? ( {isExpanded ? (
<ExpandLessIcon <ExpandLessIcon
sx={{ sx={{
@ -400,19 +402,19 @@ export const ListOfGroupPromotions = () => {
<> <>
<Box <Box
sx={{ sx={{
width: '750px',
maxWidth: '90%',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
maxWidth: '90%',
padding: '0px 20px', padding: '0px 20px',
width: '750px',
}} }}
> >
<Box <Box
sx={{ sx={{
width: '100%', alignItems: 'center',
display: 'flex', display: 'flex',
justifyContent: 'space-between', justifyContent: 'space-between',
alignItems: 'center', width: '100%',
}} }}
> >
<Typography <Typography

View File

@ -133,6 +133,7 @@ export const ListOfInvites = ({
}); });
}); });
} catch (error) { } catch (error) {
console.log(error);
} finally { } finally {
setIsLoadingCancelInvite(false); setIsLoadingCancelInvite(false);
} }
@ -168,13 +169,13 @@ export const ListOfInvites = ({
> >
<Box <Box
sx={{ sx={{
width: '325px', alignItems: 'center',
height: '250px',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center',
gap: '10px', gap: '10px',
height: '250px',
padding: '10px', padding: '10px',
width: '325px',
}} }}
> >
<LoadingButton <LoadingButton
@ -187,6 +188,7 @@ export const ListOfInvites = ({
</LoadingButton> </LoadingButton>
</Box> </Box>
</Popover> </Popover>
<ListItemButton <ListItemButton
onClick={(event) => handlePopoverOpen(event, index)} onClick={(event) => handlePopoverOpen(event, index)}
> >
@ -214,12 +216,12 @@ export const ListOfInvites = ({
<p>Invitees list</p> <p>Invitees list</p>
<div <div
style={{ style={{
position: 'relative',
height: '500px',
width: '100%',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
flexShrink: 1, flexShrink: 1,
height: '500px',
position: 'relative',
width: '100%',
}} }}
> >
<AutoSizer> <AutoSizer>

View File

@ -42,10 +42,11 @@ export const ListOfThreadPostsWatched = () => {
rej(response.error); rej(response.error);
}) })
.catch((error) => { .catch((error) => {
rej(error.message || 'An error occurred'); // TODO translate rej(error.message || 'An error occurred');
}); });
}); });
} catch (error) { } catch (error) {
console.log(error);
} finally { } finally {
setLoading(false); setLoading(false);
} }
@ -58,21 +59,21 @@ export const ListOfThreadPostsWatched = () => {
return ( return (
<Box <Box
sx={{ sx={{
width: '100%', alignItems: 'center',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', width: '100%',
}} }}
> >
<Box <Box
sx={{ sx={{
width: '322px',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
padding: '0px 20px', padding: '0px 20px',
width: '322px',
}} }}
> >
<Typography <Typography // TODO translate
sx={{ sx={{
fontSize: '13px', fontSize: '13px',
fontWeight: 600, fontWeight: 600,

View File

@ -73,7 +73,7 @@ export const ManageMembers = ({
const handleLeaveGroup = async () => { const handleLeaveGroup = async () => {
try { try {
setIsLoadingLeave(true); setIsLoadingLeave(true);
const fee = await getFee('LEAVE_GROUP'); const fee = await getFee('LEAVE_GROUP'); // TODO translate
await show({ await show({
message: 'Would you like to perform an LEAVE_GROUP transaction?', message: 'Would you like to perform an LEAVE_GROUP transaction?',
publishFee: fee.fee + ' QORT', publishFee: fee.fee + ' QORT',
@ -109,7 +109,7 @@ export const ManageMembers = ({
rej(response.error); rej(response.error);
}) })
.catch((error) => { .catch((error) => {
rej(error.message || 'An error occurred'); // TODO translate rej(error.message || 'An error occurred');
}); });
}); });
} catch (error) { } catch (error) {
@ -139,6 +139,7 @@ export const ManageMembers = ({
console.log(error); console.log(error);
} }
}; };
const getGroupInfo = async (groupId) => { const getGroupInfo = async (groupId) => {
try { try {
const response = await fetch(`${getBaseApiReact()}/groups/${groupId}`); const response = await fetch(`${getBaseApiReact()}/groups/${groupId}`);

View File

@ -11,7 +11,6 @@ import MailIcon from '@mui/icons-material/Mail';
import MailOutlineIcon from '@mui/icons-material/MailOutline'; import MailOutlineIcon from '@mui/icons-material/MailOutline';
import { executeEvent } from '../../utils/events'; import { executeEvent } from '../../utils/events';
import { CustomLoader } from '../../common/CustomLoader'; import { CustomLoader } from '../../common/CustomLoader';
import { mailsAtom, qMailLastEnteredTimestampAtom } from '../../atoms/global'; import { mailsAtom, qMailLastEnteredTimestampAtom } from '../../atoms/global';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ExpandLessIcon from '@mui/icons-material/ExpandLess'; import ExpandLessIcon from '@mui/icons-material/ExpandLess';
@ -89,7 +88,7 @@ export const QMailMessages = ({ userName, userAddress }) => {
rej(response.error); rej(response.error);
}) })
.catch((error) => { .catch((error) => {
rej(error.message || 'An error occurred'); // TODO translate rej(error.message || 'An error occurred');
}); });
}); });
} catch (error) { } catch (error) {
@ -129,24 +128,24 @@ export const QMailMessages = ({ userName, userAddress }) => {
return ( return (
<Box <Box
sx={{ sx={{
width: '100%', alignItems: 'center',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', width: '100%',
}} }}
> >
<ButtonBase <ButtonBase
sx={{ sx={{
width: '322px',
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
gap: '10px', gap: '10px',
padding: '0px 20px',
justifyContent: 'flex-start', justifyContent: 'flex-start',
padding: '0px 20px',
width: '322px',
}} }}
onClick={() => setIsExpanded((prev) => !prev)} onClick={() => setIsExpanded((prev) => !prev)}
> >
<Typography <Typography // TODO translate
sx={{ sx={{
fontSize: '1rem', fontSize: '1rem',
}} }}

View File

@ -20,7 +20,6 @@ import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import { import {
Box, Box,
Button, Button,
ButtonBase,
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogContentText, DialogContentText,
@ -32,7 +31,6 @@ import {
useTheme, useTheme,
} from '@mui/material'; } from '@mui/material';
import { enabledDevModeAtom } from '../../atoms/global'; import { enabledDevModeAtom } from '../../atoms/global';
import ThemeManager from '../Theme/ThemeManager'; import ThemeManager from '../Theme/ThemeManager';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { decryptStoredWallet } from '../../utils/decryptWallet'; import { decryptStoredWallet } from '../../utils/decryptWallet';
@ -41,6 +39,7 @@ import PhraseWallet from '../../utils/generateWallet/phrase-wallet';
import { walletVersion } from '../../background'; import { walletVersion } from '../../background';
import Base58 from '../../deps/Base58'; import Base58 from '../../deps/Base58';
import { MyContext } from '../../App'; import { MyContext } from '../../App';
import { useTranslation } from 'react-i18next';
const LocalNodeSwitch = styled(Switch)(({ theme }) => ({ const LocalNodeSwitch = styled(Switch)(({ theme }) => ({
padding: 8, padding: 8,
@ -87,8 +86,8 @@ const Transition = forwardRef(function Transition(
export const Settings = ({ open, setOpen, rawWallet }) => { export const Settings = ({ open, setOpen, rawWallet }) => {
const [checked, setChecked] = useState(false); const [checked, setChecked] = useState(false);
const [isEnabledDevMode, setIsEnabledDevMode] = useAtom(enabledDevModeAtom); const [isEnabledDevMode, setIsEnabledDevMode] = useAtom(enabledDevModeAtom);
const theme = useTheme(); const theme = useTheme();
const { t } = useTranslation(['core', 'group']);
const handleChange = (event: ChangeEvent<HTMLInputElement>) => { const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setChecked(event.target.checked); setChecked(event.target.checked);
@ -103,7 +102,7 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
if (response?.error) { if (response?.error) {
console.error('Error adding user settings:', response.error); console.error('Error adding user settings:', response.error);
} else { } else {
console.log('User settings added successfully'); // TODO translate console.log('User settings added successfully');
} }
}) })
.catch((error) => { .catch((error) => {
@ -157,7 +156,9 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
<AppBar sx={{ position: 'relative' }}> <AppBar sx={{ position: 'relative' }}>
<Toolbar> <Toolbar>
<Typography sx={{ ml: 2, flex: 1 }} variant="h4" component="div"> <Typography sx={{ ml: 2, flex: 1 }} variant="h4" component="div">
General Settings {t('core:general_settings', {
postProcess: 'capitalize',
})}
</Typography> </Typography>
<IconButton <IconButton
@ -173,13 +174,13 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
<Box <Box
sx={{ sx={{
flexGrow: 1,
overflowY: 'auto',
color: theme.palette.text.primary, color: theme.palette.text.primary,
padding: '20px',
flexDirection: 'column',
display: 'flex', display: 'flex',
flexDirection: 'column',
flexGrow: 1,
gap: '20px', gap: '20px',
overflowY: 'auto',
padding: '20px',
}} }}
> >
<FormControlLabel <FormControlLabel
@ -189,7 +190,9 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
control={ control={
<LocalNodeSwitch checked={checked} onChange={handleChange} /> <LocalNodeSwitch checked={checked} onChange={handleChange} />
} }
label="Disable all push notifications" label={t('group:action.disable_push_notifications', {
postProcess: 'capitalize',
})}
/> />
{window?.electronAPI && ( {window?.electronAPI && (
<FormControlLabel <FormControlLabel
@ -205,7 +208,9 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
}} }}
/> />
} }
label="Enable dev mode" label={t('group:action.enable_dev_mode', {
postProcess: 'capitalize',
})}
/> />
)} )}
{isEnabledDevMode && <ExportPrivateKey rawWallet={rawWallet} />} {isEnabledDevMode && <ExportPrivateKey rawWallet={rawWallet} />}
@ -222,11 +227,15 @@ const ExportPrivateKey = ({ rawWallet }) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const { setOpenSnackGlobal, setInfoSnackCustom } = useContext(MyContext); const { setOpenSnackGlobal, setInfoSnackCustom } = useContext(MyContext);
const { t } = useTranslation(['core', 'group']);
const exportPrivateKeyFunc = async () => { const exportPrivateKeyFunc = async () => {
try { try {
setInfoSnackCustom({ setInfoSnackCustom({
type: 'info', type: 'info',
message: 'Decrypting wallet...', message: t('group:message.generic.descrypt_wallet', {
postProcess: 'capitalize',
}),
}); });
setOpenSnackGlobal(true); setOpenSnackGlobal(true);
@ -247,13 +256,19 @@ const ExportPrivateKey = ({ rawWallet }) => {
setInfoSnackCustom({ setInfoSnackCustom({
type: 'error', type: 'error',
message: error?.message message: error?.message
? `Error decrypting wallet: ${error?.message}` ? t('group:message.error.decrypt_wallet', {
: 'Error decrypting wallet', errorMessage: error?.message,
postProcess: 'capitalize',
})
: t('group:message.error.descrypt_wallet', {
postProcess: 'capitalize',
}),
}); });
setOpenSnackGlobal(true); setOpenSnackGlobal(true);
} }
}; };
return ( return (
<> <>
<Button <Button
@ -263,14 +278,22 @@ const ExportPrivateKey = ({ rawWallet }) => {
}} }}
onClick={() => setIsOpen(true)} onClick={() => setIsOpen(true)}
> >
Export private key {t('group:action.export_private_key', {
postProcess: 'capitalize',
})}
</Button> </Button>
<Dialog <Dialog
open={isOpen} open={isOpen}
aria-labelledby="alert-dialog-title" aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description" aria-describedby="alert-dialog-description"
> >
<DialogTitle id="alert-dialog-title">Export password</DialogTitle> <DialogTitle id="alert-dialog-title">
{t('group:action.export_password', {
postProcess: 'capitalize',
})}
</DialogTitle>
<DialogContent <DialogContent
sx={{ sx={{
flexDirection: 'column', flexDirection: 'column',
@ -279,9 +302,13 @@ const ExportPrivateKey = ({ rawWallet }) => {
}} }}
> >
<DialogContentText id="alert-dialog-description"> <DialogContentText id="alert-dialog-description">
Keep your private key in a secure place. Do not share! {t('group:message.generic.secure_place', {
postProcess: 'capitalize',
})}
</DialogContentText> </DialogContentText>
<Spacer height="20px" /> <Spacer height="20px" />
<TextField <TextField
autoFocus autoFocus
type="password" type="password"
@ -296,17 +323,22 @@ const ExportPrivateKey = ({ rawWallet }) => {
navigator.clipboard.writeText(privateKey); navigator.clipboard.writeText(privateKey);
setInfoSnackCustom({ setInfoSnackCustom({
type: 'success', type: 'success',
message: 'Copied privated key', message: t('group:message.generic.private_key_copied', {
postProcess: 'capitalize',
}),
}); });
setOpenSnackGlobal(true); setOpenSnackGlobal(true);
}} }}
> >
{`Copy private key `} {t('group:action.copy_private_key', {
postProcess: 'capitalize',
})}{' '}
<ContentCopyIcon color="primary" /> <ContentCopyIcon color="primary" />
</Button> </Button>
)} )}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button <Button
variant="contained" variant="contained"
@ -316,10 +348,15 @@ const ExportPrivateKey = ({ rawWallet }) => {
setPrivateKey(''); setPrivateKey('');
}} }}
> >
Cancel {t('group:action.cancel', {
postProcess: 'capitalize',
})}
</Button> </Button>
<Button variant="contained" onClick={exportPrivateKeyFunc}> <Button variant="contained" onClick={exportPrivateKeyFunc}>
Decrypt {t('group:action.decrypt', {
postProcess: 'capitalize',
})}
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>

View File

@ -55,18 +55,18 @@ export const ThingsToDoInitial = ({
return ( return (
<Box <Box
sx={{ sx={{
width: '100%', alignItems: 'center',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', width: '100%',
}} }}
> >
<Box <Box
sx={{ sx={{
width: '322px',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
padding: '0px 20px', padding: '0px 20px',
width: '322px',
}} }}
> >
<Typography <Typography
@ -125,6 +125,7 @@ export const ThingsToDoInitial = ({
postProcess: 'capitalize', postProcess: 'capitalize',
})} })}
/> />
<ListItemIcon <ListItemIcon
sx={{ sx={{
justifyContent: 'flex-end', justifyContent: 'flex-end',
@ -144,6 +145,7 @@ export const ThingsToDoInitial = ({
</ListItemIcon> </ListItemIcon>
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
<ListItem <ListItem
sx={{ sx={{
marginBottom: '20px', marginBottom: '20px',

View File

@ -22,6 +22,7 @@ import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmail
import { Spacer } from '../../common/Spacer'; import { Spacer } from '../../common/Spacer';
import { useSetAtom } from 'jotai'; import { useSetAtom } from 'jotai';
import { txListAtom } from '../../atoms/global'; import { txListAtom } from '../../atoms/global';
import { useTranslation } from 'react-i18next';
const cache = new CellMeasurerCache({ const cache = new CellMeasurerCache({
fixedWidth: true, fixedWidth: true,
@ -60,6 +61,7 @@ export const UserListOfInvites = ({
const [invites, setInvites] = useState<any[]>([]); const [invites, setInvites] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const theme = useTheme(); const theme = useTheme();
const { t } = useTranslation(['core', 'group']);
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
const listRef = useRef(); const listRef = useRef();
@ -94,9 +96,12 @@ export const UserListOfInvites = ({
const handleJoinGroup = async (groupId, groupName) => { const handleJoinGroup = async (groupId, groupName) => {
try { try {
const fee = await getFee('JOIN_GROUP'); // TODO translate const fee = await getFee('JOIN_GROUP');
await show({ await show({
message: 'Would you like to perform an JOIN_GROUP transaction?', message: t('group:question.join_group', {
postProcess: 'capitalize',
}),
publishFee: fee.fee + ' QORT', publishFee: fee.fee + ' QORT',
}); });
@ -123,8 +128,9 @@ export const UserListOfInvites = ({
res(response); res(response);
setInfoSnack({ setInfoSnack({
type: 'success', type: 'success',
message: message: t('group:message.success.group_join', {
'Successfully requested to join group. It may take a couple of minutes for the changes to propagate', postProcess: 'capitalize',
}),
}); });
setOpenSnack(true); setOpenSnack(true);
handlePopoverClose(); handlePopoverClose();
@ -140,13 +146,16 @@ export const UserListOfInvites = ({
.catch((error) => { .catch((error) => {
setInfoSnack({ setInfoSnack({
type: 'error', type: 'error',
message: error.message || 'An error occurred', message:
error.message ||
t('core:message.error.generic', { postProcess: 'capitalize' }),
}); });
setOpenSnack(true); setOpenSnack(true);
rej(error); rej(error);
}); });
}); });
} catch (error) { } catch (error) {
console.log(error);
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@ -182,16 +191,22 @@ export const UserListOfInvites = ({
> >
<Box <Box
sx={{ sx={{
width: '325px', alignItems: 'center',
height: '250px',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center',
gap: '10px', gap: '10px',
height: '250px',
padding: '10px', padding: '10px',
width: '325px',
}} }}
> >
<Typography>Join {invite?.groupName}</Typography> <Typography>
{t('core:action.join', {
postProcess: 'capitalize',
})}{' '}
{invite?.groupName}
</Typography>
<LoadingButton <LoadingButton
loading={isLoading} loading={isLoading}
loadingPosition="start" loadingPosition="start"
@ -200,10 +215,13 @@ export const UserListOfInvites = ({
handleJoinGroup(invite?.groupId, invite?.groupName) handleJoinGroup(invite?.groupId, invite?.groupName)
} }
> >
Join group {t('group:action.join_group', {
postProcess: 'capitalize',
})}
</LoadingButton> </LoadingButton>
</Box> </Box>
</Popover> </Popover>
<ListItemButton <ListItemButton
onClick={(event) => handlePopoverOpen(event, index)} onClick={(event) => handlePopoverOpen(event, index)}
> >
@ -221,7 +239,9 @@ export const UserListOfInvites = ({
}} }}
/> />
)} )}
<Spacer width="15px" /> <Spacer width="15px" />
<ListItemText <ListItemText
primary={invite?.groupName} primary={invite?.groupName}
secondary={invite?.description} secondary={invite?.description}
@ -242,14 +262,19 @@ export const UserListOfInvites = ({
flexGrow: 1, flexGrow: 1,
}} }}
> >
<p>Invite list</p> <p>
{t('core:invite_list', {
postProcess: 'capitalize',
})}
</p>
<div <div
style={{ style={{
position: 'relative',
width: '100%',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
flexGrow: 1, flexGrow: 1,
position: 'relative',
width: '100%',
}} }}
> >
<AutoSizer> <AutoSizer>

View File

@ -19,7 +19,6 @@ export const WalletsAppWrapper = () => {
const [navigationController, setNavigationController] = useAtom( const [navigationController, setNavigationController] = useAtom(
navigationControllerAtom navigationControllerAtom
); );
const [selectedTab, setSelectedTab] = useState({ const [selectedTab, setSelectedTab] = useState({
tabId: '5558589', tabId: '5558589',
name: 'Q-Wallets', name: 'Q-Wallets',
@ -60,17 +59,17 @@ export const WalletsAppWrapper = () => {
{isOpen && ( {isOpen && (
<Box <Box
sx={{ sx={{
position: 'fixed', backgroundColor: theme.palette.background.paper,
height: '100vh',
width: '100vw',
backgroundColor: theme.palette.background.paper, // TODO: set color theme
zIndex: 100,
bottom: 0,
right: 0,
overflow: 'hidden',
borderTopLeftRadius: '10px', borderTopLeftRadius: '10px',
borderTopRightRadius: '10px', borderTopRightRadius: '10px',
bottom: 0,
boxShadow: 4, boxShadow: 4,
height: '100vh',
overflow: 'hidden',
position: 'fixed',
right: 0,
width: '100vw',
zIndex: 100,
}} }}
> >
<Box <Box
@ -85,11 +84,11 @@ export const WalletsAppWrapper = () => {
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
padding: '5px', padding: '5px',
justifyContent: 'space-between', justifyContent: 'space-between',
}} }}
> >
<Typography>Q-Wallets</Typography> <Typography>Q-Wallets</Typography>
<ButtonBase onClick={handleClose}> <ButtonBase onClick={handleClose}>
<CloseIcon <CloseIcon
sx={{ sx={{
@ -108,6 +107,7 @@ export const WalletsAppWrapper = () => {
ref={iframeRef} ref={iframeRef}
skipAuth={true} skipAuth={true}
/> />
<AppsNavBarParent> <AppsNavBarParent>
<AppsNavBarLeft <AppsNavBarLeft
sx={{ sx={{
@ -126,6 +126,7 @@ export const WalletsAppWrapper = () => {
> >
<NavBack /> <NavBack />
</ButtonBase> </ButtonBase>
<ButtonBase <ButtonBase
onClick={() => { onClick={() => {
if (selectedTab?.refreshFunc) { if (selectedTab?.refreshFunc) {

View File

@ -164,6 +164,7 @@ export const useBlockedAddresses = () => {
}); });
}); });
} }
if (address) { if (address) {
await new Promise((res, rej) => { await new Promise((res, rej) => {
window window

View File

@ -1,4 +1,4 @@
import React, { useCallback, useContext, useEffect, useState } from 'react'; import { useCallback, useContext, useEffect, useState } from 'react';
import Logo2 from '../assets/svgs/Logo2.svg'; import Logo2 from '../assets/svgs/Logo2.svg';
import { MyContext, getArbitraryEndpointReact, getBaseApiReact } from '../App'; import { MyContext, getArbitraryEndpointReact, getBaseApiReact } from '../App';
import { import {

View File

@ -1,9 +1,9 @@
import React from 'react' import { Box, CircularProgress } from '@mui/material';
import { Box, CircularProgress } from "@mui/material";
export const Loader = () => { export const Loader = () => {
return ( return (
<Box sx={{ <Box
sx={{
display: 'flex', display: 'flex',
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
@ -15,9 +15,10 @@ export const Loader = () => {
right: '0px', right: '0px',
bottom: '0px', bottom: '0px',
zIndex: 10, zIndex: 10,
background: 'rgba(0, 0, 0, 0.4)' background: 'rgba(0, 0, 0, 0.4)',
}}> }}
>
<CircularProgress color="success" size={25} /> <CircularProgress color="success" size={25} />
</Box> </Box>
) );
} };

View File

@ -1,4 +1,4 @@
import React, { useContext, useEffect, useState } from 'react'; import { useContext, useEffect, useState } from 'react';
import Logo2 from '../assets/svgs/Logo2.svg'; import Logo2 from '../assets/svgs/Logo2.svg';
import { MyContext, getArbitraryEndpointReact, getBaseApiReact } from '../App'; import { MyContext, getArbitraryEndpointReact, getBaseApiReact } from '../App';
import { import {

View File

@ -1,33 +1,22 @@
import React, { useCallback, useContext, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { import {
Avatar,
Box, Box,
Button, Button,
ButtonBase,
Collapse,
Dialog, Dialog,
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogContentText,
DialogTitle, DialogTitle,
Input,
ListItem, ListItem,
ListItemAvatar,
ListItemButton,
ListItemIcon, ListItemIcon,
ListItemText, ListItemText,
List, List,
MenuItem,
Popover,
Select,
TextField, TextField,
Typography, Typography,
useTheme, useTheme,
} from '@mui/material'; } from '@mui/material';
import { Label } from './Group/AddGroup'; import { Label } from './Group/AddGroup';
import { Spacer } from '../common/Spacer'; import { Spacer } from '../common/Spacer';
import { LoadingButton } from '@mui/lab'; import { getBaseApiReact } from '../App';
import { getBaseApiReact, MyContext } from '../App';
import { getFee } from '../background'; import { getFee } from '../background';
import RadioButtonCheckedIcon from '@mui/icons-material/RadioButtonChecked'; import RadioButtonCheckedIcon from '@mui/icons-material/RadioButtonChecked';
import { subscribeToEvent, unsubscribeFromEvent } from '../utils/events'; import { subscribeToEvent, unsubscribeFromEvent } from '../utils/events';
@ -43,6 +32,7 @@ enum Availability {
AVAILABLE = 'available', AVAILABLE = 'available',
NOT_AVAILABLE = 'not-available', NOT_AVAILABLE = 'not-available',
} }
export const RegisterName = ({ export const RegisterName = ({
setOpenSnack, setOpenSnack,
setInfoSnack, setInfoSnack,
@ -77,7 +67,6 @@ export const RegisterName = ({
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} finally {
} }
}; };
// Debounce logic // Debounce logic
@ -195,21 +184,22 @@ export const RegisterName = ({
aria-describedby="alert-dialog-description" aria-describedby="alert-dialog-description"
> >
<DialogTitle id="alert-dialog-title">{'Register name'}</DialogTitle> <DialogTitle id="alert-dialog-title">{'Register name'}</DialogTitle>
<DialogContent> <DialogContent>
<Box <Box
sx={{ sx={{
width: '400px', alignItems: 'center',
maxWidth: '90vw',
height: '500px',
maxHeight: '90vh',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center',
gap: '10px', gap: '10px',
height: '500px',
maxHeight: '90vh',
maxWidth: '90vw',
padding: '10px', padding: '10px',
width: '400px',
}} }}
> >
<Label>Choose a name</Label> <Label>Choose a name</Label> // TODO: translate
<TextField <TextField
autoComplete="off" autoComplete="off"
autoFocus autoFocus
@ -237,6 +227,7 @@ export const RegisterName = ({
requires a {nameFee} QORT fee requires a {nameFee} QORT fee
</Typography> </Typography>
</Box> </Box>
<Spacer height="10px" /> <Spacer height="10px" />
</> </>
)} )}
@ -307,6 +298,7 @@ export const RegisterName = ({
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Publish data to Qortal: anything from apps to videos. Fully decentralized!" /> <ListItemText primary="Publish data to Qortal: anything from apps to videos. Fully decentralized!" />
</ListItem> </ListItem>
<ListItem disablePadding> <ListItem disablePadding>
<ListItemIcon> <ListItemIcon>
<RadioButtonCheckedIcon <RadioButtonCheckedIcon
@ -320,6 +312,7 @@ export const RegisterName = ({
</List> </List>
</Box> </Box>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button <Button
disabled={isLoadingRegisterName} disabled={isLoadingRegisterName}
@ -331,6 +324,7 @@ export const RegisterName = ({
> >
Close Close
</Button> </Button>
<Button <Button
disabled={ disabled={
!registerNameValue.trim() || !registerNameValue.trim() ||

View File

@ -56,6 +56,7 @@ const commonThemeOptions = {
xl: 1536, xl: 1536,
}, },
}, },
components: { components: {
MuiButton: { MuiButton: {
styleOverrides: { styleOverrides: {
@ -72,6 +73,7 @@ const commonThemeOptions = {
disableRipple: true, disableRipple: true,
}, },
}, },
MuiModal: { MuiModal: {
styleOverrides: { styleOverrides: {
root: { root: {

View File

@ -48,6 +48,7 @@ export const darkThemeOptions: ThemeOptions = {
}, },
}, },
}, },
MuiCssBaseline: { MuiCssBaseline: {
styleOverrides: (theme) => ({ styleOverrides: (theme) => ({
':root': { ':root': {
@ -61,13 +62,16 @@ export const darkThemeOptions: ThemeOptions = {
'--background-paper': theme.palette.background.paper, '--background-paper': theme.palette.background.paper,
'--background-surface': theme.palette.background.surface, '--background-surface': theme.palette.background.surface,
}, },
'*, *::before, *::after': { '*, *::before, *::after': {
boxSizing: 'border-box', boxSizing: 'border-box',
}, },
html: { html: {
padding: 0, padding: 0,
margin: 0, margin: 0,
}, },
body: { body: {
padding: 0, padding: 0,
margin: 0, margin: 0,
@ -100,6 +104,7 @@ export const darkThemeOptions: ThemeOptions = {
}, },
}), }),
}, },
MuiIcon: { MuiIcon: {
defaultProps: { defaultProps: {
style: { style: {
@ -108,6 +113,7 @@ export const darkThemeOptions: ThemeOptions = {
}, },
}, },
}, },
MuiDialog: { MuiDialog: {
styleOverrides: { styleOverrides: {
paper: { paper: {
@ -115,6 +121,7 @@ export const darkThemeOptions: ThemeOptions = {
}, },
}, },
}, },
MuiPopover: { MuiPopover: {
styleOverrides: { styleOverrides: {
paper: { paper: {

View File

@ -32,6 +32,7 @@ export const lightThemeOptions: ThemeOptions = {
unread: 'rgb(66, 151, 226)', unread: 'rgb(66, 151, 226)',
}, },
}, },
components: { components: {
MuiCard: { MuiCard: {
styleOverrides: { styleOverrides: {
@ -48,6 +49,7 @@ export const lightThemeOptions: ThemeOptions = {
}, },
}, },
}, },
MuiCssBaseline: { MuiCssBaseline: {
styleOverrides: (theme) => ({ styleOverrides: (theme) => ({
':root': { ':root': {
@ -113,6 +115,7 @@ export const lightThemeOptions: ThemeOptions = {
}, },
}, },
}, },
MuiDialog: { MuiDialog: {
styleOverrides: { styleOverrides: {
paper: { paper: {
@ -120,6 +123,7 @@ export const lightThemeOptions: ThemeOptions = {
}, },
}, },
}, },
MuiPopover: { MuiPopover: {
styleOverrides: { styleOverrides: {
paper: { paper: {