2017-06-08_509bba0/509bba0_unpacked_with_node_.../discord_app/components/guild_settings/GuildSettingsOverview.js

390 lines
13 KiB
JavaScript
Executable File

/* @flow */
import React from 'react';
import Flux from '../../lib/flux';
import i18n from '../../i18n';
import lodash from 'lodash';
import GuildIconUploader from '../common/GuildIconUploader';
import AvatarUploader from '../common/AvatarUploader';
import {RegionSelectModal} from '../common/RegionSelect';
import ImageInput from '../common/ImageInput';
import ChannelStore from '../../stores/ChannelStore';
import GuildSettingsStore from '../../stores/GuildSettingsStore';
import PermissionStore from '../../stores/PermissionStore';
import RegionStore from '../../stores/RegionStore';
import GuildSettingsActionCreators from '../../actions/GuildSettingsActionCreators';
import RegionActionCreators from '../../actions/RegionActionCreators';
import ModalActionCreators from '../../actions/ModalActionCreators';
import TextInput from '../../uikit/TextInput';
import FormItem from '../../uikit/form/FormItem';
import FormSection from '../../uikit/form/FormSection';
import FormTitle, {Tags} from '../../uikit/form/FormTitle';
import Flex from '../../uikit/Flex';
import FormText, {Types} from '../../uikit/form/FormText';
import FormDivider from '../../uikit/form/FormDivider';
import Button, {ButtonLooks, ButtonColors} from '../../uikit/Button';
import SettingsNotice from '../common/SettingsNotice';
import Select from '../../uikit/Select';
import RadioGroup from '../../uikit/RadioGroup';
import RegionSelector from '../../uikit/RegionSelector';
import AvatarUtils from '../../utils/AvatarUtils';
import type GuildRecord from '../../records/GuildRecord';
import {SPLASH_SIZE, ChannelTypes, UserNotificationSettings, GuildFeatures, Permissions} from '../../Constants';
import '../../styles/guild_settings_overview.styl';
import type ChannelRecord from '../../records/ChannelRecord';
type Region = {
name: string,
deprecated: boolean,
custom: boolean,
vip: boolean,
optimal: boolean,
id: string,
};
type Props = {
submitting: boolean,
region: Region,
regions: Array<Region>,
errors: {[key: string]: string},
guild: GuildRecord,
canManageGuild: boolean,
channels: Array<ChannelRecord>,
};
const NO_AFK_CHANNEL_SENTINEL = 'NO_AFK_CHANNEL';
const TIMEOUT_1_MIN = `${60}`;
const TIMEOUT_5_MIN = `${60 * 5}`;
const TIMEOUT_15_MIN = `${60 * 15}`;
const TIMEOUT_30_MIN = `${60 * 30}`;
const TIMEOUT_1_HR = `${60 * 60}`;
export const GuildSettingsOverviewNotice = Flux.connectStores([GuildSettingsStore], () => {
const {guild, submitting} = GuildSettingsStore.getProps();
return {
guild,
submitting,
onReset() {
GuildSettingsActionCreators.init(guild.id);
},
onSave() {
GuildSettingsActionCreators.saveGuild(guild.id, {
name: guild.name,
region: guild.region,
icon: guild.icon,
splash: guild.splash,
afkChannelId: guild.afkChannelId,
afkTimeout: guild.afkTimeout,
verificationLevel: guild.verificationLevel,
defaultMessageNotifications: guild.defaultMessageNotifications,
explicitContentFilter: guild.explicitContentFilter,
});
},
};
})(SettingsNotice);
class GuildSettingsOverview extends React.PureComponent {
props: Props;
constructor(props: Props) {
super(props);
lodash.bindAll(this, [
'handleNameChange',
'handleIconChange',
'handleAFKChannelChange',
'handleAFKTimeoutChange',
'handleDefaultMessageNotificationsChange',
'handleSplashChange',
'handleRegionSelectorClick',
'handleRegionChange',
]);
}
componentDidMount() {
if (this.props.regions == null) {
RegionActionCreators.fetchRegions(this.props.guild.id);
}
}
componentWillReceiveProps(nextProps) {
if (this.props.guild.id !== nextProps.guild.id) {
const regions = RegionStore.getRegions(nextProps.guild.id);
if (regions == null) {
RegionActionCreators.fetchRegions(nextProps.guild.id);
}
}
}
handleNameChange(name) {
GuildSettingsActionCreators.updateGuild({name});
}
handleIconChange(icon) {
GuildSettingsActionCreators.updateGuild({icon});
}
handleAFKChannelChange({value: afkChannelId}) {
if (afkChannelId === NO_AFK_CHANNEL_SENTINEL) {
afkChannelId = null;
}
GuildSettingsActionCreators.updateGuild({afkChannelId});
}
handleAFKTimeoutChange({value: afkTimeout}) {
GuildSettingsActionCreators.updateGuild({afkTimeout: parseInt(afkTimeout, 10)});
}
handleDefaultMessageNotificationsChange({value: defaultMessageNotifications}) {
GuildSettingsActionCreators.updateGuild({defaultMessageNotifications});
}
handleSplashChange(splash) {
GuildSettingsActionCreators.updateGuild({splash});
}
handleRegionChange({id}) {
GuildSettingsActionCreators.updateGuild({region: id});
}
handleRegionSelectorClick() {
const {regions} = this.props;
if (regions == null) {
return;
}
const selectableRegions = regions.filter(region => !region.deprecated);
ModalActionCreators.push(props =>
<RegionSelectModal regions={selectableRegions} onChange={this.handleRegionChange} {...props} />
);
}
renderBaseSettings() {
const {guild, region, regions, errors, canManageGuild} = this.props;
const regionDisabled = regions == null || regions.length == 0;
return (
<Flex className="guild-settings-base-section margin-bottom-40">
<Flex basis="50%" justify={Flex.Justify.BETWEEN}>
<Flex.Child wrap>
<GuildIconUploader
showIcon
name={guild.name}
icon={guild.icon}
onChange={this.handleIconChange}
disabled={!canManageGuild}
makeURL={icon => icon && AvatarUtils.getGuildIconURL({id: guild.id, icon})}
/>
</Flex.Child>
<Flex direction={Flex.Direction.VERTICAL} align={Flex.Align.START} style={{maxWidth: 180}}>
<FormText type={Types.DESCRIPTION} className="margin-bottom-8">
{i18n.Messages.GUILD_SETTINGS_ICON_RECOMMEND}
</FormText>
<Button
look={ButtonLooks.OUTLINED}
color={ButtonColors.WHITE}
disabled={!canManageGuild}
className="margin-top-8">
{i18n.Messages.UPLOAD_IMAGE}
<ImageInput onChange={this.handleIconChange} disabled={!canManageGuild} />
</Button>
</Flex>
</Flex>
<Flex.Child basis="50%">
<FormItem title={i18n.Messages.FORM_LABEL_SERVER_NAME} className="margin-bottom-20">
<TextInput
type="text"
disabled={!canManageGuild}
value={guild.name}
maxLength={100}
onChange={this.handleNameChange}
error={errors['name']}
/>
</FormItem>
<FormItem title={i18n.Messages.FORM_LABEL_SERVER_REGION}>
<RegionSelector
disabled={!canManageGuild || regionDisabled}
region={region}
onClick={this.handleRegionSelectorClick}
error={errors['region'] != null ? true : false}
/>
</FormItem>
</Flex.Child>
</Flex>
);
}
renderAFKSection() {
const {guild, canManageGuild, channels} = this.props;
const afkTimeout = guild.afkTimeout != null ? `${guild.afkTimeout}` : null;
const afkChannelId = guild.afkChannelId || NO_AFK_CHANNEL_SENTINEL;
const afkTimeouts = [
{value: TIMEOUT_1_MIN, label: i18n.Messages.DURATION_MINUTES.format({minutes: 1})},
{value: TIMEOUT_5_MIN, label: i18n.Messages.DURATION_MINUTES.format({minutes: 5})},
{value: TIMEOUT_15_MIN, label: i18n.Messages.DURATION_MINUTES.format({minutes: 15})},
{value: TIMEOUT_30_MIN, label: i18n.Messages.DURATION_MINUTES.format({minutes: 30})},
{value: TIMEOUT_1_HR, label: i18n.Messages.DURATION_HOURS.format({hours: 1})},
];
const channelsOptions = lodash(channels)
.filter(channel => channel['guild_id'] === guild.id)
.filter(channel => channel.type === ChannelTypes.GUILD_VOICE)
.map(channel => {
return {
value: channel.id,
label: channel.toString(),
};
})
.value();
channelsOptions.unshift({value: NO_AFK_CHANNEL_SENTINEL, label: i18n.Messages.NO_AFK_CHANNEL});
return (
<FormSection className="margin-bottom-40">
<Flex>
<Flex.Child>
<FormItem title={i18n.Messages.FORM_LABEL_AFK_CHANNEL}>
<Select
value={afkChannelId}
clearable={false}
searchable={false}
options={channelsOptions}
disabled={!canManageGuild}
onChange={this.handleAFKChannelChange}
/>
</FormItem>
</Flex.Child>
<Flex.Child>
<FormItem title={i18n.Messages.FORM_LABEL_AFK_TIMEOUT}>
<Select
value={afkTimeout}
clearable={false}
searchable={false}
options={afkTimeouts}
disabled={afkChannelId === NO_AFK_CHANNEL_SENTINEL || !canManageGuild}
onChange={this.handleAFKTimeoutChange}
/>
</FormItem>
</Flex.Child>
</Flex>
<FormText className="margin-top-8" type={Types.DESCRIPTION}>
{i18n.Messages.FORM_HELP_AFK_CHANNEL}
</FormText>
</FormSection>
);
}
renderNotificationSection() {
const {guild, canManageGuild} = this.props;
const options = [
{
name: i18n.Messages.FORM_LABEL_ALL_MESSAGES,
value: UserNotificationSettings.ALL_MESSAGES,
},
{
name: i18n.Messages.FORM_LABEL_ONLY_MENTIONS.format(),
value: UserNotificationSettings.ONLY_MENTIONS,
},
];
return (
<FormSection className="margin-bottom-40">
<FormTitle>{i18n.Messages.FORM_LABEL_DEFAULT_NOTIFICATION_SETTINGS}</FormTitle>
<FormText type={Types.DESCRIPTION} className="margin-bottom-20">
{i18n.Messages.GUILD_SETTINGS_DEFAULT_NOTIFICATION_SETTINGS_INTRO}
</FormText>
<FormText type={Types.DESCRIPTION} className="margin-bottom-20">
{i18n.Messages.GUILD_SETTINGS_DEFAULT_NOTIFICATION_SETTINGS_PROTIP.format({
videoURL: 'https://www.youtube.com/watch?v=zGl796352RI',
})}
</FormText>
<RadioGroup
options={options}
value={guild.defaultMessageNotifications}
disabled={!canManageGuild}
onChange={this.handleDefaultMessageNotificationsChange}
/>
</FormSection>
);
}
renderServerInviteBGSection() {
const {guild, canManageGuild} = this.props;
return (
<FormSection
title={i18n.Messages.GUILD_SETTINGS_SERVER_INVITE_BACKGROUND}
className="guild-settings-splash-section">
<Flex>
<Flex basis="50%" direction={Flex.Direction.VERTICAL} align={Flex.Align.START}>
<FormText type={Types.DESCRIPTION} className="margin-bottom-8">
{i18n.Messages.GUILD_SETTINGS_SPLASH_RECOMMEND}
</FormText>
<Button look={ButtonLooks.OUTLINED} color={ButtonColors.WHITE} className="margin-top-8">
{i18n.Messages.UPLOAD_BACKGROUND}
<ImageInput onChange={this.handleSplashChange} />
</Button>
</Flex>
<Flex.Child wrap basis="50%">
<AvatarUploader
avatar={guild.splash}
size={SPLASH_SIZE}
makeURL={splash => splash && AvatarUtils.getGuildSplashURL({id: guild.id, splash})}
disabled={!canManageGuild}
onChange={this.handleSplashChange}
hint={i18n.Messages.CHANGE_SPLASH}
/>
</Flex.Child>
</Flex>
</FormSection>
);
}
render() {
const hasSplash = this.props.guild.hasFeature(GuildFeatures.INVITE_SPLASH);
return (
<FormSection title={i18n.Messages.SERVER_OVERVIEW} tag={Tags.H2}>
{this.renderBaseSettings()}
<FormDivider className="margin-bottom-40" />
{this.renderAFKSection()}
<FormDivider className="margin-bottom-40" />
{this.renderNotificationSection()}
{hasSplash && <FormDivider className="margin-top-40 margin-bottom-20" />}
{hasSplash && this.renderServerInviteBGSection()}
</FormSection>
);
}
}
export default Flux.connectStores([ChannelStore, GuildSettingsStore, PermissionStore, RegionStore], () => {
const {guild, errors, submitting} = GuildSettingsStore.getProps();
const regions = RegionStore.getRegions(guild.id);
let region = {
id: 'unknown',
name: i18n.Messages.UNKNOWN_REGION,
vip: false,
};
if (regions != null) {
region = regions.find(region => region.id === guild.region) || region;
}
const permissions = PermissionStore.getGuildPermissions(guild.id) || 0;
const canManageGuild = (permissions & Permissions.MANAGE_GUILD) === Permissions.MANAGE_GUILD;
return {
channels: ChannelStore.getChannels(),
canManageGuild,
regions,
region,
guild,
errors,
submitting,
};
})(GuildSettingsOverview);
// WEBPACK FOOTER //
// ./discord_app/components/guild_settings/GuildSettingsOverview.js