-
+
{account}
-
+
|
{!isSmall && !creatingNew && }
diff --git a/src/components/elements/messages/ConversationListItem/ConversationListItem.css b/src/components/elements/messages/ConversationListItem/ConversationListItem.css
index 11346a85f..cd6555601 100644
--- a/src/components/elements/messages/ConversationListItem/ConversationListItem.css
+++ b/src/components/elements/messages/ConversationListItem/ConversationListItem.css
@@ -33,7 +33,7 @@
}
.conversation-info {
- width: 100%;
+ width: calc(100% - 60px);
}
.conversation-snippet {
diff --git a/src/components/elements/messages/Message/Message.css b/src/components/elements/messages/Message/Message.css
index c235da713..b9b92b7c0 100644
--- a/src/components/elements/messages/Message/Message.css
+++ b/src/components/elements/messages/Message/Message.css
@@ -179,3 +179,17 @@
.msgs-message.mine .bubble-container.selected .quote-from {
color: white;
}
+
+.msgs-adds {
+ display: flex;
+}
+
+@media screen and (max-width: 39.9375em) {
+ .msgs-adds {
+ display: block;
+
+ .msgs-donating {
+ margin-left: 3px;
+ }
+ }
+}
diff --git a/src/components/elements/messages/Message/index.jsx b/src/components/elements/messages/Message/index.jsx
index 37c1d8a7e..c02ad2fc4 100644
--- a/src/components/elements/messages/Message/index.jsx
+++ b/src/components/elements/messages/Message/index.jsx
@@ -2,6 +2,7 @@ import React from 'react';
import {connect} from 'react-redux'
import { Fade } from 'react-foundation-components/lib/global/fade'
import { LinkWithDropdown } from 'react-foundation-components/lib/global/dropdown'
+import { withRouter } from 'react-router'
import { Link } from 'react-router-dom'
import tt from 'counterpart';
import cn from 'classnames'
@@ -33,6 +34,30 @@ class Message extends React.Component {
event.stopPropagation();
};
+ linkClicked = (event) => {
+ this.doNotSelectMessage(event)
+ if (process.env.MOBILE_APP) {
+ event.preventDefault()
+ let node, href
+ do {
+ node = node ? node.parentNode : event.target
+ if (!node) break
+ href = node.href
+ } while (!href)
+ try {
+ let url = new URL(href)
+ if (url.host === location.host) {
+ const { history } = this.props
+ history.push(url.pathname)
+ return
+ }
+ } catch (err) {
+ console.error(err)
+ }
+ window.open(href, '_system')
+ }
+ }
+
render() {
let username
@@ -61,7 +86,7 @@ class Message extends React.Component {
const previewWidth = message.previewWidth ? message.previewWidth + 'px' : 'auto';
const previewHeight = message.previewHeight ? message.previewHeight + 'px' : 'auto';
- content = (
+ content = (
);
} else {
@@ -77,7 +102,7 @@ class Message extends React.Component {
if (!href.startsWith('http://') && !href.startsWith('https://')) {
href = 'http://' + href;
}
- spans.push({word});
+ spans.push({word});
spans.push(' ');
} else if (word.length <= 2 && /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/.test(word)) {
spans.push({word});
@@ -130,12 +155,14 @@ class Message extends React.Component {
if (startsSequence) {
author = {
- e.preventDefault()
- e.stopPropagation()
- this.dropdown.current.click()
- }}>
- {from}
+ })}>
+ {
+ e.preventDefault()
+ e.stopPropagation()
+ this.dropdown.current.click()
+ }}>
+ {from}
+
avatar =
- {!isMine ? adds : null}
+ {!isMine ? {adds} : null}
);
}
}
-export default connect(
+export default withRouter(connect(
(state, ownProps) => {
const accounts = state.global.get('accounts')
@@ -199,4 +226,4 @@ export default connect(
},
dispatch => ({
}),
-)(Message)
+)(Message))
diff --git a/src/components/modules/MessagesTopCenter.jsx b/src/components/modules/MessagesTopCenter.jsx
index a4744ff6d..23201bd25 100644
--- a/src/components/modules/MessagesTopCenter.jsx
+++ b/src/components/modules/MessagesTopCenter.jsx
@@ -248,10 +248,13 @@ class MessagesTopCenter extends React.Component {
this.setState({ refreshing: true })
e.preventDefault()
e.stopPropagation()
- this.props.fetchState(this.props.to)
+ this.props.loginUser()
setTimeout(() => {
- this.setState({ refreshing: false })
- }, 500)
+ this.props.fetchState(this.props.to)
+ setTimeout(() => {
+ this.setState({ refreshing: false })
+ }, 500)
+ }, 1000)
}
render() {
diff --git a/src/components/modules/MessagesTopCenter.scss b/src/components/modules/MessagesTopCenter.scss
index d1302f4fc..e1f10b667 100644
--- a/src/components/modules/MessagesTopCenter.scss
+++ b/src/components/modules/MessagesTopCenter.scss
@@ -48,6 +48,7 @@
@media screen and (max-width: 39.9375em) {
.GroupDropdown {
left: 10px !important;
+ position: fixed;
}
}
diff --git a/src/components/modules/Modals.jsx b/src/components/modules/Modals.jsx
index f4bbcba82..4243c734f 100644
--- a/src/components/modules/Modals.jsx
+++ b/src/components/modules/Modals.jsx
@@ -16,6 +16,7 @@ import LoginForm from 'app/components/modules/LoginForm';
import AppDownload from 'app/components/modules/app/AppDownload'
import user from 'app/redux/UserReducer'
//import tr from 'app/redux/Transaction';
+import isScreenSmall from 'app/utils/isScreenSmall'
let keyIndex = 0;
@@ -76,10 +77,15 @@ class Modals extends React.Component {
return n;
}) : [];
- const modalStyle = {
- borderRadius: '8px',
- boxShadow: '0 0 19px 3px rgba(0,0,0, 0.2)',
- overflow: 'hidden',
+ let modalStyle = {
+ overflowX: 'hidden',
+ }
+ if (!isScreenSmall()) {
+ modalStyle = {
+ borderRadius: '8px',
+ boxShadow: '0 0 19px 3px rgba(0,0,0, 0.2)',
+ ...modalStyle,
+ }
}
const doHideLogin = (e) => {
diff --git a/src/components/modules/groups/GroupMembers.jsx b/src/components/modules/groups/GroupMembers.jsx
index 3bbde6f79..18e450340 100644
--- a/src/components/modules/groups/GroupMembers.jsx
+++ b/src/components/modules/groups/GroupMembers.jsx
@@ -1,5 +1,6 @@
import React from 'react'
import { connect } from 'react-redux'
+import { Link } from 'react-router-dom'
import { Field, ErrorMessage, } from 'formik'
import tt from 'counterpart'
import { validateAccountName } from 'golos-lib-js/lib/utils'
@@ -11,8 +12,8 @@ import AccountName from 'app/components/elements/common/AccountName'
import Input from 'app/components/elements/common/Input';
import GroupMember from 'app/components/elements/groups/GroupMember'
import LoadingIndicator from 'app/components/elements/LoadingIndicator'
-import MarkNotificationRead from 'app/components/elements/MarkNotificationRead'
import { getRoleInGroup, getGroupMeta, getGroupTitle } from 'app/utils/groups'
+import isScreenSmall from 'app/utils/isScreenSmall'
export async function validateMembersStep(values, errors) {
// nothing yet...
@@ -149,7 +150,7 @@ class GroupMembers extends React.Component {
}
render() {
- const { currentGroup, group, username } = this.props
+ const { currentGroup, group, username, closeMe } = this.props
const loading = this.isLoading()
let members = group && group.get('members')
if (members) members = members.get('data')
@@ -162,6 +163,12 @@ class GroupMembers extends React.Component {
amModer = true
}
+ const isSmall = isScreenSmall()
+
+ const linkClick = () => {
+ if (closeMe) closeMe()
+ }
+
let mems
if (loading) {
mems =
@@ -178,6 +185,7 @@ class GroupMembers extends React.Component {
mems.push( )
}
@@ -197,7 +205,7 @@ class GroupMembers extends React.Component {
{amModer ?
{
@@ -222,7 +230,7 @@ class GroupMembers extends React.Component {
} else {
- const { name, json_metadata, pendings, banneds, } = currentGroup
+ const { name, owner, json_metadata, pendings, banneds, } = currentGroup
const meta = getGroupMeta(json_metadata)
let title = getGroupTitle(meta, name)
@@ -231,12 +239,31 @@ class GroupMembers extends React.Component {
const { showPendings, showBanneds } = this.state
+ let ownerRight, ownerRow
+ let ownerBlock =
+ {tt('group_settings_jsx.owner') + ' - '}
+ {amOwner ? {tt('g.you')} :
+ {('@' + owner)}}
+
+ if (isSmall) {
+ ownerRow =
+ } else {
+ ownerRight =
+ {ownerBlock}
+
+ }
+
header =
+ {ownerRow}
{amModer ? :
{this._renderMemberTypeSwitch()}
+ {ownerRight}
}
- {(username && showPendings) ? : null}
}
diff --git a/src/components/modules/groups/GroupName.jsx b/src/components/modules/groups/GroupName.jsx
index 46c467025..856fc5679 100644
--- a/src/components/modules/groups/GroupName.jsx
+++ b/src/components/modules/groups/GroupName.jsx
@@ -19,10 +19,10 @@ export async function validateNameStep(values, errors) {
for (let i = 0; i < 3; ++i) {
try {
console.time('group_exists')
- group = await api.getGroupsAsync({
+ group = (await api.getGroupsAsync({
start_group: values.name,
limit: 1
- })
+ })).groups
console.timeEnd('group_exists')
break
} catch (err) {
@@ -30,7 +30,7 @@ export async function validateNameStep(values, errors) {
errors.name = 'Blockchain unavailable :('
}
}
- if (group && group[0] && group[0].name === values.name) {
+ if (group[0] && group[0].name === values.name) {
errors.name = tt('create_group_jsx.group_already_exists')
}
}
diff --git a/src/components/modules/groups/MyGroups.jsx b/src/components/modules/groups/MyGroups.jsx
index 9de07e978..6b69b1f0a 100644
--- a/src/components/modules/groups/MyGroups.jsx
+++ b/src/components/modules/groups/MyGroups.jsx
@@ -14,6 +14,7 @@ import DropdownMenu from 'app/components/elements/DropdownMenu'
import Icon from 'app/components/elements/Icon'
import LoadingIndicator from 'app/components/elements/LoadingIndicator'
import MarkNotificationRead from 'app/components/elements/MarkNotificationRead'
+import NotifiCounter from 'app/components/elements/NotifiCounter'
import { showLoginDialog } from 'app/components/dialogs/LoginDialog'
import { getGroupLogo, getGroupMeta, getRoleInGroup } from 'app/utils/groups'
import isScreenSmall from 'app/utils/isScreenSmall'
@@ -28,7 +29,11 @@ class MyGroups extends React.Component {
refetch = () => {
const { currentUser } = this.props
- this.props.fetchMyGroups(currentUser)
+ this.setState({
+ currentTab: null,
+ }, () => {
+ this.props.fetchMyGroups(currentUser)
+ })
}
componentDidMount = async () => {
@@ -124,7 +129,7 @@ class MyGroups extends React.Component {
}
_renderGroup = (group) => {
- const { name, json_metadata, pendings } = group
+ const { name, json_metadata, pendings, members, moders, } = group
const meta = getGroupMeta(json_metadata)
@@ -156,6 +161,9 @@ class MyGroups extends React.Component {
}, value: tt('msgs_group_dropdown.retire') })
}
+
+ const noMembers = !pendings && !members && !moders
+
return
{this._renderGroupLogo(group, meta)}
@@ -175,7 +183,7 @@ class MyGroups extends React.Component {
{amPending ? tt('msgs_group_dropdown.cancel') : tt('msgs_group_dropdown.retire')}
: null}
- {(amModer && pendings) ?
}
+ _renderGroupTypeSwitch = () => {
+ const { stat, } = this.props
+ let { currentTab } = this.state
+ currentTab = currentTab || stat.current
+ let tabs = []
+ for (const key of ['pending', 'member', 'moder', 'own']) {
+ if (!stat[key]) continue
+ let counter
+ if (key === 'member') {
+ counter = 'group_member_mem'
+ } else if (key === 'moder') {
+ counter = 'join_request_mod,group_member_mod'
+ } else if (key === 'own') {
+ counter = 'join_request_own'
+ }
+ tabs.push( {
+ this.setState({
+ currentTab: key
+ })
+ }} >
+
+ {tt('my_groups_jsx.tab_' + key) + ' (' + stat[key] + ')'}
+
+ {counter && }
+ )
+ }
+ if (tabs.length < 1) return null
+ return
+ {tabs}
+
+ }
+
render() {
let groups, hasGroups
@@ -231,23 +274,33 @@ class MyGroups extends React.Component {
} else {
hasGroups = true
+
+ const { stat, } = this.props
+ let { currentTab } = this.state
+ currentTab = currentTab || stat.current
+
groups = []
for (const g of my_groups) {
+ if (currentTab && g.my_role !== currentTab) continue
groups.push(this._renderGroup(g))
}
- groups =
+ groups =
+ {this._renderGroupTypeSwitch()}
+
+
}
}
let button
if (hasGroups) {
+ const isSmall = isScreenSmall()
button =
- {tt('my_groups_jsx.create_more')}
+ {isSmall ? tt('my_groups_jsx.create_more2') : tt('my_groups_jsx.create_more')}
@@ -265,7 +318,7 @@ class MyGroups extends React.Component {
{button}
{groups}
{hasGroups ? : null}
- {username ? : null}
}
@@ -276,11 +329,13 @@ export default connect(
const currentUser = state.user.getIn(['current'])
const username = currentUser && currentUser.get('username')
const my_groups = state.global.get('my_groups')
+ const my_groups_stat = state.global.get('my_groups_stat')
return { ...ownProps,
currentUser,
username,
my_groups,
+ stat: my_groups_stat ? my_groups_stat.toJS() : {},
}
},
dispatch => ({
diff --git a/src/components/modules/groups/MyGroups.scss b/src/components/modules/groups/MyGroups.scss
index d0cfc5749..5b12e5721 100644
--- a/src/components/modules/groups/MyGroups.scss
+++ b/src/components/modules/groups/MyGroups.scss
@@ -19,6 +19,8 @@
}
.more-group {
float: right;
+ padding-top: 0.725em;
+ padding-bottom: 0.725em;
&:not(:hover) {
border-color: transparent;
}
@@ -44,4 +46,40 @@
display: none;
}
}
+ .button.force-white {
+ color: #fefefe !important;
+ fill: #fefefe !important;
+ }
+ .label {
+ padding: 0.5rem;
+ padding-top: 0.6rem;
+ padding-bottom: 0.4rem;
+
+ transition: all .1s ease-in;
+ user-select: none;
+
+ margin-right: 0.5rem;
+ margin-bottom: 0.5rem;
+
+ .label-text {
+ display: inline-block;
+ height: 16px;
+ }
+ .NotifiCounter {
+ margin-left: 0.35rem;
+ vertical-align: top;
+ }
+
+ &:not(.disabled) {
+ cursor: pointer;
+ }
+ &:not(.checked) {
+ background: #f4f4f8;
+ color: #333333;
+ }
+ &:hover:not(.disabled) {
+ background: #0078C4;
+ color: #fefefe;
+ }
+ }
}
diff --git a/src/components/modules/groups/TopGroups.scss b/src/components/modules/groups/TopGroups.scss
index a0f5e79b7..578d8727e 100644
--- a/src/components/modules/groups/TopGroups.scss
+++ b/src/components/modules/groups/TopGroups.scss
@@ -16,6 +16,9 @@
vertical-align: middle;
img {
border-radius: 50%;
+ width: 50px;
+ height: 50px;
+ object-fit: cover;
}
}
.group-stats {
diff --git a/src/components/pages/Messages.jsx b/src/components/pages/Messages.jsx
index 6b0c40241..df75c236a 100644
--- a/src/components/pages/Messages.jsx
+++ b/src/components/pages/Messages.jsx
@@ -34,7 +34,7 @@ import { getProfileImage, } from 'app/utils/NormalizeProfile';
import { normalizeContacts, normalizeMessages, cacheMyOwnMsg } from 'app/utils/Normalizators';
import { fitToPreview } from 'app/utils/ImageUtils';
import { notificationSubscribe, notificationSubscribeWs, notifyWsPing,
- notificationShallowUnsubscribe, notificationTake, queueWatch, sendOffchainMessage, notifyWsHost, notifyUrl } from 'app/utils/NotifyApiClient';
+ notificationShallowUnsubscribe, notificationTake, queueWatchWs, sendOffchainMessage, notifyWsHost, notifyUrl } from 'app/utils/NotifyApiClient';
import { flash, unflash } from 'app/components/elements/messages/FlashTitle';
import { addShortcut } from 'app/utils/app/ShortcutUtils'
import { hideSplash } from 'app/utils/app/SplashUtils'
@@ -252,15 +252,17 @@ class Messages extends React.Component {
const {username} = this.props
if (!username) {
- console.log('watchGroup -', to, ' - no username')
+ console.log('watchGroupWs -', to, ' - no username')
return false
}
try {
- await queueWatch(username, to)
- console.log('watchGroup - ', to)
+ window.errorLogs.push({ details: { watchGroup: to } })
+ await queueWatchWs(username, to)
+ console.log('watchGroupWs - ', to)
+ window.errorLogs.push({ details: { watchGroup: 'ok' } })
return true
} catch (err) {
- console.error('watchGroup - ', to, err)
+ console.error('watchGroupWs - ', to, err)
this.notifyErrorsInc(30, err, {watchGroup: notifyUrl()})
}
return false
@@ -323,6 +325,7 @@ class Messages extends React.Component {
this.notifyErrorsClear()
const ping = async (firstCall = false) => {
if (!firstCall) {
+ window.errorLogs.push({ details: { ping: Date.now() } })
try {
await notifyWsPing()
if (this.state.notifyErrors) {
@@ -340,6 +343,7 @@ class Messages extends React.Component {
}
setTimeout(ping, 10000)
}
+ ping(true)
this.watchGroup(this.props.to)
}
@@ -878,11 +882,11 @@ class Messages extends React.Component {
>
e.preventDefault()}>
-
@@ -903,7 +907,7 @@ class Messages extends React.Component {
};
_renderMessagesTopCenter = ({ isSmall }) => {
- const { fetchState, to } = this.props
+ const { fetchState, loginUser, to } = this.props
const toAcc = this.getToAcc()
const { notifyErrors, } = this.state
@@ -914,6 +918,7 @@ class Messages extends React.Component {
notifyErrors={notifyErrors}
errorLogs={window.errorLogs}
fetchState={fetchState}
+ loginUser={loginUser}
/>
};
@@ -940,7 +945,7 @@ class Messages extends React.Component {
}
let user_menu = [
- {link: '#', onClick: openMyGroups, icon: 'voters', value: tt('g.groups') + (isSmall ? (' @' + username) : ''), addon: },
+ {link: '#', onClick: openMyGroups, icon: 'voters', value: tt('g.groups') + (isSmall ? (' @' + username) : ''), addon: },
{link: accountLink, extLink: 'blogs', icon: 'new/blogging', value: tt('g.blog'), addon: },
{link: mentionsLink, extLink: 'blogs', icon: 'new/mention', value: tt('g.mentions'), addon: },
{link: donatesLink, extLink: 'wallet', icon: 'editor/coin', value: tt('g.rewards'), addon: },
@@ -956,7 +961,25 @@ class Messages extends React.Component {
]
if (process.env.MOBILE_APP) {
- user_menu.push({link: '#', onClick: this.props.openSettings, icon: 'new/setting', value: tt('g.settings')})
+ user_menu.push({link: '#', onClick: this.props.openSettings, icon: 'new/setting', value: tt('g.settings'),
+ onTouchStart: (e) => {
+ window.settingsTouch = setTimeout(() => {
+ try {
+ const { errorLogs } = window
+ let msg = ''
+ for (const err of errorLogs) {
+ msg += (err.err ? err.err.toString() : '') + '\n' + JSON.stringify(err.details) + '\n\n'
+ }
+ alert(msg)
+ } catch (err) {
+ alert('Cannot display error logs, due to: ' + (err && err.toString()))
+ }
+ }, 3000)
+ },
+ onTouchEnd: (e) => {
+ clearTimeout(window.settingsTouch)
+ }
+ })
}
user_menu.push({link: '#', icon: 'new/logout', onClick: logout, value: tt('g.logout')})
@@ -982,7 +1005,7 @@ class Messages extends React.Component {
{!isSmall ?
diff --git a/src/locales/en.json b/src/locales/en.json
index 3f0dbb4e7..aba3e3c07 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -181,7 +181,8 @@
"members_list": "Members:",
"image_wrong": "Cannot load this image.",
"image_timeout": "Cannot load this image, it is loading too long...",
- "add_member": "+ Add Member..."
+ "add_member": "+ Add Member...",
+ "add_member2": "+ Add..."
},
"my_groups_jsx": {
"title": "My Groups",
@@ -192,12 +193,19 @@
"create": "create",
"create2": "your own one",
"create_more": "+ Create a group",
+ "create_more2": "+ Create...",
"more_groups": "More groups...",
"edit": "Edit",
"login_hint_GROUP": "(delete \"%(GROUP)s\" group)",
"members": "Members",
"cancel_pending": "Cancel request",
- "are_you_sure_cancel": "Do you sure you don't want to join"
+ "are_you_sure_cancel": "Do you sure you don't want to join",
+ "tab_pending": "Pending",
+ "tab_member": "Member",
+ "tab_moder": "Moder",
+ "tab_own": "Owner",
+ "tabs_title": "Your status in groups",
+ "total_MEMBERS": "Total: %(MEMBERS)s member(-s)."
},
"top_groups_jsx": {
"title": "Popular Groups",
@@ -265,6 +273,9 @@
"flags": "Флаги"
}
},
+ "fatal_error_jsx": {
+ "render_error": ";( Render Error"
+ },
"stub_jsx": {
"read_only": "Only members can post messages in this group.",
"private_group": "This group is private. To read and write messages, you should be a member.",
@@ -389,6 +400,7 @@
"submit": "Submit",
"unblock": "Unblock",
"username_does_not_exist": "Username does not exist",
- "wallet": "Wallet"
+ "wallet": "Wallet",
+ "you": "you"
}
}
diff --git a/src/locales/ru-RU.json b/src/locales/ru-RU.json
index 910190bc4..0e8d495c1 100644
--- a/src/locales/ru-RU.json
+++ b/src/locales/ru-RU.json
@@ -189,6 +189,7 @@
"image_wrong": "Не удается загрузить картинку.",
"image_timeout": "Не удается загрузить картинку, она загружается слишком долго...",
"add_member": "+ Добавить участника...",
+ "add_member2": "+ Добавить...",
"cannot_set_members": "Группа создана успешно. Но, к сожалению, не получилось задать участников из-за ошибки.",
"cannot_set_members2": "Вы можете попытаться сделать это заново в настройках группы."
},
@@ -200,13 +201,20 @@
"find2": "интересную для себя группу",
"create": "создать",
"create2": "свою собственную",
- "create_more": "+ Создать группу",
+ "create_more": "+ Создать группу",
+ "create_more2": "+ Создать...",
"more_groups": "Еще группы...",
"edit": "Изменить",
"login_hint_GROUP": "(удаления группы \"%(GROUP)s\")",
"members": "Участники",
"cancel_pending": "Отменить заявку",
- "are_you_sure_cancel": "Вы уверены, что хотите отказаться от вступления в группу"
+ "are_you_sure_cancel": "Вы уверены, что хотите отказаться от вступления в группу",
+ "tab_pending": "Заявки",
+ "tab_member": "Участник",
+ "tab_moder": "Модератор",
+ "tab_own": "Владелец",
+ "tabs_title": "Ваш статус в группах",
+ "total_MEMBERS": "Всего %(MEMBERS)s участник(-ов)."
},
"top_groups_jsx": {
"title": "Топ популярных групп",
@@ -281,8 +289,11 @@
"flags": "Флаги"
}
},
+ "fatal_error_jsx": {
+ "render_error": ";( Ошибка рендеринга"
+ },
"stub_jsx": {
- "read_only": "Писать сообщения в этой группе могут лишь ее члены.",
+ "read_only": "Писать сообщения могут только члены группы.",
"private_group": "Это закрытая группа. Чтобы видеть сообщения и общаться в ней, надо стать ее членом.",
"pending": "Вы подали заявку на вступление в группу.",
"banned": "Вы забанены в этой группе.",
@@ -407,6 +418,7 @@
"unblock": "Разблокировать",
"username_does_not_exist": "Такого имени не существует",
"wallet": "Кошелек",
- "wait": "Ждите..."
+ "wait": "Ждите...",
+ "you": "вы"
}
}
\ No newline at end of file
diff --git a/src/redux/FetchDataSaga.js b/src/redux/FetchDataSaga.js
index e27de9470..639f3ec55 100644
--- a/src/redux/FetchDataSaga.js
+++ b/src/redux/FetchDataSaga.js
@@ -3,6 +3,7 @@ import golos, { api, auth } from 'golos-lib-js'
import tt from 'counterpart'
import g from 'app/redux/GlobalReducer'
+import { getRoleInGroup } from 'app/utils/groups'
import { getSpaceInCache, saveToCache } from 'app/utils/Normalizators'
export function* fetchDataWatches () {
@@ -129,8 +130,8 @@ export function* fetchState(location_change_action) {
}
})
if (hasErr) return
- if (the_group[0] && the_group[0].name === path) {
- the_group = the_group[0]
+ if (the_group && the_group.groups && the_group.groups[0] && the_group.groups[0].name === path) {
+ the_group = the_group.groups[0]
} else {
the_group = null
}
@@ -226,7 +227,13 @@ export function* watchFetchMyGroups() {
export function* fetchMyGroups({ payload: { account } }) {
try {
- const groupsOwn = yield call([api, api.getGroupsAsync], {
+ const stat = {
+ pending: 0,
+ member: 0,
+ moder: 0,
+ own: 0,
+ }
+ const groupsOwn = (yield call([api, api.getGroupsAsync], {
member: account,
member_types: [],
start_group: '',
@@ -234,8 +241,9 @@ export function* fetchMyGroups({ payload: { account } }) {
with_members: {
accounts: [account]
}
- })
- let groups = yield call([api, api.getGroupsAsync], {
+ })).groups
+
+ let groups = (yield call([api, api.getGroupsAsync], {
member: account,
member_types: ['pending', 'member', 'moder'],
start_group: '',
@@ -243,13 +251,39 @@ export function* fetchMyGroups({ payload: { account } }) {
with_members: {
accounts: [account]
}
- })
+ })).groups
+
groups = [...groupsOwn, ...groups]
+ for (const group of groups) {
+ const { amPending, amMember, amModer, amOwner } = getRoleInGroup(group, account)
+ if (amOwner) {
+ group.my_role = 'own'
+ stat.own++
+ } else if (amPending) {
+ group.my_role = 'pending'
+ stat.pending++
+ } else if (amMember) {
+ group.my_role = 'member'
+ stat.member++
+ } else if (amModer) {
+ group.my_role = 'moder'
+ stat.moder++
+ }
+ }
groups.sort((a, b) => {
return b.pendings - a.pendings
})
- yield put(g.actions.receiveMyGroups({ groups }))
+ let current = 'member'
+ if (stat.pending) {
+ current = 'pending'
+ } else {
+ if (stat.moder > stat[current]) current = 'moder'
+ if (stat.own > stat[current]) current = 'own'
+ }
+ stat.current = current
+
+ yield put(g.actions.receiveMyGroups({ groups, stat }))
} catch (err) {
console.error('fetchMyGroups', err)
}
@@ -269,7 +303,7 @@ export function* fetchTopGroups({ payload: { account } }) {
groupsWithoutMe.pop()
}
- const groups = yield call([api, api.getGroupsAsync], {
+ const { groups } = yield call([api, api.getGroupsAsync], {
sort: 'by_popularity',
start_group,
limit: 100,
@@ -310,7 +344,7 @@ export function* fetchGroupMembers({ payload: { group, creatingNew, memberTypes,
yield put(g.actions.receiveGroupMembers({ group, loading: true }))
- const members = yield call([api, api.getGroupMembersAsync], {
+ const { members } = yield call([api, api.getGroupMembersAsync], {
group,
member_types: memberTypes,
sort_conditions: sortConditions,
diff --git a/src/redux/GlobalReducer.js b/src/redux/GlobalReducer.js
index 3e421ce00..0952f21fd 100644
--- a/src/redux/GlobalReducer.js
+++ b/src/redux/GlobalReducer.js
@@ -70,6 +70,7 @@ export default createModule({
})
let new_state = state.set('messages', List());
new_state = new_state.set('contacts', List());
+ new_state = new_state.delete('the_group');
new_state = new_state.mergeDeep(payload)
return new_state
},
@@ -366,8 +367,10 @@ export default createModule({
},
{
action: 'RECEIVE_MY_GROUPS',
- reducer: (state, { payload: { groups } }) => {
- return state.set('my_groups', fromJS(groups))
+ reducer: (state, { payload: { groups, stat } }) => {
+ let new_state = state.set('my_groups', fromJS(groups))
+ new_state = new_state.set('my_groups_stat', fromJS(stat))
+ return new_state
},
},
{
diff --git a/src/utils/NotifyApiClient.js b/src/utils/NotifyApiClient.js
index 602892e90..28d722e7f 100644
--- a/src/utils/NotifyApiClient.js
+++ b/src/utils/NotifyApiClient.js
@@ -39,6 +39,10 @@ function saveSession(response) {
}
}
if (!session) return;
+ if (window.errorLogs) {
+ let xSess = session && session.substring && (session.substring(0, 5) + '...')
+ window.errorLogs.push({ details: { xsession: xSess } })
+ }
localStorage.setItem('X-Session', session);
}
@@ -330,9 +334,10 @@ export async function queueWatchWs(account, group, sidKey = '__subscriber_id') {
if (!notifyWsHost()) return null
const xSession = notifySession()
return await new Promise(async (resolve, reject) => {
- await notifyWsSend('queues/subscribe', {
+ await notifyWsSend('queues/watch', {
account,
'X-Session': xSession,
+ subscriber_id: window[sidKey],
objects: {
[group]: {
type: 'group',
diff --git a/src/utils/RenderError.jsx b/src/utils/RenderError.jsx
new file mode 100644
index 000000000..ed7b65324
--- /dev/null
+++ b/src/utils/RenderError.jsx
@@ -0,0 +1,28 @@
+import React from 'react'
+
+import tt from 'counterpart'
+
+class RenderError extends React.Component {
+ refreshIt = () => {
+ if (window.location.pathname === '/') {
+ window.location.reload()
+ return
+ }
+ window.location.href = '/'
+ }
+
+ render() {
+ const { error } = this.props
+ const refreshBtn = {tt('g.refresh')}
+ const { errStr, infoStr } = error
+ return
+ {tt('fatal_error_jsx.render_error')}
+ {refreshBtn}
+ {errStr}
+ {infoStr}
+ {refreshBtn}
+
+ }
+}
+
+export default RenderError
diff --git a/src/utils/ServerApiClient.js b/src/utils/ServerApiClient.js
index 8d9fff818..7e8d04c8b 100644
--- a/src/utils/ServerApiClient.js
+++ b/src/utils/ServerApiClient.js
@@ -3,7 +3,7 @@ import { fetchEx } from 'golos-lib-js/lib/utils'
export function getHost() {
const { location, } = window;
if (process.env.NODE_ENV === 'development') {
- return location.protocol + '//'+ location.hostname + ':8080';
+ return location.protocol + '//'+ location.hostname + ':8088';
}
return location.origin;
}
|