Updated StatusSharePopover -> SharePopover, Added group, account share

• Updated:
- StatusSharePopover -> SharePopover

• Added:
- group, account share
- group url in routes.rb
- group url in GroupSerializer.rb
- share buttons in ProfileOptionsPopover, GroupOptionsPopover
This commit is contained in:
mgabdev 2020-12-24 13:27:55 -05:00
parent 0ceccce04a
commit 7dd71a06ca
11 changed files with 119 additions and 49 deletions

View File

@ -8,7 +8,11 @@ import {
addShortcut, addShortcut,
removeShortcut, removeShortcut,
} from '../../actions/shortcuts' } from '../../actions/shortcuts'
import { closePopover } from '../../actions/popover' import {
openPopover,
closePopover,
} from '../../actions/popover'
import { POPOVER_SHARE } from '../../constants'
import PopoverLayout from './popover_layout' import PopoverLayout from './popover_layout'
import List from '../list' import List from '../list'
@ -27,6 +31,10 @@ class GroupOptionsPopover extends ImmutablePureComponent {
} }
} }
handleOnShare = () => {
this.props.onShare(this.props.group)
}
render() { render() {
const { const {
group, group,
@ -66,8 +74,16 @@ class GroupOptionsPopover extends ImmutablePureComponent {
to: `/groups/${groupId}/edit`, to: `/groups/${groupId}/edit`,
isHidden: !isAdmin, isHidden: !isAdmin,
}) })
listItems.push({})
} }
listItems.push({
hideArrow: true,
icon: 'share',
title: 'Share group',
onClick: this.handleOnShare,
})
listItems.push({})
listItems.push({ listItems.push({
hideArrow: true, hideArrow: true,
icon: 'star', icon: 'star',
@ -109,7 +125,7 @@ const mapStateToProps = (state, { group }) => {
return { isShortcut } return { isShortcut }
} }
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch, { innerRef }) => ({
onClosePopover: () => dispatch(closePopover()), onClosePopover: () => dispatch(closePopover()),
onAddShortcut(groupId) { onAddShortcut(groupId) {
dispatch(addShortcut('group', groupId)) dispatch(addShortcut('group', groupId))
@ -117,6 +133,13 @@ const mapDispatchToProps = (dispatch) => ({
onRemoveShortcut(groupId) { onRemoveShortcut(groupId) {
dispatch(removeShortcut(null, 'group', groupId)) dispatch(removeShortcut(null, 'group', groupId))
}, },
onShare(group) {
dispatch(openPopover(POPOVER_SHARE, {
innerRef,
group,
position: 'top',
}))
},
}) })
GroupOptionsPopover.defaultProps = { GroupOptionsPopover.defaultProps = {

View File

@ -18,7 +18,7 @@ import {
POPOVER_SIDEBAR_MORE, POPOVER_SIDEBAR_MORE,
POPOVER_STATUS_OPTIONS, POPOVER_STATUS_OPTIONS,
POPOVER_STATUS_EXPIRATION_OPTIONS, POPOVER_STATUS_EXPIRATION_OPTIONS,
POPOVER_STATUS_SHARE, POPOVER_SHARE,
POPOVER_STATUS_VISIBILITY, POPOVER_STATUS_VISIBILITY,
POPOVER_TIMELINE_INJECTION_OPTIONS, POPOVER_TIMELINE_INJECTION_OPTIONS,
POPOVER_USER_INFO, POPOVER_USER_INFO,
@ -43,7 +43,7 @@ import {
SidebarMorePopover, SidebarMorePopover,
StatusExpirationOptionsPopover, StatusExpirationOptionsPopover,
StatusOptionsPopover, StatusOptionsPopover,
StatusSharePopover, SharePopover,
StatusVisibilityPopover, StatusVisibilityPopover,
TimelineInjectionOptionsPopover, TimelineInjectionOptionsPopover,
UserInfoPopover, UserInfoPopover,
@ -82,7 +82,7 @@ const POPOVER_COMPONENTS = {
[POPOVER_SIDEBAR_MORE]: SidebarMorePopover, [POPOVER_SIDEBAR_MORE]: SidebarMorePopover,
[POPOVER_STATUS_OPTIONS]: StatusOptionsPopover, [POPOVER_STATUS_OPTIONS]: StatusOptionsPopover,
[POPOVER_STATUS_EXPIRATION_OPTIONS]: StatusExpirationOptionsPopover, [POPOVER_STATUS_EXPIRATION_OPTIONS]: StatusExpirationOptionsPopover,
[POPOVER_STATUS_SHARE]: StatusSharePopover, [POPOVER_SHARE]: SharePopover,
[POPOVER_STATUS_VISIBILITY]: StatusVisibilityPopover, [POPOVER_STATUS_VISIBILITY]: StatusVisibilityPopover,
[POPOVER_TIMELINE_INJECTION_OPTIONS]: TimelineInjectionOptionsPopover, [POPOVER_TIMELINE_INJECTION_OPTIONS]: TimelineInjectionOptionsPopover,
[POPOVER_USER_INFO]: UserInfoPopover, [POPOVER_USER_INFO]: UserInfoPopover,
@ -135,6 +135,10 @@ class PopoverRoot extends React.PureComponent {
return <ErrorPopover isXS={isXS} onClose={this.props.onClose} /> return <ErrorPopover isXS={isXS} onClose={this.props.onClose} />
} }
setRef = () => {
// : todo : ?
}
render() { render() {
const { type, props, onClose } = this.props const { type, props, onClose } = this.props
const { width } = this.state const { width } = this.state

View File

@ -17,7 +17,11 @@ import {
} from '../../actions/shortcuts' } from '../../actions/shortcuts'
import { initReport } from '../../actions/reports' import { initReport } from '../../actions/reports'
import { openModal } from '../../actions/modal' import { openModal } from '../../actions/modal'
import { closePopover } from '../../actions/popover' import {
openPopover,
closePopover,
} from '../../actions/popover'
import { POPOVER_SHARE } from '../../constants'
import { unfollowModal, me, isStaff } from '../../initial_state' import { unfollowModal, me, isStaff } from '../../initial_state'
import { makeGetAccount } from '../../selectors' import { makeGetAccount } from '../../selectors'
import PopoverLayout from './popover_layout' import PopoverLayout from './popover_layout'
@ -37,14 +41,12 @@ class ProfileOptionsPopover extends React.PureComponent {
if (!account) return menu if (!account) return menu
if (account.get('id') === me) return menu if (account.get('id') === me) return menu
if ('share' in navigator) {
menu.push({ menu.push({
hideArrow: true, hideArrow: true,
icon: 'share', icon: 'share',
title: intl.formatMessage(messages.share, { name: account.get('username') }), title: intl.formatMessage(messages.share, { name: account.get('username') }),
onClick: this.handleShare onClick: this.handleShare
}); });
}
menu.push({ menu.push({
hideArrow: true, hideArrow: true,
@ -119,7 +121,7 @@ class ProfileOptionsPopover extends React.PureComponent {
} }
handleShare = () => { handleShare = () => {
// : todo : this.props.onShare(this.props.account)
} }
handleFollow = () => { handleFollow = () => {
@ -225,7 +227,7 @@ const mapStateToProps = (state, { account }) => {
} }
} }
const mapDispatchToProps = (dispatch, { intl }) => ({ const mapDispatchToProps = (dispatch, { intl, innerRef }) => ({
onFollow(account) { onFollow(account) {
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) { if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
if (unfollowModal) { if (unfollowModal) {
@ -291,6 +293,13 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
dispatch(closePopover()) dispatch(closePopover())
dispatch(removeShortcut(null, 'account', accountId)) dispatch(removeShortcut(null, 'account', accountId))
}, },
onShare(account) {
dispatch(openPopover(POPOVER_SHARE, {
innerRef,
account,
position: 'top',
}))
},
}) })
ProfileOptionsPopover.defaultProps = { ProfileOptionsPopover.defaultProps = {

View File

@ -3,20 +3,51 @@ import PropTypes from 'prop-types'
import ImmutablePropTypes from 'react-immutable-proptypes' import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component' import ImmutablePureComponent from 'react-immutable-pure-component'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { defineMessages, injectIntl } from 'react-intl'
import { openModal } from '../../actions/modal' import { openModal } from '../../actions/modal'
import { showToast } from '../../actions/toasts' import { showToast } from '../../actions/toasts'
import { closePopover } from '../../actions/popover' import { closePopover } from '../../actions/popover'
import { TOAST_TYPE_SUCCESS } from '../../constants'
import PopoverLayout from './popover_layout' import PopoverLayout from './popover_layout'
import Button from '../button' import Button from '../button'
import Heading from '../heading' import Heading from '../heading'
import Text from '../text' import Text from '../text'
import List from '../list' import List from '../list'
class StatusSharePopover extends ImmutablePureComponent { class SharePopover extends ImmutablePureComponent {
state = {
url: '',
type: '',
}
componentDidMount() {
this._setUrl()
}
componentDidUpdate() {
this._setUrl()
}
_setUrl = () => {
const { account, group, status } = this.props
let url, type
if (!!account) {
type = 'account'
url = account.get('url')
} else if (!!group) {
type = 'group'
url = group.get('url')
} else if (!!status) {
type = 'status'
url = status.get('url')
}
this.setState({ url, type })
}
handleCopy = () => { handleCopy = () => {
const url = this.props.status.get('url') const { url } = this.state
const textarea = document.createElement('textarea') const textarea = document.createElement('textarea')
textarea.textContent = url textarea.textContent = url
@ -41,13 +72,12 @@ class StatusSharePopover extends ImmutablePureComponent {
} }
render() { render() {
const { intl, status } = this.props const { url, type } = this.state
if (!status) return <div /> if (!url) return <div />
const encodedStatusUrl = encodeURIComponent(status.get('url')) const encodedUrl = encodeURIComponent(url)
const mailToHref = `mailto:?subject=Gab&body=${encodedStatusUrl}` const mailToHref = `mailto:?subject=Gab&body=${encodedUrl}`
const content = status.get('contentHtml')
const iconSize = '18px' const iconSize = '18px'
return ( return (
@ -56,7 +86,7 @@ class StatusSharePopover extends ImmutablePureComponent {
> >
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.jcCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.h53PX, _s.px15].join(' ')}> <div className={[_s.d, _s.flexRow, _s.aiCenter, _s.jcCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.h53PX, _s.px15].join(' ')}>
<Heading size='h3'> <Heading size='h3'>
Share Gab Share Gab {type}
</Heading> </Heading>
</div> </div>
<div className={[_s.d, _s.w100PC, _s.px15, _s.py15, _s.flexRow, _s.noScrollbar, _s.aiCenter, _s.overflowXScroll, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}> <div className={[_s.d, _s.w100PC, _s.px15, _s.py15, _s.flexRow, _s.noScrollbar, _s.aiCenter, _s.overflowXScroll, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
@ -67,7 +97,7 @@ class StatusSharePopover extends ImmutablePureComponent {
color='primary' color='primary'
backgroundColor='secondary' backgroundColor='secondary'
onClick={this.handleCopy} onClick={this.handleCopy}
title={intl.formatMessage(messages.copy)} title={`Copy this ${type}`}
className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10].join(' ')} className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10].join(' ')}
/> />
<Button <Button
@ -76,7 +106,7 @@ class StatusSharePopover extends ImmutablePureComponent {
iconClassName={_s.inheritFill} iconClassName={_s.inheritFill}
color='white' color='white'
backgroundColor='none' backgroundColor='none'
href={`sms:+&body=${encodedStatusUrl}`} href={`sms:+&body=${encodedUrl}`}
target='_blank' target='_blank'
title='Share via text message' title='Share via text message'
className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10, _s.bgSMS].join(' ')} className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10, _s.bgSMS].join(' ')}
@ -87,7 +117,7 @@ class StatusSharePopover extends ImmutablePureComponent {
iconClassName={_s.inheritFill} iconClassName={_s.inheritFill}
color='white' color='white'
backgroundColor='none' backgroundColor='none'
href={`https://www.facebook.com/sharer/sharer.php?u=${encodedStatusUrl}`} href={`https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`}
target='_blank' target='_blank'
title='Share on Facebook' title='Share on Facebook'
className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10, _s.bgFacebook].join(' ')} className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10, _s.bgFacebook].join(' ')}
@ -98,7 +128,7 @@ class StatusSharePopover extends ImmutablePureComponent {
iconClassName={_s.inheritFill} iconClassName={_s.inheritFill}
color='white' color='white'
backgroundColor='none' backgroundColor='none'
href={`https://twitter.com/intent/tweet?url=${encodedStatusUrl}`} href={`https://twitter.com/intent/tweet?url=${encodedUrl}`}
target='_blank' target='_blank'
title='Share on Twitter' title='Share on Twitter'
className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10, _s.bgTwitter].join(' ')} className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10, _s.bgTwitter].join(' ')}
@ -109,7 +139,7 @@ class StatusSharePopover extends ImmutablePureComponent {
iconClassName={_s.inheritFill} iconClassName={_s.inheritFill}
color='white' color='white'
backgroundColor='none' backgroundColor='none'
href={`https://telegram.me/share/?url=${encodedStatusUrl}`} href={`https://telegram.me/share/?url=${encodedUrl}`}
target='_blank' target='_blank'
title='Share on Telegram' title='Share on Telegram'
className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10, _s.bgTelegram].join(' ')} className={[_s.jcCenter, _s.aiCenter, _s.mr10, _s.px10, _s.bgTelegram].join(' ')}
@ -120,7 +150,7 @@ class StatusSharePopover extends ImmutablePureComponent {
iconClassName={_s.inheritFill} iconClassName={_s.inheritFill}
color='white' color='white'
backgroundColor='none' backgroundColor='none'
href={`http://www.reddit.com/submit?url=${encodedStatusUrl}&title=Gab`} href={`http://www.reddit.com/submit?url=${encodedUrl}&title=Gab`}
title='Share on Reddit' title='Share on Reddit'
target='_blank' target='_blank'
className={[_s.jcCenter, _s.aiCenter, _s.px10, _s.mr10, _s.bgReddit].join(' ')} className={[_s.jcCenter, _s.aiCenter, _s.px10, _s.mr10, _s.bgReddit].join(' ')}
@ -152,22 +182,20 @@ class StatusSharePopover extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
email: { id: 'status.email', defaultMessage: 'Email this gab' },
copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },
})
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
onClosePopover: () => dispatch(closePopover()), onClosePopover: () => dispatch(closePopover()),
onShowCopyToast() { onShowCopyToast() {
dispatch(showToast()) dispatch(showToast(TOAST_TYPE_SUCCESS, {
type: "SUCCESSFULLY_COPIED_TO_CLIPBOARD"
}))
}, },
}) })
StatusSharePopover.propTypes = { SharePopover.propTypes = {
intl: PropTypes.object.isRequired,
onClosePopover: PropTypes.func.isRequired, onClosePopover: PropTypes.func.isRequired,
status: ImmutablePropTypes.map.isRequired, account: ImmutablePropTypes.map,
group: ImmutablePropTypes.map,
status: ImmutablePropTypes.map,
} }
export default injectIntl(connect(null, mapDispatchToProps)(StatusSharePopover)) export default connect(null, mapDispatchToProps)(SharePopover)

View File

@ -45,7 +45,7 @@ import {
} from '../../actions/popover' } from '../../actions/popover'
import { import {
MODAL_PRO_UPGRADE, MODAL_PRO_UPGRADE,
POPOVER_STATUS_SHARE, POPOVER_SHARE,
} from '../../constants' } from '../../constants'
import PopoverLayout from './popover_layout' import PopoverLayout from './popover_layout'
import Button from '../button' import Button from '../button'
@ -529,7 +529,7 @@ const mapDispatchToProps = (dispatch) => ({
onOpenSharePopover(targetRef, status) { onOpenSharePopover(targetRef, status) {
dispatch(closePopover()) dispatch(closePopover())
dispatch(openPopover(POPOVER_STATUS_SHARE, { dispatch(openPopover(POPOVER_SHARE, {
targetRef, targetRef,
status, status,
position: 'top', position: 'top',

View File

@ -42,7 +42,7 @@ export const POPOVER_PROFILE_OPTIONS = 'PROFILE_OPTIONS'
export const POPOVER_SIDEBAR_MORE = 'SIDEBAR_MORE' export const POPOVER_SIDEBAR_MORE = 'SIDEBAR_MORE'
export const POPOVER_STATUS_OPTIONS = 'STATUS_OPTIONS' export const POPOVER_STATUS_OPTIONS = 'STATUS_OPTIONS'
export const POPOVER_STATUS_EXPIRATION_OPTIONS = 'STATUS_EXPIRATION_OPTIONS' export const POPOVER_STATUS_EXPIRATION_OPTIONS = 'STATUS_EXPIRATION_OPTIONS'
export const POPOVER_STATUS_SHARE = 'STATUS_SHARE' export const POPOVER_SHARE = 'POPOVER_SHARE'
export const POPOVER_STATUS_VISIBILITY = 'STATUS_VISIBILITY' export const POPOVER_STATUS_VISIBILITY = 'STATUS_VISIBILITY'
export const POPOVER_TIMELINE_INJECTION_OPTIONS = 'TIMELINE_INJECTION_OPTIONS' export const POPOVER_TIMELINE_INJECTION_OPTIONS = 'TIMELINE_INJECTION_OPTIONS'
export const POPOVER_USER_INFO = 'USER_INFO' export const POPOVER_USER_INFO = 'USER_INFO'

View File

@ -35,7 +35,7 @@ import {
MODAL_STATUS, MODAL_STATUS,
MODAL_PRO_UPGRADE, MODAL_PRO_UPGRADE,
POPOVER_COMMENT_SORTING_OPTIONS, POPOVER_COMMENT_SORTING_OPTIONS,
POPOVER_STATUS_SHARE, POPOVER_SHARE,
COMMENT_SORTING_TYPE_OLDEST, COMMENT_SORTING_TYPE_OLDEST,
COMMENT_SORTING_TYPE_NEWEST, COMMENT_SORTING_TYPE_NEWEST,
COMMENT_SORTING_TYPE_TOP, COMMENT_SORTING_TYPE_TOP,
@ -323,7 +323,7 @@ const mapDispatchToProps = (dispatch) => ({
} }
} }
dispatch(openPopover(POPOVER_STATUS_SHARE, { dispatch(openPopover(POPOVER_SHARE, {
targetRef, targetRef,
status, status,
position: 'top', position: 'top',

View File

@ -136,7 +136,7 @@ export function SignUpPanel() { return import(/* webpackChunkName: "components/s
export function StatusExpirationOptionsPopover() { return import(/* webpackChunkName: "components/status_expiration_options_popover" */'../../../components/popover/status_expiration_options_popover') } export function StatusExpirationOptionsPopover() { return import(/* webpackChunkName: "components/status_expiration_options_popover" */'../../../components/popover/status_expiration_options_popover') }
export function StatusLikes() { return import(/* webpackChunkName: "features/status_likes" */'../../status_likes') } export function StatusLikes() { return import(/* webpackChunkName: "features/status_likes" */'../../status_likes') }
export function StatusOptionsPopover() { return import(/* webpackChunkName: "components/status_options_popover" */'../../../components/popover/status_options_popover') } export function StatusOptionsPopover() { return import(/* webpackChunkName: "components/status_options_popover" */'../../../components/popover/status_options_popover') }
export function StatusSharePopover() { return import(/* webpackChunkName: "components/status_share_popover" */'../../../components/popover/status_share_popover') } export function SharePopover() { return import(/* webpackChunkName: "components/share_popover" */'../../../components/popover/share_popover') }
export function StatusPromotionPanel() { return import(/* webpackChunkName: "components/status_promotion_panel" */'../../../components/panel/status_promotion_panel') } export function StatusPromotionPanel() { return import(/* webpackChunkName: "components/status_promotion_panel" */'../../../components/panel/status_promotion_panel') }
export function StatusReposts() { return import(/* webpackChunkName: "features/status_reposts" */'../../status_reposts') } export function StatusReposts() { return import(/* webpackChunkName: "features/status_reposts" */'../../status_reposts') }
export function StatusModal() { return import(/* webpackChunkName: "modals/status_modal" */'../../../components/modal/status_modal') } export function StatusModal() { return import(/* webpackChunkName: "modals/status_modal" */'../../../components/modal/status_modal') }

View File

@ -45,7 +45,7 @@ class TagManager
case target.object_type case target.object_type
when :person when :person
"/#{target.username}" short_account_with_replies_url(target)
when :note, :comment, :activity when :note, :comment, :activity
short_account_status_url(target.account, target) short_account_status_url(target.account, target)
end end

View File

@ -5,7 +5,7 @@ class REST::GroupSerializer < ActiveModel::Serializer
attributes :id, :title, :description, :description_html, attributes :id, :title, :description, :description_html,
:cover_image_url, :is_archived, :member_count, :cover_image_url, :is_archived, :member_count,
:created_at, :is_private, :is_visible, :slug, :created_at, :is_private, :is_visible, :slug, :url,
:tags, :group_category, :password, :has_password :tags, :group_category, :password, :has_password
def id def id
@ -59,4 +59,9 @@ class REST::GroupSerializer < ActiveModel::Serializer
full_asset_url(object.cover_image.url) full_asset_url(object.cover_image.url)
end end
def url
group_show_page_url(object)
end
end end

View File

@ -408,6 +408,7 @@ Rails.application.routes.draw do
get '/(*any)', to: 'react#react', as: :web get '/(*any)', to: 'react#react', as: :web
get '/:username', to: 'react#account_show', username: username_regex, as: :short_account_with_replies get '/:username', to: 'react#account_show', username: username_regex, as: :short_account_with_replies
get '/groups/:groupId', to: 'react#group_show', as: :group_show_page
root 'react#react' root 'react#react'
get '/', to: 'react#react', as: :homepage get '/', to: 'react#react', as: :homepage