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

356 lines
11 KiB
JavaScript
Executable file

import React from 'react';
import classNames from 'classnames';
import Flux from '../lib/flux';
import TransitionGroup from '../lib/transitions/TransitionGroup';
import RegionSelect from './common/RegionSelect';
import GuildIconUploader from './common/GuildIconUploader';
import CreateGuildModalStore from '../stores/CreateGuildModalStore';
import CreateGuildModalActionCreators from '../actions/CreateGuildModalActionCreators';
import i18n from '../i18n';
import '../styles/create_guild.styl';
import InstantInviteActionCreators from '../actions/InstantInviteActionCreators';
import InviteStore from '../stores/InviteStore';
import Animated from '../lib/animated';
import {InviteStates, CreateGuildModalScreens, Routes} from '../Constants';
function createAnimationMixin(reverse = false, duration = 250, easing = Animated.Easing.inOut(Animated.Easing.cubic)) {
return {
getInitialState() {
return {
translateX: new Animated.Value(0),
};
},
componentDidAppear() {
this.state.translateX.setValue(1);
},
componentWillEnter(callback) {
Animated.timing(this.state.translateX, {toValue: 1, duration, easing}).start(callback);
},
componentWillLeave(callback) {
Animated.timing(this.state.translateX, {toValue: 0, duration, easing}).start(callback);
},
getAnimatedStyle() {
return Animated.accelerate({
transform: [
{
translateX: this.state.translateX.interpolate({
inputRange: [0, 1],
outputRange: [reverse ? '-100%' : '100%', '0%'],
}),
},
],
});
},
};
}
const JoinGuildModal = React.createClass({
mixins: [Flux.StoreListenerMixin(InviteStore), createAnimationMixin()],
getInitialState() {
return {
code: null,
submitting: false,
hasError: false,
};
},
getStateFromStores() {
const code = this.state ? this.state.code : null;
return {
invite: InviteStore.getInvite(code) || {},
};
},
componentWillUpdate(nextProps, nextState) {
if (nextState.invite != null && this.state.invite !== nextState.invite) {
if (nextState.invite.state === InviteStates.RESOLVED) {
InstantInviteActionCreators.acceptInvite(nextState.invite.code, 'Join a Server Modal', () => {
CreateGuildModalActionCreators.close();
InstantInviteActionCreators.transitionToInviteChannel(
nextState.invite.guild.id,
nextState.invite.channel.id,
nextState.invite.channel.type
);
});
} else if (nextState.invite.state === InviteStates.EXPIRED) {
this.setState({submitting: false, hasError: true});
}
}
},
render() {
const isInviteInvalid = this.state.hasError;
//this.state.invite && this.state.invite.state === InviteStates.EXPIRED;
const errorMessage = isInviteInvalid
? <span className="error">({i18n.Messages.INSTANT_INVITE_EXPIRED})</span>
: null;
let host = process.env.INVITE_HOST;
let path = '/';
if (host == null) {
host = location.host;
path = Routes.INVITE('');
}
const examplePrefix = `${location.protocol}//${host}${path}`;
return (
<Animated.form className="form join-server" onSubmit={this.handleSubmit} style={this.getAnimatedStyle()}>
<div className="form-inner">
<h5>{i18n.Messages.JOIN_SERVER_TITLE}</h5>
<div className={classNames({'control-group': true})}>
<div className="instructions">
<p>{i18n.Messages.JOIN_SERVER_DESCRIPTION}</p>
<p className="sample-link">{examplePrefix}qJq5C</p>
<p className="sample-link">{examplePrefix}discord-developers</p>
<p className="sample-link">qJq5C</p>
</div>
</div>
<div className="link-container control-group">
<input
className={classNames({error: isInviteInvalid})}
type="text"
ref="invite"
onChange={this.handleTyped}
autoFocus
/>
<label htmlFor="invite">{i18n.Messages.FORM_LABEL_INSTANT_INVITE} {errorMessage}</label>
</div>
</div>
<div className="form-actions">
<button type="button" className="btn btn-default" onClick={this.props.onCancel}>
{i18n.Messages.BACK}
</button>
<button type="submit" className="btn btn-primary" disabled={this.state.submitting}>
{i18n.Messages.JOIN}
</button>
</div>
</Animated.form>
);
},
handleTyped() {
if (this.state.hasError) {
this.setState({hasError: false});
}
},
handleSubmit(e) {
e.preventDefault();
const inviteString = this.refs['invite'].value.trim();
if (inviteString === '') {
this.setState({hasError: true});
return;
}
const segments = inviteString.split('/');
const inviteCode = segments[segments.length - 1];
InstantInviteActionCreators.resolveInvite(inviteCode, 'Join Guild Modal');
this.setState({code: inviteCode, submitting: true});
},
});
const CreateGuildModal = React.createClass({
mixins: [createAnimationMixin()],
componentDidMount() {
if (this.props.guild.name.length === 0) {
this.refs['name'].focus();
}
},
render() {
const hasError = field => this.props.errors && this.props.errors[field] != null;
const renderError = field => {
if (hasError(field)) {
return <span className="error">({this.props.errors[field]})</span>;
} else {
return null;
}
};
return (
<Animated.form className="form create-guild" onSubmit={this.handleSubmit} style={this.getAnimatedStyle()}>
<div className="form-inner">
<h5>{i18n.Messages.CREATE_SERVER_TITLE}</h5>
<p>{i18n.Messages.CREATE_SERVER_DESCRIPTION.format()}</p>
<ul className="guild-form">
<li>
<div className={classNames({'control-group': true, error: hasError('name')})}>
<label htmlFor="guild-name">{i18n.Messages.FORM_LABEL_SERVER_NAME} {renderError('name')}</label>
<input
id="guild-name"
ref="name"
type="text"
onChange={this.handleNameChange}
defaultValue={this.props.guild.name}
placeholder={i18n.Messages.FORM_PLACEHOLDER_SERVER_NAME}
/>
</div>
<div className="control-group">
<label htmlFor="guild-region">{i18n.Messages.FORM_LABEL_SERVER_REGION}</label>
<RegionSelect
id="guild-region"
ref="region"
value={this.props.guild.region}
onChange={this.handleRegionChange}
/>
</div>
</li>
<li>
<GuildIconUploader
name={this.props.guild.name}
icon={this.props.guild.icon}
onChange={this.handleIconChange}
/>
</li>
</ul>
</div>
<div className="form-actions">
<button type="button" className="btn btn-default" onClick={this.props.onCancel}>
{i18n.Messages.BACK}
</button>
<button type="submit" className="btn btn-primary" disabled={this.props.submitting}>
{i18n.Messages.CREATE}
</button>
</div>
</Animated.form>
);
},
// Handlers
handleNameChange(e) {
CreateGuildModalActionCreators.updateTemporaryGuild({name: e.currentTarget.value});
},
handleRegionChange(region) {
CreateGuildModalActionCreators.updateTemporaryGuild({region});
},
handleIconChange(icon) {
CreateGuildModalActionCreators.updateTemporaryGuild({icon});
},
handleSubmit(e) {
e.preventDefault();
CreateGuildModalActionCreators.createGuild(this.props.guild.name, this.props.guild.region, this.props.guild.icon);
},
});
const GuildActionButton = React.createClass({
render() {
let header;
let body;
let cta;
switch (this.props.type) {
case 'create':
header = i18n.Messages.CREATE;
body = i18n.Messages.CREATE_SERVER_BUTTON_BODY;
cta = i18n.Messages.CREATE_SERVER_BUTTON_CTA;
break;
case 'join':
header = i18n.Messages.JOIN;
body = i18n.Messages.JOIN_SERVER_BUTTON_BODY;
cta = i18n.Messages.JOIN_SERVER_BUTTON_CTA;
break;
}
return (
<div className={`action ${this.props.type}`} onMouseEnter={this.props.onMouseEnter} onClick={this.props.onClick}>
<div className="action-header">{header}</div>
<div className="action-body">{body}</div>
<div className="action-icon" />
<button className="btn btn-primary" type="button" onClick={this.props.onClick}>{cta}</button>
</div>
);
},
});
const CreateOrJoinGuildModal = React.createClass({
mixins: [createAnimationMixin(true)],
render() {
return (
<Animated.div className="form create-or-join" style={this.getAnimatedStyle()}>
<div className="form-inner">
<header>{i18n.Messages.CREATE_OR_JOIN_MODAL_HEADER}</header>
<div className="actions">
<GuildActionButton
type="create"
onClick={this.handleClick.bind(this, CreateGuildModalScreens.CreateGuild)}
/>
<GuildActionButton type="join" onClick={this.handleClick.bind(this, CreateGuildModalScreens.JoinGuild)} />
<div className="or">or</div>
</div>
</div>
</Animated.div>
);
},
handleClick(selectedScreen) {
this.props.onClick(selectedScreen);
},
});
const CreateOrJoinGuildContainer = React.createClass({
statics: {
modalConfig: {
store: CreateGuildModalStore,
},
},
propTypes: {
errors: React.PropTypes.object.isRequired,
submitting: React.PropTypes.bool.isRequired,
},
close() {
CreateGuildModalActionCreators.close();
},
handleNavigateScreen(selectedScreen) {
CreateGuildModalActionCreators.setScreen(selectedScreen);
},
render() {
let body;
if (this.props.screen === CreateGuildModalScreens.Choose) {
body = <CreateOrJoinGuildModal key={CreateGuildModalScreens.Choose} onClick={this.handleNavigateScreen} />;
} else if (this.props.screen === CreateGuildModalScreens.CreateGuild) {
body = (
<CreateGuildModal
key={CreateGuildModalScreens.CreateGuild}
onCancel={() => this.handleNavigateScreen(CreateGuildModalScreens.Choose)}
{...this.props}
/>
);
} else if (this.props.screen === CreateGuildModalScreens.JoinGuild) {
body = (
<JoinGuildModal
key={CreateGuildModalScreens.JoinGuild}
onCancel={() => this.handleNavigateScreen(CreateGuildModalScreens.Choose)}
{...this.props}
/>
);
}
return (
<TransitionGroup className="create-guild-container" component="div">
{body}
</TransitionGroup>
);
},
});
export default CreateOrJoinGuildContainer;
// WEBPACK FOOTER //
// ./discord_app/components/CreateGuildModal.js