diff --git a/net/web/src/constants/Strings.js b/net/web/src/constants/Strings.js index d9682785..a5ef5c55 100644 --- a/net/web/src/constants/Strings.js +++ b/net/web/src/constants/Strings.js @@ -107,6 +107,48 @@ export const en = { createMessage: 'Please check with your administrator.', adminError: 'Admin Access Error', adminMessage: 'Please confirm your password.', + + confirmDelete: 'Deleting Account', + areSure: 'Are you sure you want to delete the account?', + + mb: 'MB', + gb: 'GB', + copied: 'Copied', + accounts: 'Accounts', + accessAccount: 'Access Account', + createAccount: 'Create Account', + browserLink: 'Browser Link', + mobileToken: 'Mobile Token', + createLink: 'Create Account Link', + configureServer: 'Configure Server', + reloadAccounts: 'Reload Accounts', + disableAccount: 'Disable Account', + enableAccount: 'Enable Account', + deleteAccount: 'Delete Account', + settings: 'Settings', + hostHint: 'domain:port/app', + federatedHost: 'Federated Host', + storageLimit: 'Storage Limit (GB) / Account', + storageHint: '0 for Unlimited', + keyType: 'Account Key Type', + accountCreation: 'Public Account Creation', + enablePush: 'Enable Push Notifications', + allowUnsealed: 'Allow Unsealed Topics', + topicContent: 'Topic Content:', + enableImage: 'Enable Image Queue', + imageHint: 'Allow images to be posted in topics', + enableAudio: 'Enable Audio Queue', + audioHint: 'Allow audio to be posted in topics', + enableVideo: 'Enable Video Queue', + videoHint: 'Allow video to be posted in topics', + enableWeb: 'Enable WebRTC Calls', + webHint: 'Enable audio and video calls to contacts', + serverUrl: 'WebRTC Server URL', + urlHint: 'turn:ip:port?transport=udp', + webUsername: 'WebRTC Username', + webPassword: 'WebRTC Password', + failedLoad: 'Failed to Load', + limit: 'Limit', }; export const fr = { @@ -218,5 +260,47 @@ export const fr = { createMessage: 'Veuillez vérifier auprès de votre administrateur.', adminError: 'Erreur d\'Accès', adminMessage: 'Veuillez confirmer votre mot de passe', + + confirmDelete: 'Suppression de Compte', + areSure: 'Êtes-vous sûr de vouloir supprimer le compte?', + + mb: 'Mo', + gb: 'Go', + copied: 'Copié', + accounts: 'Comptes', + accessAccount: 'Accéder au Compte', + createAccount: 'Créer un Compte', + browserLink: 'Lien du Navigateur', + mobileToken: 'Code Mobile', + createLink: 'Lien pour Créer un Compte', + configureServer: 'Configurer le Serveur', + reloadAccounts: 'Recharger les Comptes', + disableAccount: 'Désactiver le Compte', + enableAccount: 'Activer le Compte', + deleteAccount: 'Supprimer le Compte', + settings: 'Paramètres', + hostHint: 'domaine:port/app', + federatedHost: 'Hôte Fédéré', + storageLimit: 'Limite de Espace (Go) / Compte', + storageHint: '0 pour Illimité', + keyType: 'Type de Clé', + accountCreation: 'Création de Compte Public', + enablePush: 'Activer les Notifications Push', + allowUnsealed: 'Autoriser les Sujets non Sécurisés', + topicContent: 'Contenu du Sujet:', + enableImage: 'Activer les Images du Sujet', + imageHint: 'Autoriser la publication d\'images dans des sujets', + enableAudio: 'Activer l\'Audio du Suject', + audioHint: 'Autoriser la publication d\'audio dans des sujets', + enableVideo: 'Activer les Videos du Sujet', + videoHint: 'Autoriser la publication de video dans des sujets', + enableWeb: 'Activer les Appels WebRTC', + webHint: 'Autoriser les appels audio et vidéo aux contacts', + serverUrl: 'URL du Serveur WebRTC', + urlHint: 'turn:ip:port?transport=udp', + webUsername: 'Nom d\'Utilisateur WebRTC', + webPassword: 'Mot de Passe WebRTC', + failedLoad: 'Échec du Chargement', + limit: 'Limite', }; diff --git a/net/web/src/dashboard/Dashboard.jsx b/net/web/src/dashboard/Dashboard.jsx index 66e65146..97945985 100644 --- a/net/web/src/dashboard/Dashboard.jsx +++ b/net/web/src/dashboard/Dashboard.jsx @@ -1,6 +1,7 @@ import { AlertIcon, DashboardWrapper, SettingsButton, AddButton, SettingsLayout, CreateLayout } from './Dashboard.styled'; import { Tooltip, Switch, Select, Button, Space, Modal, Input, InputNumber, List } from 'antd'; import { ExclamationCircleOutlined, SettingOutlined, UserAddOutlined, LogoutOutlined, ReloadOutlined } from '@ant-design/icons'; +import { ThemeProvider } from "styled-components"; import { useDashboard } from './useDashboard.hook'; import { AccountItem } from './accountItem/AccountItem'; import { CopyButton } from './copyButton/CopyButton'; @@ -18,199 +19,200 @@ export function Dashboard() { }; return ( - -
-
-
Accounts
- { state.display === 'small' && ( - <> -
- } - onClick={() => actions.reload()}> -
-
- } - onClick={() => actions.setShowSettings(true)}> -
-
- } - onClick={() => actions.logout()}> -
- { (state.configError || state.accountsError) && ( - - - - )} -
- } - loading={state.createBusy} onClick={() => actions.setCreateLink()}> -
- - )} - { state.display !== 'small' && ( - <> -
- - } - onClick={() => actions.reload()}> - -
-
- - } - onClick={() => actions.setShowSettings(true)}> - -
-
- - } - onClick={() => actions.logout()}> - -
- { state.configError && ( - - - + + +
+
+
{ state.strings.accounts }
+ { state.display === 'small' && ( + <> +
+ } + onClick={() => actions.reload()}> +
+
+ } + onClick={() => actions.setShowSettings(true)}> +
+
+ } + onClick={() => actions.logout()}> +
+ { (state.configError || state.accountsError) && ( + + - - )} - { state.accountsError && ( - - - - - - )} -
- - } - loading={state.createBusy} onClick={() => actions.setCreateLink()}> - + )} +
+ } + loading={state.createBusy} onClick={() => actions.setCreateLink()}> +
+ + )} + { state.display !== 'small' && ( + <> +
+ + } + onClick={() => actions.reload()}> + +
+
+ + } + onClick={() => actions.setShowSettings(true)}> + +
+
+ + } + onClick={() => actions.logout()}> + +
+ { (state.configError || state.accountsError) && ( + + + + + + )} +
+ + } + loading={state.createBusy} onClick={() => actions.setCreateLink()}> + +
+ + )} +
+
+ ()} + /> +
+
+ actions.setShowSettings(false)}> + +
{state.strings.settings}
+
+
{ state.strings.federatedHost }
+ actions.setHost(e.target.value)} + value={state.domain} /> +
+
+
{state.strings.storageLimit}
+ actions.setStorage(e)} + placeholder={state.strings.storageHint} value={state.accountStorage} /> +
+
+
{state.strings.keyType}
+ +
+
+ +
{state.strings.accountCreation}
+ actions.setEnableOpenAccess(e)} size="small" + defaultChecked={false} checked={state.enableOpenAccess} /> + { state.enableOpenAccess && ( + actions.setOpenAccessLimit(e)} + placeholder={state.strings.limit} value={state.openAccessLimit} /> + )} +
+
+
+
{state.strings.enablePush}
+ actions.setPushSupported(e)} size="small" + defaultChecked={true} checked={state.pushSupported} /> +
+ { state.transformSupported && ( +
+
{state.strings.allowUnsealed}
+ actions.setAllowUnsealed(e)} size="small" + defaultChecked={true} checked={state.allowUnsealed} />
- - )} -
- -
- ()} - /> -
-
- - actions.setSettings()} onCancel={() => actions.setShowSettings(false)}> - -
-
Federated Host: 
- actions.setHost(e.target.value)} - value={state.domain} /> -
-
-
Storage Limit (GB) / Account: 
- actions.setStorage(e)} - placeholder="0 for unrestricted" value={state.accountStorage} /> -
-
-
Account Key Type: 
- -
-
- -
Public Account Creation:
- actions.setEnableOpenAccess(e)} size="small" - defaultChecked={false} checked={state.enableOpenAccess} /> - { state.enableOpenAccess && ( - actions.setOpenAccessLimit(e)} - placeholder="Limit" value={state.openAccessLimit} /> - )} -
-
-
-
Enable Push Notification: 
- actions.setPushSupported(e)} size="small" - defaultChecked={true} checked={state.pushSupported} /> -
- { state.transformSupported && ( -
-
Allow Unsealed Topics: 
- actions.setAllowUnsealed(e)} size="small" - defaultChecked={true} checked={state.allowUnsealed} /> -
- )} -
- Topic Content: -
- -
-
Enable Image Queue: 
- actions.setEnableImage(e)} size="small" - defaultChecked={true} checked={state.enableImage} /> -
-
- -
-
Enable Audio Queue: 
- actions.setEnableAudio(e)} size="small" - defaultChecked={true} checked={state.enableAudio} /> -
-
- -
-
Enable Video Queue: 
- actions.setEnableVideo(e)} size="small" - defaultChecked={true} checked={state.enableVideo} /> -
-
- + )}
-
Enable WebRTC calls: 
- actions.setEnableIce(e)} size="small" - defaultChecked={false} checked={state.enableIce} /> + {state.strings.topicContent}
-
-
-
WebRTC Server URL: 
- actions.setIceUrl(e.target.value)} - disabled={!state.enableIce} value={state.iceUrl} /> -
-
-
WebRTC Username: 
- actions.setIceUsername(e.target.value)} - disabled={!state.enableIce} value={state.iceUsername} /> -
-
-
WebRTC Password: 
- actions.setIcePassword(e.target.value)} - disabled={!state.enableIce} value={state.icePassword} /> -
-
-
- actions.setShowCreate(false)}>OK ]} - onCancel={() => actions.setShowCreate(false)}> - -
-
Browser Link:
-
{createLink()}
- await onClipboard(createLink())} /> -
-
-
App Token:
-
{state.createToken}
- await onClipboard(state.createToken)} /> -
-
-
- + +
+
{state.strings.enableImage}
+ actions.setEnableImage(e)} size="small" + defaultChecked={true} checked={state.enableImage} /> +
+
+ +
+
{state.strings.enableAudio}
+ actions.setEnableAudio(e)} size="small" + defaultChecked={true} checked={state.enableAudio} /> +
+
+ +
+
{state.strings.enableVideo}
+ actions.setEnableVideo(e)} size="small" + defaultChecked={true} checked={state.enableVideo} /> +
+
+ +
+
{state.strings.enableWeb}
+ actions.setEnableIce(e)} size="small" + defaultChecked={false} checked={state.enableIce} /> +
+
+
+
{state.strings.serverUrl}
+ actions.setIceUrl(e.target.value)} + disabled={!state.enableIce} value={state.iceUrl} /> +
+
+
{state.strings.webUsername}
+ actions.setIceUsername(e.target.value)} + disabled={!state.enableIce} value={state.iceUsername} /> +
+
+
{state.strings.webPassword}
+ actions.setIcePassword(e.target.value)} + disabled={!state.enableIce} value={state.icePassword} /> +
+
+ + +
+ + + actions.setShowCreate(false)}> + +
{state.strings.createAccount}
+
+
{state.strings.browserLink}
+
{createLink()}
+ await onClipboard(createLink())} /> +
+
+
{state.strings.mobileToken}
+
{state.createToken}
+ await onClipboard(state.createToken)} /> +
+
+ +
+
+
+ + ); } diff --git a/net/web/src/dashboard/Dashboard.styled.js b/net/web/src/dashboard/Dashboard.styled.js index 50cd1150..6c990b0d 100644 --- a/net/web/src/dashboard/Dashboard.styled.js +++ b/net/web/src/dashboard/Dashboard.styled.js @@ -11,6 +11,8 @@ export const DashboardWrapper = styled.div` height: 100%; padding-left: 8px; padding-right: 8px; + background-color: ${props => props.theme.baseArea}; + color: ${props => props.theme.hintText}; .container { display: flex; @@ -21,21 +23,21 @@ export const DashboardWrapper = styled.div` border-radius: 4px; max-width: 100%; max-height: 80%; - background-color: ${Colors.formBackground}; + background-color: ${props => props.theme.itemArea}; .header { - color: #444444; + color: ${props => props.theme.hintText}; display: flex; flex-direction: row; font-size: 20px; - border-bottom: 1px solid #aaaaaa; + border-bottom: 1px solid ${props => props.theme.headerBorder}; } .body { padding-top: 8px; min-height: 0; overflow: auto; - border-bottom: 1px solid #aaaaaa; + border-bottom: 1px solid ${props => props.theme.headerBorder}; margin-bottom: 16px; } @@ -86,6 +88,19 @@ export const AlertIcon = styled.div` export const SettingsLayout = styled(Space)` width: 100%; + .header { + display: flex; + justify-content: center; + font-size: 1.2rem; + } + + .control { + display: flex; + justify-content: flex-end; + margin-top: 16px; + gap: 16px; + } + .label { border-top: 1px solid ${Colors.divider}; padding-top: 8px; @@ -101,10 +116,24 @@ export const SettingsLayout = styled(Space)` display: flex; flex-direction: row; align-items: center; + gap: 16px; } `; export const CreateLayout = styled.div` + .header { + display: flex; + justify-content: center; + font-size: 1.2rem; + } + + .control { + display: flex; + justify-content: flex-end; + margin-top: 16px; + gap: 16px; + } + .url { display: flex; flex-direction: row; @@ -113,7 +142,7 @@ export const CreateLayout = styled.div` .label { padding-right: 16px; - width: 112px; + width: 145px; } .token { diff --git a/net/web/src/dashboard/accountItem/AccountItem.jsx b/net/web/src/dashboard/accountItem/AccountItem.jsx index 55c6eb97..9ce8a283 100644 --- a/net/web/src/dashboard/accountItem/AccountItem.jsx +++ b/net/web/src/dashboard/accountItem/AccountItem.jsx @@ -12,9 +12,12 @@ export function AccountItem({ item, remove }) { const removeAccount = () => { modal.confirm({ - title: 'Are you sure you want to delete the account?', + title: {state.strings.confirmDelete}, + content: {state.strings.areSure}, icon: , - bodyStyle: { padding: 16 }, + bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, + okText: state.strings.ok, + cancelText: state.strings.cancel, onOk() { applyRemoveAccount(); }, @@ -27,10 +30,10 @@ export function AccountItem({ item, remove }) { await actions.remove(); } catch(err) { - modal.error({ - title: 'Failed to Remove Account', - content: 'Please try again.', - bodyStyle: { padding: 16 }, + modal.error({ + title: {state.strings.operationFailed}, + content: {state.strings.tryAgain}, + bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, }); } } @@ -41,9 +44,9 @@ export function AccountItem({ item, remove }) { } catch(err) { modal.error({ - title: 'Failed to Set Account Status', - content: 'Please try again.', - bodyStyle: { padding: 16 }, + title: {state.strings.operationFailed}, + content: {state.strings.tryAgain}, + bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, }); } } @@ -54,9 +57,9 @@ export function AccountItem({ item, remove }) { } catch(err) { modal.error({ - title: 'Failed to Set Account Access', - content: 'Please try again.', - bodyStyle: { padding: 16 }, + title: {state.strings.operationFailed}, + content: {state.strings.tryAgain}, + bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, }); } } @@ -103,43 +106,46 @@ export function AccountItem({ item, remove }) { )} { state.display !== 'small' && ( <> - + } loading={state.accessBusy} onClick={setAccountAccess}> { state.disabled && ( - + } loading={state.statusBusy} onClick={() => applyAccountStatus(false)}> )} { !state.disabled && ( - + } loading={state.statusBusy} onClick={() => applyAccountStatus(true)}> )} - + } loading={state.removeBusy} onClick={removeAccount}> )}
- actions.setShowAccess(false)}>OK ]} - bodyStyle={{ padding: 16 }} onCancel={() => actions.setShowAccess(false)}> + actions.setShowAccess(false)}> +
{ state.strings.accessAccount }
-
Browser Link:
+
{ state.strings.browserLink }
{accessLink()}
await onClipboard(accessLink())} />
-
App Token:
+
{ state.strings.mobileToken }
{state.accessToken}
await onClipboard(state.accessToken)} />
+
+ +
diff --git a/net/web/src/dashboard/accountItem/AccountItem.styled.js b/net/web/src/dashboard/accountItem/AccountItem.styled.js index fd6911f4..72d5b6c8 100644 --- a/net/web/src/dashboard/accountItem/AccountItem.styled.js +++ b/net/web/src/dashboard/accountItem/AccountItem.styled.js @@ -10,11 +10,12 @@ export const AccountItemWrapper = styled.div` padding-right: 16px; padding-top: 2px; padding-bottom: 2px; - border-bottom: 1px solid #eeeeee; + border-bottom: 1px solid ${props => props.theme.itemBorder}; align-items: center; + color: ${props => props.theme.mainText}; &:hover { - background-color: #eeeeee; + background-color: ${props => props.theme.hoverArea}; } .avatar { @@ -52,7 +53,7 @@ export const AccountItemWrapper = styled.div` } .storage { - color: #555555; + color: ${props => props.theme.hintText}; padding-left: 8px; } @@ -89,6 +90,18 @@ export const DeleteButton = styled(Button)` ` export const AccessLayout = styled.div` + .control { + display: flex; + justify-content: flex-end; + margin-top: 16px; + } + + .header { + display: flex; + justify-content: center; + font-size: 1.2rem; + } + .url { display: flex; flex-direction: row; @@ -97,7 +110,7 @@ export const AccessLayout = styled.div` .label { padding-right: 16px; - width: 112px; + min-width: 145px; } .token { diff --git a/net/web/src/dashboard/accountItem/useAccountItem.hook.js b/net/web/src/dashboard/accountItem/useAccountItem.hook.js index f8b9bf5b..4230f9ef 100644 --- a/net/web/src/dashboard/accountItem/useAccountItem.hook.js +++ b/net/web/src/dashboard/accountItem/useAccountItem.hook.js @@ -12,6 +12,9 @@ export function useAccountItem(item, remove) { removeBusy: false, accessBusy: false, showAccess: false, + display: null, + menuStyle: {}, + strings: {}, }); const app = useContext(AppContext); @@ -31,14 +34,15 @@ export function useAccountItem(item, remove) { guid: item?.guid, handle: item?.handle, storage: Math.floor(item?.storageUsed > 1073741824 ? item?.storageUsed / 1073741824 : item?.storageUsed / 1048576), - storageUnit: item?.storageUsed > 1073741824 ? "GB" : "MB", + storageUnit: item?.storageUsed > 1073741824 ? state.strings.gb : state.strings.mb, imageUrl: item?.imageSet ? getAccountImageUrl(app.state.adminToken, item?.accountId) : null, }); - }, [app.state.adminToken, item]); + }, [app.state.adminToken, item, state.strings]); useEffect(() => { - updateState({ display: settings.state.display }); - }, [settings]); + const { display, menuStyle, strings } = settings.state; + updateState({ display, menuStyle, strings }); + }, [settings.state]); const actions = { setAccessLink: async () => { diff --git a/net/web/src/dashboard/useDashboard.hook.js b/net/web/src/dashboard/useDashboard.hook.js index 519a8357..ac13c071 100644 --- a/net/web/src/dashboard/useDashboard.hook.js +++ b/net/web/src/dashboard/useDashboard.hook.js @@ -6,6 +6,7 @@ import { removeAccount } from 'api/removeAccount'; import { addAccountCreate } from 'api/addAccountCreate'; import { useNavigate } from 'react-router-dom'; import { AppContext } from 'context/AppContext'; +import { SettingsContext } from 'context/SettingsContext'; export function useDashboard() { @@ -33,10 +34,14 @@ export function useDashboard() { showCreate: false, busy: false, accounts: [], + colors: {}, + menuStyle: {}, + strings: {}, }); const navigate = useNavigate(); const app = useContext(AppContext); + const settings = useContext(SettingsContext); const updateState = (value) => { setState((s) => ({ ...s, ...value })); @@ -53,6 +58,11 @@ export function useDashboard() { // eslint-disable-next-line }, [app]); + useEffect(() => { + const { strings, colors, menuStyle } = settings.state; + updateState({ strings, colors, menuStyle }); + }, [settings.state]); + const actions = { setCreateLink: async () => { if (!state.createBusy) { diff --git a/todo b/todo index 1fba4882..02a0194c 100644 --- a/todo +++ b/todo @@ -1,11 +1,4 @@ -access: - - dark style - - translation - - language - - color theme - - more text hints - thread: - dark style - translation @@ -24,7 +17,3 @@ calling: - fullscreen - device selection -admin: - - dark style - - translation -