Skip to content

Commit

Permalink
HF 30 - Private message groups
Browse files Browse the repository at this point in the history
  • Loading branch information
1aerostorm committed Jun 10, 2024
1 parent 2a1fd8b commit d23818e
Show file tree
Hide file tree
Showing 8 changed files with 345 additions and 140 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-dom-confetti": "^0.2.0",
"react-dropzone": "^12.0.4",
"react-dropzone": "^14.2.3",
"react-foundation-components": "git+https://github.com/golos-blockchain/react-foundation-components.git#6606fd5529f1ccbc77cd8d33a8ce139fdf8f9a11",
"react-intl": "^5.24.6",
"react-notification": "^6.8.5",
Expand Down
145 changes: 18 additions & 127 deletions src/components/modules/CreateGroup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Map } from 'immutable'
import { api, formatter } from 'golos-lib-js'
import { Asset, Price, AssetEditor } from 'golos-lib-js/lib/utils'
import tt from 'counterpart'
import getSlug from 'speakingurl'

import g from 'app/redux/GlobalReducer'
import transaction from 'app/redux/TransactionReducer'
Expand All @@ -15,13 +14,15 @@ import Icon from 'app/components/elements/Icon'
import LoadingIndicator from 'app/components/elements/LoadingIndicator'
import FormikAgent from 'app/components/elements/donate/FormikUtils'
import Stepper from 'app/components/elements/messages/Stepper'
import GroupName, { validateNameStep } from 'app/components/modules/groups/GroupName'
import GroupLogo from 'app/components/modules/groups/GroupLogo'

const STEPS = {
const STEPS = () => { return {
name: tt('create_group_jsx.step_name'),
logo: tt('create_group_jsx.step_logo'),
admin: tt('create_group_jsx.step_admin'),
create: tt('create_group_jsx.step_create')
}
} }

class CreateGroup extends React.Component {
constructor(props) {
Expand All @@ -32,7 +33,9 @@ class CreateGroup extends React.Component {
title: '',
name: '',
is_encrypted: true,
privacy: 'public_group'
privacy: 'public_group',

logo: '',
}
}
this.stepperRef = React.createRef()
Expand Down Expand Up @@ -80,28 +83,9 @@ class CreateGroup extends React.Component {

validate = async (values) => {
const errors = {}
if (!values.title) {
errors.title = tt('g.required')
}
if (values.name) {
if (values.name.length < 3) {
errors.name = tt('create_group_jsx.group_min_length')
} else {
let group
try {
console.time('x')
group = await api.getGroupsAsync({
start_group: values.name,
limit: 1
})
console.timeEnd('x')
} catch (err) {
console.error(err)
}
if (group && group[0]) {
errors.name = tt('create_group_jsx.group_already_exists')
}
}
const { step } = this.state
if (step === 'name') {
await validateNameStep(values, errors, (validating) => this.setState({ validating }))
}
return errors
}
Expand All @@ -117,37 +101,8 @@ class CreateGroup extends React.Component {
})
}

onTitleChange = (e, setFieldValue, setFieldTouched) => {
const { value } = e.target
if (value.trimLeft() !== value) {
return
}
setFieldValue('title', value)
let link = getSlug(value)
setFieldValue('name', link)
setFieldTouched('name', true)
this.setState({
showName: true
})
}

onNameChange = (e, setFieldValue) => {
const { value } = e.target
for (const c of value) {
if ((c > 'z' || c < 'a') && c !== '-' && c !== '_') {
return
}
}
setFieldValue('name', value)
}

onPrivacyChange = (e, setFieldValue) => {
setFieldValue('privacy', e.target.value)
setFieldValue('is_encrypted', true)
}

render() {
const { showName, step, loaded, createError } = this.state
const { step, loaded, createError, validating } = this.state

let form
if (!loaded) {
Expand Down Expand Up @@ -181,83 +136,19 @@ class CreateGroup extends React.Component {
{({
handleSubmit, isSubmitting, isValid, values, setFieldValue, setFieldTouched, handleChange,
}) => {
const disabled = !isValid
const disabled = !isValid || validating
return (
<Form>

{step === 'name' ? <React.Fragment>
<div className='row' style={{ marginTop: '1.0rem', marginBottom: '1.0rem' }}>
<div className='column small-5' style={{paddingTop: 5}}>
{tt('create_group_jsx.title')}
</div>
<div className='column small-7'>
<Field
type='text'
name='title'
maxLength='48'
onChange={e => this.onTitleChange(e, setFieldValue, setFieldTouched)}
autoFocus
/>
<ErrorMessage name='title' component='div' className='error' />
</div>
</div>

{showName ? <div className='row' style={{ marginTop: '1.0rem', marginBottom: '1.0rem' }}>
<div className='column small-5' style={{paddingTop: 5}}>
{tt('create_group_jsx.name')}
</div>
<div className='column small-7'>
<Field
type='text'
name='name'
maxLength='32'
onChange={e => this.onNameChange(e, setFieldValue)}
/>
<ErrorMessage name='name' component='div' className='error' />
</div>
</div> : null}

<div className='row' style={{ marginTop: '1.0rem', marginBottom: '1.0rem' }}>
<div className='column small-5' style={{paddingTop: 5}}>
{tt('create_group_jsx.access')}
<Icon name='info_o' className='icon-hint' title={tt('create_group_jsx.access_hint')} />
</div>
<div className='column small-7'>
<Field
as='select'
name='privacy'
onChange={e => this.onPrivacyChange(e, setFieldValue)}
>
<option value='public_group'>{tt('create_group_jsx.access_all')}</option>
<option value='public_read_only'>{tt('create_group_jsx.all_read_only')}</option>
<option value='private_group'>{tt('create_group_jsx.access_private')}</option>
</Field>
<ErrorMessage name='privacy' component='div' className='error' />
</div>
</div>

<div className='row' style={{ marginTop: '1.0rem', marginBottom: '1.0rem' }}>
<div className='column small-12'>
<label style={{fontSize: '100%'}}>
<Field
type='checkbox'
name='is_encrypted'
disabled={values.privacy === 'private_group'}
/>
{tt('create_group_jsx.encrypted')}
<Icon name='info_o' className='icon-hint' title={tt('create_group_jsx.encrypted_hint')} />
{values.privacy === 'private_group' ? <span className='secondary'>{tt('create_group_jsx.encrypted_dis')}</span> : null}
</label>
<ErrorMessage name='is_encrypted' component='div' className='error' />
</div>
</div>
</React.Fragment> : <React.Fragment>
</React.Fragment>}
{step === 'name' ? <GroupName values={values} setFieldValue={setFieldValue} setFieldTouched={setFieldTouched} /> :
step === 'logo' ? <GroupLogo values={values} setFieldValue={setFieldValue} setFieldTouched={setFieldTouched} /> :
<React.Fragment></React.Fragment>}

<Stepper ref={this.stepperRef} steps={STEPS} startStep='name' />
<Stepper ref={this.stepperRef} steps={STEPS()} startStep='name' />
{isSubmitting ? <span><LoadingIndicator type='circle' /><br /></span>
: <span>
<button onClick={this.goNext} disabled={disabled} className='button small next-button' title={tt('g.submit')}>
<button onClick={this.goNext} disabled={disabled} className='button small next-button' title={validating ?
tt('create_group_jsx.validating') : tt('create_group_jsx.submit')}>
<Icon name='chevron-right' size='1_25x' />
</button>
</span>}
Expand Down
3 changes: 3 additions & 0 deletions src/components/modules/CreateGroup.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
.CreateGroup {
h3 {
padding-left: 0.75rem;
}
.next-button {
width: 48px;
height: 48px;
Expand Down
144 changes: 144 additions & 0 deletions src/components/modules/groups/GroupLogo.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import React from 'react'
import DropZone from 'react-dropzone'
import { connect } from 'react-redux'
import { Field, ErrorMessage, } from 'formik'
import tt from 'counterpart'

import Input from 'app/components/elements/common/Input';
import PictureSvg from 'app/assets/icons/editor-toolbar/picture.svg';
import DialogManager from 'app/components/elements/common/DialogManager'

class GroupLogo extends React.Component {
state = {}

constructor(props) {
super(props)
}

uploadLogo = (file, name, setFieldValue) => {
const { notify } = this.props
const { uploadImage } = this.props
this.setState({ uploading: true })
uploadImage(file, progress => {
if (progress.url) {
alert(progress.url)
}
if (progress.error) {
const { error } = progress;
notify(error, 10000)
}
this.setState({ uploading: false })
})
}

_onDrop = (acceptedFiles, rejectedFiles, setFieldValue) => {
const file = acceptedFiles[0]

if (!file) {
if (rejectedFiles.length) {
DialogManager.alert(
tt('post_editor.please_insert_only_image_files')
)
}
return
}

this.uploadLogo(file, file.name, setFieldValue)
};

_onInputKeyDown = e => {
if (e.which === keyCodes.ENTER) {
e.preventDefault();
//this.props.onClose({
//e.target.value,
//});
}
};


render() {
const { values, setFieldValue, setFieldTouched } = this.props
const { uploading } = this.state

const selectorStyleCover = uploading ?
{
whiteSpace: `nowrap`,
display: `flex`,
alignItems: `center`,
padding: `0 6px`,
pointerEvents: `none`,
cursor: `default`,
opacity: `0.6`
} :
{
display: `flex`,
alignItems: `center`,
padding: `0 6px`
}

return <React.Fragment>
<div className='row' style={{ marginTop: '0rem' }}>
<div className='column small-12' style={{paddingTop: 5, fontSize: '110%'}}>
{tt('create_group_jsx.logo_desc')}
</div>
</div>
<div className='row' style={{ marginTop: '0.5rem', marginBottom: '2rem' }}>
<div className='AddImageDialog column small-12' style={{paddingTop: 5}}>
<DropZone
multiple={false}
accept="image/*"
onDrop={this._onDrop}
>
{({getRootProps, getInputProps}) => (<div className="AddImageDialog__drop-zone" {...getRootProps()}>
<input {...getInputProps()} />
<i
className="AddImageDialog__drop-zone-icon"
dangerouslySetInnerHTML={{ __html: PictureSvg }}
/>
<span className="AddImageDialog__drop-zone-text">
{tt('create_group_jsx.logo_upload')}
</span>
</div>)}
</DropZone>
<div className="AddImageDialog__splitter" />
<div>
<div className="AddImageDialog__link-text">
{tt('create_group_jsx.logo_link')}:
</div>
<Field name='logo' type='text'
placeholder='https://'
>
{({ field, form }) => <Input
block
className="AddImageDialog__link-input"
autoFocus
onKeyDown={this._onInputKeyDown}
/>}
</Field>
</div>
</div>
</div>
</React.Fragment>
}
}

export default connect(
// mapStateToProps
(state, ownProps) => {
},
dispatch => ({
uploadImage: (file, progress) => {
dispatch({
type: 'user/UPLOAD_IMAGE',
payload: {file, progress},
})
},
notify: (message, dismiss = 3000) => {
dispatch({type: 'ADD_NOTIFICATION', payload: {
key: 'group_logo_' + Date.now(),
message,
dismissAfter: dismiss}
});
}
})
)(GroupLogo)
Loading

0 comments on commit d23818e

Please sign in to comment.