mirror of
https://github.com/balzack/databag.git
synced 2025-02-11 19:19:16 +00:00
style and translate dashboard
This commit is contained in:
parent
2541417662
commit
71d6598556
@ -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',
|
||||
};
|
||||
|
||||
|
@ -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 (
|
||||
<DashboardWrapper>
|
||||
<div className="container">
|
||||
<div className="header">
|
||||
<div className="label">Accounts</div>
|
||||
{ state.display === 'small' && (
|
||||
<>
|
||||
<div className="settings">
|
||||
<SettingsButton type="text" size="small" icon={<ReloadOutlined />}
|
||||
onClick={() => actions.reload()}></SettingsButton>
|
||||
</div>
|
||||
<div className="settings">
|
||||
<SettingsButton type="text" size="small" icon={<SettingOutlined />}
|
||||
onClick={() => actions.setShowSettings(true)}></SettingsButton>
|
||||
</div>
|
||||
<div className="settings">
|
||||
<SettingsButton type="text" size="small" icon={<LogoutOutlined />}
|
||||
onClick={() => actions.logout()}></SettingsButton>
|
||||
</div>
|
||||
{ (state.configError || state.accountsError) && (
|
||||
<AlertIcon>
|
||||
<ExclamationCircleOutlined />
|
||||
</AlertIcon>
|
||||
)}
|
||||
<div className="add">
|
||||
<AddButton type="text" size="large" icon={<UserAddOutlined />}
|
||||
loading={state.createBusy} onClick={() => actions.setCreateLink()}></AddButton>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{ state.display !== 'small' && (
|
||||
<>
|
||||
<div className="settings">
|
||||
<Tooltip placement="topRight" title="Reload Accounts">
|
||||
<SettingsButton type="text" size="small" icon={<ReloadOutlined />}
|
||||
onClick={() => actions.reload()}></SettingsButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="settings">
|
||||
<Tooltip placement="topRight" title="Configure Server">
|
||||
<SettingsButton type="text" size="small" icon={<SettingOutlined />}
|
||||
onClick={() => actions.setShowSettings(true)}></SettingsButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="settings">
|
||||
<Tooltip placement="topRight" title="Logout">
|
||||
<SettingsButton type="text" size="small" icon={<LogoutOutlined />}
|
||||
onClick={() => actions.logout()}></SettingsButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{ state.configError && (
|
||||
<Tooltip placement="topRight" title="failed to load accounts">
|
||||
<AlertIcon className="alert">
|
||||
<ExclamationCircleOutlined />
|
||||
<ThemeProvider theme={state.colors}>
|
||||
<DashboardWrapper>
|
||||
<div className="container">
|
||||
<div className="header">
|
||||
<div className="label">{ state.strings.accounts }</div>
|
||||
{ state.display === 'small' && (
|
||||
<>
|
||||
<div className="settings">
|
||||
<SettingsButton type="text" size="small" icon={<ReloadOutlined />}
|
||||
onClick={() => actions.reload()}></SettingsButton>
|
||||
</div>
|
||||
<div className="settings">
|
||||
<SettingsButton type="text" size="small" icon={<SettingOutlined />}
|
||||
onClick={() => actions.setShowSettings(true)}></SettingsButton>
|
||||
</div>
|
||||
<div className="settings">
|
||||
<SettingsButton type="text" size="small" icon={<LogoutOutlined />}
|
||||
onClick={() => actions.logout()}></SettingsButton>
|
||||
</div>
|
||||
{ (state.configError || state.accountsError) && (
|
||||
<AlertIcon>
|
||||
<ExclamationCircleOutlined />
|
||||
</AlertIcon>
|
||||
</Tooltip>
|
||||
)}
|
||||
{ state.accountsError && (
|
||||
<Tooltip placement="topRight" title="failed to load config">
|
||||
<AlertIcon className="alert">
|
||||
<ExclamationCircleOutlined />
|
||||
</AlertIcon>
|
||||
</Tooltip>
|
||||
)}
|
||||
<div className="add">
|
||||
<Tooltip placement="topRight" title="Create Account Link">
|
||||
<AddButton type="text" size="large" icon={<UserAddOutlined />}
|
||||
loading={state.createBusy} onClick={() => actions.setCreateLink()}></AddButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<div className="add">
|
||||
<AddButton type="text" size="large" icon={<UserAddOutlined />}
|
||||
loading={state.createBusy} onClick={() => actions.setCreateLink()}></AddButton>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{ state.display !== 'small' && (
|
||||
<>
|
||||
<div className="settings">
|
||||
<Tooltip placement="topRight" title={state.strings.reloadAccounts}>
|
||||
<SettingsButton type="text" size="small" icon={<ReloadOutlined />}
|
||||
onClick={() => actions.reload()}></SettingsButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="settings">
|
||||
<Tooltip placement="topRight" title={state.strings.configureServer}>
|
||||
<SettingsButton type="text" size="small" icon={<SettingOutlined />}
|
||||
onClick={() => actions.setShowSettings(true)}></SettingsButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="settings">
|
||||
<Tooltip placement="topRight" title={state.strings.logout}>
|
||||
<SettingsButton type="text" size="small" icon={<LogoutOutlined />}
|
||||
onClick={() => actions.logout()}></SettingsButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{ (state.configError || state.accountsError) && (
|
||||
<Tooltip placement="topRight" title={state.strings.failedLoad}>
|
||||
<AlertIcon className="alert">
|
||||
<ExclamationCircleOutlined />
|
||||
</AlertIcon>
|
||||
</Tooltip>
|
||||
)}
|
||||
<div className="add">
|
||||
<Tooltip placement="topRight" title={state.strings.createAccount}>
|
||||
<AddButton type="text" size="large" icon={<UserAddOutlined />}
|
||||
loading={state.createBusy} onClick={() => actions.setCreateLink()}></AddButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="body">
|
||||
<List
|
||||
locale={{ emptyText: '' }}
|
||||
itemLayout="horizontal"
|
||||
dataSource={state.accounts}
|
||||
loading={state.loading}
|
||||
renderItem={item => (<AccountItem item={item} remove={actions.removeAccount}/>)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Modal bodyStyle={{ borderRadius: 8, padding: 16, ...state.menuStyle }} closable={false} visible={state.showSettings}
|
||||
centered width="fitContent" footer={null} onCancel={() => actions.setShowSettings(false)}>
|
||||
<SettingsLayout direction="vertical">
|
||||
<div className="header">{state.strings.settings}</div>
|
||||
<div className="field">
|
||||
<div>{ state.strings.federatedHost }</div>
|
||||
<Input placeholder={state.strings.hostHint} onChange={(e) => actions.setHost(e.target.value)}
|
||||
value={state.domain} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>{state.strings.storageLimit}</div>
|
||||
<InputNumber defaultValue={0} onChange={(e) => actions.setStorage(e)}
|
||||
placeholder={state.strings.storageHint} value={state.accountStorage} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>{state.strings.keyType}</div>
|
||||
<Select labelInValue defaultValue={{ value: 'RSA4096', label: 'RSA 4096' }}
|
||||
value={state.keyType} onChange={(o) => actions.setKeyType(o.value)}>
|
||||
<Select.Option value="RSA2048">RSA 2048</Select.Option>
|
||||
<Select.Option value="RSA4096">RSA 4096</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="field">
|
||||
<Space className="minHeight" size="middle">
|
||||
<div>{state.strings.accountCreation}</div>
|
||||
<Switch onChange={(e) => actions.setEnableOpenAccess(e)} size="small"
|
||||
defaultChecked={false} checked={state.enableOpenAccess} />
|
||||
{ state.enableOpenAccess && (
|
||||
<InputNumber defaultValue={0} onChange={(e) => actions.setOpenAccessLimit(e)}
|
||||
placeholder={state.strings.limit} value={state.openAccessLimit} />
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>{state.strings.enablePush}</div>
|
||||
<Switch onChange={(e) => actions.setPushSupported(e)} size="small"
|
||||
defaultChecked={true} checked={state.pushSupported} />
|
||||
</div>
|
||||
{ state.transformSupported && (
|
||||
<div className="field">
|
||||
<div>{state.strings.allowUnsealed}</div>
|
||||
<Switch onChange={(e) => actions.setAllowUnsealed(e)} size="small"
|
||||
defaultChecked={true} checked={state.allowUnsealed} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="body">
|
||||
<List
|
||||
locale={{ emptyText: '' }}
|
||||
itemLayout="horizontal"
|
||||
dataSource={state.accounts}
|
||||
loading={state.loading}
|
||||
renderItem={item => (<AccountItem item={item} remove={actions.removeAccount}/>)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal title="Settings" visible={state.showSettings} centered bodyStyle={{ padding: 16 }}
|
||||
okText="Save" onOk={() => actions.setSettings()} onCancel={() => actions.setShowSettings(false)}>
|
||||
<SettingsLayout direction="vertical">
|
||||
<div className="field">
|
||||
<div>Federated Host: </div>
|
||||
<Input placeholder="domain:port/app" onChange={(e) => actions.setHost(e.target.value)}
|
||||
value={state.domain} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>Storage Limit (GB) / Account: </div>
|
||||
<InputNumber defaultValue={0} onChange={(e) => actions.setStorage(e)}
|
||||
placeholder="0 for unrestricted" value={state.accountStorage} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>Account Key Type: </div>
|
||||
<Select labelInValue defaultValue={{ value: 'RSA4096', label: 'RSA 4096' }}
|
||||
value={state.keyType} onChange={(o) => actions.setKeyType(o.value)}>
|
||||
<Select.Option value="RSA2048">RSA 2048</Select.Option>
|
||||
<Select.Option value="RSA4096">RSA 4096</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="field">
|
||||
<Space className="minHeight" size="middle">
|
||||
<div>Public Account Creation:</div>
|
||||
<Switch onChange={(e) => actions.setEnableOpenAccess(e)} size="small"
|
||||
defaultChecked={false} checked={state.enableOpenAccess} />
|
||||
{ state.enableOpenAccess && (
|
||||
<InputNumber defaultValue={0} onChange={(e) => actions.setOpenAccessLimit(e)}
|
||||
placeholder="Limit" value={state.openAccessLimit} />
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>Enable Push Notification: </div>
|
||||
<Switch onChange={(e) => actions.setPushSupported(e)} size="small"
|
||||
defaultChecked={true} checked={state.pushSupported} />
|
||||
</div>
|
||||
{ state.transformSupported && (
|
||||
<div className="field">
|
||||
<div>Allow Unsealed Topics: </div>
|
||||
<Switch onChange={(e) => actions.setAllowUnsealed(e)} size="small"
|
||||
defaultChecked={true} checked={state.allowUnsealed} />
|
||||
</div>
|
||||
)}
|
||||
<div className="field label">
|
||||
<span>Topic Content:</span>
|
||||
</div>
|
||||
<Tooltip placement="topLeft" title="Allows images to be posted and processed in topics">
|
||||
<div className="field">
|
||||
<div>Enable Image Queue: </div>
|
||||
<Switch onChange={(e) => actions.setEnableImage(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableImage} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title="Allows for audio to be posted and processed in topics">
|
||||
<div className="field">
|
||||
<div>Enable Audio Queue: </div>
|
||||
<Switch onChange={(e) => actions.setEnableAudio(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableAudio} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title="Allows videos to be posted and processed in topics">
|
||||
<div className="field">
|
||||
<div>Enable Video Queue: </div>
|
||||
<Switch onChange={(e) => actions.setEnableVideo(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableVideo} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title="Enabled audio and video calls to contacts">
|
||||
)}
|
||||
<div className="field label">
|
||||
<div>Enable WebRTC calls: </div>
|
||||
<Switch onChange={(e) => actions.setEnableIce(e)} size="small"
|
||||
defaultChecked={false} checked={state.enableIce} />
|
||||
<span>{state.strings.topicContent}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="field">
|
||||
<div>WebRTC Server URL: </div>
|
||||
<Input placeholder="turn:ip:port?transport=udp" onChange={(e) => actions.setIceUrl(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.iceUrl} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>WebRTC Username: </div>
|
||||
<Input placeholder="username" onChange={(e) => actions.setIceUsername(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.iceUsername} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>WebRTC Password: </div>
|
||||
<Input placeholder="password" onChange={(e) => actions.setIcePassword(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.icePassword} />
|
||||
</div>
|
||||
</SettingsLayout>
|
||||
</Modal>
|
||||
<Modal bodyStyle={{ padding: 16 }} title="Create Account" visible={state.showCreate} centered width="fitContent"
|
||||
footer={[ <Button type="primary" onClick={() => actions.setShowCreate(false)}>OK</Button> ]}
|
||||
onCancel={() => actions.setShowCreate(false)}>
|
||||
<CreateLayout>
|
||||
<div className="url">
|
||||
<div className="label">Browser Link:</div>
|
||||
<div className="link">{createLink()}</div>
|
||||
<CopyButton onCopy={async () => await onClipboard(createLink())} />
|
||||
</div>
|
||||
<div className="url">
|
||||
<div className="label">App Token:</div>
|
||||
<div className="token">{state.createToken}</div>
|
||||
<CopyButton onCopy={async () => await onClipboard(state.createToken)} />
|
||||
</div>
|
||||
</CreateLayout>
|
||||
</Modal>
|
||||
</DashboardWrapper>
|
||||
<Tooltip placement="topLeft" title={state.strings.imageHint}>
|
||||
<div className="field">
|
||||
<div>{state.strings.enableImage}</div>
|
||||
<Switch onChange={(e) => actions.setEnableImage(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableImage} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title={state.strings.audioHint}>
|
||||
<div className="field">
|
||||
<div>{state.strings.enableAudio}</div>
|
||||
<Switch onChange={(e) => actions.setEnableAudio(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableAudio} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title={state.strings.videoHint}>
|
||||
<div className="field">
|
||||
<div>{state.strings.enableVideo}</div>
|
||||
<Switch onChange={(e) => actions.setEnableVideo(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableVideo} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title={state.strings.webHint}>
|
||||
<div className="field label">
|
||||
<div>{state.strings.enableWeb}</div>
|
||||
<Switch onChange={(e) => actions.setEnableIce(e)} size="small"
|
||||
defaultChecked={false} checked={state.enableIce} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="field">
|
||||
<div>{state.strings.serverUrl}</div>
|
||||
<Input placeholder={state.strings.urlHint} onChange={(e) => actions.setIceUrl(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.iceUrl} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>{state.strings.webUsername}</div>
|
||||
<Input placeholder={state.strings.username} onChange={(e) => actions.setIceUsername(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.iceUsername} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>{state.strings.webPassword}</div>
|
||||
<Input placeholder={state.strings.password} onChange={(e) => actions.setIcePassword(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.icePassword} />
|
||||
</div>
|
||||
<div className="control">
|
||||
<Button key="back" onClick={() => actions.setShowSettings(false)}>{state.strings.cancel}</Button>
|
||||
<Button key="save" type="primary" onClick={() => actions.setSettings()} loading={state.busy}>{state.strings.save}</Button>
|
||||
</div>
|
||||
</SettingsLayout>
|
||||
</Modal>
|
||||
<Modal bodyStyle={{ borderRadius: 8, padding: 16, ...state.menuStyle }} closable={false} visible={state.showCreate} centered width="fitContent"
|
||||
footer={null} onCancel={() => actions.setShowCreate(false)}>
|
||||
<CreateLayout>
|
||||
<div className="header">{state.strings.createAccount}</div>
|
||||
<div className="url">
|
||||
<div className="label">{state.strings.browserLink}</div>
|
||||
<div className="link">{createLink()}</div>
|
||||
<CopyButton onCopy={async () => await onClipboard(createLink())} />
|
||||
</div>
|
||||
<div className="url">
|
||||
<div className="label">{state.strings.mobileToken}</div>
|
||||
<div className="token">{state.createToken}</div>
|
||||
<CopyButton onCopy={async () => await onClipboard(state.createToken)} />
|
||||
</div>
|
||||
<div className="control">
|
||||
<Button type="primary" onClick={() => actions.setShowCreate(false)}>{state.strings.ok}</Button>
|
||||
</div>
|
||||
</CreateLayout>
|
||||
</Modal>
|
||||
</DashboardWrapper>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -12,9 +12,12 @@ export function AccountItem({ item, remove }) {
|
||||
|
||||
const removeAccount = () => {
|
||||
modal.confirm({
|
||||
title: 'Are you sure you want to delete the account?',
|
||||
title: <span style={state.menuStyle}>{state.strings.confirmDelete}</span>,
|
||||
content: <span style={state.menuStyle}>{state.strings.areSure}</span>,
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
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: <span style={state.menuStyle}>{state.strings.operationFailed}</span>,
|
||||
content: <span style={state.menuStyle}>{state.strings.tryAgain}</span>,
|
||||
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: <span style={state.menuStyle}>{state.strings.operationFailed}</span>,
|
||||
content: <span style={state.menuStyle}>{state.strings.tryAgain}</span>,
|
||||
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: <span style={state.menuStyle}>{state.strings.operationFailed}</span>,
|
||||
content: <span style={state.menuStyle}>{state.strings.tryAgain}</span>,
|
||||
bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -103,43 +106,46 @@ export function AccountItem({ item, remove }) {
|
||||
)}
|
||||
{ state.display !== 'small' && (
|
||||
<>
|
||||
<Tooltip placement="topLeft" title="Account Login Link">
|
||||
<Tooltip placement="topLeft" title={state.strings.accessAccount}>
|
||||
<ResetButton type="text" size="large" icon={<UnlockOutlined />}
|
||||
loading={state.accessBusy} onClick={setAccountAccess}></ResetButton>
|
||||
</Tooltip>
|
||||
{ state.disabled && (
|
||||
<Tooltip placement="topLeft" title="Enable Account">
|
||||
<Tooltip placement="topLeft" title={state.strings.enableAccount}>
|
||||
<EnableButton type="text" size="large" icon={<CheckCircleOutlined />}
|
||||
loading={state.statusBusy} onClick={() => applyAccountStatus(false)}></EnableButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{ !state.disabled && (
|
||||
<Tooltip placement="topLeft" title="Disable Account">
|
||||
<Tooltip placement="topLeft" title={state.strings.disableAccount}>
|
||||
<DisableButton type="text" size="large" icon={<CloseCircleOutlined />}
|
||||
loading={state.statusBusy} onClick={() => applyAccountStatus(true)}></DisableButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip placement="topLeft" title="Delete Account">
|
||||
<Tooltip placement="topLeft" title={state.strings.deleteAccount}>
|
||||
<DeleteButton type="text" size="large" icon={<UserDeleteOutlined />}
|
||||
loading={state.removeBusy} onClick={removeAccount}></DeleteButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Modal title="Access Account" visible={state.showAccess} centered width="fitContent"
|
||||
footer={[ <Button type="primary" onClick={() => actions.setShowAccess(false)}>OK</Button> ]}
|
||||
bodyStyle={{ padding: 16 }} onCancel={() => actions.setShowAccess(false)}>
|
||||
<Modal bodyStyle={{ borderRadius: 8, padding: 16, ...state.menuStyle }} closable={false} visible={state.showAccess} centered width="fitContent"
|
||||
footer={null} onCancel={() => actions.setShowAccess(false)}>
|
||||
<AccessLayout>
|
||||
<div className="header">{ state.strings.accessAccount }</div>
|
||||
<div className="url">
|
||||
<div className="label">Browser Link:</div>
|
||||
<div className="label">{ state.strings.browserLink }</div>
|
||||
<div className="link">{accessLink()}</div>
|
||||
<CopyButton onCopy={async () => await onClipboard(accessLink())} />
|
||||
</div>
|
||||
<div className="url">
|
||||
<div className="label">App Token:</div>
|
||||
<div className="label">{ state.strings.mobileToken }</div>
|
||||
<div className="token">{state.accessToken}</div>
|
||||
<CopyButton onCopy={async () => await onClipboard(state.accessToken)} />
|
||||
</div>
|
||||
<div className="control">
|
||||
<Button type="primary" onClick={() => actions.setShowAccess(false)}>{state.strings.ok}</Button>
|
||||
</div>
|
||||
</AccessLayout>
|
||||
</Modal>
|
||||
</AccountItemWrapper>
|
||||
|
@ -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 {
|
||||
|
@ -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 () => {
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user