Skip to content

Commit

Permalink
HF 30 - Private message groups - members, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
1aerostorm committed Jun 29, 2024
1 parent 58e7238 commit 8dfa1f4
Show file tree
Hide file tree
Showing 33 changed files with 1,085 additions and 200 deletions.
1 change: 1 addition & 0 deletions config-overrides.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module.exports = function override(config, env) {
'process.env.IS_APP': JSON.stringify(!!process.env.IS_APP),
'process.env.DESKTOP_APP': JSON.stringify(!!process.env.DESKTOP_APP),
'process.env.MOBILE_APP': JSON.stringify(!!process.env.MOBILE_APP),
//'process.env.NO_NOTIFY': JSON.stringify(true),
}),
)

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"react-notification": "^6.8.5",
"react-redux": "^7.2.6",
"react-router-dom": "^5.3.0",
"react-select": "^5.8.0",
"react-textarea-autosize": "^8.3.3",
"redux": "^4.1.2",
"redux-logger": "^3.0.6",
Expand Down
2 changes: 2 additions & 0 deletions src/_themes.scss
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ $themes: (
navBackgroundColor: $color-white,
highlightBackgroundColor: #f3faf0,
tableRowEvenBackgroundColor: #f4f4f4,
borderColor: $light-gray,
border: 1px solid $light-gray,
borderLight: 1px solid $color-border-light-lightest,
borderDark: 1px solid $color-text-gray,
Expand Down Expand Up @@ -98,6 +99,7 @@ $themes: (
zebra: $black-gray,
highlighted: $black-gray,
tableRowEvenBackgroundColor: #212C33,
borderColor: $color-border-dark,
border: 1px solid $color-border-dark,
borderLight: 1px solid $color-border-dark-lightest,
textColorPrimaryborderDark: 1px solid $color-text-gray-light,
Expand Down
1 change: 1 addition & 0 deletions src/assets/icons/ionicons/ban-outline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/icons/ionicons/ban.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/assets/icons/ionicons/checkmark-circle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/assets/icons/ionicons/checkmark-sharp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/icons/ionicons/person-add.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/icons/ionicons/person.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/components/all.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
@import "./elements/VerticalMenu";
@import "./elements/app/AppReminder";
@import "./elements/app/LoginAppReminder";
@import "./elements/common/AccountName/index";
@import "./elements/common/DialogManager/index";
@import "./elements/common/Input/index";
@import './elements/donate/PresetSelector';
Expand All @@ -23,6 +24,7 @@
@import './modules/LoginForm.scss';
@import './modules/CreateGroup.scss';
@import './modules/groups/MyGroups.scss';
@import './modules/groups/GroupMembers.scss';
@import './modules/groups/GroupSettings.scss';
@import './modules/Modals.scss';

Expand Down
4 changes: 4 additions & 0 deletions src/components/elements/Icon.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ const icons = new Map([
// ['editor-toolbar/picture', require('app/assets/icons/editor-toolbar/picture.svg')],
// ['editor-toolbar/video', require('app/assets/icons/editor-toolbar/video.svg')],
// ['editor-toolbar/search', require('app/assets/icons/editor-toolbar/search.svg')],
['ionicons/ban', require('app/assets/icons/ionicons/ban.svg')],
['ionicons/ban-outline', require('app/assets/icons/ionicons/ban-outline.svg')],
['ionicons/checkmark-circle', require('app/assets/icons/ionicons/checkmark-circle.svg')],
['ionicons/checkmark-sharp', require('app/assets/icons/ionicons/checkmark-sharp.svg')],
['ionicons/gift', require('app/assets/icons/ionicons/gift.svg')],
Expand All @@ -137,6 +139,8 @@ const icons = new Map([
['ionicons/lock-closed-outline', require('app/assets/icons/ionicons/lock-closed-outline.svg')],
['ionicons/lock-open-outline', require('app/assets/icons/ionicons/lock-open-outline.svg')],
['ionicons/trash-outline', require('app/assets/icons/ionicons/trash-outline.svg')],
['ionicons/person', require('app/assets/icons/ionicons/person.svg')],
['ionicons/person-add', require('app/assets/icons/ionicons/person-add.svg')],
// ['notification/comment', require('app/assets/icons/notification/comment.svg')],
// ['notification/donate', require('app/assets/icons/notification/donate.svg')],
// ['notification/transfer', require('app/assets/icons/notification/transfer.svg')],
Expand Down
66 changes: 66 additions & 0 deletions src/components/elements/common/AccountName/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react'
import tt from 'counterpart'
import AsyncSelect from 'react-select/async'
import { api } from 'golos-lib-js'

import Userpic from 'app/components/elements/Userpic'

class AccountName extends React.Component {
constructor(props) {
super(props)
}

lookupAccounts = async (value) => {
try {
const { includeFrozen, filterAccounts } = this.props
const accNames = await api.lookupAccountsAsync(value.toLowerCase(), 6, {
include_frozen: includeFrozen,
filter_accounts: [...filterAccounts],
})
const accs = await api.lookupAccountNamesAsync(accNames)
return accs
} catch (err) {
console.error(err)
return []
}
}

onChange = (acc) => {
const { onChange } = this.props
if (onChange) {
const e = { target: { value: acc.name, account: acc } }
onChange(e, acc)
}
}

render() {
const { onChange, className, ...rest } = this.props
return <AsyncSelect
placeholder={tt('g.name')}
loadingMessage={() => tt('account_name_jsx.loading')}
noOptionsMessage={() => tt('account_name_jsx.no_options')}

loadOptions={this.lookupAccounts}
defaultOptions={true}
cacheOptions={false}

className={'AccountName ' + (className || ' ')}
getOptionLabel={(option) => {
return <span className='name-item'>
<Userpic account={option.name} width={24} height={24} />
<span className='title' style={{ verticalAlign: 'top' }}>{`${option.name}`}</span>
</span>
}}
controlShouldRenderValue={false}
onChange={this.onChange}
{...rest}
/>
}
}

AccountName.defaultProps = {
includeFrozen: false,
filterAccounts: [],
}

export default AccountName
14 changes: 14 additions & 0 deletions src/components/elements/common/AccountName/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.AccountName {
input {
box-shadow: none !important;
line-height: 1 !important;
height: 1.8rem !important;
}
.name-item {
margin-top: 0.45rem;
display: inline-block;
.title {
margin-left: 0.25rem;
}
}
}
121 changes: 121 additions & 0 deletions src/components/elements/groups/GroupMember.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React from 'react'
import tt from 'counterpart'
import cn from 'classnames'

import Icon from 'app/components/elements/Icon'
import TimeAgoWrapper from 'app/components/elements/TimeAgoWrapper'
import Userpic from 'app/components/elements/Userpic'

class GroupMember extends React.Component {
// shouldComponentUpdate(nextProps) {
// const { member } = this.props
// if (member.member_type !== nextProps.member_type) {
// return true
// }
// return false
// }

groupMember = (e, member, setMemberType) => {
e.preventDefault()
const { username, currentGroup } = this.props
const { account } = member
const currentMemberType = member.member_type

if (currentMemberType === setMemberType) return;
if (username === account) return
const group = currentGroup.name

// Update in UI immediately
this.props.updateGroupMember(group, account, setMemberType)

const { creatingNew } = currentGroup
if (!creatingNew) {
this.props.groupMember({
requester: username, group,
member: account,
member_type: setMemberType,
onSuccess: () => {
},
onError: (err, errStr) => {
// Update it back!
this.props.updateGroupMember(group, account, currentMemberType)

if (errStr.includes('duplicate transaction')) {
// "Too Many Requests" - just nothing action, not alert
return
}
alert(errStr)
}
})
}
}

render() {
const { member, username, currentGroup } = this.props
const { account, member_type, joined } = member
const { creatingNew } = currentGroup

const isMe = username === account
const isOwner = currentGroup.owner === account
const isMember = !isOwner && member_type === 'member'
const isModer = !isOwner && member_type === 'moder'
const isBanned = !isOwner && member_type === 'banned'

let memberTitle, moderTitle, banTitle
let memberBtn, moderBtn, banBtn, deleteBtn
let ownerTitle = tt('group_members_jsx.owner')
if (account !== username) {
memberTitle = (isMember && tt('group_members_jsx.member')) ||
(isBanned && tt('group_members_jsx.unban')) ||
(!isMember && tt('group_members_jsx.make_member'))
moderTitle = (isModer && tt('group_members_jsx.moder')) ||
tt('group_members_jsx.make_moder')
banTitle = (isBanned && tt('group_members_jsx.unban')) ||
tt('group_members_jsx.ban')
} else {
memberTitle = tt('group_members_jsx.member')
moderTitle = tt('group_members_jsx.moder')
banTitle = tt('group_members_jsx.banned')
}

if (!creatingNew) {
if (!isMe || isBanned) {
banBtn = <Icon className={cn('member-btn ban', { selected: isBanned })}
title={banTitle} name='ionicons/ban' size='1_25x'
onClick={e => this.groupMember(e, member, 'banned')} />
}
} else {
deleteBtn = <Icon className={'member-btn delete'} title={tt('g.delete')} name='cross' size='1x'
onClick={e => this.groupMember(e, member, 'retired')} />
}

return <tr key={account}>
<td style={{ paddingBottom: '0px' }}>
<a href={'/@' + account} target='_blank' rel='noopener noreferrer'>
<Userpic account={account} title={account} width={40} height={40} />
<span className='member-name'>
{account}
</span>
</a>
</td>
<td>
{!creatingNew && <TimeAgoWrapper date={joined} />}
</td>
<td className='member-btns'>
{isOwner && <Icon className={cn('member-btn owner selected')}
title={ownerTitle}
name='ionicons/checkmark-circle' size='1_5x' />}
{(!isMe || isMember) && <Icon className={cn('member-btn member', { selected: isMember })}
title={memberTitle}
name='ionicons/person' size='1_5x' onClick={e => this.groupMember(e, member, 'member')} />}
{(!isMe || isModer) && <Icon className={cn('member-btn moder', { selected: isModer })}
title={moderTitle}
name='ionicons/person-add' size='1_5x' onClick={e => this.groupMember(e, member, 'moder')} />}
{banBtn}
{deleteBtn}
</td>
</tr>
}
}

export default GroupMember
Loading

0 comments on commit 8dfa1f4

Please sign in to comment.