263 lines
7.8 KiB
JavaScript
Executable File
263 lines
7.8 KiB
JavaScript
Executable File
/* @flow */
|
|
|
|
import React from 'react';
|
|
import lodash from 'lodash';
|
|
import Flux from '../../lib/flux';
|
|
import Alert from '../Alert';
|
|
import i18n from '../../i18n';
|
|
import UserSettingsStore from '../../stores/UserSettingsStore';
|
|
import {FormSection, FormTitleTags, FormItem, FormText, FormTextTypes, FormNotice} from '../../uikit/form';
|
|
import Flex from '../../uikit/Flex';
|
|
import Card, {Types as CardTypes} from '../../uikit/Card';
|
|
import Button, {ButtonColors, ButtonSizes, ButtonLooks} from '../../uikit/Button';
|
|
import EmptyState, {EmptyStateText, EmptyStateImage} from '../../uikit/EmptyState';
|
|
import Spinner from '../../uikit/Spinner';
|
|
import AvatarUtils from '../../utils/AvatarUtils';
|
|
import StreamerModeEnabled from '../StreamerModeEnabled';
|
|
import ModalActionCreators from '../../actions/ModalActionCreators';
|
|
import AuthorizedAppsActionCreators from '../../actions/AuthorizedAppsActionCreators';
|
|
import AuthorizedAppsStore from '../../stores/AuthorizedAppsStore';
|
|
import type {ConnectedApp} from '../../stores/AuthorizedAppsStore';
|
|
import StreamerModeStore from '../../stores/StreamerModeStore';
|
|
import {OAuth2Scopes} from '../../Constants';
|
|
import type {OAuth2Token} from '../../flow/Server';
|
|
import '../../styles/user_settings_authorized_apps.styl';
|
|
|
|
const ThemedEmptyState = Flux.connectStores([UserSettingsStore], () => ({
|
|
theme: UserSettingsStore.theme,
|
|
}))(EmptyState);
|
|
|
|
class AuthorizedApp extends React.PureComponent {
|
|
renderPermissions = () => {
|
|
const permissions = this.props.scopes.map(scope => {
|
|
let humanReadableScope;
|
|
|
|
switch (scope) {
|
|
case OAuth2Scopes.IDENTIFY:
|
|
humanReadableScope = i18n.Messages.SCOPE_IDENTIFY;
|
|
break;
|
|
case OAuth2Scopes.EMAIL:
|
|
humanReadableScope = i18n.Messages.SCOPE_EMAIL;
|
|
break;
|
|
case OAuth2Scopes.CONNECTIONS:
|
|
humanReadableScope = i18n.Messages.SCOPE_CONNECTIONS;
|
|
break;
|
|
case OAuth2Scopes.GUILDS:
|
|
humanReadableScope = i18n.Messages.SCOPE_GUILDS;
|
|
break;
|
|
case OAuth2Scopes.GUILDS_JOIN:
|
|
humanReadableScope = i18n.Messages.SCOPE_GUILDS_JOIN;
|
|
break;
|
|
case OAuth2Scopes.GDM_JOIN:
|
|
humanReadableScope = i18n.Messages.SCOPE_GDM_JOIN;
|
|
break;
|
|
case OAuth2Scopes.BOT:
|
|
humanReadableScope = i18n.Messages.SCOPE_BOT;
|
|
break;
|
|
case OAuth2Scopes.RPC:
|
|
humanReadableScope = i18n.Messages.SCOPE_RPC;
|
|
break;
|
|
case OAuth2Scopes.RPC_API:
|
|
humanReadableScope = i18n.Messages.SCOPE_RPC_API;
|
|
break;
|
|
case OAuth2Scopes.RPC_NOTIFICATIONS_READ:
|
|
humanReadableScope = i18n.Messages.SCOPE_RPC_NOTIFICATIONS_READ;
|
|
break;
|
|
case OAuth2Scopes.MESSAGES_READ:
|
|
humanReadableScope = i18n.Messages.SCOPE_MESSAGES_READ;
|
|
break;
|
|
default:
|
|
humanReadableScope = scope;
|
|
}
|
|
return (
|
|
<li key={scope} className="permission margin-top-8">
|
|
<i className="permission-checkmark" />
|
|
<FormText>{humanReadableScope}</FormText>
|
|
</li>
|
|
);
|
|
});
|
|
|
|
if (permissions.length) {
|
|
return (
|
|
<FormItem faded title={i18n.Messages.PERMISSIONS} className="margin-top-20">
|
|
<ul>
|
|
{permissions}
|
|
</ul>
|
|
</FormItem>
|
|
);
|
|
}
|
|
};
|
|
|
|
renderDescription() {
|
|
const {application} = this.props;
|
|
|
|
if (application.description) {
|
|
return (
|
|
<FormItem faded title={i18n.Messages.ABOUT_THIS_APP}>
|
|
<FormText>
|
|
{application.description}
|
|
</FormText>
|
|
</FormItem>
|
|
);
|
|
}
|
|
}
|
|
|
|
renderHeader = () => {
|
|
const {application, controlling} = this.props;
|
|
|
|
const iconSrc = AvatarUtils.getAppIconURL(application);
|
|
const icon = iconSrc
|
|
? <Flex.Child className="app-avatar no-user-drag" grow={0}>
|
|
<img src={iconSrc} />
|
|
</Flex.Child>
|
|
: null;
|
|
|
|
return (
|
|
<Flex className="header margin-bottom-20">
|
|
<Flex className="header-info">
|
|
{icon}
|
|
<Flex.Child>
|
|
<FormText type={FormTextTypes.LABEL_BOLD}>
|
|
<span>{application.name}</span>
|
|
{controlling ? <span className="controlling">{i18n.Messages.CURRENTLY_CONTROLLING}</span> : null}
|
|
</FormText>
|
|
</Flex.Child>
|
|
</Flex>
|
|
<Flex.Child wrap grow={0}>
|
|
<Button
|
|
className="delete-app"
|
|
color={ButtonColors.RED}
|
|
look={ButtonLooks.OUTLINED}
|
|
size={ButtonSizes.SMALL}
|
|
onClick={this.handleDeleteApp}>
|
|
{i18n.Messages.DEAUTHORIZE}
|
|
</Button>
|
|
</Flex.Child>
|
|
</Flex>
|
|
);
|
|
};
|
|
|
|
render() {
|
|
return (
|
|
<Card className="authed-app margin-bottom-8" outline>
|
|
{this.renderHeader()}
|
|
{this.renderDescription()}
|
|
{this.renderPermissions()}
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
// Handlers
|
|
|
|
handleDeleteApp = () => {
|
|
ModalActionCreators.push(props => {
|
|
return (
|
|
<Alert
|
|
title={i18n.Messages.DEAUTHORIZE_APP}
|
|
body={i18n.Messages.DELETE_APP_CONFIRM_MSG}
|
|
confirmText={i18n.Messages.DEAUTHORIZE}
|
|
cancelText={i18n.Messages.CANCEL}
|
|
onConfirm={this.props.onDelete}
|
|
{...props}
|
|
/>
|
|
);
|
|
});
|
|
};
|
|
}
|
|
|
|
class UserSettingsAuthedApps extends React.PureComponent {
|
|
props: {
|
|
hide: boolean,
|
|
applications: ?Array<OAuth2Token>,
|
|
connectedApps: Array<ConnectedApp>,
|
|
};
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
lodash.bindAll(this, ['handleDelete']);
|
|
}
|
|
|
|
isControlling(app) {
|
|
return this.props.connectedApps.find(a => a.id === app.id) ? true : false;
|
|
}
|
|
|
|
componentDidMount() {
|
|
AuthorizedAppsActionCreators.fetch();
|
|
}
|
|
|
|
handleDelete({id}) {
|
|
AuthorizedAppsActionCreators.delete(id);
|
|
}
|
|
|
|
renderEmpty() {
|
|
return (
|
|
<ThemedEmptyState className="margin-top-20">
|
|
<EmptyStateImage
|
|
darkSrc={require('../../images/empties/empty_user_settings_authed_apps_dark.svg')}
|
|
lightSrc={require('../../images/empties/empty_user_settings_authed_apps_light.svg')}
|
|
width={380}
|
|
height={282}
|
|
/>
|
|
<EmptyStateText note={i18n.Messages.NO_AUTHORIZED_APPS_NOTE}>
|
|
{i18n.Messages.NO_AUTHORIZED_APPS}
|
|
</EmptyStateText>
|
|
</ThemedEmptyState>
|
|
);
|
|
}
|
|
|
|
renderContent() {
|
|
const {applications} = this.props;
|
|
|
|
if (!applications) {
|
|
return <Spinner className="margin-top-20" type={Spinner.Type.SPINNING_CIRCLE} />;
|
|
}
|
|
|
|
if (applications.length === 0) {
|
|
return this.renderEmpty();
|
|
}
|
|
|
|
return applications
|
|
.map(a => ({
|
|
controlling: this.isControlling(a.application),
|
|
...a,
|
|
}))
|
|
.filter(({scopes, controlling}) => !(scopes.includes(OAuth2Scopes.RPC) && !controlling))
|
|
.sort((a, b) => +b.controlling - +a.controlling)
|
|
.map(app => <AuthorizedApp key={app.id} onDelete={this.handleDelete.bind(this, app)} {...app} />);
|
|
}
|
|
|
|
render() {
|
|
if (this.props.hide) {
|
|
return <StreamerModeEnabled />;
|
|
}
|
|
|
|
return (
|
|
<FormSection
|
|
className="user-settings-authorized-apps"
|
|
tag={FormTitleTags.H2}
|
|
title={i18n.Messages.AUTHORIZED_APPS}>
|
|
<FormNotice
|
|
className="margin-bottom-40"
|
|
type={CardTypes.PRIMARY}
|
|
title={i18n.Messages.APPLICATIONS_AND_CONNECTIONS}
|
|
body={i18n.Messages.APPLICATIONS_AND_CONNECTIONS_BODY}
|
|
/>
|
|
{this.renderContent()}
|
|
</FormSection>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default Flux.connectStores([AuthorizedAppsStore, StreamerModeStore], () => {
|
|
return {
|
|
hide: StreamerModeStore.hidePersonalInformation,
|
|
applications: AuthorizedAppsStore.getApps(),
|
|
connectedApps: AuthorizedAppsStore.getConnectedApps(),
|
|
};
|
|
})(UserSettingsAuthedApps);
|
|
|
|
|
|
|
|
// WEBPACK FOOTER //
|
|
// ./discord_app/components/user_settings/UserSettingsAuthedApps.js
|