diff --git a/src/App.tsx b/src/App.tsx index 90db808..feb0d66 100644 --- a/src/App.tsx +++ b/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', + })} } placement="left" diff --git a/src/components/Apps/TabComponent.tsx b/src/components/Apps/TabComponent.tsx index 2558a9f..a7584c0 100644 --- a/src/components/Apps/TabComponent.tsx +++ b/src/components/Apps/TabComponent.tsx @@ -40,6 +40,7 @@ const TabComponent = ({ isSelected, app }) => { }} /> )} + {app?.isPrivate && !app?.privateAppProperties?.logo ? ( @@ -55,8 +55,8 @@ export const DesktopSideBar = ({ { goToHome(); diff --git a/src/components/Group/AddGroup.tsx b/src/components/Group/AddGroup.tsx index 2a83e5a..53fc1c9 100644 --- a/src/components/Group/AddGroup.tsx +++ b/src/components/Group/AddGroup.tsx @@ -593,6 +593,7 @@ export const AddGroup = ({ address, open, setOpen }) => { )} + {value === 1 && ( { 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: 'capitalizeFirst', + }), }); setOpenSnack(true); rej(error); @@ -248,10 +250,14 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => { })}{' '} {group?.groupName} + {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', + })} + { + handlePopoverOpen(event, index)} > @@ -274,6 +281,7 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => { }} /> )} + {group?.isOpen === true && ( { }} /> )} + + { 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: 'capitalizeFirst', + }) + ); if (data?.owner) { userAddress = data.owner; userName = valUser; diff --git a/src/components/Group/Forum/GroupMail.tsx b/src/components/Group/Forum/GroupMail.tsx index 3e0783c..afa6e91 100644 --- a/src/components/Group/Forum/GroupMail.tsx +++ b/src/components/Group/Forum/GroupMail.tsx @@ -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(null); - const firstMount = useRef(false); const filterModeRef = useRef(''); @@ -575,6 +575,7 @@ export const GroupMail = ({ }} > + {filterOptions?.map((filter) => { return ( @@ -796,6 +797,7 @@ export const GroupMail = ({ postProcess: 'capitalizeFirstChar', })} + { return ( { {formatTimestampForum(message?.created)} +
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 = ({ })} + {/* Conditionally render the scroll buttons */} {showScrollButton && (isAtBottom ? ( diff --git a/src/components/MainAvatar.tsx b/src/components/MainAvatar.tsx index 6058558..d81c029 100644 --- a/src/components/MainAvatar.tsx +++ b/src/components/MainAvatar.tsx @@ -68,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', { @@ -93,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: 'capitalizeFirst', + }) + ); }); }); setAvatarFile(null); @@ -125,6 +140,7 @@ export const MainAvatar = ({ myName, balance, setOpenSnack, setInfoSnack }) => { > {myName?.charAt(0)} + { opacity: 0.5, }} > - change avatar + {t('core:action.change_avatar', { + postProcess: 'capitalizeFirstChar', + })} + { > {myName?.charAt(0)} + { opacity: 0.5, }} > - change avatar + {t('core:action.change_avatar', { + postProcess: 'capitalizeFirstChar', + })} + { opacity: 0.5, }} > - set avatar + {t('core:action.set_avatar', { postProcess: 'capitalizeFirstChar' })} + { ); }; +// TODO the following part is the same as in GroupAvatar.tsx const PopoverComp = ({ avatarFile, setAvatarFile, @@ -228,6 +253,8 @@ const PopoverComp = ({ myName, }) => { const theme = useTheme(); + const { t } = useTranslation(['auth', 'core', 'group']); + return ( - (500 KB max. for GIFS){' '} + {t('core:message.generic.avatar_size', { + size: 500, // TODO magic number + postProcess: 'capitalizeFirstChar', + })} + setAvatarFile(file)}> - + + {avatarFile?.name} + + {!myName && ( - A registered name is required to set an avatar + {t('core:message.generic.avatar_registered_name', { + postProcess: 'capitalizeFirstChar', + })} )} + - Publish avatar + {t('group:action.publish_avatar', { + postProcess: 'capitalizeFirstChar', + })} diff --git a/src/components/UserLookup.tsx/UserLookup.tsx b/src/components/UserLookup.tsx/UserLookup.tsx index ee0b8c9..b1bf858 100644 --- a/src/components/UserLookup.tsx/UserLookup.tsx +++ b/src/components/UserLookup.tsx/UserLookup.tsx @@ -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: 'capitalizeFirst', + }) + ); + 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: 'capitalizeFirst', + }) + ); 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: 'capitalizeFirst', + }) + ); } 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: 'capitalizeFirst', + })} onKeyDown={(e) => { if (e.key === 'Enter' && nameOrAddress) { lookupFunc(inputValue); @@ -200,6 +218,7 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { /> + { {errorMessage} )} + {isLoadingUser && ( { /> )} + {!isLoadingUser && addressInfo && ( <> @@ -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: 'capitalizeFirst', + })} @@ -307,7 +331,8 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { textAlign: 'center', }} > - Level {addressInfo?.level} + {t('core:level', { postProcess: 'capitalizeFirst' })}{' '} + {addressInfo?.level} @@ -336,8 +361,11 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { flexShrink: 0, }} > - Address + + {t('auth:address', { postProcess: 'capitalizeFirst' })} + + { fontWeight: 700, }} > - copy address + {t('auth:action.copy_address', { + postProcess: 'capitalizeFirst', + })} } placement="bottom" @@ -391,7 +421,10 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { width: '100%', }} > - Balance + + {t('core:balance', { postProcess: 'capitalizeFirst' })} + + {addressInfo?.balance} @@ -406,7 +439,9 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { }); }} > - Send QORT + {t('core:action.send_qort', { + postProcess: 'capitalizeFirst', + })} @@ -440,7 +475,12 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { padding: '15px', }} > - 20 most recent payments + + {t('core:message.generic.most_recent_payment', { + count: 20, + postProcess: 'capitalizeFirst', + })} + @@ -452,17 +492,29 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { width: '100%', }} > - No payments + + {t('core:message.generic.no_payments', { + postProcess: 'capitalizeFirst', + })} + )} - Sender - Reciver - Amount - Time + + {t('core:sender', { postProcess: 'capitalizeFirst' })} + + + {t('core:receiver', { postProcess: 'capitalizeFirst' })} + + + {t('core:amount', { postProcess: 'capitalizeFirst' })} + + + {t('core:time', { postProcess: 'capitalizeFirst' })} + @@ -479,7 +531,9 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { fontWeight: 700, }} > - copy address + {t('auth:action.copy_address', { + postProcess: 'capitalizeFirst', + })} } placement="bottom" @@ -522,7 +576,9 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { fontWeight: 700, }} > - copy address + {t('auth:action.copy_address', { + postProcess: 'capitalizeFirst', + })} } placement="bottom" @@ -552,7 +608,9 @@ export const UserLookup = ({ isOpenDrawerLookup, setIsOpenDrawerLookup }) => { + {payment?.amount} + {formatTimestamp(payment?.timestamp)} diff --git a/src/components/WrapperUserAction.tsx b/src/components/WrapperUserAction.tsx index 07b5d45..afcb686 100644 --- a/src/components/WrapperUserAction.tsx +++ b/src/components/WrapperUserAction.tsx @@ -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: 'capitalizeFirst' })} {/* 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: 'capitalizeFirst', + })} + + {!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) && ( )} - {isAlreadyBlocked && 'Unblock name'} - {isAlreadyBlocked === false && 'Block name'} + {isAlreadyBlocked && + t('core:action.unblock_name', { postProcess: 'capitalizeFirst' })} + {isAlreadyBlocked === false && t('core:action.block_name', { postProcess: 'capitalizeFirst' })}} ); }; diff --git a/src/i18n/locales/en/auth.json b/src/i18n/locales/en/auth.json index a62b460..a1dca21 100644 --- a/src/i18n/locales/en/auth.json +++ b/src/i18n/locales/en/auth.json @@ -11,17 +11,21 @@ "seed_phrase": "add seed-phrase" }, "authenticate": "authenticate", + "copy_address": "copy address", "create_account": "create account", "create_qortal_account": "create your Qortal account by clicking NEXT below.", "choose_password": "choose new password", "download_account": "download account", "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" }, + "address": "address", + "address_name": "address or name", "advanced_users": "for advanced users", "apikey": { "alternative": "alternative: File select", @@ -35,10 +39,13 @@ "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_decrypt": "unable to decrypt", "unable_reencrypt_secret_key": "unable to re-encrypt secret key" }, diff --git a/src/i18n/locales/en/core.json b/src/i18n/locales/en/core.json index ba9d509..d91851d 100644 --- a/src/i18n/locales/en/core.json +++ b/src/i18n/locales/en/core.json @@ -8,6 +8,7 @@ "access_app": "access app", "backup_account": "backup account", "backup_wallet": "backup wallet", + "block_name": "block name", "cancel": "cancel", "cancel_invitation": "cancel invitation", "change": "change", @@ -70,12 +71,14 @@ "select_app_type": "select App Type", "select_category": "select Category", "select_name_app": "select Name/App", + "send_qort": "send QORT", "set_avatar": "set avatar", "show": "show", "show_poll": "show poll", "start_minting": "start minting", "start_typing": "start typing here...", "transfer_qort": "Transfer QORT", + "unblock_name": "unblock name", "unpin": "unpin", "unpin_app": "unpin app", "unpin_from_dashboard": "unpin from dashboard", @@ -86,6 +89,7 @@ "admin": "admin", "admin_other": "admins", "all": "all", + "amount": "amount", "announcement": "announcement", "announcement_other": "announcements", "api": "API", @@ -96,6 +100,7 @@ "apps_dashboard": "apps Dashboard", "apps_official": "official Apps", "attachment": "attachment", + "balance": "balance", "category": "category", "category_other": "categories", "chat": "chat", @@ -194,6 +199,7 @@ "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,6 +213,7 @@ "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.", @@ -236,6 +243,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?", @@ -290,6 +298,8 @@ "q_manager": "q-manager", "q_sandbox": "q-Sandbox" }, + "receiver": "receiver", + "sender": "sender", "server": "server", "settings": "settings", "sort": { @@ -311,6 +321,7 @@ "minute_one": "{{count}} minute", "minute_other": "{{count}} minutes" }, + "time": "time", "title": "title", "tutorial": "tutorial", "user_lookup": "user lookup",