diff --git a/src/assets/icons/chevron-right.svg b/src/assets/icons/chevron-right.svg
new file mode 100644
index 000000000..f922ce9f7
--- /dev/null
+++ b/src/assets/icons/chevron-right.svg
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/src/components/all.scss b/src/components/all.scss
index 5e942a191..0f9e5ce22 100644
--- a/src/components/all.scss
+++ b/src/components/all.scss
@@ -20,6 +20,7 @@
// modules
@import './modules/LoginForm.scss';
+@import './modules/CreateGroup.scss';
@import './modules/Modals.scss';
@import "./pages/Messages";
diff --git a/src/components/elements/Icon.jsx b/src/components/elements/Icon.jsx
index 120f3e412..26dff1106 100644
--- a/src/components/elements/Icon.jsx
+++ b/src/components/elements/Icon.jsx
@@ -9,6 +9,7 @@ const icons = new Map([
// ['chevron-up-circle', require('app/assets/icons/chevron-up-circle.svg')],
// ['chevron-down-circle', require('app/assets/icons/chevron-down-circle.svg')],
['chevron-left', require('app/assets/icons/chevron-left.svg')],
+ ['chevron-right', require('app/assets/icons/chevron-right.svg')],
// ['chatboxes', require('app/assets/icons/chatboxes.svg')],
['cross', require('app/assets/icons/cross.svg')],
// ['chatbox', require('app/assets/icons/chatbox.svg')],
diff --git a/src/components/elements/messages/StartPanel/StartPanel.scss b/src/components/elements/messages/StartPanel/StartPanel.scss
new file mode 100644
index 000000000..63dac7e5a
--- /dev/null
+++ b/src/components/elements/messages/StartPanel/StartPanel.scss
@@ -0,0 +1,5 @@
+.msgs-start-panel {
+ .button {
+ display: block;
+ }
+}
diff --git a/src/components/elements/messages/StartPanel/index.jsx b/src/components/elements/messages/StartPanel/index.jsx
new file mode 100644
index 000000000..3dd02c37c
--- /dev/null
+++ b/src/components/elements/messages/StartPanel/index.jsx
@@ -0,0 +1,56 @@
+import React from 'react'
+import tt from 'counterpart'
+import {connect} from 'react-redux'
+
+import user from 'app/redux/UserReducer'
+import './StartPanel.scss'
+
+class StartPanel extends React.Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ }
+ }
+
+ startChat = (e) => {
+ e.preventDefault()
+ const inp = document.getElementsByClassName('conversation-search-input')
+ if (!inp.length) {
+ console.error('startChat - no conversation-search-input')
+ return
+ }
+ if (inp.length > 1) {
+ console.error('startChat - multiple conversation-search-input:', inp)
+ return
+ }
+ inp[0].focus()
+ }
+
+ goCreateGroup = (e) => {
+ e.preventDefault()
+ this.props.showCreateGroup()
+ }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+ )
+ }
+}
+
+export default connect(
+ (state, ownProps) => {
+ return { ...ownProps }
+ },
+ dispatch => ({
+ showCreateGroup() {
+ dispatch(user.actions.showCreateGroup())
+ },
+ })
+)(StartPanel)
diff --git a/src/components/elements/messages/Stepper/Stepper.scss b/src/components/elements/messages/Stepper/Stepper.scss
new file mode 100644
index 000000000..fef8b68a6
--- /dev/null
+++ b/src/components/elements/messages/Stepper/Stepper.scss
@@ -0,0 +1,28 @@
+.Stepper {
+ width: 100%;
+
+ .step {
+ display: inline-block;
+ text-align: center;
+ color: gray;
+ font-size: 90%;
+ .bar {
+ background-color: gray;
+ height: 8px;
+ margin-top: 0.25rem;
+ margin-bottom: 0.25rem;
+ }
+
+ &.left {
+ .bar {
+ background-color: #0078C4;
+ }
+ }
+ &.current {
+ color: #0078C4;
+ .bar {
+ background-color: #0078C4;
+ }
+ }
+ }
+}
diff --git a/src/components/elements/messages/Stepper/index.jsx b/src/components/elements/messages/Stepper/index.jsx
new file mode 100644
index 000000000..6006feee4
--- /dev/null
+++ b/src/components/elements/messages/Stepper/index.jsx
@@ -0,0 +1,56 @@
+import React from 'react'
+
+import './Stepper.scss'
+
+class Stepper extends React.Component {
+ constructor(props) {
+ super(props)
+ const { steps, startStep } = this.props
+ const entr = Object.entries(steps)
+ this.state = {
+ currentStep: startStep || entr[0][0]
+ }
+ }
+
+ nextStep = () => {
+ const { steps } = this.props
+ const entr = Object.entries(steps)
+ const { currentStep } = this.state
+ let found
+ for (const [key, content] of entr) {
+ if (found) {
+ this.setState({
+ currentStep: key
+ })
+ return
+ }
+ found = key === currentStep
+ }
+ }
+
+ render() {
+ const { steps } = this.props
+ let { currentStep } = this.state
+
+ const entr = Object.entries(steps)
+ currentStep = currentStep || entr[0][0]
+ const width = (100 / entr.length).toFixed(1)
+ const stepObjs = []
+ let foundCurrent
+ for (const [key, content] of entr) {
+ const isCurrent = key === currentStep
+ foundCurrent = foundCurrent || isCurrent
+ const cn = foundCurrent ? (isCurrent ? 'current' : '') : 'left'
+ stepObjs.push()
+ }
+
+ return
+ {stepObjs}
+
+ }
+}
+
+export default Stepper
diff --git a/src/components/modules/CreateGroup.jsx b/src/components/modules/CreateGroup.jsx
new file mode 100644
index 000000000..b19e6823a
--- /dev/null
+++ b/src/components/modules/CreateGroup.jsx
@@ -0,0 +1,134 @@
+import React from 'react'
+import {connect} from 'react-redux'
+import { Formik, Form, Field, ErrorMessage, } from 'formik'
+import { Map } from 'immutable'
+import { Asset, AssetEditor } from 'golos-lib-js/lib/utils'
+import tt from 'counterpart'
+
+import g from 'app/redux/GlobalReducer'
+import transaction from 'app/redux/TransactionReducer'
+import user from 'app/redux/UserReducer'
+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'
+
+class CreateGroup extends React.Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ initialValues: {
+ name: '',
+ is_encrypted: true,
+ privacy: 'public_group'
+ }
+ }
+ this.stepperRef = React.createRef()
+ }
+
+ validate = () => {
+ }
+
+ _onSubmit = () => {
+ }
+
+ goNext = (e) => {
+ e.preventDefault()
+ this.stepperRef.current.nextStep()
+ }
+
+ render() {
+ const form = (
+ {({
+ handleSubmit, isSubmitting, isValid, values, setFieldValue, handleChange,
+ }) => {
+ const disabled = !isValid
+ return (
+
+ )}})
+
+ return
+
+
{tt('msgs_start_panel.create_group')}
+
+ {form}
+
+ }
+}
+
+export default connect(
+ (state, ownProps) => {
+ const currentUser = state.user.getIn(['current'])
+ const currentAccount = currentUser && state.global.getIn(['accounts', currentUser.get('username')])
+
+ return { ...ownProps,
+ currentUser,
+ currentAccount,
+ }
+ },
+ dispatch => ({
+ })
+)(CreateGroup)
diff --git a/src/components/modules/CreateGroup.scss b/src/components/modules/CreateGroup.scss
new file mode 100644
index 000000000..386d59a69
--- /dev/null
+++ b/src/components/modules/CreateGroup.scss
@@ -0,0 +1,15 @@
+.CreateGroup {
+ .next-button {
+ width: 48px;
+ height: 48px;
+ padding-left: 13px !important;
+ color: white;
+ position: absolute;
+ bottom: 0.4rem;
+ right: 0.5rem;
+ }
+ .Stepper {
+ width: 85%;
+ margin-left: 1rem;
+ }
+}
diff --git a/src/components/modules/Modals.jsx b/src/components/modules/Modals.jsx
index 8fcb103c1..c3643426d 100644
--- a/src/components/modules/Modals.jsx
+++ b/src/components/modules/Modals.jsx
@@ -5,6 +5,7 @@ import { connect } from 'react-redux';
import CloseButton from 'react-foundation-components/lib/global/close-button';
import Reveal from 'react-foundation-components/lib/global/reveal';
+import CreateGroup from 'app/components/modules/CreateGroup'
import Donate from 'app/components/modules/Donate'
import LoginForm from 'app/components/modules/LoginForm';
import AppDownload from 'app/components/modules/app/AppDownload'
@@ -17,6 +18,7 @@ class Modals extends React.Component {
static propTypes = {
show_login_modal: PropTypes.bool,
show_donate_modal: PropTypes.bool,
+ show_create_group_modal: PropTypes.bool,
show_app_download_modal: PropTypes.bool,
hideDonate: PropTypes.func.isRequired,
hideAppDownload: PropTypes.func.isRequired,
@@ -34,9 +36,11 @@ class Modals extends React.Component {
const {
show_login_modal,
show_donate_modal,
+ show_create_group_modal,
show_app_download_modal,
hideLogin,
hideDonate,
+ hideCreateGroup,
hideAppDownload,
notifications,
removeNotification,
@@ -60,6 +64,10 @@ class Modals extends React.Component {
}
+ {show_create_group_modal &&
+
+
+ }
{show_app_download_modal &&
@@ -81,6 +89,7 @@ export default connect(
return {
show_login_modal: state.user.get('show_login_modal'),
show_donate_modal: state.user.get('show_donate_modal'),
+ show_create_group_modal: state.user.get('show_create_group_modal'),
show_app_download_modal: state.user.get('show_app_download_modal'),
loginUnclosable,
notifications: state.app.get('notifications'),
@@ -95,6 +104,10 @@ export default connect(
if (e) e.preventDefault()
dispatch(user.actions.hideDonate())
},
+ hideCreateGroup: e => {
+ if (e) e.preventDefault()
+ dispatch(user.actions.hideCreateGroup())
+ },
hideAppDownload: e => {
if (e) e.preventDefault()
dispatch(user.actions.hideAppDownload())
diff --git a/src/components/modules/messages/Messenger/Messenger.css b/src/components/modules/messages/Messenger/Messenger.css
index d5db6318a..6dc153449 100644
--- a/src/components/modules/messages/Messenger/Messenger.css
+++ b/src/components/modules/messages/Messenger/Messenger.css
@@ -85,3 +85,16 @@
transform: translateX(-50%) translateY(-50%);
left: 50%;
}
+
+.msgs-start-panel {
+ top: 50%;
+ transform: translateX(-50%) translateY(-50%);
+ left: 50%;
+ position: absolute;
+ z-index: 10;
+ background-color: rgba(255, 255, 255, 0.5);
+ backdrop-filter: blur(5px);
+ padding: 1rem;
+ border-radius: 10px;
+ border: 1px solid black;
+}
diff --git a/src/components/modules/messages/Messenger/index.js b/src/components/modules/messages/Messenger/index.js
index e3ad9747e..2f04d2255 100644
--- a/src/components/modules/messages/Messenger/index.js
+++ b/src/components/modules/messages/Messenger/index.js
@@ -3,6 +3,7 @@ import Dropzone from 'react-dropzone';
import ConversationList from '../ConversationList';
import MessageList from '../MessageList';
+import StartPanel from 'app/components/elements/messages/StartPanel'
import isScreenSmall from 'app/utils/isScreenSmall'
import './Messenger.css';
@@ -83,7 +84,7 @@ export default class Messages extends React.Component {
topRight={messagesTopRight}
renderEmpty={() => {
if ((localStorage.getItem('msgr_auth') && !account) || process.env.MOBILE_APP) return null
- return ()
+ return
}}
messages={messages}
replyingMessage={replyingMessage}
diff --git a/src/locales/en.json b/src/locales/en.json
index 91abf9e1b..aafdb332e 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -76,6 +76,29 @@
"blocked_BY": "You are blocked by @%(BY)s.",
"do_not_bother_BY": "@%(BY)s wants to not be bothered by low-reputation users."
},
+ "msgs_start_panel": {
+ "start_chat": "Start chat",
+ "create_group": "Create group"
+ },
+ "create_group_jsx": {
+ "name": "Name",
+ "logo": "Logo",
+ "admin": "Admin",
+ "encrypted": "Encrypt messages in group",
+ "encrypted_hint": "Шифрование позволяет сделать сообщения доступными только тем, кто имеет доступ к группе.",
+ "access": "Who will see this group",
+ "access_hint": "Можно сделать группу открытой, или доступной только тем, чьи заявки на вступление в группу одобрит администрация.",
+ "access_all": "Everyone",
+ "all_read_only": "Everyone, but posting only for members",
+ "access_private": "Only members",
+ "next": "Next",
+ "back": "Back",
+ "submit": "Create",
+ "step_name": "Name",
+ "step_logo": "Logo",
+ "step_admin": "Administrator",
+ "step_create": "Create!"
+ },
"emoji_i18n": {
"categoriesLabel": "Категории",
"emojiUnsupportedMessage": "Ваш браузер не поддерживает эмодзи.",
diff --git a/src/locales/ru-RU.json b/src/locales/ru-RU.json
index 65fb2f390..650998743 100644
--- a/src/locales/ru-RU.json
+++ b/src/locales/ru-RU.json
@@ -77,6 +77,29 @@
"blocked_BY": "Вы заблокированы пользователем @%(BY)s.",
"do_not_bother_BY": "@%(BY)s просит пользователей с низкой репутацией не беспокоить."
},
+ "msgs_start_panel": {
+ "start_chat": "Начать чат",
+ "create_group": "Создать группу"
+ },
+ "create_group_jsx": {
+ "name": "Название",
+ "logo": "Логотип",
+ "admin": "Администратор",
+ "encrypted": "Шифровать сообщения в группе",
+ "encrypted_hint": "Шифрование позволяет сделать сообщения доступными только тем, кто имеет доступ к группе.",
+ "access": "Кому будет доступна группа",
+ "access_hint": "Можно сделать группу открытой, или доступной только тем, чьи заявки на вступление в группу одобрит администрация.",
+ "access_all": "Всем",
+ "all_read_only": "Всем, но постить только участникам",
+ "access_private": "Только участникам",
+ "next": "Далее",
+ "back": "Назад",
+ "submit": "Создать",
+ "step_name": "Имя",
+ "step_logo": "Логотип",
+ "step_admin": "Администратор",
+ "step_create": "Создать!"
+ },
"emoji_i18n": {
"categoriesLabel": "Категории",
"emojiUnsupportedMessage": "Ваш браузер не поддерживает эмодзи.",
diff --git a/src/redux/UserReducer.js b/src/redux/UserReducer.js
index 20fe4bfd1..e60902e38 100644
--- a/src/redux/UserReducer.js
+++ b/src/redux/UserReducer.js
@@ -5,6 +5,7 @@ const defaultState = fromJS({
current: null,
show_login_modal: false,
show_donate_modal: false,
+ show_create_group_modal: false,
show_app_download_modal: false,
loginLoading: false,
pub_keys_used: null,
@@ -128,6 +129,8 @@ export default createModule({
{ action: 'HIDE_CONNECTION_ERROR_MODAL', reducer: state => state.set('hide_connection_error_modal', true) },
{ action: 'SHOW_DONATE', reducer: state => state.set('show_donate_modal', true) },
{ action: 'HIDE_DONATE', reducer: state => state.set('show_donate_modal', false) },
+ { action: 'SHOW_CREATE_GROUP', reducer: state => state.set('show_create_group_modal', true) },
+ { action: 'HIDE_CREATE_GROUP', reducer: state => state.set('show_create_group_modal', false) },
{ action: 'SHOW_APP_DOWNLOAD', reducer: state => state.set('show_app_download_modal', true) },
{ action: 'HIDE_APP_DOWNLOAD', reducer: state => state.set('show_app_download_modal', false) },
{ action: 'SET_DONATE_DEFAULTS', reducer: (state, {payload}) => state.set('donate_defaults', fromJS(payload)) },