// Account registration. import React, { Suspense } from 'react'; import { FormattedMessage } from 'react-intl'; import AvatarCrop from '../widgets/avatar-crop.jsx'; import AvatarUpload from '../widgets/avatar-upload.jsx'; import CheckBox from '../widgets/checkbox.jsx'; import PhoneEdit from '../widgets/phone-edit.jsx'; import VisiblePassword from '../widgets/visible-password.jsx'; import LocalStorageUtil from '../lib/local-storage.js'; import { imageScaled, blobToBase64, makeImageUrl } from '../lib/blob-helpers.js'; import { theCard } from '../lib/utils.js'; import { truncateString } from '../lib/strformat.js'; import { AVATAR_SIZE, MAX_AVATAR_BYTES, MAX_EXTERN_ATTACHMENT_SIZE, MAX_TITLE_LENGTH } from '../config.js'; export default class CreateAccountView extends React.PureComponent { constructor(props) { super(props); this.state = { login: '', password: '', meth: '', email: '', tel: '', fn: '', // full/formatted name imageUrl: null, uploadUrl: null, newAvatar: null, newAvatarMime: null, buttonDisabled: false, saveToken: LocalStorageUtil.getObject('keep-logged-in') }; this.handleLoginChange = this.handleLoginChange.bind(this); this.handlePasswordChange = this.handlePasswordChange.bind(this); this.handleEmailChange = this.handleEmailChange.bind(this); this.handlePhoneChange = this.handlePhoneChange.bind(this); this.handleFnChange = this.handleFnChange.bind(this); this.handleImageChanged = this.handleImageChanged.bind(this); this.handleToggleSaveToken = this.handleToggleSaveToken.bind(this); this.handleAvatarCropped = this.handleAvatarCropped.bind(this); this.handleAvatarCropCancel = this.handleAvatarCropCancel.bind(this); this.uploadAvatar = this.uploadAvatar.bind(this); this.handleSubmit = this.handleSubmit.bind(this); // Connection will trigger change by changing the this.props.serverVersion. props.tinode.connect() .catch(err => { this.props.onError(err.message, 'err'); }); } handleLoginChange(e) { this.setState({login: e.target.value}); } handlePasswordChange(password) { this.setState({password: password}); } handleEmailChange(e) { this.setState({meth: 'email', email: e.target.value}); } handlePhoneChange(number) { this.setState({meth: 'tel', tel: number}); } handleFnChange(e) { this.setState({fn: e.target.value}); } handleImageChanged(mime, img) { this.setState({newAvatar: img, newAvatarMime: mime}); if (!img) { // User cleared the image. this.setState({imageUrl: null, uploadUrl: null}); } } handleToggleSaveToken() { LocalStorageUtil.setObject('keep-logged-in', !this.state.saveToken); this.setState({saveToken: !this.state.saveToken}); } handleSubmit(e) { e.preventDefault(); this.props.onCreateAccount( this.state.login.trim(), this.state.password.trim(), theCard(truncateString(this.state.fn.trim(), MAX_TITLE_LENGTH), this.state.uploadUrl), { 'meth': this.state.meth, 'val': this.state.meth == 'email' ? this.state.email : this.state.meth == 'tel' ? this.state.tel : null } ); } // AvatarCropView calls this method when the user has cropped the image. handleAvatarCropped(mime, blob, width, height) { const url = blob ? URL.createObjectURL(blob) : null; this.setState({newAvatar: null, newAvatarMime: null}); if (blob) { this.uploadAvatar(mime, blob, width, height); } } handleAvatarCropCancel() { this.setState({newAvatar: null, newAvatarMime: null}); } // Utility method for converting cropped avatar blob to bytes for sending inband or // for uploading it to the server out of band. uploadAvatar(mime, blob, width, height) { const readyToUpload = image => { let {mime, blob} = image; this.setState({imageUrl: URL.createObjectURL(blob), buttonDisabled: true}); if (blob.size > MAX_AVATAR_BYTES) { // Too large to send inband - uploading out of band and sending as a link. const uploader = this.props.tinode.getLargeFileHelper(); uploader.upload(blob, 'newacc') .then(url => this.setState({uploadUrl: url})) .catch(err => this.props.onError(err.message, 'err')) .finally(_ => this.setState({buttonDisabled: false})); } else { // Convert blob to base64-encoded bits. blobToBase64(blob) .then(b64 => this.setState({uploadUrl: makeImageUrl({data: b64.bits, type: mime})})) .finally(_ => this.setState({buttonDisabled: false})); } }; if (width > AVATAR_SIZE || height > AVATAR_SIZE || width != height) { // Avatar is not square or too large even after cropping. Shrink it and make square. imageScaled(blob, AVATAR_SIZE, AVATAR_SIZE, MAX_EXTERN_ATTACHMENT_SIZE, true) .then(scaled => readyToUpload(scaled)) .catch(err => this.props.onError(err.message, 'err')); } else { readyToUpload({mime: mime, blob: blob, width: width, height: height}); } } render() { if (this.state.newAvatar) { return ( ); } let submitClasses = 'primary'; if (this.props.disabled) { submitClasses += ' disabled'; } return (
{ (login_prompt) => } { (password_prompt) => }
{ (full_name_prompt) => }
{this.props.reqCredMethod == 'email' ?
{ (email_prompt) => }
: this.props.reqCredMethod == 'tel' ? <>
: null }
{ (stay_logged_in) => }
); } };