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

362 lines
12 KiB
JavaScript
Executable file

import React from 'react';
import Flux from '../../lib/flux';
import i18n from '../../i18n';
import AvatarUtils from '../../utils/AvatarUtils';
import Alert from '../Alert';
import Platforms from '../../lib/Platforms';
import Tooltip from '../common/Tooltip';
import {FormSection, FormTitle, FormTitleTags, FormText, FormTextTypes, FormDivider} from '../../uikit/form';
import Flex from '../../uikit/Flex';
import Spinner from '../../uikit/Spinner';
import Select from '../../uikit/Select';
import Integration from '../../uikit/Integration';
import EmptyState, {EmptyStateText, EmptyStateImage} from '../../uikit/EmptyState';
import Switch from '../../uikit/Switch';
import moment from 'moment';
import UserSettingsStore from '../../stores/UserSettingsStore';
import EmojiStore from '../../stores/EmojiStore';
import GuildSettingsStore from '../../stores/GuildSettingsStore';
import ModalActionCreators from '../../actions/ModalActionCreators';
import UserSettingsModalActionCreators from '../../actions/UserSettingsModalActionCreators';
import GuildSettingsActionCreators from '../../actions/GuildSettingsActionCreators';
import {GuildSettingsSections, UserSettingsSections} from '../../Constants';
import '../../styles/guild_settings_integrations.styl';
const SUB_EXPIRE_BEHAVIOR_OPTIONS = [
{value: '0', label: i18n.Messages.REMOVE_SYNCED_ROLE},
{value: '1', label: i18n.Messages.KICK_FROM_SERVER},
];
const SUB_GRACE_PERIOD_OPTIONS = [1, 3, 7, 14, 30].map(days => {
return {
value: `${days}`,
label: i18n.Messages.N_DAYS.format({days}),
};
});
class IntegrationItem extends React.PureComponent {
constructor(props) {
super(props);
(this: any).handleToggleEnabled = this.handleToggleEnabled.bind(this);
(this: any).handleExpireBehaviorChange = this.handleExpireBehaviorChange.bind(this);
(this: any).handleExpireGracePeriodChange = this.handleExpireGracePeriodChange.bind(this);
(this: any).handleSync = this.handleSync.bind(this);
(this: any).handleShowRole = this.handleShowRole.bind(this);
(this: any).handleToggleEmotes = this.handleToggleEmotes.bind(this);
}
renderTwitchEmoticons(platform) {
const {guild, integration} = this.props;
let syncedEmoji = null;
const emojis = EmojiStore.getGuildEmoji(guild.id);
if (integration['enable_emoticons'] && emojis) {
const emoticons = Object.values(emojis)
.sort((a, b) => a.name.localeCompare(b.name))
.filter(emoji => !emoji.roles.length || emoji.roles.indexOf(integration['role_id']) >= 0)
.map((emoji, index) => {
return (
<Tooltip key={index} text={emoji.name}>
<img
key={emoji.name}
draggable={false}
className="emoji jumboable"
src={AvatarUtils.getEmojiURL({id: emoji.id})}
/>
</Tooltip>
);
});
if (emoticons.length > 0) {
syncedEmoji = <div className="twitch-emojis margin-top-8">{emoticons}</div>;
}
}
return (
<div>
<FormDivider className="margin-top-20 margin-bottom-20" />
<Flex className="emoji-sync margin-bottom-8">
<Flex align={Flex.Align.CENTER}>
<FormText>{i18n.Messages.ENABLE_TWITCH_EMOJI_SYNC}</FormText>
</Flex>
<Flex.Child grow={0} shrink={0}>
<Switch
value={integration['enable_emoticons']}
onChange={this.handleToggleEmotes}
disabled={integration.syncing}
fill={platform.color}
/>
</Flex.Child>
</Flex>
{syncedEmoji}
</div>
);
}
renderSyncDetails(formLabelSyncedSubs, numSubscribers) {
const {guild, integration} = this.props;
const role = guild.getRole(integration['role_id']);
let roleLink;
if (role != null) {
roleLink = <a className="synced-role-link" onClick={this.handleShowRole}>{role.name}</a>;
} else {
roleLink = i18n.Messages.NONE;
}
return (
<Flex>
<Flex.Child basis="50%">
<FormTitle className="margin-bottom-8">
{i18n.Messages.FORM_LABEL_SYNCED_ROLE}
</FormTitle>
<FormText>{roleLink}</FormText>
</Flex.Child>
<Flex.Child basis="50%">
<div className="sync-wrapper">
<FormTitle className="margin-bottom-8">
{formLabelSyncedSubs}
</FormTitle>
<Tooltip text={i18n.Messages.FORCE_SYNC}>
<button className="force-sync" disabled={integration.syncing} onClick={this.handleSync} />
</Tooltip>
</div>
<FormText>
{numSubscribers.format({subscribers: integration['subscriber_count']})}
</FormText>
<FormText type={FormTextTypes.DESCRIPTION}>
{i18n.Messages.LAST_SYNC.format({datetime: moment(integration['synced_at']).calendar()})}
</FormText>
</Flex.Child>
</Flex>
);
}
renderExpireToggles(formLabelExpireBehavior) {
const {integration} = this.props;
return (
<Flex>
<Flex.Child basis="50%">
<FormTitle className="margin-bottom-8">{formLabelExpireBehavior}</FormTitle>
<Select
transparent
value={`${integration['expire_behavior']}`}
clearable={false}
searchable={false}
options={SUB_EXPIRE_BEHAVIOR_OPTIONS}
disabled={integration.syncing}
onChange={this.handleExpireBehaviorChange}
/>
</Flex.Child>
<Flex.Child basis="50%">
<FormTitle className="margin-bottom-8">
{i18n.Messages.FORM_LABEL_EXPIRE_GRACE_PERIOD}
</FormTitle>
<Select
transparent
value={`${integration['expire_grace_period']}`}
clearable={false}
searchable={false}
options={SUB_GRACE_PERIOD_OPTIONS}
disabled={integration.syncing}
onChange={this.handleExpireGracePeriodChange}
/>
</Flex.Child>
</Flex>
);
}
render() {
const {integration, theme} = this.props;
const {enabled, syncing} = integration;
const platform = Platforms.get(integration.type);
let channelName;
let channelURL;
let formLabelExpireBehavior;
let formLabelSyncedSubs;
let numSubscribers;
let syncEmoticons;
switch (integration.type) {
case 'youtube':
channelName = integration.account.name;
channelURL = `gaming.youtube.com/channel/${integration.account.id}`;
formLabelExpireBehavior = i18n.Messages.FORM_LABEL_SPONSOR_EXPIRE_BEHAVIOR;
formLabelSyncedSubs = i18n.Messages.FORM_LABEL_SYNCED_SPONSORS;
numSubscribers = i18n.Messages.NUM_SPONSORS;
syncEmoticons = null;
break;
case 'twitch':
default:
channelName = channelURL = `twitch.tv/${integration.name}`;
formLabelExpireBehavior = i18n.Messages.FORM_LABEL_SUB_EXPIRE_BEHAVIOR;
formLabelSyncedSubs = i18n.Messages.FORM_LABEL_SYNCED_SUBS;
numSubscribers = i18n.Messages.NUM_SUBSCRIBERS;
syncEmoticons = this.renderTwitchEmoticons(platform);
}
let options;
if (enabled) {
options = (
<div className="integration-body">
{this.renderSyncDetails(formLabelSyncedSubs, numSubscribers)}
<FormDivider className="margin-top-20 margin-bottom-20" />
{this.renderExpireToggles(formLabelExpireBehavior)}
{syncEmoticons}
</div>
);
}
return (
<Integration
name={integration.user.toString()}
label={channelName}
labelUrl={`//${channelURL}`}
color={platform.color}
icon={platform.icon.color}
enabled={enabled}
syncing={syncing}
theme={theme}
handleSyncToggle={this.handleToggleEnabled}>
{options}
</Integration>
);
}
// Handlers
handleToggleEnabled() {
const {guild, integration} = this.props;
if (integration.syncing) return;
if (!integration.enabled) {
GuildSettingsActionCreators.enableIntegration(guild.id, integration.type, integration.id);
} else {
ModalActionCreators.push(props => {
const confirmText = integration['expire_behavior'] === 0
? i18n.Messages.REMOVE_SYNCED_ROLE
: i18n.Messages.KICK_FROM_SERVER;
return (
<Alert
title={i18n.Messages.DISABLE_INTEGRATION_TITLE}
body={
integration.type === 'youtube'
? i18n.Messages.DISABLE_INTEGRATION_YOUTUBE_BODY
: i18n.Messages.DISABLE_INTEGRATION_TWITCH_BODY
}
confirmText={confirmText}
cancelText={i18n.Messages.CANCEL}
onConfirm={() => GuildSettingsActionCreators.disableIntegration(guild.id, integration.id)}
{...props}
/>
);
});
}
}
handleExpireBehaviorChange(expireBehavior) {
const {guild, integration} = this.props;
GuildSettingsActionCreators.updateIntegration(
guild.id,
integration.id,
parseInt(expireBehavior.value),
integration['expire_grace_period'],
integration['enable_emoticons']
);
}
handleExpireGracePeriodChange(expireGracePeriod) {
const {guild, integration} = this.props;
GuildSettingsActionCreators.updateIntegration(
guild.id,
integration.id,
integration['expire_behavior'],
parseInt(expireGracePeriod.value),
integration['enable_emoticons']
);
}
handleSync() {
const {guild, integration} = this.props;
GuildSettingsActionCreators.syncIntegration(guild.id, integration.id);
}
handleShowRole() {
const {integration} = this.props;
GuildSettingsActionCreators.setSection(GuildSettingsSections.ROLES);
GuildSettingsActionCreators.selectRole(integration['role_id']);
}
handleToggleEmotes(e) {
const {guild, integration} = this.props;
GuildSettingsActionCreators.updateIntegration(
guild.id,
integration.id,
integration['expire_behavior'],
integration['expire_grace_period'],
e.currentTarget.checked
);
}
}
class GuildSettingsIntegrations extends React.PureComponent {
render() {
const {guild, integrations, theme} = this.props;
let content;
if (integrations == null) {
content = <Spinner className="margin-top-40" type={Spinner.Type.SPINNING_CIRCLE} />;
} else if (integrations.length === 0) {
content = (
<EmptyState theme={theme} className="margin-top-20">
<EmptyStateImage
darkSrc={require('../../images/empties/empty_server_settings_integrations_dark.svg')}
lightSrc={require('../../images/empties/empty_server_settings_integrations_light.svg')}
width={294}
height={192}
/>
<EmptyStateText note={i18n.Messages.NO_INTEGRATIONS.format({onConnect: this.handleConnect})}>
{i18n.Messages.NO_INTEGRATIONS_LABEL}
</EmptyStateText>
</EmptyState>
);
} else {
content = integrations.map((integration, i) =>
<IntegrationItem key={i} integration={integration} guild={guild} theme={theme} />
);
}
return (
<FormSection className="guild-settings-integrations" tag={FormTitleTags.H2} title={i18n.Messages.INTEGRATIONS}>
<FormText type={FormTextTypes.DESCRIPTION}>
{i18n.Messages.INTEGRATIONS_PRO_TIP.format({streamkitURL: 'https://discordapp.com/streamkit'})}
</FormText>
<FormDivider className="margin-top-20 margin-bottom-20" />
{content}
</FormSection>
);
}
// Handlers
handleConnect() {
UserSettingsModalActionCreators.open(UserSettingsSections.CONNECTIONS);
}
}
export default Flux.connectStores([GuildSettingsStore, UserSettingsStore], () => {
const {guild, integrations} = GuildSettingsStore.getProps();
return {
guild,
integrations,
theme: UserSettingsStore.theme,
};
})(GuildSettingsIntegrations);
// WEBPACK FOOTER //
// ./discord_app/components/guild_settings/GuildSettingsIntegrations.js