Unverified Commit 09e5463e authored by roadscape's avatar roadscape Committed by GitHub
Browse files

Merge pull request #107 from steemit/106-community-create-UI-tweaks

106 community create ui tweaks
parents ffd08186 aace1cf4
......@@ -25,6 +25,7 @@
@import './elements/SanitizedLink/styles';
@import './elements/HelpTip/styles';
@import './elements/Dropdown';
@import './elements/CreateCommunity';
// modules
@import './modules/Header/styles';
......
......@@ -4,6 +4,8 @@ import { connect } from 'react-redux';
import * as communityActions from 'app/redux/CommunityReducer';
import tt from 'counterpart';
import { key_utils } from '@steemit/steem-js/lib/auth/ecc';
import LoadingIndicator from 'app/components/elements/LoadingIndicator';
import Unicode from 'app/utils/Unicode';
class CreateCommunity extends React.Component {
constructor() {
......@@ -23,19 +25,24 @@ class CreateCommunity extends React.Component {
communityCreateSuccess,
createCommunity,
communityDescription,
communityNSFW,
communityOwnerWifPassword,
communityOwnerName,
communityTitle,
updateCommunityTitle,
updateCommunityDescription,
updateCommunityNSFW,
updateCommunityOwnerAccountName,
updateCommunityOwnerWifPassword,
broadcastOps,
communityCreationPending,
socialUrl,
} = this.props;
const handleAccountCreateError = () => {
const handleAccountCreateError = error => {
// If the user cancels the account creation do not show an error.
if (error === undefined) {
communityCreationPending(false);
return;
}
this.setState({ accountError: true });
};
......@@ -53,15 +60,13 @@ class CreateCommunity extends React.Component {
}
updateCommunityTitle(e.target.value);
};
const handleCommunityDescriptionInput = e => {
if (e.target.value.length > 120) {
return;
}
updateCommunityDescription(e.target.value);
};
const handleCommunityNSFWInput = e => {
updateCommunityNSFW(e.target.checked);
};
const handleCommunitySubmit = e => {
e.preventDefault();
......@@ -69,7 +74,6 @@ class CreateCommunity extends React.Component {
accountName,
communityTitle,
communityDescription,
communityNSFW,
communityOwnerName,
communityOwnerWifPassword,
createAccountSuccessCB: handleAccountCreateSuccess,
......@@ -101,160 +105,115 @@ class CreateCommunity extends React.Component {
updateCommunityOwnerAccountName(ownerUsername);
};
const generateCommunityCredentials = () => {
const generateCreds = () => {
generateWif();
generateUsername();
};
const generateCommunityCredentialsButton = (
<button
type="button"
className="button hollow"
onClick={generateCommunityCredentials}
>
{tt('g.click_to_generate_password')}
<button type="button" className="button" onClick={generateCreds}>
Next
</button>
);
const rememberCredentialsPrompt = (
<div>
<div>{`${tt(
'g.community_owner_name_is'
)}: ${communityOwnerName}`}</div>
<div>{`${tt(
'g.community_password_is'
)}: ${communityOwnerWifPassword}`}</div>
</div>
);
const rememberCredentialsCheckbox1 = (
<label htmlFor="box1">
<input type="checkbox" name="box1" required />
{tt('g.understand_that_APP_NAME_cannot_recover_password', {
APP_NAME,
})}.
</label>
);
const rememberCredentialsCheckbox2 = (
<label htmlFor="box2">
<input type="checkbox" name="box2" required />
{tt('g.i_saved_password')}.
</label>
);
const submitCreateCommunityFormButton = (
<input type="submit" value="Submit" />
);
const createCommunityAccountSuccessMessage = (
<div>
Community account created on the blockchain. Setting current
user to be community admin...
</div>
);
const createCommunityAccountErrorMessage = (
const credentialsPane = (
<div>
Unable to create that community. Please ensure you used the
correct key.
<label>
Owner Name / Password
<code className="pwd">
{communityOwnerName}
<br />
{communityOwnerWifPassword}
</code>
</label>
<label style={{ marginTop: '0px' }}>
<input type="checkbox" name="box2" required />
I have securely saved my owner name and password.
</label>
</div>
);
const createCommunityBroadcastOpsErrorMessage = (
<div>
The community was created but setting current user to be admin
failed. Wait a moment and try again
</div>
const submitCreateCommunityFormButton = error => (
<input
className="button"
type="submit"
value="Create Community"
disabled={!!error}
/>
);
const createCommunitySuccessMessage = (
<div>
<p>Your community was created!</p>
<a
href={`https://steemitdev.com/trending/${communityOwnerName}`}
>
{tt('g.community_visit')}
</a>
</div>
);
const createCommunityErrorMessage = (
<div>{tt('g.community_error')}</div>
);
const hasPass = communityOwnerWifPassword.length > 0;
const createCommunityLoading = <div>{tt('g.community_creating')}</div>;
let formError = null;
const rx = new RegExp('^[' + Unicode.L + ']');
if (!rx.test(communityTitle) && (communityTitle || hasPass))
formError = 'Must start with a letter.';
const createCommunityForm = (
<form onSubmit={handleCommunitySubmit}>
const form = (
<form className="community--form" onSubmit={handleCommunitySubmit}>
<div>{tt('g.community_create')}</div>
<label htmlFor="community_title">
<label>
Title
<input
id="community_title"
name="community_title"
type="text"
minLength="4"
maxLength="30"
minLength="3"
maxLength="20"
onChange={handleCommunityTitleInput}
value={communityTitle}
required
/>
</label>
<label htmlFor="community_description">
{formError && <span className="error">{formError}</span>}
<label>
{tt('g.community_description')}
<input
id="community_description"
name="community_description"
type="text"
minLength="10"
maxLength="140"
maxLength="120"
onChange={handleCommunityDescriptionInput}
value={communityDescription}
required
/>
</label>
<label id="is_nsfw" htmlFor="is_nsfw">
{tt('g.community_nsfw')}
<input
type="checkbox"
name="is_nsfw"
checked={communityNSFW}
onChange={handleCommunityNSFWInput}
/>
</label>
{communityOwnerWifPassword.length <= 0 &&
generateCommunityCredentialsButton}
{communityOwnerWifPassword.length > 0 &&
rememberCredentialsPrompt}
{communityOwnerWifPassword.length > 0 &&
rememberCredentialsCheckbox1}
{communityOwnerWifPassword.length > 0 &&
rememberCredentialsCheckbox2}
{communityOwnerWifPassword.length > 0 &&
submitCreateCommunityFormButton}
{!hasPass && generateCommunityCredentialsButton}
{hasPass && credentialsPane}
{hasPass && submitCreateCommunityFormButton(formError)}
</form>
);
const accountCreated = this.state.accountCreated;
const accountError = this.state.accountError;
const settingsError = this.state.broadcastOpsError;
const errored = accountError || settingsError;
const pending = communityCreatePending && !errored;
const finished = communityCreateSuccess;
const sagaError = communityCreateError;
if (finished) {
const url = `${socialUrl}/trending/${communityOwnerName}`;
return (
<div className="row">
<div className="column large-6 small-12">
Your community was created!<br />
<strong>
<a href={url}>Get started.</a>
</strong>
</div>
</div>
);
}
const showErr = msg => <div className="community--error">{msg}</div>;
const adminMsg = `Account created. Setting @${accountName} as admin...`;
return (
<div className="row">
<div className="column large-6 small-12">
{this.state.accountError &&
createCommunityAccountErrorMessage}
{this.state.accountCreated &&
!communityCreateSuccess &&
createCommunityAccountSuccessMessage}
{this.state.broadcastOpsError &&
createCommunityBroadcastOpsErrorMessage}
{this.state.accountError && createCommunityForm}
{this.state.broadcastOpsError && createCommunityForm}
{!communityCreatePending &&
!communityCreateSuccess &&
createCommunityForm}
{communityCreatePending &&
!this.state.accountError &&
!this.state.broadcastOpsError &&
createCommunityLoading}
{communityCreateSuccess && createCommunitySuccessMessage}
{communityCreateError && createCommunityErrorMessage}
{accountError && showErr('Account creation failed.')}
{settingsError && showErr('Update settings failed.')}
{sagaError && showErr('Failed. Please report this issue.')}
{accountCreated && <div>{adminMsg}</div>}
{pending ? <LoadingIndicator type="circle" /> : form}
</div>
</div>
);
......@@ -269,11 +228,13 @@ export default connect(
const current = state.user.get('current');
const username = current && current.get('username');
const isMyAccount = username === accountName;
const socialUrl = state.app.get('socialUrl');
return {
...ownProps,
...state.community.toJS(),
isMyAccount,
accountName,
socialUrl,
};
},
// mapDispatchToProps
......@@ -285,9 +246,6 @@ export default connect(
updateCommunityDescription: description => {
dispatch(communityActions.setCommunityDescription(description));
},
updateCommunityNSFW: isNSFW => {
dispatch(communityActions.setCommunityNSFW(isNSFW));
},
updateCommunityOwnerAccountName: accountName => {
dispatch(
communityActions.setCommunityOwnerAccountName(accountName)
......@@ -318,6 +276,13 @@ export default connect(
)
);
},
communityCreationPending: createCommunityAccountPending => {
dispatch(
communityActions.createCommunityAccountPending(
createCommunityAccountPending
)
);
},
};
}
)(CreateCommunity);
.community--form {
label {margin-top: 1rem;}
.button {margin-top: 1rem;}
.pwd {
text-transform: none;
display: block;
padding: 0.2rem 0.5rem;
color: rgb(199, 37, 78);
font-size: 1rem;
background: #fff;
word-break: break-all;
text-align: left;
}
}
.community--error {
color: rgb(199, 37, 78);
}
......@@ -29,8 +29,7 @@
"community_error":
"Oops, there was an error creating the community, please try again.",
"community_create": "CREATE A COMMUNITY",
"community_description": "Description",
"community_nsfw": "Is Not Safe For Work",
"community_description": "About",
"confirm": "Confirm",
"convert": "Convert",
"date": "Date",
......
......@@ -3,7 +3,6 @@ import { fromJS } from 'immutable';
// Action constants
const SET_COMMUNITY_TITLE = 'community/SET_COMMUNITY_TITLE';
const SET_COMMUNITY_DESCRIPTION = 'community/SET_COMMUNITY_DESCRIPTION';
const SET_COMMUNITY_NSFW = 'community/SET_COMMUNITY_NSFW';
const SET_COMMUNITY_OWNER_ACCOUNT_NAME =
'community/SET_COMMUNITY_OWNER_ACCOUNT_NAME';
......@@ -28,7 +27,6 @@ const COMMUNITY_HIVEMIND_OPERATION_ERROR =
const defaultState = fromJS({
communityTitle: '',
communityDescription: '',
communityNSFW: false,
communityOwnerName: '',
communityOwnerWifPassword: '',
communityCreatePending: false,
......@@ -49,10 +47,6 @@ export default function reducer(state = defaultState, action) {
const description = fromJS(payload);
return state.merge({ communityDescription: description });
}
case SET_COMMUNITY_NSFW: {
const nsfw = fromJS(payload);
return state.merge({ communityNSFW: nsfw });
}
case SET_COMMUNITY_OWNER_ACCOUNT_NAME: {
const name = fromJS(payload);
return state.merge({ communityOwnerName: name });
......@@ -107,10 +101,6 @@ export const setCommunityDescription = payload => ({
type: SET_COMMUNITY_DESCRIPTION,
payload,
});
export const setCommunityNSFW = payload => ({
type: SET_COMMUNITY_NSFW,
payload,
});
export const setCommunityOwnerAccountName = payload => ({
type: SET_COMMUNITY_OWNER_ACCOUNT_NAME,
......
......@@ -20,7 +20,7 @@ const generateAuth = (user, pass, type) => {
};
};
const generateHivemindOperation = (action, params, actor_name) => {
const generateHivemindOperation = (actor_name, action, params) => {
return [
'custom_json',
{
......@@ -49,14 +49,16 @@ export function* customOps(action) {
accountName,
communityTitle,
communityDescription,
communityNSFW,
communityOwnerName,
communityOwnerWifPassword,
createAccountSuccessCB,
createAccountErrorCB,
broadcastOpsErrorCB,
} = action.payload;
yield call(wait, 9000);
// wait 3s for account creation to settle
yield call(wait, 3000);
try {
const communityOwnerPosting = auth.getPrivateKeys(
communityOwnerName,
......@@ -65,28 +67,33 @@ export function* customOps(action) {
);
const setRoleOperation = generateHivemindOperation(
communityOwnerName,
'setRole',
{
community: communityOwnerName,
account: accountName,
role: 'admin',
},
communityOwnerName,
communityOwnerPosting
}
);
const updatePropsOperation = generateHivemindOperation(
communityOwnerName,
'updateProps',
{
community: communityOwnerName,
props: {
title: communityTitle,
about: communityDescription,
is_nsfw: !!communityNSFW,
},
},
communityOwnerName,
communityOwnerPosting
}
);
const subscribeToCommunityOperation = generateHivemindOperation(
accountName,
'subscribe',
{
community: communityOwnerName,
}
);
yield broadcast.sendAsync(
......@@ -103,6 +110,23 @@ export function* customOps(action) {
]
);
// subscription op must be broadcast from logged in user
yield put(
transactionActions.broadcastOperation({
type: subscribeToCommunityOperation[0],
operation: subscribeToCommunityOperation[1],
successCallback: res => {
console.log('subscribed');
},
errorCallback: res => {
console.log('subscribe error', res);
},
})
);
// wait a few blocks for hivemind to index ops before alerting user
yield call(wait, 6000);
yield put({
type: communityActions.CREATE_COMMUNITY_SUCCESS,
payload: true,
......@@ -130,7 +154,6 @@ export function* createCommunityAccount(createCommunityAction) {
accountName,
communityTitle,
communityDescription,
communityNSFW,
communityOwnerName,
communityOwnerWifPassword,
broadcastOpsCb,
......@@ -175,7 +198,8 @@ export function* createCommunityAccount(createCommunityAction) {
yield put(
transactionActions.broadcastOperation({
type: 'account_create',
confirm: 'Are you sure?',
confirm:
'This operation will cost 3 STEEM. Would you like to proceed?',
operation: op,
successCallback: res => {
createAccountSuccessCB();
......@@ -183,7 +207,7 @@ export function* createCommunityAccount(createCommunityAction) {
},
errorCallback: res => {
console.log('error', res);
createAccountErrorCB();
createAccountErrorCB(res);
},
})
);
......
This diff is collapsed.
......@@ -2500,18 +2500,7 @@ create-ecdh@^4.0.0:
bn.js "^4.1.0"
elliptic "^6.0.0"
create-hash@^1.1.0, create-hash@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
dependencies:
cipher-base "^1.0.1"
inherits "^2.0.1"
md5.js "^1.3.4"
ripemd160 "^2.0.1"
sha.js "^2.4.0"
create-hash@^1.2.0:
create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
......@@ -3165,20 +3154,7 @@ elegant-spinner@^1.0.1:
resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=
elliptic@^6.0.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.0.tgz#2b8ed4c891b7de3200e14412a5b8248c7af505ca"
integrity sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==
dependencies:
bn.js "^4.4.0"
brorand "^1.0.1"
hash.js "^1.0.0"
hmac-drbg "^1.0.0"
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.0"
elliptic@^6.4.1:
elliptic@^6.0.0, elliptic@^6.4.1:
version "6.5.0"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.0.tgz#2b8ed4c891b7de3200e14412a5b8248c7af505ca"
integrity sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==
......@@ -6871,7 +6847,7 @@ mz@~2.4.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nan@^2.10.0, nan@^2.12.1, nan@^2.3.3:
nan@^2.10.0, nan@^2.12.1, nan@^2.14.0, nan@^2.3.3:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
......@@ -6893,11 +6869,6 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1"
to-regex "^3.0.1"
nan@^2.14.0:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
native-or-bluebird@1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/native-or-bluebird/-/native-or-bluebird-1.2.0.tgz#39c47bfd7825d1fb9ffad32210ae25daadf101c9"
......@@ -8974,6 +8945,20 @@ scss-tokenizer@^0.2.3:
js-base64 "^2.1.8"
source-map "^0.4.2"
secp256k1@^3.5.2:
version "3.7.1"
resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.7.1.tgz#12e473e0e9a7c2f2d4d4818e722ad0e14cc1e2f1"
integrity sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==
dependencies:
bindings "^1.5.0"
bip66 "^1.1.5"
bn.js "^4.11.8"
create-hash "^1.2.0"
drbg.js "^1.0.1"
elliptic "^6.4.1"
nan "^2.14.0"
safe-buffer "^5.1.2"
secure-random@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/secure-random/-/secure-random-1.1.1.tgz#0880f2d8c5185f4bcb4684058c836b4ddb07145a"
......@@ -10463,7 +10448,7 @@ whatwg-fetch@2.0.3:
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
integrity sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=
whatwg-fetch@>=0.10.0:
whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==
......@@ -10473,11 +10458,6 @@ whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0:
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==