import React from 'react'; import { CLAIM_VALUES, isNameValid } from 'lbry-redux'; import { ActivityIndicator, Picker, Text, TextInput, TouchableOpacity, View } from 'react-native'; import Button from 'component/button'; import Colors from 'styles/colors'; import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Icon from 'react-native-vector-icons/FontAwesome5'; import Link from 'component/link'; import channelSelectorStyle from 'styles/channelSelector'; export default class ChannelSelector extends React.PureComponent { constructor(props) { super(props); this.state = { currentSelectedValue: Constants.ITEM_ANONYMOUS, newChannelName: '', newChannelBid: 0.1, addingChannel: false, creatingChannel: false, newChannelNameError: '', newChannelBidError: '', createChannelError: undefined, showCreateChannel: false, }; } componentDidMount() { const { channels = [], channelName, fetchChannelListMine, fetchingChannels } = this.props; if ((!channels || channels.length === 0) && !fetchingChannels) { fetchChannelListMine(); } this.setState({ currentSelectedValue: channelName }); } componentWillReceiveProps(nextProps) { const { channels: prevChannels = [], channelName } = this.props; const { channels = [] } = nextProps; if (channels && channels.length !== prevChannels.length && channelName !== this.state.currentSelectedValue) { this.setState({ currentSelectedValue: channelName }); } } handleCreateCancel = () => { this.setState({ showCreateChannel: false, newChannelName: '', newChannelBid: 0.1 }); }; handlePickerValueChange = (itemValue, itemIndex) => { if (Constants.ITEM_CREATE_A_CHANNEL === itemValue) { this.setState({ showCreateChannel: true }); } else { this.handleCreateCancel(); this.handleChannelChange(Constants.ITEM_ANONYMOUS === itemValue ? CLAIM_VALUES.CHANNEL_ANONYMOUS : itemValue); } this.setState({ currentSelectedValue: itemValue }); }; handleChannelChange = value => { const { onChannelChange } = this.props; const { newChannelBid } = this.state; const channel = value; if (channel === CLAIM_VALUES.CHANNEL_NEW) { this.setState({ addingChannel: true }); if (onChannelChange) { onChannelChange(value); } this.handleNewChannelBidChange(newChannelBid); } else { this.setState({ addingChannel: false }); if (onChannelChange) { onChannelChange(value); } } }; handleNewChannelNameChange = value => { const { notify } = this.props; let newChannelName = value, newChannelNameError = ''; if (newChannelName.startsWith('@')) { newChannelName = newChannelName.slice(1); } if (newChannelName.trim().length > 0 && !isNameValid(newChannelName)) { newChannelNameError = 'Your channel name contains invalid characters.'; } else if (this.channelExists(newChannelName)) { newChannelNameError = 'You have already created a channel with the same name.'; } this.setState({ newChannelName, newChannelNameError, }); }; handleNewChannelBidChange = newChannelBid => { const { balance, notify } = this.props; let newChannelBidError; if (newChannelBid <= 0) { newChannelBidError = __('Please enter a deposit above 0'); } else if (newChannelBid === balance) { newChannelBidError = __('Please decrease your deposit to account for transaction fees'); } else if (newChannelBid > balance) { newChannelBidError = __('Deposit cannot be higher than your balance'); } notify({ message: newChannelBidError }); this.setState({ newChannelBid, newChannelBidError, }); }; handleCreateChannelClick = () => { const { balance, createChannel, onChannelChange, notify } = this.props; const { newChannelBid, newChannelName } = this.state; if (newChannelName.trim().length === 0 || !isNameValid(newChannelName.substr(1), false)) { notify({ message: 'Your channel name contains invalid characters.' }); return; } if (this.channelExists(newChannelName)) { notify({ message: 'You have already created a channel with the same name.' }); return; } if (newChannelBid > balance) { notify({ message: 'Deposit cannot be higher than your balance' }); return; } const channelName = `@${newChannelName}`; this.setState({ creatingChannel: true, createChannelError: undefined, }); const success = () => { this.setState({ creatingChannel: false, addingChannel: false, currentSelectedValue: channelName, showCreateChannel: false, }); if (onChannelChange) { onChannelChange(channelName); } }; const failure = () => { notify({ message: 'Unable to create channel due to an internal error.' }); this.setState({ creatingChannel: false, }); }; createChannel(channelName, newChannelBid).then(success, failure); }; channelExists = name => { const { channels = [] } = this.props; if (channels) { for (let channel of channels) { if ( name.toLowerCase() === channel.name.toLowerCase() || `@${name}`.toLowerCase() === channel.name.toLowerCase() ) { return true; } } } return false; }; render() { const channel = this.state.addingChannel ? 'new' : this.props.channel; const { enabled, fetchingChannels, channels = [] } = this.props; const pickerItems = [Constants.ITEM_ANONYMOUS, Constants.ITEM_CREATE_A_CHANNEL].concat( channels ? channels.map(ch => ch.name) : [] ); const { newChannelName, newChannelNameError, newChannelBid, newChannelBidError, creatingChannel, createChannelError, addingChannel, showCreateChannel, } = this.state; return ( <View style={channelSelectorStyle.container}> <Picker enabled={enabled} selectedValue={this.state.currentSelectedValue} style={channelSelectorStyle.channelPicker} itemStyle={channelSelectorStyle.channelPickerItem} onValueChange={this.handlePickerValueChange} > {pickerItems.map(item => ( <Picker.Item label={item} value={item} key={item} /> ))} </Picker> {showCreateChannel && ( <View style={channelSelectorStyle.createChannelContainer}> <View style={channelSelectorStyle.channelInputContainer}> <Text style={channelSelectorStyle.channelAt}>@</Text> <TextInput style={channelSelectorStyle.channelNameInput} value={this.state.newChannelName} onChangeText={this.handleNewChannelNameChange} placeholder={'Channel name'} underlineColorAndroid={Colors.NextLbryGreen} /> </View> {newChannelNameError.length > 0 && ( <Text style={channelSelectorStyle.inlineError}>{newChannelNameError}</Text> )} <View style={channelSelectorStyle.bidRow}> <Text style={channelSelectorStyle.label}>Deposit</Text> <TextInput style={channelSelectorStyle.bidAmountInput} value={String(newChannelBid)} onChangeText={this.handleNewChannelBidChange} placeholder={'0.00'} keyboardType={'number-pad'} underlineColorAndroid={Colors.NextLbryGreen} /> <Text style={channelSelectorStyle.currency}>LBC</Text> </View> <Text style={channelSelectorStyle.helpText}> This LBC remains yours. It is a deposit to reserve the name and can be undone at any time. </Text> <View style={channelSelectorStyle.buttonContainer}> {creatingChannel && <ActivityIndicator size={'small'} color={Colors.LbryGreen} />} {!creatingChannel && ( <View style={channelSelectorStyle.buttons}> <Link style={channelSelectorStyle.cancelLink} text="Cancel" onPress={this.handleCreateCancel} /> <Button style={channelSelectorStyle.createButton} disabled={!(newChannelName.trim().length > 0 && newChannelBid > 0)} text="Create" onPress={this.handleCreateChannelClick} /> </View> )} </View> </View> )} </View> ); } }