2017-06-08_509bba0/509bba0_unpacked_with_node_modules/discord_app/components/user_settings/UserSettingsConnections.js
2022-07-26 10:06:20 -07:00

473 lines
14 KiB
JavaScript
Executable file

import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import Flux from '../../lib/flux';
import Platforms from '../../lib/Platforms';
import Alert from '../Alert';
import GuildIcon from '../common/GuildIcon';
import {FormSection, FormTitle, FormTitleTags, FormText, FormTextTypes, FormItem, FormDivider} from '../../uikit/form';
import Card from '../../uikit/Card';
import Spinner from '../../uikit/Spinner';
import Button, {ButtonLooks, ButtonColors, ButtonSizes} from '../../uikit/Button';
import SwitchItem from '../../uikit/SwitchItem';
import EmptyState, {EmptyStateText, EmptyStateImage} from '../../uikit/EmptyState';
import ConnectAccountButton, {authorize} from '../common/ConnectAccountButton';
import StreamerModeEnabled from '../StreamerModeEnabled';
import ConnectedAccountRecord from '../../records/ConnectedAccountRecord';
import ConnectedAccountsStore from '../../stores/ConnectedAccountsStore';
import GuildStore from '../../stores/GuildStore';
import StreamerModeStore from '../../stores/StreamerModeStore';
import UserSettingsStore from '../../stores/UserSettingsStore';
import DetectedPlatformAccountsStore from '../../stores/DetectedPlatformAccountsStore';
import ModalActionCreators from '../../actions/ModalActionCreators';
import ConnectedAccountsActionCreators from '../../actions/ConnectedAccountsActionCreators';
import UserSettingsActionCreators from '../../actions/UserSettingsActionCreators';
import i18n from '../../i18n';
import {Colors, UNSAFE_PLATFORM_TYPES, VERIFIABLE_PLATFORM_TYPES} from '../../Constants';
import NativeUtils from '../../utils/NativeUtils';
import classNames from 'classnames';
import '../../styles/user_settings_connections.styl';
import '../../styles/elevations.styl';
const ThemedEmptyState = Flux.connectStores([UserSettingsStore], () => ({
theme: UserSettingsStore.theme,
}))(EmptyState);
const Integration = React.createClass({
mixins: [PureRenderMixin, Flux.StoreListenerMixin(GuildStore, ConnectedAccountsStore)],
getStateFromStores() {
const {integration} = this.props;
return {
isJoining: ConnectedAccountsStore.isJoining(integration.id),
isMember: GuildStore.getGuild(integration.guild.id),
};
},
render() {
const {isMember, isJoining} = this.state;
const {integration} = this.props;
let joinButton;
if (!isMember) {
joinButton = (
<Button
size={ButtonSizes.SMALL}
look={ButtonLooks.GHOST}
color={ButtonColors.WHITE}
onClick={this.handleJoinGuild}
disabled={isJoining}>
<span>
{isJoining ? i18n.Messages.JOINING_SERVER : i18n.Messages.JOIN_SERVER}
</span>
</Button>
);
}
let channelName;
let channelURL;
switch (integration.type) {
case 'youtube':
channelName = integration.account.name;
channelURL = `gaming.youtube.com/channel/${integration.account.id}`;
break;
case 'twitch':
default:
channelName = channelURL = `twitch.tv/${integration.account.name}`;
}
return (
<div className="integration margin-top-8">
<div>
<GuildIcon size="small" guild={integration.guild} />
<div className="integration-inner">
<FormText>
{integration.guild.toString()}
</FormText>
<a className="channel-link" href={`//${channelURL}`} target="_blank">
{channelName}
</a>
</div>
</div>
{joinButton}
</div>
);
},
// Handlers
handleJoinGuild() {
ConnectedAccountsActionCreators.joinServer(this.props.integration.id);
},
});
class ConnectedAccount extends React.PureComponent {
static propTypes = {
onDisconnect: React.PropTypes.func.isRequired,
account: React.PropTypes.instanceOf(ConnectedAccountRecord).isRequired,
};
constructor(props) {
super(props);
const {friendSync, visibility, verified} = props.account;
this.state = {
friendSync,
visibility,
verified,
};
}
componentWillReceiveProps({account}) {
const {friendSync, visibility, verified} = account;
// The user just verified their connection
if (!this.state.verified && verified) {
this.handleInProgressVisibilityChange();
}
this.setState({
friendSync,
visibility,
verified,
});
}
renderHeader(platform) {
const {account} = this.props;
return (
<div className="connection-header margin-bottom-20">
<img className="connection-icon no-user-drag" src={platform.icon.color} />
<div>
<FormText className="connection-account-value">
{account.name}
</FormText>
<FormText className="connection-account-label" type={FormTextTypes.DESCRIPTION}>
{i18n.Messages.ACCOUNT_NAME}
</FormText>
</div>
<div className="connection-delete flex-center" onClick={this.handleDisconnect}>
<span>{i18n.Messages.SERVICE_CONNECTIONS_DISCONNECT}</span>
</div>
</div>
);
}
renderConnectionOptions() {
const {visibility, friendSync} = this.state;
const {account} = this.props;
let syncFriendsCheckbox;
if (UNSAFE_PLATFORM_TYPES.has(account.type)) {
syncFriendsCheckbox = (
<SwitchItem
className="connection-option-switch margin-bottom-20"
clear
hideBorder
value={friendSync}
onChange={this.handleFriendSyncChange}>
{i18n.Messages.SYNC_FRIENDS}
</SwitchItem>
);
}
return (
<div className="connection-options-wrapper">
<div className="connection-options">
<SwitchItem
className="connection-option-switch margin-bottom-20"
clear
hideBorder
value={visibility === 1}
onChange={this.handleVisibilityChange}>
{i18n.Messages.DISPLAY_ON_PROFILE}
</SwitchItem>
{syncFriendsCheckbox}
</div>
<div />
</div>
);
}
renderIntegrations(platform) {
const {account} = this.props;
// Grab the name in all caps for Colors
const platformName = platform.name.toUpperCase().replace(/\./g, '');
if (account.revoked) {
return (
<FormItem className="integrations-wrapper">
<FormTitle tag={FormTitleTags.H5}>
<span style={{color: Colors[`${platformName}_200`]}}>{i18n.Messages.SUB_ENABLED_SERVERS}</span>
</FormTitle>
<FormText>
{i18n.Messages.CONNECTED_ACCOUNT_REVOKED.format({
onReconnect: this.handleReconnect,
})}
</FormText>
</FormItem>
);
} else if (account.integrations.length > 0) {
return (
<FormItem className="integrations-wrapper">
<FormTitle tag={FormTitleTags.H5} className="integration-sub-enabled-title">
<span style={{color: Colors[`${platformName}_200`]}}>
{i18n.Messages.SUB_ENABLED_SERVERS}
</span>
</FormTitle>
<div className="connection-integrations-inner">
{account.integrations.map(integration =>
<Integration key={integration.id} integration={integration} color={platform.color} />
)}
</div>
</FormItem>
);
}
}
renderDivider() {
const {revoked, integrations} = this.props.account;
if (revoked || integrations.length > 0) {
return <FormDivider className="connected-account-separator" />;
}
}
render() {
const {account} = this.props;
const platform = Platforms.get(account.type);
return (
<div
className="connection elevation-low margin-bottom-8"
style={{
borderColor: platform.color,
backgroundColor: platform.color,
}}>
{this.renderHeader(platform)}
{this.renderConnectionOptions()}
{this.renderDivider()}
{this.renderIntegrations(platform)}
</div>
);
}
// Handlers
handleReconnect = () => {
authorize(this.props.account.type);
};
handleDisconnect = () => {
if (UNSAFE_PLATFORM_TYPES.has(this.props.account.type)) {
this.props.onDisconnect();
} else {
const platform = Platforms.get(this.props.account.type);
ModalActionCreators.push(props => {
return (
<Alert
title={i18n.Messages.DISCONNECT_ACCOUNT_TITLE.format({
name: platform.name,
})}
body={i18n.Messages.DISCONNECT_ACCOUNT_BODY}
confirmText={i18n.Messages.DISCONNECT_ACCOUNT}
cancelText={i18n.Messages.CANCEL}
onConfirm={this.props.onDisconnect}
{...props}
/>
);
});
}
};
handleVisibilityChange = e => {
const {account} = this.props;
const visibility = e.currentTarget.checked ? 1 : 0;
if (VERIFIABLE_PLATFORM_TYPES.has(account.type) && !this.state.verified) {
this._inProgressVisibility = visibility;
authorize(account.type);
return;
}
this.setState({visibility});
ConnectedAccountsActionCreators.setVisibility(account.type, account.id, visibility);
};
handleInProgressVisibilityChange = () => {
if (this._inProgressVisibility == null) {
return;
}
const {account} = this.props;
ConnectedAccountsActionCreators.setVisibility(account.type, account.id, this._inProgressVisibility);
this._inProgressVisibility = null;
};
handleFriendSyncChange = e => {
const {account} = this.props;
const friendSync = e.currentTarget.checked;
this.setState({friendSync});
ConnectedAccountsActionCreators.setFriendSync(account.type, account.id, friendSync);
};
}
const UserSettingsConnections = React.createClass({
mixins: [
PureRenderMixin,
Flux.StoreListenerMixin(
ConnectedAccountsStore,
DetectedPlatformAccountsStore,
UserSettingsStore,
StreamerModeStore
),
],
getInitialState() {
return {
descriptionWarning: false,
};
},
getStateFromStores() {
return {
hide: StreamerModeStore.hidePersonalInformation,
fetching: ConnectedAccountsStore.isFetching(),
accounts: ConnectedAccountsStore.getAccounts(),
notDetectedPlatformTypes: DetectedPlatformAccountsStore.getNotDetectedPlatformTypes(),
detectPlatformAccounts: UserSettingsStore.detectPlatformAccounts,
};
},
componentDidUpdate(prevProps, prevState) {
const {notDetectedPlatformTypes} = this.state;
if (prevState.notDetectedPlatformTypes !== notDetectedPlatformTypes) {
this.setState({
descriptionWarning: true,
});
}
},
componentDidMount() {
ConnectedAccountsActionCreators.fetch();
},
handleDisconnect({type, id, name}) {
ConnectedAccountsActionCreators.disconnect(type, id, name);
},
handleDetectPlatformAccounts(e) {
UserSettingsActionCreators.updateRemoteSettings({
detectPlatformAccounts: e.currentTarget.checked,
});
},
renderConnectCard() {
const {descriptionWarning} = this.state;
let description = i18n.Messages.CONNECT_ACCOUNT_DESCRIPTION;
if (descriptionWarning) {
description = (
<div className="warning">
{i18n.Messages.CONNECT_ACCOUNT_NONE_DETECTED}
</div>
);
}
return (
<Card
className={classNames('connect-account-list', {
'margin-bottom-20': !NativeUtils.embedded,
})}>
<FormTitle faded className="margin-bottom-4">
{i18n.Messages.CONNECT_ACCOUNT_TITLE}
</FormTitle>
<FormText className="user-settings-connections-list-description margin-bottom-8">
{description}
</FormText>
<div className="settings-connected-accounts">
{Platforms.filter(platform => platform.enabled).map(platform =>
<ConnectAccountButton key={platform.type} type={platform.type} location="User Settings" />
)}
</div>
</Card>
);
},
renderDetectPlatformAccounts() {
const {detectPlatformAccounts} = this.state;
if (NativeUtils.embedded) {
return (
<SwitchItem
value={detectPlatformAccounts}
onChange={this.handleDetectPlatformAccounts}
className="margin-top-20 margin-bottom-20">
{i18n.Messages.DETECT_PLATFORM_ACCOUNTS}
</SwitchItem>
);
}
},
renderConnectionList() {
const {fetching, accounts} = this.state;
let connectionList;
if (fetching) {
connectionList = <Spinner className="margin-top-20" type={Spinner.Type.SPINNING_CIRCLE} />;
} else if (accounts.length === 0) {
connectionList = (
<ThemedEmptyState className="margin-top-40">
<EmptyStateImage
darkSrc={require('../../images/empties/empty_user_settings_connections_dark.svg')}
lightSrc={require('../../images/empties/empty_user_settings_connections_light.svg')}
width={230}
height={220}
/>
<EmptyStateText note={i18n.Messages.CONNECTED_ACCOUNTS_NONE}>
{i18n.Messages.CONNECTED_ACCOUNTS_NONE_TITLE}
</EmptyStateText>
</ThemedEmptyState>
);
} else {
connectionList = accounts.map((account, i) =>
<ConnectedAccount key={i} account={account} onDisconnect={this.handleDisconnect.bind(this, account)} />
);
}
return (
<FormItem className="connection-list">
{connectionList}
</FormItem>
);
},
render() {
if (this.state.hide) {
return <StreamerModeEnabled />;
}
return (
<FormSection className="user-settings-connections" tag={FormTitleTags.H2} title={i18n.Messages.CONNECTIONS}>
{this.renderConnectCard()}
{this.renderDetectPlatformAccounts()}
{this.renderConnectionList()}
</FormSection>
);
},
});
export default UserSettingsConnections;
// WEBPACK FOOTER //
// ./discord_app/components/user_settings/UserSettingsConnections.js