390 lines
13 KiB
JavaScript
Executable file
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
|