mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-05-22 09:36:58 +00:00
Merge pull request #54 from nbenaglia/feature/i18n-other-minor-files
i18n: Add translations for minor files
This commit is contained in:
commit
4cb66a1193
5
.gitignore
vendored
5
.gitignore
vendored
@ -24,4 +24,7 @@ dist-ssr
|
||||
*.sln
|
||||
*.sw?
|
||||
release-builds/
|
||||
.env
|
||||
.env
|
||||
|
||||
# reports from scripts
|
||||
scripts/i18n_report*
|
@ -20,6 +20,20 @@ Translation in GUI:
|
||||
- For all translation in uppercase `{ postProcess: 'capitalizeAll' }`
|
||||
- See `.src/i18n/i18n.ts` for processor definition
|
||||
|
||||
## Namespace
|
||||
|
||||
These are the current namespaces, in which all translations are organized:
|
||||
|
||||
- `auth`: relative to the authentication (name, addresses, keys, secrets, seedphrase, and so on...)
|
||||
- `core`: all the core translation
|
||||
- `group`: all translations concerning group management
|
||||
- `tutorial`: dedicated to the tutorial pages
|
||||
|
||||
Please avoid duplication of the same translation.
|
||||
In the same page the usage of translations from different namespaces is permissible.
|
||||
|
||||
## Missing language?
|
||||
|
||||
- Please open an issue on the project's github repository and specify the missing language
|
||||
- Please open an issue on the project's github repository and specify the missing language, by clicking [here](https://github.com/Qortal/Qortal-Hub/issues/new)
|
||||
|
||||
- You can also open a Pull Request if you like to contribute directly to the project.
|
||||
|
108
scripts/i18n-checker.py
Normal file
108
scripts/i18n-checker.py
Normal file
@ -0,0 +1,108 @@
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import csv
|
||||
import argparse
|
||||
|
||||
# Customize as needed
|
||||
I18N_FUNCTIONS = ['t', 'i18next.t']
|
||||
FILE_EXTENSIONS = ['.tsx']
|
||||
EXCLUDED_DIRS = ['node_modules', 'build', 'dist']
|
||||
|
||||
# Regex patterns
|
||||
STRING_LITERAL_REGEX = re.compile(r'(?<!t\()\s*["\']([A-Z][^"\']{2,})["\']')
|
||||
JSX_TEXT_REGEX = re.compile(r'>\s*([A-Z][a-z].*?)\s*<')
|
||||
|
||||
def is_excluded(path):
|
||||
return any(excluded in path for excluded in EXCLUDED_DIRS)
|
||||
|
||||
def is_ignorable(text):
|
||||
return (
|
||||
re.fullmatch(r'[A-Z0-9_]+', text) and
|
||||
any(keyword in text.lower() for keyword in ['action', 'status'])
|
||||
)
|
||||
|
||||
def is_console_log_line(line):
|
||||
return any(kw in line for kw in ['console.log', 'console.error', 'console.warn'])
|
||||
|
||||
def find_untranslated_strings(file_path):
|
||||
issues = []
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
lines = content.splitlines()
|
||||
|
||||
for idx, line in enumerate(lines, start=1):
|
||||
if is_console_log_line(line):
|
||||
continue # Skip entire line if it's a console log statement
|
||||
|
||||
# Match suspicious string literals
|
||||
for match in STRING_LITERAL_REGEX.finditer(line):
|
||||
string = match.group(1).strip()
|
||||
if is_ignorable(string):
|
||||
continue
|
||||
if not any(fn + '(' in line[:match.start()] for fn in I18N_FUNCTIONS):
|
||||
issues.append({
|
||||
'file': file_path,
|
||||
'line': idx,
|
||||
'type': 'StringLiteral',
|
||||
'text': string
|
||||
})
|
||||
|
||||
# Match JSX text nodes
|
||||
for match in JSX_TEXT_REGEX.finditer(line):
|
||||
text = match.group(1).strip()
|
||||
if is_ignorable(text):
|
||||
continue
|
||||
if not text.startswith('{t('):
|
||||
issues.append({
|
||||
'file': file_path,
|
||||
'line': idx,
|
||||
'type': 'JSXText',
|
||||
'text': text
|
||||
})
|
||||
|
||||
return issues
|
||||
|
||||
|
||||
def scan_directory(directory):
|
||||
all_issues = []
|
||||
for root, _, files in os.walk(directory):
|
||||
if is_excluded(root):
|
||||
continue
|
||||
for file in files:
|
||||
if any(file.endswith(ext) for ext in FILE_EXTENSIONS):
|
||||
file_path = os.path.join(root, file)
|
||||
issues = find_untranslated_strings(file_path)
|
||||
all_issues.extend(issues)
|
||||
return all_issues
|
||||
|
||||
def save_report(results, output_file):
|
||||
_, ext = os.path.splitext(output_file)
|
||||
if ext.lower() == '.json':
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(results, f, indent=2)
|
||||
elif ext.lower() == '.csv':
|
||||
with open(output_file, 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.DictWriter(f, fieldnames=['file', 'line', 'type', 'text'])
|
||||
writer.writeheader()
|
||||
for row in results:
|
||||
writer.writerow(row)
|
||||
else:
|
||||
raise ValueError("Unsupported output format. Use .json or .csv")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Detect untranslated strings in React (.tsx) files.')
|
||||
parser.add_argument('-path', default='../src/', help='Path to the source directory (e.g. ./src)')
|
||||
parser.add_argument('-o', '--output', default='./i18n_report.json', help='Report output file (.json or .csv)')
|
||||
|
||||
args = parser.parse_args()
|
||||
results = scan_directory(args.path)
|
||||
|
||||
if results:
|
||||
save_report(results, args.output)
|
||||
print(f"⚠️ Found {len(results)} potential untranslated strings. Report saved to {args.output}")
|
||||
else:
|
||||
print("✅ No obvious untranslated strings found.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
13
src/App.tsx
13
src/App.tsx
@ -1697,10 +1697,11 @@ function App() {
|
||||
style={{
|
||||
fontSize: '14px',
|
||||
fontWeight: 700,
|
||||
textTransform: 'uppercase',
|
||||
}}
|
||||
>
|
||||
{t('core:user_lookup')}
|
||||
{t('core:user_lookup', {
|
||||
postProcess: 'capitalizeAll',
|
||||
})}
|
||||
</span>
|
||||
}
|
||||
placement="left"
|
||||
@ -2334,7 +2335,7 @@ function App() {
|
||||
hostname: requestBuyOrder?.hostname,
|
||||
count: requestBuyOrder?.crosschainAtInfo?.length || 0,
|
||||
}}
|
||||
tOptions={{ postProcess: ['capitalizeFirst'] }}
|
||||
tOptions={{ postProcess: ['capitalizeFirstChar'] }}
|
||||
>
|
||||
The Application <br />
|
||||
<italic>{{ hostname }}</italic> <br />
|
||||
@ -2445,7 +2446,7 @@ function App() {
|
||||
hostname: requestBuyOrder?.hostname,
|
||||
count: requestBuyOrder?.crosschainAtInfo?.length || 0,
|
||||
}}
|
||||
tOptions={{ postProcess: ['capitalizeFirst'] }}
|
||||
tOptions={{ postProcess: ['capitalizeFirstChar'] }}
|
||||
>
|
||||
The Application <br />
|
||||
<italic>{{ hostname }}</italic> <br />
|
||||
@ -2927,7 +2928,7 @@ function App() {
|
||||
/>
|
||||
),
|
||||
}}
|
||||
tOptions={{ postProcess: ['capitalizeFirst'] }}
|
||||
tOptions={{ postProcess: ['capitalizeFirstChar'] }}
|
||||
>
|
||||
A <seed>SEEDPHRASE</seed> has been randomly generated in
|
||||
the background.
|
||||
@ -2964,7 +2965,7 @@ function App() {
|
||||
/>
|
||||
),
|
||||
}}
|
||||
tOptions={{ postProcess: ['capitalizeFirst'] }}
|
||||
tOptions={{ postProcess: ['capitalizeFirstChar'] }}
|
||||
>
|
||||
Create your Qortal account by clicking <next>NEXT</next>{' '}
|
||||
below.
|
||||
|
@ -367,6 +367,7 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
|
||||
}}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
|
||||
<ListItemText
|
||||
sx={{
|
||||
'& .MuiTypography-root': {
|
||||
@ -377,7 +378,7 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
|
||||
: theme.palette.text.primary,
|
||||
},
|
||||
}}
|
||||
primary={`${
|
||||
primary={
|
||||
isSelectedAppPinned
|
||||
? t('core:action.unpin_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
@ -385,7 +386,7 @@ export const AppsNavBarDesktop = ({ disableBack }) => {
|
||||
: t('core:action.pin_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
}}`}
|
||||
}
|
||||
/>
|
||||
</MenuItem>
|
||||
|
||||
|
@ -40,6 +40,7 @@ const TabComponent = ({ isSelected, app }) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{app?.isPrivate && !app?.privateAppProperties?.logo ? (
|
||||
<LockIcon
|
||||
sx={{
|
||||
|
@ -249,6 +249,7 @@ export const GroupAvatar = ({
|
||||
);
|
||||
};
|
||||
|
||||
// TODO the following part is the same as in MainAvatar.tsx
|
||||
const PopoverComp = ({
|
||||
avatarFile,
|
||||
setAvatarFile,
|
||||
|
@ -34,20 +34,20 @@ export const DesktopSideBar = ({
|
||||
<Box
|
||||
sx={{
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.palette.background.surface,
|
||||
borderRight: `1px solid ${theme.palette.border.subtle}`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '25px',
|
||||
height: '100vh',
|
||||
width: '60px',
|
||||
backgroundColor: theme.palette.background.surface,
|
||||
borderRight: `1px solid ${theme.palette.border.subtle}`,
|
||||
}}
|
||||
>
|
||||
<ButtonBase
|
||||
sx={{
|
||||
width: '70px',
|
||||
height: '70px',
|
||||
paddingTop: '23px',
|
||||
width: '70px',
|
||||
}}
|
||||
>
|
||||
<CoreSyncStatus />
|
||||
@ -55,8 +55,8 @@ export const DesktopSideBar = ({
|
||||
|
||||
<ButtonBase
|
||||
sx={{
|
||||
width: '60px',
|
||||
height: '60px',
|
||||
width: '60px',
|
||||
}}
|
||||
onClick={() => {
|
||||
goToHome();
|
||||
|
@ -215,7 +215,9 @@ export const PollCard = ({
|
||||
setIsOpen(true);
|
||||
}}
|
||||
>
|
||||
{t('core:action.show_poll', { postProcess: 'capitalizeFirst' })}
|
||||
{t('core:action.show_poll', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
@ -273,7 +275,7 @@ export const PollCard = ({
|
||||
fontSize: '18px',
|
||||
}}
|
||||
>
|
||||
{t('core:option_other', { postProcess: 'capitalizeFirst' })}
|
||||
{t('core:option_other', { postProcess: 'capitalizeFirstChar' })}
|
||||
</Typography>
|
||||
|
||||
<RadioGroup
|
||||
@ -308,7 +310,7 @@ export const PollCard = ({
|
||||
disabled={!selectedOption || isLoadingSubmit}
|
||||
onClick={handleVote}
|
||||
>
|
||||
{t('core:action.vote', { postProcess: 'capitalizeFirst' })}
|
||||
{t('core:action.vote', { postProcess: 'capitalizeFirstChar' })}
|
||||
</Button>
|
||||
|
||||
<Typography
|
||||
@ -337,7 +339,7 @@ export const PollCard = ({
|
||||
}}
|
||||
>
|
||||
{t('core:message.generic.already_voted', {
|
||||
postProcess: 'capitalizeFirst',
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
@ -350,7 +352,7 @@ export const PollCard = ({
|
||||
}}
|
||||
>
|
||||
{t('core:message.generic.processing_transaction', {
|
||||
postProcess: 'capitalizeFirst',
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
)}
|
||||
@ -361,8 +363,8 @@ export const PollCard = ({
|
||||
}}
|
||||
>
|
||||
{showResults
|
||||
? t('core:action.hide', { postProcess: 'capitalizeFirst' })
|
||||
: t('core:action.close', { postProcess: 'capitalizeFirst' })}
|
||||
? t('core:action.hide', { postProcess: 'capitalizeFirstChar' })
|
||||
: t('core:action.close', { postProcess: 'capitalizeFirstChar' })}
|
||||
</ButtonBase>
|
||||
</CardContent>
|
||||
|
||||
|
@ -67,7 +67,7 @@ interface VideoPlayerProps {
|
||||
user?: string;
|
||||
}
|
||||
|
||||
// TODO translate and theme? Is it worth?
|
||||
// TODO translate and theme (optional)
|
||||
export const VideoPlayer: FC<VideoPlayerProps> = ({
|
||||
poster,
|
||||
name,
|
||||
|
@ -593,6 +593,7 @@ export const AddGroup = ({ address, open, setOpen }) => {
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{value === 1 && (
|
||||
<Box
|
||||
sx={{
|
||||
|
@ -41,9 +41,7 @@ const cache = new CellMeasurerCache({
|
||||
export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
|
||||
const { show } = useContext(MyContext);
|
||||
const [memberGroups] = useAtom(memberGroupsAtom);
|
||||
|
||||
const setTxList = useSetAtom(txListAtom);
|
||||
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
const [groups, setGroups] = useState([]);
|
||||
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
|
||||
@ -189,7 +187,11 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
|
||||
.catch((error) => {
|
||||
setInfoSnack({
|
||||
type: 'error',
|
||||
message: error.message || 'An error occurred',
|
||||
message:
|
||||
error.message ||
|
||||
t('core:message.error.generic', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
}),
|
||||
});
|
||||
setOpenSnack(true);
|
||||
rej(error);
|
||||
@ -248,10 +250,14 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
|
||||
})}{' '}
|
||||
{group?.groupName}
|
||||
</Typography>
|
||||
|
||||
<Typography>
|
||||
{group?.isOpen === false &&
|
||||
'This is a closed/private group, so you will need to wait until an admin accepts your request'}
|
||||
t('group:message.generic.closed_group', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
<LoadingButton
|
||||
loading={isLoading}
|
||||
loadingPosition="start"
|
||||
@ -264,6 +270,7 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
|
||||
</LoadingButton>
|
||||
</Box>
|
||||
</Popover>
|
||||
|
||||
<ListItemButton
|
||||
onClick={(event) => handlePopoverOpen(event, index)}
|
||||
>
|
||||
@ -274,6 +281,7 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{group?.isOpen === true && (
|
||||
<NoEncryptionGmailerrorredIcon
|
||||
sx={{
|
||||
@ -281,7 +289,9 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Spacer width="15px" />
|
||||
|
||||
<ListItemText
|
||||
primary={group?.groupName}
|
||||
secondary={group?.description}
|
||||
|
@ -24,13 +24,14 @@ import { useModal } from '../../common/useModal';
|
||||
import { isOpenBlockedModalAtom } from '../../atoms/global';
|
||||
import InfoIcon from '@mui/icons-material/Info';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const BlockedUsersModal = () => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
const [isOpenBlockedModal, setIsOpenBlockedModal] = useAtom(
|
||||
isOpenBlockedModalAtom
|
||||
);
|
||||
|
||||
const [hasChanged, setHasChanged] = useState(false);
|
||||
const [value, setValue] = useState('');
|
||||
const [addressesWithNames, setAddressesWithNames] = useState({});
|
||||
@ -95,7 +96,12 @@ export const BlockedUsersModal = () => {
|
||||
if (!isAddress) {
|
||||
const response = await fetch(`${getBaseApiReact()}/names/${valUser}`);
|
||||
const data = await response.json();
|
||||
if (!data?.owner) throw new Error('Name does not exist');
|
||||
if (!data?.owner)
|
||||
throw new Error(
|
||||
t('auth:message.error.name_not_existing', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
if (data?.owner) {
|
||||
userAddress = data.owner;
|
||||
userName = valUser;
|
||||
@ -133,7 +139,11 @@ export const BlockedUsersModal = () => {
|
||||
setOpenSnackGlobal(true);
|
||||
setInfoSnackCustom({
|
||||
type: 'error',
|
||||
message: error?.message || 'Unable to block user',
|
||||
message:
|
||||
error?.message ||
|
||||
t('auth:message.error.unable_block_user', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
}),
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -161,7 +171,9 @@ export const BlockedUsersModal = () => {
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle>Blocked Users</DialogTitle>
|
||||
<DialogTitle>
|
||||
{t('auth:blocked_users', { postProcess: 'capitalizeFirstChar' })}
|
||||
</DialogTitle>
|
||||
<DialogContent
|
||||
sx={{
|
||||
padding: '20px',
|
||||
@ -188,20 +200,28 @@ export const BlockedUsersModal = () => {
|
||||
variant="contained"
|
||||
onClick={blockUser}
|
||||
>
|
||||
Block
|
||||
{t('auth:action.block', { postProcess: 'capitalizeFirstChar' })}
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{Object.entries(blockedUsers?.addresses).length > 0 && (
|
||||
<>
|
||||
<Spacer height="20px" />
|
||||
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Blocked addresses- blocks processing of txs
|
||||
{t('auth:message.generic.blocked_addresses', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</DialogContentText>
|
||||
|
||||
<Spacer height="10px" />
|
||||
|
||||
<Button variant="contained" size="small" onClick={getNames}>
|
||||
Fetch names
|
||||
{t('auth:action.fetch_names', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
|
||||
<Spacer height="10px" />
|
||||
</>
|
||||
)}
|
||||
@ -243,19 +263,26 @@ export const BlockedUsersModal = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
Unblock
|
||||
{t('auth:action.unblock', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{Object.entries(blockedUsers?.names).length > 0 && (
|
||||
<>
|
||||
<Spacer height="20px" />
|
||||
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Blocked names for QDN
|
||||
{t('core:message.generic.blocked_names', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</DialogContentText>
|
||||
|
||||
<Spacer height="10px" />
|
||||
</>
|
||||
)}
|
||||
@ -279,6 +306,7 @@ export const BlockedUsersModal = () => {
|
||||
}}
|
||||
>
|
||||
<Typography>{key}</Typography>
|
||||
|
||||
<Button
|
||||
size="small"
|
||||
sx={{
|
||||
@ -295,13 +323,16 @@ export const BlockedUsersModal = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
Unblock
|
||||
{t('auth:action.unblock', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button
|
||||
sx={{
|
||||
@ -323,7 +354,7 @@ export const BlockedUsersModal = () => {
|
||||
setIsOpenBlockedModal(false);
|
||||
}}
|
||||
>
|
||||
close
|
||||
{t('core:action.close', { postProcess: 'capitalizeFirstChar' })}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
||||
@ -333,13 +364,19 @@ export const BlockedUsersModal = () => {
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{'Decide what to block'}
|
||||
{t('auth:message.generic.decide_block', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Blocking {message?.userName || message?.userAddress}
|
||||
{t('auth:message.generic.blocking', {
|
||||
name: message?.userName || message?.userAddress,
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</DialogContentText>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
alignItems: 'center',
|
||||
@ -354,7 +391,9 @@ export const BlockedUsersModal = () => {
|
||||
}}
|
||||
/>{' '}
|
||||
<Typography>
|
||||
Choose "block txs" or "all" to block chat messages{' '}
|
||||
{t('auth:message.generic.choose_block', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
@ -366,7 +405,7 @@ export const BlockedUsersModal = () => {
|
||||
onOk('address');
|
||||
}}
|
||||
>
|
||||
Block txs
|
||||
{t('auth:action.block_txs', { postProcess: 'capitalizeFirstChar' })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
@ -374,7 +413,9 @@ export const BlockedUsersModal = () => {
|
||||
onOk('name');
|
||||
}}
|
||||
>
|
||||
Block QDN data
|
||||
{t('auth:action.block_data', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
@ -382,7 +423,7 @@ export const BlockedUsersModal = () => {
|
||||
onOk('both');
|
||||
}}
|
||||
>
|
||||
Block All
|
||||
{t('auth:action.block_all', { postProcess: 'capitalizeFirstChar' })}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
@ -271,6 +271,7 @@ export const GroupMail = ({
|
||||
},
|
||||
[allThreads, isPrivate]
|
||||
);
|
||||
|
||||
const getMailMessages = useCallback(
|
||||
async (groupId: string, members: any) => {
|
||||
try {
|
||||
@ -385,7 +386,6 @@ export const GroupMail = ({
|
||||
}, [getMailMessages, groupId, members, secretKey, isPrivate]);
|
||||
|
||||
const interval = useRef<any>(null);
|
||||
|
||||
const firstMount = useRef(false);
|
||||
const filterModeRef = useRef('');
|
||||
|
||||
@ -575,6 +575,7 @@ export const GroupMail = ({
|
||||
}}
|
||||
>
|
||||
<InstanceListHeader />
|
||||
|
||||
<InstanceListContainer>
|
||||
{filterOptions?.map((filter) => {
|
||||
return (
|
||||
@ -796,6 +797,7 @@ export const GroupMail = ({
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
<ArrowForwardIosIcon
|
||||
sx={{
|
||||
color: theme.palette.text.primary,
|
||||
|
@ -13,7 +13,6 @@ import {
|
||||
NewMessageSendButton,
|
||||
NewMessageSendP,
|
||||
} from './Mail-styles';
|
||||
|
||||
import { ReusableModal } from './ReusableModal';
|
||||
import { Spacer } from '../../../common/Spacer';
|
||||
import { CreateThreadIcon } from '../../../assets/Icons/CreateThreadIcon';
|
||||
|
@ -29,10 +29,10 @@ export const ShowMessage = ({ message, openNewPostWithQuote, myName }: any) => {
|
||||
return (
|
||||
<SingleTheadMessageParent
|
||||
sx={{
|
||||
height: 'auto',
|
||||
alignItems: 'flex-start',
|
||||
cursor: 'default',
|
||||
borderRadius: '35px 4px 4px 4px',
|
||||
cursor: 'default',
|
||||
height: 'auto',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
@ -80,6 +80,7 @@ export const ShowMessage = ({ message, openNewPostWithQuote, myName }: any) => {
|
||||
{formatTimestampForum(message?.created)}
|
||||
</ThreadInfoColumnTime>
|
||||
</ThreadInfoColumn>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
|
@ -278,12 +278,14 @@ export const Thread = ({
|
||||
const urlNewer = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=${threadIdentifier}&identifier=${identifier}&limit=1&includemetadata=false&reverse=false&prefix=true&before=${
|
||||
fullArrayMsg[0].created
|
||||
}`;
|
||||
|
||||
const responseNewer = await fetch(urlNewer, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
const responseDataNewer = await responseNewer.json();
|
||||
if (responseDataNewer.length > 0) {
|
||||
setHasFirstPage(true);
|
||||
@ -296,12 +298,14 @@ export const Thread = ({
|
||||
const urlOlder = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=${threadIdentifier}&identifier=${identifier}&limit=1&includemetadata=false&reverse=false&prefix=true&after=${
|
||||
fullArrayMsg[fullArrayMsg.length - 1].created
|
||||
}`;
|
||||
|
||||
const responseOlder = await fetch(urlOlder, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
const responseDataOlder = await responseOlder.json();
|
||||
if (responseDataOlder.length > 0) {
|
||||
setHasLastPage(true);
|
||||
@ -321,6 +325,7 @@ export const Thread = ({
|
||||
},
|
||||
[messages, secretKey]
|
||||
);
|
||||
|
||||
const getMessages = useCallback(async () => {
|
||||
if (
|
||||
!currentThread ||
|
||||
@ -337,6 +342,7 @@ export const Thread = ({
|
||||
groupInfo?.groupId,
|
||||
isPrivate,
|
||||
]);
|
||||
|
||||
const firstMount = useRef(false);
|
||||
|
||||
const saveTimestamp = useCallback((currentThread: any, username?: string) => {
|
||||
@ -613,6 +619,7 @@ export const Thread = ({
|
||||
})}
|
||||
</ComposeP>
|
||||
</ShowMessageReturnButton>
|
||||
|
||||
{/* Conditionally render the scroll buttons */}
|
||||
{showScrollButton &&
|
||||
(isAtBottom ? (
|
||||
|
@ -2388,6 +2388,7 @@ export const Group = ({
|
||||
: 'flex',
|
||||
}}
|
||||
></AuthenticatedContainerInnerRight>
|
||||
|
||||
<LoadingSnackbar
|
||||
open={isLoadingGroup}
|
||||
info={{
|
||||
|
@ -17,8 +17,9 @@ import { useTranslation } from 'react-i18next';
|
||||
export const GroupInvites = ({ myAddress, setOpenAddGroup }) => {
|
||||
const [groupsWithJoinRequests, setGroupsWithJoinRequests] = useState([]);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
const theme = useTheme();
|
||||
|
||||
const getJoinRequests = async () => {
|
||||
try {
|
||||
@ -37,9 +38,6 @@ export const GroupInvites = ({ myAddress, setOpenAddGroup }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
const theme = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
if (myAddress) {
|
||||
getJoinRequests();
|
||||
@ -75,6 +73,7 @@ export const GroupInvites = ({ myAddress, setOpenAddGroup }) => {
|
||||
{groupsWithJoinRequests?.length > 0 &&
|
||||
` (${groupsWithJoinRequests?.length})`}
|
||||
</Typography>
|
||||
|
||||
{isExpanded ? (
|
||||
<ExpandLessIcon
|
||||
sx={{
|
||||
@ -113,6 +112,7 @@ export const GroupInvites = ({ myAddress, setOpenAddGroup }) => {
|
||||
<CustomLoader />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{!loading && groupsWithJoinRequests.length === 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
@ -136,6 +136,7 @@ export const GroupInvites = ({ myAddress, setOpenAddGroup }) => {
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<List
|
||||
sx={{
|
||||
width: '100%',
|
||||
|
@ -1,4 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import List from '@mui/material/List';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import ListItemButton from '@mui/material/ListItemButton';
|
||||
@ -27,12 +27,10 @@ export const GroupJoinRequests = ({
|
||||
setMobileViewMode,
|
||||
setDesktopViewMode,
|
||||
}) => {
|
||||
const [isExpanded, setIsExpanded] = React.useState(false);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
const [groupsWithJoinRequests, setGroupsWithJoinRequests] = React.useState(
|
||||
[]
|
||||
);
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const [groupsWithJoinRequests, setGroupsWithJoinRequests] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [txList] = useAtom(txListAtom);
|
||||
|
||||
const setMyGroupsWhereIAmAdmin = useSetAtom(myGroupsWhereIAmAdminAtom);
|
||||
@ -91,7 +89,7 @@ export const GroupJoinRequests = ({
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (myAddress && groups.length > 0) {
|
||||
getJoinRequests();
|
||||
} else {
|
||||
@ -99,7 +97,7 @@ export const GroupJoinRequests = ({
|
||||
}
|
||||
}, [myAddress, groups]);
|
||||
|
||||
const filteredJoinRequests = React.useMemo(() => {
|
||||
const filteredJoinRequests = useMemo(() => {
|
||||
return groupsWithJoinRequests.map((group) => {
|
||||
const filteredGroupRequests = group?.data?.filter((gd) => {
|
||||
const findJoinRequsetInTxList = txList?.find(
|
||||
@ -149,6 +147,7 @@ export const GroupJoinRequests = ({
|
||||
?.length > 0 &&
|
||||
` (${filteredJoinRequests?.filter((group) => group?.data?.length > 0)?.length})`}
|
||||
</Typography>
|
||||
|
||||
{isExpanded ? (
|
||||
<ExpandLessIcon
|
||||
sx={{
|
||||
@ -163,6 +162,7 @@ export const GroupJoinRequests = ({
|
||||
/>
|
||||
)}
|
||||
</ButtonBase>
|
||||
|
||||
<Collapse in={isExpanded} timeout="auto" unmountOnExit>
|
||||
<Box
|
||||
sx={{
|
||||
@ -186,6 +186,7 @@ export const GroupJoinRequests = ({
|
||||
<CustomLoader />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{!loading &&
|
||||
(filteredJoinRequests.length === 0 ||
|
||||
filteredJoinRequests?.filter((group) => group?.data?.length > 0)
|
||||
@ -212,6 +213,7 @@ export const GroupJoinRequests = ({
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<List
|
||||
className="scrollable-container"
|
||||
sx={{
|
||||
@ -268,7 +270,14 @@ export const GroupJoinRequests = ({
|
||||
fontWeight: 400,
|
||||
},
|
||||
}}
|
||||
primary={`${group?.group?.groupName} has ${group?.data?.length} pending join requests.`}
|
||||
primary={t(
|
||||
'group:message.generic.pending_join_requests',
|
||||
{
|
||||
group: group?.group?.groupName,
|
||||
count: group?.data?.length,
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
|
@ -29,7 +29,6 @@ import {
|
||||
isRunningPublicNodeAtom,
|
||||
timestampEnterDataSelector,
|
||||
} from '../../atoms/global';
|
||||
|
||||
import { timeDifferenceForNotificationChats } from './Group';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -56,23 +55,23 @@ export const GroupList = ({
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
width: '380px',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
height: '100%',
|
||||
background: theme.palette.background.surface,
|
||||
borderRadius: '0px 15px 15px 0px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
padding: '0px 2px',
|
||||
width: '380px',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
display: 'flex',
|
||||
gap: '10px',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<ButtonBase
|
||||
@ -252,7 +251,7 @@ const GroupItem = React.memo(
|
||||
padding: '10px',
|
||||
width: '100%',
|
||||
'&:hover': {
|
||||
backgroundColor: 'action.hover', // background on hover
|
||||
backgroundColor: 'action.hover',
|
||||
},
|
||||
}}
|
||||
>
|
||||
@ -296,7 +295,7 @@ const GroupItem = React.memo(
|
||||
theme.palette.text.primary,
|
||||
fontSize: '16px',
|
||||
},
|
||||
}} // Change the color of the primary text
|
||||
}}
|
||||
secondaryTypographyProps={{
|
||||
style: {
|
||||
color:
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Box, Divider, Typography, useTheme } from '@mui/material';
|
||||
import React from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Spacer } from '../../common/Spacer';
|
||||
import { ThingsToDoInitial } from './ThingsToDoInitial';
|
||||
import { GroupJoinRequests } from './GroupJoinRequests';
|
||||
@ -28,28 +28,28 @@ export const HomeDesktop = ({
|
||||
setDesktopViewMode,
|
||||
desktopViewMode,
|
||||
}) => {
|
||||
const [checked1, setChecked1] = React.useState(false);
|
||||
const [checked2, setChecked2] = React.useState(false);
|
||||
const [checked1, setChecked1] = useState(false);
|
||||
const [checked2, setChecked2] = useState(false);
|
||||
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
const theme = useTheme();
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (balance && +balance >= 6) {
|
||||
setChecked1(true);
|
||||
}
|
||||
}, [balance]);
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (name) setChecked2(true);
|
||||
}, [name]);
|
||||
|
||||
const isLoaded = React.useMemo(() => {
|
||||
const isLoaded = useMemo(() => {
|
||||
if (userInfo !== null) return true;
|
||||
return false;
|
||||
}, [userInfo]);
|
||||
|
||||
const hasDoneNameAndBalanceAndIsLoaded = React.useMemo(() => {
|
||||
const hasDoneNameAndBalanceAndIsLoaded = useMemo(() => {
|
||||
if (isLoaded && checked1 && checked2) return true;
|
||||
return false;
|
||||
}, [checked1, isLoaded, checked2]);
|
||||
@ -136,14 +136,6 @@ export const HomeDesktop = ({
|
||||
|
||||
{desktopViewMode === 'home' && (
|
||||
<>
|
||||
{/* <Box sx={{
|
||||
width: '330px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}>
|
||||
<ListOfThreadPostsWatched />
|
||||
</Box> */}
|
||||
{hasDoneNameAndBalanceAndIsLoaded && (
|
||||
<>
|
||||
<Box
|
||||
|
@ -87,6 +87,7 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
|
||||
const handleCancelBan = async (address) => {
|
||||
try {
|
||||
const fee = await getFee('CANCEL_GROUP_BAN');
|
||||
|
||||
await show({
|
||||
message: t('core:message.question.perform_transaction', {
|
||||
action: 'CANCEL_GROUP_BAN',
|
||||
@ -94,6 +95,7 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
|
||||
}),
|
||||
publishFee: fee.fee + ' QORT',
|
||||
});
|
||||
|
||||
setIsLoadingUnban(true);
|
||||
new Promise((res, rej) => {
|
||||
window
|
||||
@ -125,7 +127,11 @@ export const ListOfBans = ({ groupId, setInfoSnack, setOpenSnack, show }) => {
|
||||
.catch((error) => {
|
||||
setInfoSnack({
|
||||
type: 'error',
|
||||
message: error.message || 'An error occurred',
|
||||
message:
|
||||
error.message ||
|
||||
t('core:message.error.generic', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
}),
|
||||
});
|
||||
setOpenSnack(true);
|
||||
rej(error);
|
||||
|
@ -1,10 +1,4 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
@ -88,7 +82,7 @@ export const ListOfGroupPromotions = () => {
|
||||
const [promotionTimeInterval, setPromotionTimeInterval] = useAtom(
|
||||
promotionTimeIntervalAtom
|
||||
);
|
||||
const [isExpanded, setIsExpanded] = React.useState(false);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const [openSnack, setOpenSnack] = useState(false);
|
||||
const [infoSnack, setInfoSnack] = useState(null);
|
||||
const [fee, setFee] = useState(null);
|
||||
@ -101,7 +95,7 @@ export const ListOfGroupPromotions = () => {
|
||||
const listRef = useRef(null);
|
||||
const rowVirtualizer = useVirtualizer({
|
||||
count: promotions.length,
|
||||
getItemKey: React.useCallback(
|
||||
getItemKey: useCallback(
|
||||
(index) => promotions[index]?.identifier,
|
||||
[promotions]
|
||||
),
|
||||
@ -275,6 +269,7 @@ export const ListOfGroupPromotions = () => {
|
||||
try {
|
||||
const groupId = group.groupId;
|
||||
const fee = await getFee('JOIN_GROUP');
|
||||
|
||||
await show({
|
||||
message: t('core:message.question.perform_transaction', {
|
||||
action: 'JOIN_GROUP',
|
||||
@ -282,6 +277,7 @@ export const ListOfGroupPromotions = () => {
|
||||
}),
|
||||
publishFee: fee.fee + ' QORT',
|
||||
});
|
||||
|
||||
setIsLoadingJoinGroup(true);
|
||||
await new Promise((res, rej) => {
|
||||
window
|
||||
@ -495,6 +491,7 @@ export const ListOfGroupPromotions = () => {
|
||||
<CustomLoader />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{!loading && promotions.length === 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
@ -518,6 +515,7 @@ export const ListOfGroupPromotions = () => {
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<div
|
||||
style={{
|
||||
height: '600px',
|
||||
@ -776,6 +774,7 @@ export const ListOfGroupPromotions = () => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{promotion?.isOpen === true && (
|
||||
<NoEncryptionGmailerrorredIcon
|
||||
sx={{
|
||||
@ -783,6 +782,7 @@ export const ListOfGroupPromotions = () => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: '15px',
|
||||
|
@ -210,13 +210,13 @@ export const ListOfJoinRequests = ({
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: '325px',
|
||||
height: '250px',
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
gap: '10px',
|
||||
height: '250px',
|
||||
padding: '10px',
|
||||
width: '325px',
|
||||
}}
|
||||
>
|
||||
<LoadingButton
|
||||
@ -261,12 +261,12 @@ export const ListOfJoinRequests = ({
|
||||
</p>
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
height: '500px',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 1,
|
||||
height: '500px',
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<AutoSizer>
|
||||
|
@ -117,6 +117,7 @@ export const ListOfThreadPostsWatched = () => {
|
||||
<CustomLoader />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{!loading && posts.length === 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
@ -140,6 +141,7 @@ export const ListOfThreadPostsWatched = () => {
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{posts?.length > 0 && (
|
||||
<List
|
||||
className="scrollable-container"
|
||||
@ -173,7 +175,10 @@ export const ListOfThreadPostsWatched = () => {
|
||||
>
|
||||
<ListItemButton disableRipple role={undefined} dense>
|
||||
<ListItemText
|
||||
primary={`New post in ${post?.thread?.threadData?.title}`}
|
||||
primary={t('core:new_post_in', {
|
||||
title: post?.thread?.threadData?.title,
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
|
@ -367,9 +367,9 @@ export const ManageMembers = ({
|
||||
{value === 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
padding: '25px',
|
||||
maxWidth: '750px',
|
||||
padding: '25px',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
@ -398,9 +398,9 @@ export const ManageMembers = ({
|
||||
{value === 1 && (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
padding: '25px',
|
||||
maxWidth: '750px',
|
||||
padding: '25px',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<InviteMember
|
||||
@ -415,9 +415,9 @@ export const ManageMembers = ({
|
||||
{value === 2 && (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
padding: '25px',
|
||||
maxWidth: '750px',
|
||||
padding: '25px',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<ListOfInvites
|
||||
@ -432,8 +432,8 @@ export const ManageMembers = ({
|
||||
{value === 3 && (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
padding: '25px',
|
||||
width: '100%',
|
||||
maxWidth: '750px',
|
||||
}}
|
||||
>
|
||||
@ -449,9 +449,9 @@ export const ManageMembers = ({
|
||||
{value === 4 && (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
padding: '25px',
|
||||
maxWidth: '750px',
|
||||
padding: '25px',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<ListOfJoinRequests
|
||||
|
@ -210,6 +210,7 @@ export const QMailMessages = ({ userName, userAddress }) => {
|
||||
<CustomLoader />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{!loading && mails.length === 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
|
@ -199,6 +199,7 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
/>
|
||||
|
||||
{window?.electronAPI && (
|
||||
<FormControlLabel
|
||||
control={
|
||||
@ -320,6 +321,7 @@ const ExportPrivateKey = ({ rawWallet }) => {
|
||||
autoComplete="off"
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
|
||||
{privateKey && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
|
@ -12,8 +12,10 @@ import { AppsNavBarLeft, AppsNavBarParent } from '../Apps/Apps-styles';
|
||||
import { NavBack } from '../../assets/Icons/NavBack.tsx';
|
||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const WalletsAppWrapper = () => {
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
const iframeRef = useRef(null);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [navigationController, setNavigationController] = useAtom(
|
||||
@ -87,7 +89,11 @@ export const WalletsAppWrapper = () => {
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<Typography>Q-Wallets</Typography>
|
||||
<Typography>
|
||||
{t('core:q_apps.q_wallets', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
<ButtonBase onClick={handleClose}>
|
||||
<CloseIcon
|
||||
|
@ -16,6 +16,7 @@ import { getFee } from '../background';
|
||||
import { fileToBase64 } from '../utils/fileReading';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import ErrorIcon from '@mui/icons-material/Error';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
|
||||
const [hasAvatar, setHasAvatar] = useState(false);
|
||||
@ -40,6 +41,8 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? 'avatar-img' : undefined;
|
||||
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
|
||||
const checkIfAvatarExists = async () => {
|
||||
try {
|
||||
const identifier = `qortal_avatar`;
|
||||
@ -65,16 +68,26 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
|
||||
|
||||
const publishAvatar = async () => {
|
||||
try {
|
||||
// TODO translate
|
||||
const fee = await getFee('ARBITRARY');
|
||||
|
||||
if (+balance < +fee.fee)
|
||||
throw new Error(`Publishing an Avatar requires ${fee.fee}`);
|
||||
throw new Error(
|
||||
t('core:message.generic.avatar_publish_fee', {
|
||||
fee: fee.fee,
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
|
||||
await show({
|
||||
message: 'Would you like to publish an avatar?',
|
||||
message: t('core:message.question.publish_avatar', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
}),
|
||||
publishFee: fee.fee + ' QORT',
|
||||
});
|
||||
|
||||
setIsLoading(true);
|
||||
const avatarBase64 = await fileToBase64(avatarFile);
|
||||
|
||||
await new Promise((res, rej) => {
|
||||
window
|
||||
.sendMessage('publishOnQDN', {
|
||||
@ -90,7 +103,12 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
|
||||
rej(response.error);
|
||||
})
|
||||
.catch((error) => {
|
||||
rej(error.message || 'An error occurred');
|
||||
rej(
|
||||
error.message ||
|
||||
t('core:message.error.generic', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
setAvatarFile(null);
|
||||
@ -122,6 +140,7 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
|
||||
>
|
||||
{myName?.charAt(0)}
|
||||
</Avatar>
|
||||
|
||||
<ButtonBase onClick={handleChildClick}>
|
||||
<Typography
|
||||
sx={{
|
||||
@ -129,9 +148,12 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
|
||||
opacity: 0.5,
|
||||
}}
|
||||
>
|
||||
change avatar
|
||||
{t('core:action.change_avatar', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
</ButtonBase>
|
||||
|
||||
<PopoverComp
|
||||
myName={myName}
|
||||
avatarFile={avatarFile}
|
||||
@ -160,6 +182,7 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
|
||||
>
|
||||
{myName?.charAt(0)}
|
||||
</Avatar>
|
||||
|
||||
<ButtonBase onClick={handleChildClick}>
|
||||
<Typography
|
||||
sx={{
|
||||
@ -167,9 +190,12 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
|
||||
opacity: 0.5,
|
||||
}}
|
||||
>
|
||||
change avatar
|
||||
{t('core:action.change_avatar', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
</ButtonBase>
|
||||
|
||||
<PopoverComp
|
||||
myName={myName}
|
||||
avatarFile={avatarFile}
|
||||
@ -195,9 +221,10 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
|
||||
opacity: 0.5,
|
||||
}}
|
||||
>
|
||||
set avatar
|
||||
{t('core:action.set_avatar', { postProcess: 'capitalizeFirstChar' })}
|
||||
</Typography>
|
||||
</ButtonBase>
|
||||
|
||||
<PopoverComp
|
||||
myName={myName}
|
||||
avatarFile={avatarFile}
|
||||
@ -213,6 +240,7 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => {
|
||||
);
|
||||
};
|
||||
|
||||
// TODO the following part is the same as in GroupAvatar.tsx
|
||||
const PopoverComp = ({
|
||||
avatarFile,
|
||||
setAvatarFile,
|
||||
@ -225,6 +253,8 @@ const PopoverComp = ({
|
||||
myName,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
id={id}
|
||||
@ -246,13 +276,24 @@ const PopoverComp = ({
|
||||
fontSize: '12px',
|
||||
}}
|
||||
>
|
||||
(500 KB max. for GIFS){' '}
|
||||
{t('core:message.generic.avatar_size', {
|
||||
size: 500, // TODO magic number
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
<ImageUploader onPick={(file) => setAvatarFile(file)}>
|
||||
<Button variant="contained">Choose Image</Button>
|
||||
<Button variant="contained">
|
||||
{t('core:action.choose_image', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
</ImageUploader>
|
||||
|
||||
{avatarFile?.name}
|
||||
|
||||
<Spacer height="25px" />
|
||||
|
||||
{!myName && (
|
||||
<Box
|
||||
sx={{
|
||||
@ -267,19 +308,24 @@ const PopoverComp = ({
|
||||
}}
|
||||
/>
|
||||
<Typography>
|
||||
A registered name is required to set an avatar
|
||||
{t('core:message.generic.avatar_registered_name', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Spacer height="25px" />
|
||||
|
||||
<LoadingButton
|
||||
loading={isLoading}
|
||||
disabled={!avatarFile || !myName}
|
||||
onClick={publishAvatar}
|
||||
variant="contained"
|
||||
>
|
||||
Publish avatar
|
||||
{t('group:action.publish_avatar', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</LoadingButton>
|
||||
</Box>
|
||||
</Popover>
|
||||
|
@ -1,19 +1,13 @@
|
||||
import { Box, CircularProgress, useTheme } from '@mui/material';
|
||||
import { Box, useTheme } from '@mui/material';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
CustomButton,
|
||||
CustomInput,
|
||||
CustomLabel,
|
||||
TextP,
|
||||
} from '../styles/App-styles';
|
||||
import { TextP } from '../styles/App-styles';
|
||||
import { Spacer } from '../common/Spacer';
|
||||
import BoundedNumericTextField from '../common/BoundedNumericTextField';
|
||||
import { PasswordField } from './PasswordField/PasswordField';
|
||||
import { ErrorText } from './ErrorText/ErrorText';
|
||||
import { getFee } from '../background';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
const [paymentTo, setPaymentTo] = useState<string>(defaultPaymentTo);
|
||||
const [paymentAmount, setPaymentAmount] = useState<number>(0);
|
||||
const [paymentPassword, setPaymentPassword] = useState<string>('');
|
||||
@ -26,22 +20,37 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
|
||||
setSendPaymentError('');
|
||||
setSendPaymentSuccess('');
|
||||
if (!paymentTo) {
|
||||
setSendPaymentError('Please enter a recipient');
|
||||
setSendPaymentError(
|
||||
t('auth:action.enter_recipient', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!paymentAmount) {
|
||||
setSendPaymentError('Please enter an amount greater than 0');
|
||||
setSendPaymentError(
|
||||
t('auth:action.enter_amount', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!paymentPassword) {
|
||||
setSendPaymentError('Please enter your wallet password');
|
||||
setSendPaymentError(
|
||||
t('auth:action.enter_wallet_password', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const fee = await getFee('PAYMENT'); // TODO translate
|
||||
const fee = await getFee('PAYMENT');
|
||||
|
||||
await show({
|
||||
message: `Would you like to transfer ${Number(paymentAmount)} QORT?`,
|
||||
message: t('core:message.question.transfer_qort', {
|
||||
amount: Number(paymentAmount),
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
}),
|
||||
paymentFee: fee.fee + ' QORT',
|
||||
});
|
||||
|
||||
@ -87,7 +96,9 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
|
||||
textAlign: 'start',
|
||||
}}
|
||||
>
|
||||
Transfer QORT
|
||||
{t('core:action.transfer_qort', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</TextP>
|
||||
|
||||
<Spacer height="35px" />
|
||||
@ -101,7 +112,9 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
|
||||
textAlign: 'start',
|
||||
}}
|
||||
>
|
||||
Balance:
|
||||
{t('core:balance', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</TextP>
|
||||
|
||||
<TextP
|
||||
@ -119,7 +132,11 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
|
||||
<Spacer height="35px" />
|
||||
|
||||
<Box>
|
||||
<CustomLabel htmlFor="standard-adornment-name">To</CustomLabel>
|
||||
<CustomLabel htmlFor="standard-adornment-name">
|
||||
{t('core:to', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</CustomLabel>
|
||||
|
||||
<Spacer height="5px" />
|
||||
|
||||
@ -132,7 +149,11 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
|
||||
|
||||
<Spacer height="6px" />
|
||||
|
||||
<CustomLabel htmlFor="standard-adornment-amount">Amount</CustomLabel>
|
||||
<CustomLabel htmlFor="standard-adornment-amount">
|
||||
{t('core:amount', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</CustomLabel>
|
||||
|
||||
<Spacer height="5px" />
|
||||
|
||||
@ -149,7 +170,9 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
|
||||
<Spacer height="6px" />
|
||||
|
||||
<CustomLabel htmlFor="standard-adornment-password">
|
||||
Confirm wallet password
|
||||
{t('auth:wallet.password_confirmation', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</CustomLabel>
|
||||
|
||||
<Spacer height="5px" />
|
||||
@ -171,7 +194,6 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
|
||||
<Spacer height="10px" />
|
||||
|
||||
<ErrorText>{sendPaymentError}</ErrorText>
|
||||
{/* <Typography>{sendPaymentSuccess}</Typography> */}
|
||||
|
||||
<Spacer height="25px" />
|
||||
|
||||
@ -192,7 +214,7 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
Send
|
||||
{t('core:action.send', { postProcess: 'capitalizeFirstChar' })}
|
||||
</CustomButton>
|
||||
</>
|
||||
);
|
||||
|
@ -33,6 +33,7 @@ import {
|
||||
unsubscribeFromEvent,
|
||||
} from '../../utils/events';
|
||||
import { useNameSearch } from '../../hooks/useNameSearch';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
function formatAddress(str) {
|
||||
if (str.length <= 12) return str;
|
||||
@ -45,6 +46,7 @@ function formatAddress(str) {
|
||||
|
||||
export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
const [nameOrAddress, setNameOrAddress] = useState('');
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const { results, isLoading } = useNameSearch(inputValue);
|
||||
@ -64,13 +66,27 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
const inputAddressOrName = messageAddressOrName || nameOrAddress;
|
||||
|
||||
if (!inputAddressOrName?.trim())
|
||||
throw new Error('Please insert a name or address');
|
||||
throw new Error(
|
||||
t('auth:action.insert_name_address', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
|
||||
const owner = await getNameOrAddress(inputAddressOrName);
|
||||
if (!owner) throw new Error('Name does not exist');
|
||||
if (!owner)
|
||||
throw new Error(
|
||||
t('auth:message.error.name_not_existing', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
|
||||
const addressInfoRes = await getAddressInfo(owner);
|
||||
if (!addressInfoRes?.publicKey) {
|
||||
throw new Error('Address does not exist on blockchain');
|
||||
throw new Error(
|
||||
t('auth:message.error.address_not_existing', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const name = await getNameInfo(owner);
|
||||
@ -175,7 +191,9 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
autoFocus
|
||||
autoComplete="off"
|
||||
{...params}
|
||||
label="Address or Name"
|
||||
label={t('auth:address_name', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && nameOrAddress) {
|
||||
lookupFunc(inputValue);
|
||||
@ -200,6 +218,7 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
@ -220,6 +239,7 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
<Typography>{errorMessage}</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{isLoadingUser && (
|
||||
<Box
|
||||
sx={{
|
||||
@ -236,6 +256,7 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{!isLoadingUser && addressInfo && (
|
||||
<>
|
||||
<Spacer height="30px" />
|
||||
@ -265,7 +286,10 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{addressInfo?.name ?? 'Name not registered'}
|
||||
{addressInfo?.name ??
|
||||
t('auth:message.error.name_not_registered', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
<Spacer height="20px" />
|
||||
@ -307,7 +331,8 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
Level {addressInfo?.level}
|
||||
{t('core:level', { postProcess: 'capitalizeFirstChar' })}{' '}
|
||||
{addressInfo?.level}
|
||||
</Typography>
|
||||
</Card>
|
||||
|
||||
@ -336,8 +361,13 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<Typography>Address</Typography>
|
||||
<Typography>
|
||||
{t('auth:address', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Tooltip
|
||||
title={
|
||||
<span
|
||||
@ -347,7 +377,9 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
copy address
|
||||
{t('auth:action.copy_address', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</span>
|
||||
}
|
||||
placement="bottom"
|
||||
@ -391,7 +423,12 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Typography>Balance</Typography>
|
||||
<Typography>
|
||||
{t('core:balance', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
<Typography>{addressInfo?.balance}</Typography>
|
||||
</Box>
|
||||
|
||||
@ -406,7 +443,9 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
});
|
||||
}}
|
||||
>
|
||||
Send QORT
|
||||
{t('core:action.send_qort', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
</Card>
|
||||
</Box>
|
||||
@ -440,7 +479,12 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
padding: '15px',
|
||||
}}
|
||||
>
|
||||
<Typography>20 most recent payments</Typography>
|
||||
<Typography>
|
||||
{t('core:message.generic.most_recent_payment', {
|
||||
count: 20,
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
<Spacer height="20px" />
|
||||
|
||||
@ -452,17 +496,33 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Typography>No payments</Typography>
|
||||
<Typography>
|
||||
{t('core:message.generic.no_payments', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Sender</TableCell>
|
||||
<TableCell>Reciver</TableCell>
|
||||
<TableCell>Amount</TableCell>
|
||||
<TableCell>Time</TableCell>
|
||||
<TableCell>
|
||||
{t('core:sender', { postProcess: 'capitalizeFirstChar' })}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{t('core:receiver', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{t('core:amount', { postProcess: 'capitalizeFirstChar' })}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{t('core:time.time', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
|
||||
@ -479,7 +539,9 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
copy address
|
||||
{t('auth:action.copy_address', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</span>
|
||||
}
|
||||
placement="bottom"
|
||||
@ -522,7 +584,9 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
copy address
|
||||
{t('auth:action.copy_address', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</span>
|
||||
}
|
||||
placement="bottom"
|
||||
@ -552,7 +616,9 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => {
|
||||
</ButtonBase>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>{payment?.amount}</TableCell>
|
||||
|
||||
<TableCell>
|
||||
{formatTimestamp(payment?.timestamp)}
|
||||
</TableCell>
|
||||
|
@ -10,9 +10,11 @@ import { executeEvent } from '../utils/events';
|
||||
import { MyContext } from '../App';
|
||||
import { useAtom } from 'jotai';
|
||||
import { isRunningPublicNodeAtom } from '../atoms/global';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
const [isRunningPublicNode] = useAtom(isRunningPublicNodeAtom);
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
@ -96,7 +98,7 @@ export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
||||
justifyContent: 'flex-start',
|
||||
}}
|
||||
>
|
||||
Message
|
||||
{t('core:message.message', { postProcess: 'capitalizeFirstChar' })}
|
||||
</Button>
|
||||
|
||||
{/* Option 2: Send QORT */}
|
||||
@ -114,8 +116,11 @@ export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
||||
justifyContent: 'flex-start',
|
||||
}}
|
||||
>
|
||||
Send QORT
|
||||
{t('core:action.send_qort', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="text"
|
||||
onClick={() => {
|
||||
@ -127,8 +132,11 @@ export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
||||
justifyContent: 'flex-start',
|
||||
}}
|
||||
>
|
||||
Copy address
|
||||
{t('auth:action.copy_address', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="text"
|
||||
onClick={() => {
|
||||
@ -142,7 +150,9 @@ export const WrapperUserAction = ({ children, address, name, disabled }) => {
|
||||
justifyContent: 'flex-start',
|
||||
}}
|
||||
>
|
||||
User lookup
|
||||
{t('core:user_lookup', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
|
||||
{!isRunningPublicNode && (
|
||||
@ -165,6 +175,7 @@ const BlockUser = ({ address, name, handleClose }) => {
|
||||
const { isUserBlocked, addToBlockList, removeBlockFromList } =
|
||||
useContext(MyContext);
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
|
||||
useEffect(() => {
|
||||
if (!address) return;
|
||||
@ -180,12 +191,6 @@ const BlockUser = ({ address, name, handleClose }) => {
|
||||
executeEvent('blockUserFromOutside', {
|
||||
user: address,
|
||||
});
|
||||
// if(isAlreadyBlocked === true){
|
||||
// await removeBlockFromList(address, name)
|
||||
// } else if(isAlreadyBlocked === false) {
|
||||
// await addToBlockList(address, name)
|
||||
// }
|
||||
// executeEvent('updateChatMessagesWithBlocks', true)
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
@ -202,8 +207,9 @@ const BlockUser = ({ address, name, handleClose }) => {
|
||||
{(isAlreadyBlocked === null || isLoading) && (
|
||||
<CircularProgress color="secondary" size={24} />
|
||||
)}
|
||||
{isAlreadyBlocked && 'Unblock name'}
|
||||
{isAlreadyBlocked === false && 'Block name'}
|
||||
{isAlreadyBlocked &&
|
||||
t('auth:action.unblock_name', { postProcess: 'capitalizeFirstChar' })}
|
||||
{isAlreadyBlocked === false && t('auth:action.block_name', { postProcess: 'capitalizeFirstChar' })}}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
@ -10,6 +10,7 @@ import { saveToLocalStorage } from '../components/Apps/AppsNavBarDesktop';
|
||||
import { base64ToUint8Array } from '../qdn/encryption/group-encryption';
|
||||
import { uint8ArrayToObject } from '../backgroundFunctions/encryption';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const useHandlePrivateApps = () => {
|
||||
const [status, setStatus] = useState('');
|
||||
@ -20,8 +21,8 @@ export const useHandlePrivateApps = () => {
|
||||
setInfoSnackCustom,
|
||||
} = useContext(MyContext);
|
||||
const setSortablePinnedApps = useSetAtom(sortablePinnedAppsAtom);
|
||||
|
||||
const setSettingsLocalLastUpdated = useSetAtom(settingsLocalLastUpdatedAtom);
|
||||
const { t } = useTranslation(['auth', 'core', 'group']);
|
||||
|
||||
const openApp = async (
|
||||
privateAppProperties,
|
||||
@ -30,13 +31,19 @@ export const useHandlePrivateApps = () => {
|
||||
) => {
|
||||
try {
|
||||
if (setLoadingStatePrivateApp) {
|
||||
setLoadingStatePrivateApp(`Downloading and decrypting private app.`);
|
||||
setLoadingStatePrivateApp(
|
||||
t('core:message.generic.downloading_decrypting_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
}
|
||||
setOpenSnackGlobal(true);
|
||||
|
||||
setInfoSnackCustom({
|
||||
type: 'info',
|
||||
message: 'Fetching app data',
|
||||
message: t('core:message.generic.fetching_data', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
}),
|
||||
duration: null,
|
||||
});
|
||||
const urlData = `${getBaseApiReact()}/arbitrary/${
|
||||
@ -55,7 +62,11 @@ export const useHandlePrivateApps = () => {
|
||||
|
||||
if (!responseData?.ok) {
|
||||
if (setLoadingStatePrivateApp) {
|
||||
setLoadingStatePrivateApp('Error! Unable to download private app.');
|
||||
setLoadingStatePrivateApp(
|
||||
t('core:message.generic.unable_download_private_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
throw new Error('Unable to fetch app');
|
||||
@ -64,13 +75,25 @@ export const useHandlePrivateApps = () => {
|
||||
data = await responseData.text();
|
||||
if (data?.error) {
|
||||
if (setLoadingStatePrivateApp) {
|
||||
setLoadingStatePrivateApp('Error! Unable to download private app.');
|
||||
setLoadingStatePrivateApp(
|
||||
t('core:message.generic.unable_download_private_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
}
|
||||
throw new Error('Unable to fetch app');
|
||||
throw new Error(
|
||||
t('core:message.generic.unable_fetch_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (setLoadingStatePrivateApp) {
|
||||
setLoadingStatePrivateApp('Error! Unable to download private app.');
|
||||
setLoadingStatePrivateApp(
|
||||
t('core:message.generic.unable_download_private_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
@ -78,23 +101,27 @@ export const useHandlePrivateApps = () => {
|
||||
let decryptedData;
|
||||
// eslint-disable-next-line no-useless-catch
|
||||
try {
|
||||
decryptedData = await window.sendMessage(
|
||||
'DECRYPT_QORTAL_GROUP_DATA',
|
||||
|
||||
{
|
||||
base64: data,
|
||||
groupId: privateAppProperties?.groupId,
|
||||
}
|
||||
);
|
||||
decryptedData = await window.sendMessage('DECRYPT_QORTAL_GROUP_DATA', {
|
||||
base64: data,
|
||||
groupId: privateAppProperties?.groupId,
|
||||
});
|
||||
if (decryptedData?.error) {
|
||||
if (setLoadingStatePrivateApp) {
|
||||
setLoadingStatePrivateApp('Error! Unable to decrypt private app.');
|
||||
setLoadingStatePrivateApp(
|
||||
t('core:message.generic.unable_decrypt_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
}
|
||||
throw new Error(decryptedData?.error);
|
||||
}
|
||||
} catch (error) {
|
||||
if (setLoadingStatePrivateApp) {
|
||||
setLoadingStatePrivateApp('Error! Unable to decrypt private app.');
|
||||
setLoadingStatePrivateApp(
|
||||
t('core:message.generic.unable_decrypt_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
@ -106,11 +133,15 @@ export const useHandlePrivateApps = () => {
|
||||
if (decryptedData) {
|
||||
setInfoSnackCustom({
|
||||
type: 'info',
|
||||
message: 'Building app',
|
||||
message: t('core:message.generic.building_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
}),
|
||||
});
|
||||
|
||||
const endpoint = await createEndpoint(
|
||||
`/arbitrary/APP/${privateAppProperties?.name}/zip?preview=true`
|
||||
);
|
||||
|
||||
const response = await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@ -118,7 +149,9 @@ export const useHandlePrivateApps = () => {
|
||||
},
|
||||
body: UintToObject?.app,
|
||||
});
|
||||
|
||||
const previewPath = await response.text();
|
||||
|
||||
const refreshfunc = async (tabId, privateAppProperties) => {
|
||||
const checkIfPreviewLinkStillWorksUrl = await createEndpoint(
|
||||
`/render/hash/HmtnZpcRPwisMfprUXuBp27N2xtv5cDiQjqGZo8tbZS?secret=E39WTiG4qBq3MFcMPeRZabtQuzyfHg9ZuR5SgY7nW1YH`
|
||||
@ -132,6 +165,7 @@ export const useHandlePrivateApps = () => {
|
||||
const endpoint = await createEndpoint(
|
||||
`/arbitrary/APP/${privateAppProperties?.name}/zip?preview=true`
|
||||
);
|
||||
|
||||
const response = await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@ -139,6 +173,7 @@ export const useHandlePrivateApps = () => {
|
||||
},
|
||||
body: UintToObject?.app,
|
||||
});
|
||||
|
||||
const previewPath = await response.text();
|
||||
executeEvent('updateAppUrl', {
|
||||
tabId: tabId,
|
||||
@ -173,7 +208,9 @@ export const useHandlePrivateApps = () => {
|
||||
});
|
||||
setInfoSnackCustom({
|
||||
type: 'success',
|
||||
message: 'Opened',
|
||||
message: t('core:message.generic.opened', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
}),
|
||||
});
|
||||
if (setLoadingStatePrivateApp) {
|
||||
setLoadingStatePrivateApp(``);
|
||||
@ -206,7 +243,12 @@ export const useHandlePrivateApps = () => {
|
||||
} catch (error) {
|
||||
if (setLoadingStatePrivateApp) {
|
||||
setLoadingStatePrivateApp(
|
||||
`Error! ${error?.message || 'Unable to build private app.'}`
|
||||
`Error! ${
|
||||
error?.message ||
|
||||
t('core:message.error.unable_build_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
}`
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
@ -214,7 +256,11 @@ export const useHandlePrivateApps = () => {
|
||||
} catch (error) {
|
||||
setInfoSnackCustom({
|
||||
type: 'error',
|
||||
message: error?.message || 'Unable to fetch app',
|
||||
message:
|
||||
error?.message ||
|
||||
t('core:message.error.unable_fetch_app', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
}),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -168,157 +168,157 @@ export function openIndexedDB() {
|
||||
}
|
||||
|
||||
export const listOfAllQortalRequests = [
|
||||
'GET_USER_ACCOUNT',
|
||||
'DECRYPT_DATA',
|
||||
'SEND_COIN',
|
||||
'GET_LIST_ITEMS',
|
||||
'ADD_LIST_ITEMS',
|
||||
'DELETE_LIST_ITEM',
|
||||
'VOTE_ON_POLL',
|
||||
'CREATE_POLL',
|
||||
'SEND_CHAT_MESSAGE',
|
||||
'JOIN_GROUP',
|
||||
'DEPLOY_AT',
|
||||
'GET_USER_WALLET',
|
||||
'GET_WALLET_BALANCE',
|
||||
'GET_USER_WALLET_INFO',
|
||||
'GET_CROSSCHAIN_SERVER_INFO',
|
||||
'GET_TX_ACTIVITY_SUMMARY',
|
||||
'GET_FOREIGN_FEE',
|
||||
'UPDATE_FOREIGN_FEE',
|
||||
'GET_SERVER_CONNECTION_HISTORY',
|
||||
'SET_CURRENT_FOREIGN_SERVER',
|
||||
'ADD_FOREIGN_SERVER',
|
||||
'REMOVE_FOREIGN_SERVER',
|
||||
'GET_DAY_SUMMARY',
|
||||
'ADD_GROUP_ADMIN',
|
||||
'ADD_LIST_ITEMS',
|
||||
'ADMIN_ACTION',
|
||||
'BAN_FROM_GROUP',
|
||||
'BUY_NAME',
|
||||
'CANCEL_GROUP_BAN',
|
||||
'CANCEL_GROUP_INVITE',
|
||||
'CANCEL_SELL_NAME',
|
||||
'CANCEL_TRADE_SELL_ORDER',
|
||||
'CREATE_AND_COPY_EMBED_LINK',
|
||||
'CREATE_GROUP',
|
||||
'CREATE_POLL',
|
||||
'CREATE_TRADE_BUY_ORDER',
|
||||
'CREATE_TRADE_SELL_ORDER',
|
||||
'CANCEL_TRADE_SELL_ORDER',
|
||||
'IS_USING_PUBLIC_NODE',
|
||||
'ADMIN_ACTION',
|
||||
'SIGN_TRANSACTION',
|
||||
'OPEN_NEW_TAB',
|
||||
'CREATE_AND_COPY_EMBED_LINK',
|
||||
'DECRYPT_QORTAL_GROUP_DATA',
|
||||
'DECRYPT_AESGCM',
|
||||
'DECRYPT_DATA_WITH_SHARING_KEY',
|
||||
'DECRYPT_DATA',
|
||||
'DECRYPT_QORTAL_GROUP_DATA',
|
||||
'DELETE_HOSTED_DATA',
|
||||
'GET_HOSTED_DATA',
|
||||
'PUBLISH_MULTIPLE_QDN_RESOURCES',
|
||||
'PUBLISH_QDN_RESOURCE',
|
||||
'ENCRYPT_DATA',
|
||||
'DELETE_LIST_ITEM',
|
||||
'DEPLOY_AT',
|
||||
'ENCRYPT_DATA_WITH_SHARING_KEY',
|
||||
'ENCRYPT_DATA',
|
||||
'ENCRYPT_QORTAL_GROUP_DATA',
|
||||
'SAVE_FILE',
|
||||
'FETCH_BLOCK_RANGE',
|
||||
'FETCH_BLOCK',
|
||||
'FETCH_QDN_RESOURCE',
|
||||
'GET_ACCOUNT_DATA',
|
||||
'GET_ACCOUNT_NAMES',
|
||||
'SEARCH_NAMES',
|
||||
'GET_NAME_DATA',
|
||||
'GET_QDN_RESOURCE_URL',
|
||||
'LINK_TO_QDN_RESOURCE',
|
||||
'LIST_QDN_RESOURCES',
|
||||
'SEARCH_QDN_RESOURCES',
|
||||
'FETCH_QDN_RESOURCE',
|
||||
'GET_QDN_RESOURCE_STATUS',
|
||||
'GET_QDN_RESOURCE_PROPERTIES',
|
||||
'GET_QDN_RESOURCE_METADATA',
|
||||
'SEARCH_CHAT_MESSAGES',
|
||||
'LIST_GROUPS',
|
||||
'GET_BALANCE',
|
||||
'GET_AT',
|
||||
'GET_ARRR_SYNC_STATUS',
|
||||
'GET_AT_DATA',
|
||||
'LIST_ATS',
|
||||
'FETCH_BLOCK',
|
||||
'FETCH_BLOCK_RANGE',
|
||||
'SEARCH_TRANSACTIONS',
|
||||
'GET_PRICE',
|
||||
'SHOW_ACTIONS',
|
||||
'REGISTER_NAME',
|
||||
'UPDATE_NAME',
|
||||
'LEAVE_GROUP',
|
||||
'INVITE_TO_GROUP',
|
||||
'KICK_FROM_GROUP',
|
||||
'BAN_FROM_GROUP',
|
||||
'CANCEL_GROUP_BAN',
|
||||
'ADD_GROUP_ADMIN',
|
||||
'REMOVE_GROUP_ADMIN',
|
||||
'DECRYPT_AESGCM',
|
||||
'CANCEL_GROUP_INVITE',
|
||||
'CREATE_GROUP',
|
||||
'GET_USER_WALLET_TRANSACTIONS',
|
||||
'GET_AT',
|
||||
'GET_BALANCE',
|
||||
'GET_CROSSCHAIN_SERVER_INFO',
|
||||
'GET_DAY_SUMMARY',
|
||||
'GET_FOREIGN_FEE',
|
||||
'GET_HOSTED_DATA',
|
||||
'GET_LIST_ITEMS',
|
||||
'GET_NAME_DATA',
|
||||
'GET_NODE_INFO',
|
||||
'GET_NODE_STATUS',
|
||||
'GET_ARRR_SYNC_STATUS',
|
||||
'SHOW_PDF_READER',
|
||||
'UPDATE_GROUP',
|
||||
'SELL_NAME',
|
||||
'CANCEL_SELL_NAME',
|
||||
'BUY_NAME',
|
||||
'SIGN_FOREIGN_FEES',
|
||||
'GET_PRICE',
|
||||
'GET_QDN_RESOURCE_METADATA',
|
||||
'GET_QDN_RESOURCE_PROPERTIES',
|
||||
'GET_QDN_RESOURCE_STATUS',
|
||||
'GET_QDN_RESOURCE_URL',
|
||||
'GET_SERVER_CONNECTION_HISTORY',
|
||||
'GET_TX_ACTIVITY_SUMMARY',
|
||||
'GET_USER_ACCOUNT',
|
||||
'GET_USER_WALLET_INFO',
|
||||
'GET_USER_WALLET_TRANSACTIONS',
|
||||
'GET_USER_WALLET',
|
||||
'GET_WALLET_BALANCE',
|
||||
'INVITE_TO_GROUP',
|
||||
'IS_USING_PUBLIC_NODE',
|
||||
'JOIN_GROUP',
|
||||
'KICK_FROM_GROUP',
|
||||
'LEAVE_GROUP',
|
||||
'LINK_TO_QDN_RESOURCE',
|
||||
'LIST_ATS',
|
||||
'LIST_GROUPS',
|
||||
'LIST_QDN_RESOURCES',
|
||||
'MULTI_ASSET_PAYMENT_WITH_PRIVATE_DATA',
|
||||
'OPEN_NEW_TAB',
|
||||
'PUBLISH_MULTIPLE_QDN_RESOURCES',
|
||||
'PUBLISH_QDN_RESOURCE',
|
||||
'REGISTER_NAME',
|
||||
'REMOVE_FOREIGN_SERVER',
|
||||
'REMOVE_GROUP_ADMIN',
|
||||
'SAVE_FILE',
|
||||
'SEARCH_CHAT_MESSAGES',
|
||||
'SEARCH_NAMES',
|
||||
'SEARCH_QDN_RESOURCES',
|
||||
'SEARCH_TRANSACTIONS',
|
||||
'SELL_NAME',
|
||||
'SEND_CHAT_MESSAGE',
|
||||
'SEND_COIN',
|
||||
'SET_CURRENT_FOREIGN_SERVER',
|
||||
'SHOW_ACTIONS',
|
||||
'SHOW_PDF_READER',
|
||||
'SIGN_FOREIGN_FEES',
|
||||
'SIGN_TRANSACTION',
|
||||
'TRANSFER_ASSET',
|
||||
'UPDATE_FOREIGN_FEE',
|
||||
'UPDATE_GROUP',
|
||||
'UPDATE_NAME',
|
||||
'VOTE_ON_POLL',
|
||||
];
|
||||
|
||||
export const UIQortalRequests = [
|
||||
'GET_USER_ACCOUNT',
|
||||
'DECRYPT_DATA',
|
||||
'SEND_COIN',
|
||||
'GET_LIST_ITEMS',
|
||||
'ADD_LIST_ITEMS',
|
||||
'DELETE_LIST_ITEM',
|
||||
'VOTE_ON_POLL',
|
||||
'CREATE_POLL',
|
||||
'SEND_CHAT_MESSAGE',
|
||||
'JOIN_GROUP',
|
||||
'DEPLOY_AT',
|
||||
'GET_USER_WALLET',
|
||||
'GET_WALLET_BALANCE',
|
||||
'GET_USER_WALLET_INFO',
|
||||
'GET_CROSSCHAIN_SERVER_INFO',
|
||||
'GET_TX_ACTIVITY_SUMMARY',
|
||||
'GET_FOREIGN_FEE',
|
||||
'UPDATE_FOREIGN_FEE',
|
||||
'GET_SERVER_CONNECTION_HISTORY',
|
||||
'SET_CURRENT_FOREIGN_SERVER',
|
||||
'ADD_FOREIGN_SERVER',
|
||||
'REMOVE_FOREIGN_SERVER',
|
||||
'GET_DAY_SUMMARY',
|
||||
'ADD_GROUP_ADMIN',
|
||||
'ADD_LIST_ITEMS',
|
||||
'ADMIN_ACTION',
|
||||
'BAN_FROM_GROUP',
|
||||
'BUY_NAME',
|
||||
'CANCEL_GROUP_BAN',
|
||||
'CANCEL_GROUP_INVITE',
|
||||
'CANCEL_SELL_NAME',
|
||||
'CANCEL_TRADE_SELL_ORDER',
|
||||
'CREATE_AND_COPY_EMBED_LINK',
|
||||
'CREATE_GROUP',
|
||||
'CREATE_POLL',
|
||||
'CREATE_TRADE_BUY_ORDER',
|
||||
'CREATE_TRADE_SELL_ORDER',
|
||||
'CANCEL_TRADE_SELL_ORDER',
|
||||
'IS_USING_PUBLIC_NODE',
|
||||
'ADMIN_ACTION',
|
||||
'SIGN_TRANSACTION',
|
||||
'OPEN_NEW_TAB',
|
||||
'CREATE_AND_COPY_EMBED_LINK',
|
||||
'DECRYPT_QORTAL_GROUP_DATA',
|
||||
'DECRYPT_DATA_WITH_SHARING_KEY',
|
||||
'DELETE_HOSTED_DATA',
|
||||
'GET_HOSTED_DATA',
|
||||
'SHOW_ACTIONS',
|
||||
'REGISTER_NAME',
|
||||
'UPDATE_NAME',
|
||||
'LEAVE_GROUP',
|
||||
'INVITE_TO_GROUP',
|
||||
'KICK_FROM_GROUP',
|
||||
'BAN_FROM_GROUP',
|
||||
'CANCEL_GROUP_BAN',
|
||||
'ADD_GROUP_ADMIN',
|
||||
'REMOVE_GROUP_ADMIN',
|
||||
'DECRYPT_AESGCM',
|
||||
'CANCEL_GROUP_INVITE',
|
||||
'CREATE_GROUP',
|
||||
'GET_USER_WALLET_TRANSACTIONS',
|
||||
'DECRYPT_DATA_WITH_SHARING_KEY',
|
||||
'DECRYPT_DATA',
|
||||
'DECRYPT_QORTAL_GROUP_DATA',
|
||||
'DELETE_HOSTED_DATA',
|
||||
'DELETE_LIST_ITEM',
|
||||
'DEPLOY_AT',
|
||||
'GET_ARRR_SYNC_STATUS',
|
||||
'GET_CROSSCHAIN_SERVER_INFO',
|
||||
'GET_DAY_SUMMARY',
|
||||
'GET_FOREIGN_FEE',
|
||||
'GET_HOSTED_DATA',
|
||||
'GET_LIST_ITEMS',
|
||||
'GET_NODE_INFO',
|
||||
'GET_NODE_STATUS',
|
||||
'GET_ARRR_SYNC_STATUS',
|
||||
'SHOW_PDF_READER',
|
||||
'UPDATE_GROUP',
|
||||
'SELL_NAME',
|
||||
'CANCEL_SELL_NAME',
|
||||
'BUY_NAME',
|
||||
'SIGN_FOREIGN_FEES',
|
||||
'GET_SERVER_CONNECTION_HISTORY',
|
||||
'GET_TX_ACTIVITY_SUMMARY',
|
||||
'GET_USER_ACCOUNT',
|
||||
'GET_USER_WALLET_INFO',
|
||||
'GET_USER_WALLET_TRANSACTIONS',
|
||||
'GET_USER_WALLET',
|
||||
'GET_WALLET_BALANCE',
|
||||
'INVITE_TO_GROUP',
|
||||
'IS_USING_PUBLIC_NODE',
|
||||
'JOIN_GROUP',
|
||||
'KICK_FROM_GROUP',
|
||||
'LEAVE_GROUP',
|
||||
'MULTI_ASSET_PAYMENT_WITH_PRIVATE_DATA',
|
||||
'OPEN_NEW_TAB',
|
||||
'REGISTER_NAME',
|
||||
'REMOVE_FOREIGN_SERVER',
|
||||
'REMOVE_GROUP_ADMIN',
|
||||
'SELL_NAME',
|
||||
'SEND_CHAT_MESSAGE',
|
||||
'SEND_COIN',
|
||||
'SET_CURRENT_FOREIGN_SERVER',
|
||||
'SHOW_ACTIONS',
|
||||
'SHOW_PDF_READER',
|
||||
'SIGN_FOREIGN_FEES',
|
||||
'SIGN_TRANSACTION',
|
||||
'TRANSFER_ASSET',
|
||||
'UPDATE_FOREIGN_FEE',
|
||||
'UPDATE_GROUP',
|
||||
'UPDATE_NAME',
|
||||
'VOTE_ON_POLL',
|
||||
];
|
||||
|
||||
async function retrieveFileFromIndexedDB(fileId) {
|
||||
@ -658,7 +658,7 @@ export const useQortalMessageListener = (
|
||||
setPath(pathUrl);
|
||||
if (appName?.toLowerCase() === 'q-mail') {
|
||||
window.sendMessage('addEnteredQmailTimestamp').catch((error) => {
|
||||
// error
|
||||
// TODO print error
|
||||
});
|
||||
} else if (appName?.toLowerCase() === 'q-wallets') {
|
||||
executeEvent('setLastEnteredTimestampPaymentEvent', {});
|
||||
|
@ -11,17 +11,32 @@
|
||||
"seed_phrase": "add seed-phrase"
|
||||
},
|
||||
"authenticate": "authenticate",
|
||||
"block": "block",
|
||||
"block_all": "block all",
|
||||
"block_data": "block QDN data",
|
||||
"block_name": "block name",
|
||||
"block_txs": "block tsx",
|
||||
"fetch_names": "fetch names",
|
||||
"copy_address": "copy address",
|
||||
"create_account": "create account",
|
||||
"create_qortal_account": "create your Qortal account by clicking <next>NEXT</next> below.",
|
||||
"choose_password": "choose new password",
|
||||
"download_account": "download account",
|
||||
"enter_amount": "please enter an amount greater than 0",
|
||||
"enter_recipient": "please enter a recipient",
|
||||
"enter_wallet_password": "please enter your wallet password",
|
||||
"export_seedphrase": "export Seedphrase",
|
||||
"insert_name_address": "please insert a name or address",
|
||||
"publish_admin_secret_key": "publish admin secret key",
|
||||
"publish_group_secret_key": "publish group secret key",
|
||||
"reencrypt_key": "re-encrypt key",
|
||||
"return_to_list": "return to list",
|
||||
"setup_qortal_account": "set up your Qortal account"
|
||||
"setup_qortal_account": "set up your Qortal account",
|
||||
"unblock": "unblock",
|
||||
"unblock_name": "unblock name"
|
||||
},
|
||||
"address": "address",
|
||||
"address_name": "address or name",
|
||||
"advanced_users": "for advanced users",
|
||||
"apikey": {
|
||||
"alternative": "alternative: File select",
|
||||
@ -31,19 +46,29 @@
|
||||
"key": "API key",
|
||||
"select_valid": "select a valid apikey"
|
||||
},
|
||||
"blocked_users": "blocked users",
|
||||
"build_version": "build version",
|
||||
"message": {
|
||||
"error": {
|
||||
"account_creation": "could not create account.",
|
||||
"address_not_existing": "address does not exist on blockchain",
|
||||
"decrypt_data": "could not decrypt data",
|
||||
"field_not_found_json": "{{ field }} not found in JSON",
|
||||
"incorrect_password": "incorrect password",
|
||||
"invalid_secret_key": "secretKey is not valid",
|
||||
"name_not_existing": "name does not exist",
|
||||
"name_not_registered": "name not registered",
|
||||
"unable_block_user": "unable to block user",
|
||||
"unable_decrypt": "unable to decrypt",
|
||||
"unable_reencrypt_secret_key": "unable to re-encrypt secret key"
|
||||
},
|
||||
"generic": {
|
||||
"blocked_addresses": "blocked addresses- blocks processing of txs",
|
||||
"blocked_names": "blocked names for QDN",
|
||||
"blocking": "blocking {{ name }}",
|
||||
"choose_block": "choose 'block txs' or 'all' to block chat messages",
|
||||
"congrats_setup": "congrats, you’re all set up!",
|
||||
"decide_block": "decide what to block",
|
||||
"no_account": "no accounts saved",
|
||||
"no_minimum_length": "there is no minimum length requirement",
|
||||
"no_secret_key_published": "no secret key published yet",
|
||||
|
@ -70,6 +70,8 @@
|
||||
"select_app_type": "select App Type",
|
||||
"select_category": "select Category",
|
||||
"select_name_app": "select Name/App",
|
||||
"send": "send",
|
||||
"send_qort": "send QORT",
|
||||
"set_avatar": "set avatar",
|
||||
"show": "show",
|
||||
"show_poll": "show poll",
|
||||
@ -86,6 +88,7 @@
|
||||
"admin": "admin",
|
||||
"admin_other": "admins",
|
||||
"all": "all",
|
||||
"amount": "amount",
|
||||
"announcement": "announcement",
|
||||
"announcement_other": "announcements",
|
||||
"api": "API",
|
||||
@ -96,6 +99,7 @@
|
||||
"apps_dashboard": "apps Dashboard",
|
||||
"apps_official": "official Apps",
|
||||
"attachment": "attachment",
|
||||
"balance": "balance:",
|
||||
"category": "category",
|
||||
"category_other": "categories",
|
||||
"chat": "chat",
|
||||
@ -169,8 +173,12 @@
|
||||
"rating_option": "cannot find rating option",
|
||||
"save_qdn": "unable to save to QDN",
|
||||
"send_failed": "failed to send",
|
||||
"unable_build_app": "unable to build private app",
|
||||
"unable_download_image": "unable to download IMAGE. Please try again later by clicking the refresh button",
|
||||
"unable_download_private_app": "unable to download private app",
|
||||
"unable_decrypt_app": "unable to decrypt private app'",
|
||||
"unable_encrypt_app": "unable to encrypt app. App not published'",
|
||||
"unable_fetch_app": "unable to fetch app",
|
||||
"unable_publish_app": "unable to publish app",
|
||||
"unable_publish_image": "unable to publish image",
|
||||
"unable_rate": "unable to rate",
|
||||
@ -181,19 +189,23 @@
|
||||
"already_voted": "you've already voted.",
|
||||
"avatar_size": "{{ size }} KB max. for GIFS",
|
||||
"building": "building",
|
||||
"building_app": "building app",
|
||||
"created_by": "created by {{ owner }}",
|
||||
"buy_order_request": "the Application <br/><italic>{{hostname}}</italic> <br/><span>is requesting {{count}} buy order</span>",
|
||||
"buy_order_request_other": "the Application <br/><italic>{{hostname}}</italic> <br/><span>is requesting {{count}} buy orders</span>",
|
||||
"devmode_local_node": "please use your local node for dev mode! Logout and use Local node.",
|
||||
"downloading": "downloading",
|
||||
"downloading_decrypting_app": "downloading and decrypting private app.",
|
||||
"edited": "edited",
|
||||
"editing_message": "editing message",
|
||||
"encrypted": "encrypted",
|
||||
"encrypted_not": "not encrypted",
|
||||
"fee_qort": "fee: {{ message }} QORT",
|
||||
"fetching_data": "fetching app data",
|
||||
"foreign_fee": "foreign fee: {{ message }}",
|
||||
"mentioned": "mentioned",
|
||||
"message_with_image": "this message already has an image",
|
||||
"most_recent_payment": "{{ count }} most recent payment",
|
||||
"name_available": "{{ name }} is available",
|
||||
"name_benefits": "benefits of a name",
|
||||
"name_checking": "checking if name already exists",
|
||||
@ -207,9 +219,11 @@
|
||||
"no_messages": "no messages",
|
||||
"no_minting_details": "cannot view minting details on the gateway",
|
||||
"no_notifications": "no new notifications",
|
||||
"no_payments": "no payments",
|
||||
"no_pinned_changes": "you currently do not have any changes to your pinned apps",
|
||||
"no_results": "no results",
|
||||
"one_app_per_name": "note: Currently, only one App and Website is allowed per Name.",
|
||||
"opened": "opened",
|
||||
"overwrite_qdn": "overwrite to QDN",
|
||||
"password_confirm": "please confirm a password",
|
||||
"password_enter": "please enter a password",
|
||||
@ -236,6 +250,7 @@
|
||||
"unsaved_changes": "you have unsaved changes to your pinned apps. Save them to QDN.",
|
||||
"updating": "updating"
|
||||
},
|
||||
"message": "message",
|
||||
"question": {
|
||||
"accept_vote_on_poll": "do you accept this VOTE_ON_POLL transaction? POLLS are public!",
|
||||
"logout": "are you sure you would like to logout?",
|
||||
@ -250,7 +265,8 @@
|
||||
"rate_app": "would you like to rate this app a rating of {{ rate }}?. It will create a POLL tx.",
|
||||
"register_name": "would you like to register this name?",
|
||||
"reset_pinned": "don't like your current local changes? Would you like to reset to the default pinned apps?",
|
||||
"reset_qdn": "don't like your current local changes? Would you like to reset to your saved QDN pinned apps?"
|
||||
"reset_qdn": "don't like your current local changes? Would you like to reset to your saved QDN pinned apps?",
|
||||
"transfer_qort": "would you like to transfer {{ amount }} QORT"
|
||||
},
|
||||
"status": {
|
||||
"minting": "(minting)",
|
||||
@ -271,6 +287,7 @@
|
||||
"minting_status": "minting status",
|
||||
"name": "name",
|
||||
"name_app": "name/App",
|
||||
"new_post_in": "new post in {{ title }}",
|
||||
"none": "none",
|
||||
"option": "option",
|
||||
"option_other": "options",
|
||||
@ -288,8 +305,11 @@
|
||||
"about": "about this Q-App",
|
||||
"q_mail": "q-mail",
|
||||
"q_manager": "q-manager",
|
||||
"q_sandbox": "q-Sandbox"
|
||||
"q_sandbox": "q-Sandbox",
|
||||
"q_wallets": "q-Wallets"
|
||||
},
|
||||
"receiver": "receiver",
|
||||
"sender": "sender",
|
||||
"server": "server",
|
||||
"settings": "settings",
|
||||
"sort": {
|
||||
@ -309,9 +329,11 @@
|
||||
"hour_one": "{{count}} hour",
|
||||
"hour_other": "{{count}} hours",
|
||||
"minute_one": "{{count}} minute",
|
||||
"minute_other": "{{count}} minutes"
|
||||
"minute_other": "{{count}} minutes",
|
||||
"time": "time"
|
||||
},
|
||||
"title": "title",
|
||||
"to": "to",
|
||||
"tutorial": "tutorial",
|
||||
"user_lookup": "user lookup",
|
||||
"vote": "vote",
|
||||
|
@ -99,6 +99,7 @@
|
||||
"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_private_groups": "only private groups will be shown",
|
||||
"pending_join_requests": "{{ group }} has {{ count }} pending join requests",
|
||||
"private_key_copied": "private key copied",
|
||||
"provide_message": "please provide a first message to the thread",
|
||||
"secure_place": "keep your private key in a secure place. Do not share!",
|
||||
|
Loading…
x
Reference in New Issue
Block a user