267 lines
8.6 KiB
JavaScript
267 lines
8.6 KiB
JavaScript
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>
|
|
);
|
|
}
|
|
}
|