From 5f602442e407b3d710f8eb9a8ac3f2008f79513b Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Sat, 10 May 2025 11:22:15 +0200 Subject: [PATCH] Add translations --- public/locales/en/core.json | 6 +- public/locales/en/group.json | 6 +- src/components/Group/Group.tsx | 77 +++++++++---------- .../Group/ListOfGroupPromotions.tsx | 8 +- src/components/Group/ListOfInvites.tsx | 27 +++++-- src/components/Group/ListOfJoinRequests.tsx | 42 ++++++---- src/components/Group/Settings.tsx | 5 +- src/components/Group/UserListOfInvites.tsx | 2 +- 8 files changed, 104 insertions(+), 69 deletions(-) diff --git a/public/locales/en/core.json b/public/locales/en/core.json index 5e3295d..6bb7421 100644 --- a/public/locales/en/core.json +++ b/public/locales/en/core.json @@ -5,6 +5,7 @@ "backup_account": "backup account", "backup_wallet": "backup wallet", "cancel": "cancel", + "cancel_invitation": "cancel invitation", "change": "change", "change_language": "change language", "choose": "choose", @@ -48,8 +49,11 @@ "publish": "publish fee" }, "general_settings": "general settings", - "invite_list": "invite list", "last_height": "last height", + "list": { + "invite": "invite list", + "join_request": "join request list" + }, "loading": "loading...", "loading_posts": "loading posts... please wait.", "message_us": "please message us on Telegram or Discord if you need 4 QORT to start chatting without any limitations", diff --git a/public/locales/en/group.json b/public/locales/en/group.json index 713fa9c..33c8523 100644 --- a/public/locales/en/group.json +++ b/public/locales/en/group.json @@ -31,6 +31,7 @@ "type": "group type" }, "invitation_expiry": "invitation Expiry Time", + "invitees_list": "invitees list", "join_requests": "join requests", "question": { "perform_transaction": "would you like to perform a {{action}} transaction?", @@ -72,10 +73,13 @@ "group_join_label": "joined group {{name}}: success!", "group_join_request": "requested to join Group {{group_name}}: awaiting confirmation", "group_join_outcome": "requested to join Group {{group_name}}: success!", + "invitation_cancellation": "successfully canceled invitation. It may take a couple of minutes for the changes to propagate", + "invitation_request": "accepted join request: awaiting confirmation", "loading_threads": "loading threads... please wait.", "post_creation": "successfully created post. It may take some time for the publish to propagate", "thread_creation": "successfully created thread. It may take some time for the publish to propagate", - "unbanned_user": "successfully unbanned user. It may take a couple of minutes for the changes to propagate" + "unbanned_user": "successfully unbanned user. It may take a couple of minutes for the changes to propagate", + "user_joined": "user successfully joined!" } } } diff --git a/src/components/Group/Group.tsx b/src/components/Group/Group.tsx index 2f2a314..a7e330d 100644 --- a/src/components/Group/Group.tsx +++ b/src/components/Group/Group.tsx @@ -9,20 +9,12 @@ import { Typography, useTheme, } from '@mui/material'; -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { ChatGroup } from '../Chat/ChatGroup'; import { CreateCommonSecret } from '../Chat/CreateCommonSecret'; import { base64ToUint8Array } from '../../qdn/encryption/group-encryption'; import { uint8ArrayToObject } from '../../backgroundFunctions/encryption'; -import CampaignIcon from '@mui/icons-material/Campaign'; import { AddGroup } from './AddGroup'; -import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; import CreateIcon from '@mui/icons-material/Create'; import { AuthenticatedContainerInnerRight, @@ -52,7 +44,6 @@ import { import { RequestQueueWithPromise } from '../../utils/queue/queue'; import { WebSocketActive } from './WebsocketActive'; import { useMessageQueue } from '../../MessageQueueContext'; -import { ContextMenu } from '../ContextMenu'; import { HomeDesktop } from './HomeDesktop'; import { IconWrapper } from '../Desktop/DesktopFooter'; import { DesktopHeader } from '../Desktop/DesktopHeader'; @@ -63,7 +54,6 @@ import { HubsIcon } from '../../assets/Icons/HubsIcon'; import { MessagingIcon } from '../../assets/Icons/MessagingIcon'; import { formatEmailDate } from './QMailMessages'; import { AdminSpace } from '../Chat/AdminSpace'; - import { addressInfoControllerAtom, groupAnnouncementsAtom, @@ -77,9 +67,6 @@ import { timestampEnterDataAtom, } from '../../atoms/global'; import { sortArrayByTimestampAndGroupName } from '../../utils/time'; -import PersonOffIcon from '@mui/icons-material/PersonOff'; -import LockIcon from '@mui/icons-material/Lock'; -import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred'; import { BlockedUsersModal } from './BlockedUsersModal'; import { WalletsAppWrapper } from './WalletsAppWrapper'; import { useTranslation } from 'react-i18next'; @@ -92,6 +79,7 @@ export const getPublishesFromAdmins = async (admins: string[], groupId) => { groupId }&exactmatchnames=true&limit=0&reverse=true&${queryString}&prefix=true`; const response = await fetch(url); + if (!response.ok) { throw new Error('network error'); } @@ -100,9 +88,11 @@ export const getPublishesFromAdmins = async (admins: string[], groupId) => { const filterId = adminData.filter( (data: any) => data.identifier === `symmetric-qchat-group-${groupId}` ); + if (filterId?.length === 0) { return false; } + const sortedData = filterId.sort((a: any, b: any) => { // Get the most recent date for both a and b const dateA = a.updated ? new Date(a.updated) : new Date(a.created); @@ -114,24 +104,18 @@ export const getPublishesFromAdmins = async (admins: string[], groupId) => { return sortedData[0]; }; - interface GroupProps { - myAddress: string; - isFocused: boolean; - userInfo: any; balance: number; + isFocused: boolean; + myAddress: string; + userInfo: any; } export const timeDifferenceForNotificationChats = 900000; - export const requestQueueMemberNames = new RequestQueueWithPromise(5); export const requestQueueAdminMemberNames = new RequestQueueWithPromise(5); -// const audio = new Audio(chrome.runtime?.getURL("msg-not1.wav")); - export const getGroupAdminsAddress = async (groupNumber: number) => { - // const validApi = await findUsableApi(); - const response = await fetch( `${getBaseApiReact()}/groups/members/${groupNumber}?limit=0&onlyAdmins=true` ); @@ -422,27 +406,24 @@ export const Group = ({ const [chatMode, setChatMode] = useState('groups'); const [newChat, setNewChat] = useState(false); - const [openSnack, setOpenSnack] = React.useState(false); - const [infoSnack, setInfoSnack] = React.useState(null); - const [isLoadingNotifyAdmin, setIsLoadingNotifyAdmin] = React.useState(false); - const [isLoadingGroups, setIsLoadingGroups] = React.useState(true); - const [isLoadingGroup, setIsLoadingGroup] = React.useState(false); + const [openSnack, setOpenSnack] = useState(false); + const [infoSnack, setInfoSnack] = useState(null); + const [isLoadingNotifyAdmin, setIsLoadingNotifyAdmin] = useState(false); + const [isLoadingGroups, setIsLoadingGroups] = useState(true); + const [isLoadingGroup, setIsLoadingGroup] = useState(false); const [firstSecretKeyInCreation, setFirstSecretKeyInCreation] = - React.useState(false); - const [groupSection, setGroupSection] = React.useState('home'); + useState(false); + const [groupSection, setGroupSection] = useState('home'); const [groupAnnouncements, setGroupAnnouncements] = useAtom( groupAnnouncementsAtom ); - - const [defaultThread, setDefaultThread] = React.useState(null); - const [isOpenDrawer, setIsOpenDrawer] = React.useState(false); + const [defaultThread, setDefaultThread] = useState(null); + const [isOpenDrawer, setIsOpenDrawer] = useState(false); const setIsOpenBlockedUserModal = useSetAtom(isOpenBlockedModalAtom); - - const [hideCommonKeyPopup, setHideCommonKeyPopup] = React.useState(false); - const [isLoadingGroupMessage, setIsLoadingGroupMessage] = React.useState(''); - const [drawerMode, setDrawerMode] = React.useState('groups'); + const [hideCommonKeyPopup, setHideCommonKeyPopup] = useState(false); + const [isLoadingGroupMessage, setIsLoadingGroupMessage] = useState(''); + const [drawerMode, setDrawerMode] = useState('groups'); const setMutedGroups = useSetAtom(mutedGroupsAtom); - const [mobileViewMode, setMobileViewMode] = useState('home'); const [mobileViewModeKeepOpen, setMobileViewModeKeepOpen] = useState(''); const isFocusedRef = useRef(true); @@ -531,7 +512,10 @@ export const Group = ({ rej(response.error); }) .catch((error) => { - rej(error.message || 'An error occurred'); + rej( + error.message || + t('core:message.error.generic', { postProcess: 'capitalize' }) + ); }); }); } catch (error) { @@ -557,7 +541,10 @@ export const Group = ({ rej(response.error); }) .catch((error) => { - rej(error.message || 'An error occurred'); + rej( + error.message || + t('core:message.error.generic', { postProcess: 'capitalize' }) + ); }); }); } catch (error) { @@ -586,7 +573,10 @@ export const Group = ({ rej(response.error); }) .catch((error) => { - rej(error.message || 'An error occurred'); + rej( + error.message || + t('core:message.error.generic', { postProcess: 'capitalize' }) + ); }); }); } catch (error) { @@ -1106,7 +1096,10 @@ export const Group = ({ rej(response.error); }) .catch((error) => { - rej(error.message || 'An error occurred'); + rej( + error.message || + t('core:message.error.generic', { postProcess: 'capitalize' }) + ); }); }); setInfoSnack({ diff --git a/src/components/Group/ListOfGroupPromotions.tsx b/src/components/Group/ListOfGroupPromotions.tsx index b32d433..7c31a85 100644 --- a/src/components/Group/ListOfGroupPromotions.tsx +++ b/src/components/Group/ListOfGroupPromotions.tsx @@ -140,6 +140,7 @@ export const ListOfGroupPromotions = () => { let data: any[] = []; const uniqueGroupIds = new Set(); const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000; + const getPromos = responseData?.map(async (promo: any) => { if (promo?.size < 200 && promo.created > oneWeekAgo) { const name = await requestQueuePromos.enqueue(async () => { @@ -241,9 +242,12 @@ export const ListOfGroupPromotions = () => { rej(response.error); }) .catch((error) => { - rej(error.message || 'An error occurred'); + rej( + error.message || + t('core:message.error.generic', { postProcess: 'capitalize' }) + ); }); - }); // TODO translate + }); setInfoSnack({ type: 'success', message: diff --git a/src/components/Group/ListOfInvites.tsx b/src/components/Group/ListOfInvites.tsx index 91f6c75..50b3424 100644 --- a/src/components/Group/ListOfInvites.tsx +++ b/src/components/Group/ListOfInvites.tsx @@ -61,7 +61,7 @@ export const ListOfInvites = ({ const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open const [isLoadingCancelInvite, setIsLoadingCancelInvite] = useState(false); const { t } = useTranslation(['core', 'group']); - const listRef = useRef(); + const listRef = useRef(null); const getInvites = async (groupId) => { try { @@ -91,7 +91,6 @@ export const ListOfInvites = ({ const handleCancelInvitation = async (address) => { try { - // TODO translate const fee = await getFee('CANCEL_GROUP_INVITE'); await show({ @@ -101,7 +100,9 @@ export const ListOfInvites = ({ }), publishFee: fee.fee + ' QORT', }); + setIsLoadingCancelInvite(true); + await new Promise((res, rej) => { window .sendMessage('cancelInvitationToGroup', { @@ -112,8 +113,9 @@ export const ListOfInvites = ({ if (!response?.error) { setInfoSnack({ type: 'success', - message: - 'Successfully canceled invitation. It may take a couple of minutes for the changes to propagate', + message: t('group:message.success.invitation_cancellation', { + postProcess: 'capitalize', + }), }); setOpenSnack(true); handlePopoverClose(); @@ -131,7 +133,11 @@ export const ListOfInvites = ({ .catch((error) => { setInfoSnack({ type: 'error', - message: error.message || 'An error occurred', + message: + error.message || + t('core:message.error.generic', { + postProcess: 'capitalize', + }), }); setOpenSnack(true); rej(error); @@ -189,7 +195,9 @@ export const ListOfInvites = ({ variant="contained" onClick={() => handleCancelInvitation(member?.invitee)} > - Cancel Invitation + {t('core:action.cancel_invitation', { + postProcess: 'capitalize', + })} @@ -207,6 +215,7 @@ export const ListOfInvites = ({ } /> + @@ -218,7 +227,11 @@ export const ListOfInvites = ({ return (
-

Invitees list

+

+ {t('group:invitees_list', { + postProcess: 'capitalize', + })} +

{ const response = await fetch( @@ -59,11 +60,11 @@ export const ListOfJoinRequests = ({ }) => { const [invites, setInvites] = useState([]); const [txList, setTxList] = useAtom(txListAtom); - const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open - const listRef = useRef(); + const listRef = useRef(null); const [isLoadingAccept, setIsLoadingAccept] = useState(false); + const { t } = useTranslation(['core', 'group']); const getInvites = async (groupId) => { try { @@ -93,7 +94,8 @@ export const ListOfJoinRequests = ({ const handleAcceptJoinRequest = async (address) => { try { - const fee = await getFee('GROUP_INVITE'); // TODO translate + const fee = await getFee('GROUP_INVITE'); + await show({ message: t('group:question.perform_transaction', { action: 'GROUP_INVITE', @@ -101,7 +103,9 @@ export const ListOfJoinRequests = ({ }), publishFee: fee.fee + ' QORT', }); + setIsLoadingAccept(true); + await new Promise((res, rej) => { window .sendMessage('inviteToGroup', { @@ -114,19 +118,23 @@ export const ListOfJoinRequests = ({ setIsLoadingAccept(false); setInfoSnack({ type: 'success', - message: - 'Successfully accepted join request. It may take a couple of minutes for the changes to propagate', + message: t('group:message.success,group_join', { + postProcess: 'capitalize', + }), }); setOpenSnack(true); handlePopoverClose(); res(response); - setTxList((prev) => [ { ...response, type: 'join-request-accept', - label: `Accepted join request: awaiting confirmation`, - labelDone: `User successfully joined!`, + label: t('group:message.success,invitation_request', { + postProcess: 'capitalize', + }), + labelDone: t('group:message.success,user_joined', { + postProcess: 'capitalize', + }), done: false, groupId, qortalAddress: address, @@ -147,13 +155,16 @@ export const ListOfJoinRequests = ({ .catch((error) => { setInfoSnack({ type: 'error', - message: error?.message || 'An error occurred', + message: + error?.message || + t('core:message.error.generic', { postProcess: 'capitalize' }), }); setOpenSnack(true); rej(error); }); }); } catch (error) { + console.log(error); } finally { setIsLoadingAccept(false); } @@ -161,13 +172,15 @@ export const ListOfJoinRequests = ({ const rowRenderer = ({ index, key, parent, style }) => { const member = invites[index]; - const findJoinRequsetInTxList = txList?.find( + const findJoinRequestInTxList = txList?.find( (tx) => tx?.groupId === groupId && tx?.qortalAddress === member?.joiner && tx?.type === 'join-request-accept' ); - if (findJoinRequsetInTxList) return null; + + if (findJoinRequestInTxList) return null; + return ( handleAcceptJoinRequest(member?.joiner)} > - Accept + {t('core:action.accept', { postProcess: 'capitalize' })} + handlePopoverOpen(event, index)} > @@ -238,7 +252,7 @@ export const ListOfJoinRequests = ({ return (
-

Join request list

+

{t('core:list.join_request', { postProcess: 'capitalize' })}

{ rej(response.error); }) .catch((error) => { - rej(error.message || 'An error occurred'); + rej( + error.message || + t('core:message.error.generic', { postProcess: 'capitalize' }) + ); }); }); } catch (error) { diff --git a/src/components/Group/UserListOfInvites.tsx b/src/components/Group/UserListOfInvites.tsx index a57a38c..847e926 100644 --- a/src/components/Group/UserListOfInvites.tsx +++ b/src/components/Group/UserListOfInvites.tsx @@ -264,7 +264,7 @@ export const UserListOfInvites = ({ }} >

- {t('core:invite_list', { + {t('core:list.invite', { postProcess: 'capitalize', })}