/* @flow */ import React from 'react'; import PureRenderMixin from 'react-addons-pure-render-mixin'; import Animated from '../lib/animated'; import Select from 'react-select'; import i18n from '../i18n'; import InstantInvite from './InstantInvite'; import Flux from '../lib/flux'; import AnalyticsUtils from '../utils/AnalyticsUtils'; import InstantInviteActionCreators from '../actions/InstantInviteActionCreators'; import InstantInviteStore from '../stores/InstantInviteStore'; import StreamerModeStore from '../stores/StreamerModeStore'; import InstantInviteUtils from '../utils/InstantInviteUtils'; import GuildChannelStore from '../stores/views/GuildChannelStore'; import TransitionGroup from '../lib/transitions/TransitionGroup'; import Checkbox from './common/Checkbox'; import InvitePeriodExperimentStore from '../stores/experiments/InvitePeriodExperimentStore'; import createExperimentContainer from './experiments/ExperimentContainer'; import Spinner from './common/Spinner'; import Tooltip from './common/Tooltip'; import {ChannelTypes, ExperimentTypes, ExperimentBuckets} from '../Constants'; import '../styles/instant_invite_modal.styl'; const LOCATION = 'Invite Modal'; const MAX_AGE_OPTIONS = InstantInviteUtils.getMaxAgeOptions; const MAX_USES_OPTIONS = InstantInviteUtils.getMaxUsesOptions; function createAnimationMixin(reverse = false, duration = 250, easing = Animated.Easing.inOut(Animated.Easing.cubic)) { return { getInitialState() { return { opacity: new Animated.Value(0), }; }, componentDidAppear() { this.state.opacity.setValue(1); }, componentWillEnter(callback) { Animated.timing(this.state.opacity, {toValue: 1, duration, easing}).start(callback); }, componentWillLeave(callback) { Animated.timing(this.state.opacity, {toValue: 0, duration, easing}).start(callback); }, getAnimatedStyle() { return { opacity: this.state.opacity, }; }, }; } const BasicInstantInviteModal = React.createClass({ mixins: [createAnimationMixin()], render() { const {invite, guild, hide, maxAge, handleExpiresChange, showAdvanced} = this.props; let doesNotExpire = false; let instantInvite; let expireText; if (!invite) { instantInvite = ; } else { instantInvite = ( ); doesNotExpire = maxAge == MAX_AGE_OPTIONS[0].value; if (doesNotExpire) { expireText = i18n.Messages.INVITE_LINKS_NEVER_EXPIRES; } else if (maxAge == MAX_AGE_OPTIONS[1].value) { expireText = i18n.Messages.INVITE_LINKS_EXPIRE_AFTER_BY_DEFAULT; } else { expireText = i18n.Messages.INVITE_LINKS_EXPIRE_AFTER_1_DAY; } } return ( {i18n.Messages.INVITE_TO_SERVER_NAME.format({guildName: guild.name})} {i18n.Messages.SHARE_INVITE_LINK_FOR_ACCESS} {instantInvite} {expireText} {i18n.Messages.SET_INVITE_LINK_NEVER_EXPIRE} ); }, }); const AdvancedInstantInviteModal = React.createClass({ mixins: [createAnimationMixin(true)], render() { const { maxAge, maxUses, temporary, handleTemporaryChange, handleGenerateNewLink, hideAdvanced, handleMaxUsesChange, handleExpireAfterChange, } = this.props; const maxAgeValue = MAX_AGE_OPTIONS.find(age => age.value == maxAge); const maxUsesValue = MAX_USES_OPTIONS.find(uses => uses.value == maxUses); return ( {i18n.Messages.EXPIRE_AFTER} {i18n.Messages.MAX_NUMBER_OF_USES} {i18n.Messages.GRANT_TEMPORARY_MEMBERSHIP} {i18n.Messages.TEMPORARY_MEMBERSHIP_EXPLANATION} {i18n.Messages.CANCEL} {i18n.Messages.GENERATE_A_NEW_LINK} ); }, }); const InstantInviteModal = React.createClass({ mixins: [Flux.LazyStoreListenerMixin(InstantInviteStore, StreamerModeStore), PureRenderMixin], getInitialState() { return { showAdvanced: false, maxUses: MAX_USES_OPTIONS[0].value, temporary: false, channel: this.getChannel(), ...this.getStateFromStores(), }; }, getStateFromStores() { const invite = InstantInviteStore.getInvite(this.getChannel().id); const maxAge = invite ? invite.maxAge : MAX_AGE_OPTIONS[1].value; const savedMaxAge = maxAge == MAX_USES_OPTIONS[0].value ? MAX_AGE_OPTIONS[1].value : MAX_AGE_OPTIONS[0].value; return { invite, maxAge, savedMaxAge, hide: StreamerModeStore.hideInstantInvites, }; }, componentDidMount() { const validate = this.state.invite ? this.state.invite.code : null; const experimentBucket = this.props.experiment ? this.props.experiment.bucket : 0; const maxAge = (experimentBucket => { switch (experimentBucket) { case ExperimentBuckets.TREATMENT_1: case ExperimentBuckets.TREATMENT_2: return MAX_AGE_OPTIONS[5].value; // 1 Day default: return MAX_AGE_OPTIONS[1].value; } })(experimentBucket); InstantInviteActionCreators.createInvite( this.state.channel.id, { validate, max_age: maxAge, // eslint-disable-line camelcase }, 'InstantInviteModal Mount' ); let {source} = this.props; if (source != null) { if (window.inviteButtonSource) { source = window.inviteButtonSource; window.inviteButtonSource = undefined; } AnalyticsUtils.track('open_popout', { Type: 'Instant Invite Modal', Source: source, }); } }, getChannel() { const {channel, guild} = this.props; if (channel) { return channel; } if (this.state && this.state.channel) { return this.state.channel; } const channels = GuildChannelStore.getChannels(guild.id)[ChannelTypes.GUILD_TEXT]; return channels.find(channel => channel.channel.id == guild.id).channel; }, handleExpiresChange() { this.createInvite(this.state.savedMaxAge, this.state.maxUses, this.state.temporary, 'InstantInviteModal'); this.setState({ maxAge: this.state.savedMaxAge, savedMaxAge: this.state.maxAge, }); }, handleExpireAfterChange(value: string) { this.setState({ maxAge: value, savedMaxAge: value == MAX_AGE_OPTIONS[0].value ? MAX_AGE_OPTIONS[1].value : MAX_AGE_OPTIONS[0].value, }); }, handleMaxUsesChange(value: string) { this.setState({ maxUses: value, }); }, handleTemporaryChange(e: Event) { this.setState({ // $FlowFixMe temporary: e.currentTarget.checked, }); }, showAdvanced(e: Event) { e.preventDefault(); this.setState({ showAdvanced: true, }); }, hideAdvanced(e: Event) { e.preventDefault(); this.setState({ showAdvanced: false, }); }, handleGenerateNewLink(e: Event) { e.preventDefault(); this.createInvite(this.state.maxAge, this.state.maxUses, this.state.temporary, 'InstantInviteModal Regenerate'); this.setState({showAdvanced: false}); }, createInvite(maxAge: string | number, maxUses: string | number, temporary: boolean) { InstantInviteActionCreators.createInvite( this.state.channel.id, { /* eslint-disable camelcase */ max_age: parseInt(maxAge, 10), max_uses: parseInt(maxUses, 10), /* eslint-enable camelcase */ temporary: temporary, }, 'InstantInviteModal' ); }, render() { const {showAdvanced, maxAge, maxUses, temporary, hide, invite} = this.state; const {guild} = this.props; const content = showAdvanced ? : ; return ( {content} ); }, }); const renderComponent = (props, experimentDescriptor) => { return ; }; export default createExperimentContainer(InvitePeriodExperimentStore, { [ExperimentTypes.NONE]: props => , [ExperimentTypes.USER]: { [ExperimentBuckets.CONTROL]: renderComponent, [ExperimentBuckets.TREATMENT_1]: renderComponent, [ExperimentBuckets.TREATMENT_2]: renderComponent, }, }); // WEBPACK FOOTER // // ./discord_app/components/InstantInviteModal.js