From c5b4e6b7084e8257979adec87f97d4800b7bec57 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 12 Jul 2021 17:00:14 +0200 Subject: Add modal stack to allow better boost modal and media modal interaction. --- .../flavours/glitch/features/ui/containers/modal_container.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/javascript/flavours/glitch/features/ui') diff --git a/app/javascript/flavours/glitch/features/ui/containers/modal_container.js b/app/javascript/flavours/glitch/features/ui/containers/modal_container.js index f074002e4..e13e745e6 100644 --- a/app/javascript/flavours/glitch/features/ui/containers/modal_container.js +++ b/app/javascript/flavours/glitch/features/ui/containers/modal_container.js @@ -3,8 +3,8 @@ import { closeModal } from 'flavours/glitch/actions/modal'; import ModalRoot from '../components/modal_root'; const mapStateToProps = state => ({ - type: state.get('modal').modalType, - props: state.get('modal').modalProps, + type: state.getIn(['modal', 0, 'modalType'], null), + props: state.getIn(['modal', 0, 'modalProps'], {}), }); const mapDispatchToProps = dispatch => ({ -- cgit From 6e3d5cbca26995e99d6ca8b1e3191edc539d87eb Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 12 Jul 2021 17:55:40 +0200 Subject: Fix and simplify browser history handling in relation to modals This simplifies the logic to: - when the last modal gets closed and we're in our history buffer state, go back - whenever a modal is open, ensure we're in a history buffer state by potentially pushing one --- .../flavours/glitch/components/modal_root.js | 34 ++++++++++++++-------- .../glitch/features/ui/components/modal_root.js | 8 ++--- 2 files changed, 24 insertions(+), 18 deletions(-) (limited to 'app/javascript/flavours/glitch/features/ui') diff --git a/app/javascript/flavours/glitch/components/modal_root.js b/app/javascript/flavours/glitch/components/modal_root.js index 913234d32..7b5a630e5 100644 --- a/app/javascript/flavours/glitch/components/modal_root.js +++ b/app/javascript/flavours/glitch/components/modal_root.js @@ -76,10 +76,13 @@ export default class ModalRoot extends React.PureComponent { this.activeElement = null; }).catch(console.error); - this.handleModalClose(); + this._handleModalClose(); } if (this.props.children && !prevProps.children) { - this.handleModalOpen(); + this._handleModalOpen(); + } + if (this.props.children) { + this._ensureHistoryBuffer(); } } @@ -88,22 +91,29 @@ export default class ModalRoot extends React.PureComponent { window.removeEventListener('keydown', this.handleKeyDown); } - handleModalClose () { + _handleModalOpen () { + this._modalHistoryKey = Date.now(); + this.unlistenHistory = this.history.listen((_, action) => { + if (action === 'POP') { + this.props.onClose(); + } + }); + } + + _handleModalClose () { this.unlistenHistory(); - const state = this.history.location.state; - if (state && state.mastodonModalOpen) { + const { state } = this.history.location; + if (state && state.mastodonModalKey === this._modalHistoryKey) { this.history.goBack(); } } - handleModalOpen () { - const history = this.history; - const state = {...history.location.state, mastodonModalOpen: true}; - history.push(history.location.pathname, state); - this.unlistenHistory = history.listen(() => { - this.props.onClose(); - }); + _ensureHistoryBuffer () { + const { pathname, state } = this.history.location; + if (!state || state.mastodonModalKey !== this._modalHistoryKey) { + this.history.push(pathname, { ...state, mastodonModalKey: this._modalHistoryKey }); + } } getSiblings = () => { diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js index 0fd70de34..2636e79f5 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js @@ -59,12 +59,8 @@ export default class ModalRoot extends React.PureComponent { backgroundColor: null, }; - getSnapshotBeforeUpdate () { - return { visible: !!this.props.type }; - } - - componentDidUpdate (prevProps, prevState, { visible }) { - if (visible) { + componentDidUpdate () { + if (!!this.props.type) { document.body.classList.add('with-modals--active'); document.documentElement.style.marginRight = `${getScrollbarWidth()}px`; } else { -- cgit From 84fbe4d030e3176fffaf49ac8eec0c0602b1ba87 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 13 Jul 2021 12:40:15 +0200 Subject: Refactor shouldUpdateScroll stuff --- .../flavours/glitch/components/scrollable_list.js | 11 +++-------- app/javascript/flavours/glitch/components/status_list.js | 1 - .../flavours/glitch/containers/scroll_container.js | 15 +++++++++++++++ .../flavours/glitch/features/account_gallery/index.js | 8 ++------ .../flavours/glitch/features/directory/index.js | 7 +++---- .../flavours/glitch/features/notifications/index.js | 4 +--- app/javascript/flavours/glitch/features/status/index.js | 8 ++------ app/javascript/flavours/glitch/features/ui/index.js | 2 +- 8 files changed, 27 insertions(+), 29 deletions(-) create mode 100644 app/javascript/flavours/glitch/containers/scroll_container.js (limited to 'app/javascript/flavours/glitch/features/ui') diff --git a/app/javascript/flavours/glitch/components/scrollable_list.js b/app/javascript/flavours/glitch/components/scrollable_list.js index 5d0a06561..16f13afa4 100644 --- a/app/javascript/flavours/glitch/components/scrollable_list.js +++ b/app/javascript/flavours/glitch/components/scrollable_list.js @@ -1,5 +1,5 @@ import React, { PureComponent } from 'react'; -import { ScrollContainer } from 'react-router-scroll-4'; +import ScrollContainer from 'flavours/glitch/containers/scroll_container'; import PropTypes from 'prop-types'; import IntersectionObserverArticleContainer from 'flavours/glitch/containers/intersection_observer_article_container'; import LoadMore from './load_more'; @@ -34,7 +34,6 @@ class ScrollableList extends PureComponent { onScrollToTop: PropTypes.func, onScroll: PropTypes.func, trackScroll: PropTypes.bool, - shouldUpdateScroll: PropTypes.func, isLoading: PropTypes.bool, showLoading: PropTypes.bool, hasMore: PropTypes.bool, @@ -264,10 +263,6 @@ class ScrollableList extends PureComponent { this.props.onLoadMore(); } - defaultShouldUpdateScroll = (prevRouterProps, { location }) => { - return !(prevRouterProps?.location?.state?.mastodonModalKey || location.state?.mastodonModalKey); - } - handleLoadPending = e => { e.preventDefault(); this.props.onLoadPending(); @@ -281,7 +276,7 @@ class ScrollableList extends PureComponent { } render () { - const { children, scrollKey, trackScroll, shouldUpdateScroll, showLoading, isLoading, hasMore, numPending, prepend, alwaysPrepend, append, emptyMessage, onLoadMore } = this.props; + const { children, scrollKey, trackScroll, showLoading, isLoading, hasMore, numPending, prepend, alwaysPrepend, append, emptyMessage, onLoadMore } = this.props; const { fullscreen } = this.state; const childrenCount = React.Children.count(children); @@ -347,7 +342,7 @@ class ScrollableList extends PureComponent { if (trackScroll) { return ( - + {scrollableArea} ); diff --git a/app/javascript/flavours/glitch/components/status_list.js b/app/javascript/flavours/glitch/components/status_list.js index 60cc23f4b..9095e087e 100644 --- a/app/javascript/flavours/glitch/components/status_list.js +++ b/app/javascript/flavours/glitch/components/status_list.js @@ -18,7 +18,6 @@ export default class StatusList extends ImmutablePureComponent { onScrollToTop: PropTypes.func, onScroll: PropTypes.func, trackScroll: PropTypes.bool, - shouldUpdateScroll: PropTypes.func, isLoading: PropTypes.bool, isPartial: PropTypes.bool, hasMore: PropTypes.bool, diff --git a/app/javascript/flavours/glitch/containers/scroll_container.js b/app/javascript/flavours/glitch/containers/scroll_container.js new file mode 100644 index 000000000..595f3155f --- /dev/null +++ b/app/javascript/flavours/glitch/containers/scroll_container.js @@ -0,0 +1,15 @@ +import { ScrollContainer as OriginalScrollContainer } from 'react-router-scroll-4'; + +// ScrollContainer is used to automatically scroll to the top when pushing a +// new history state and remembering the scroll position when going back. +// There are a few things we need to do differently, though. +const defaultShouldUpdateScroll = (prevRouterProps, { location }) => { + return !(prevRouterProps?.location?.state?.mastodonModalKey || location.state?.mastodonModalKey); +} + +export default +class ScrollContainer extends OriginalScrollContainer { + static defaultProps = { + shouldUpdateScroll: defaultShouldUpdateScroll, + }; +} diff --git a/app/javascript/flavours/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js index 83d623356..434a47dfc 100644 --- a/app/javascript/flavours/glitch/features/account_gallery/index.js +++ b/app/javascript/flavours/glitch/features/account_gallery/index.js @@ -11,7 +11,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import { getAccountGallery } from 'flavours/glitch/selectors'; import MediaItem from './components/media_item'; import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container'; -import { ScrollContainer } from 'react-router-scroll-4'; +import ScrollContainer from 'flavours/glitch/containers/scroll_container'; import LoadMore from 'flavours/glitch/components/load_more'; import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import { openModal } from 'flavours/glitch/actions/modal'; @@ -104,10 +104,6 @@ class AccountGallery extends ImmutablePureComponent { this.handleScrollToBottom(); } - shouldUpdateScroll = (prevRouterProps, { location }) => { - return !(prevRouterProps?.location?.state?.mastodonModalKey || location.state?.mastodonModalKey); - } - setColumnRef = c => { this.column = c; } @@ -164,7 +160,7 @@ class AccountGallery extends ImmutablePureComponent { - +
diff --git a/app/javascript/flavours/glitch/features/directory/index.js b/app/javascript/flavours/glitch/features/directory/index.js index 858a8fa55..cde5926e0 100644 --- a/app/javascript/flavours/glitch/features/directory/index.js +++ b/app/javascript/flavours/glitch/features/directory/index.js @@ -12,7 +12,7 @@ import AccountCard from './components/account_card'; import RadioButton from 'flavours/glitch/components/radio_button'; import classNames from 'classnames'; import LoadMore from 'flavours/glitch/components/load_more'; -import { ScrollContainer } from 'react-router-scroll-4'; +import ScrollContainer from 'flavours/glitch/containers/scroll_container'; const messages = defineMessages({ title: { id: 'column.directory', defaultMessage: 'Browse profiles' }, @@ -40,7 +40,6 @@ class Directory extends React.PureComponent { isLoading: PropTypes.bool, accountIds: ImmutablePropTypes.list.isRequired, dispatch: PropTypes.func.isRequired, - shouldUpdateScroll: PropTypes.func, columnId: PropTypes.string, intl: PropTypes.object.isRequired, multiColumn: PropTypes.bool, @@ -125,7 +124,7 @@ class Directory extends React.PureComponent { } render () { - const { isLoading, accountIds, intl, columnId, multiColumn, domain, shouldUpdateScroll } = this.props; + const { isLoading, accountIds, intl, columnId, multiColumn, domain } = this.props; const { order, local } = this.getParams(this.props, this.state); const pinned = !!columnId; @@ -163,7 +162,7 @@ class Directory extends React.PureComponent { multiColumn={multiColumn} /> - {multiColumn && !pinned ? {scrollableArea} : scrollableArea} + {multiColumn && !pinned ? {scrollableArea} : scrollableArea} ); } diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js index 6fc951e37..075e729b1 100644 --- a/app/javascript/flavours/glitch/features/notifications/index.js +++ b/app/javascript/flavours/glitch/features/notifications/index.js @@ -99,7 +99,6 @@ class Notifications extends React.PureComponent { notifications: ImmutablePropTypes.list.isRequired, showFilterBar: PropTypes.bool.isRequired, dispatch: PropTypes.func.isRequired, - shouldUpdateScroll: PropTypes.func, intl: PropTypes.object.isRequired, isLoading: PropTypes.bool, isUnread: PropTypes.bool, @@ -220,7 +219,7 @@ class Notifications extends React.PureComponent { } render () { - const { intl, notifications, shouldUpdateScroll, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, showFilterBar, lastReadId, canMarkAsRead, needsNotificationPermission } = this.props; + const { intl, notifications, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, showFilterBar, lastReadId, canMarkAsRead, needsNotificationPermission } = this.props; const { notifCleaning, notifCleaningActive } = this.props; const { animatingNCD } = this.state; const pinned = !!columnId; @@ -273,7 +272,6 @@ class Notifications extends React.PureComponent { onLoadPending={this.handleLoadPending} onScrollToTop={this.handleScrollToTop} onScroll={this.handleScroll} - shouldUpdateScroll={shouldUpdateScroll} bindToDocument={!multiColumn} > {scrollableContent} diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index 230966f2a..9dbba4772 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -32,7 +32,7 @@ import { initBlockModal } from 'flavours/glitch/actions/blocks'; import { initReport } from 'flavours/glitch/actions/reports'; import { initBoostModal } from 'flavours/glitch/actions/boosts'; import { makeGetStatus } from 'flavours/glitch/selectors'; -import { ScrollContainer } from 'react-router-scroll-4'; +import ScrollContainer from 'flavours/glitch/containers/scroll_container'; import ColumnBackButton from 'flavours/glitch/components/column_back_button'; import ColumnHeader from '../../components/column_header'; import StatusContainer from 'flavours/glitch/containers/status_container'; @@ -507,10 +507,6 @@ class Status extends ImmutablePureComponent { this.setState({ fullscreen: isFullscreen() }); } - shouldUpdateScroll = (prevRouterProps, { location }) => { - return !(prevRouterProps?.location?.state?.mastodonModalKey || location.state?.mastodonModalKey); - } - render () { let ancestors, descendants; const { setExpansion } = this; @@ -561,7 +557,7 @@ class Status extends ImmutablePureComponent { )} /> - +
{ancestors} diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 1149eb14e..ad063f01b 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -212,7 +212,7 @@ class SwitchingColumnsArea extends React.PureComponent { - + -- cgit From 34a573ac27fe9d5fb324d8910759cd2233911646 Mon Sep 17 00:00:00 2001 From: Claire Date: Sun, 25 Jul 2021 01:14:43 +0200 Subject: [Glitch] Add confirmation modal when closing media edit modal with unsaved changes Port a8a7066e977cb0aa1988d340ef8b7c542f179b14 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/actions/compose.js | 32 ++++++ .../compose/containers/upload_container.js | 5 +- .../features/ui/components/focal_point_modal.js | 108 +++++++++------------ .../glitch/features/ui/components/modal_root.js | 23 ++++- .../features/ui/containers/modal_container.js | 16 ++- app/javascript/flavours/glitch/reducers/compose.js | 24 +++++ app/javascript/flavours/glitch/reducers/modal.js | 3 + 7 files changed, 142 insertions(+), 69 deletions(-) (limited to 'app/javascript/flavours/glitch/features/ui') diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index f83738093..eebe98626 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -10,6 +10,7 @@ import { importFetchedAccounts } from './importer'; import { updateTimeline } from './timelines'; import { showAlertForError } from './alerts'; import { showAlert } from './alerts'; +import { openModal } from './modal'; import { defineMessages } from 'react-intl'; let cancelFetchComposeSuggestionsAccounts, cancelFetchComposeSuggestionsTags; @@ -68,6 +69,11 @@ export const COMPOSE_POLL_OPTION_CHANGE = 'COMPOSE_POLL_OPTION_CHANGE'; export const COMPOSE_POLL_OPTION_REMOVE = 'COMPOSE_POLL_OPTION_REMOVE'; export const COMPOSE_POLL_SETTINGS_CHANGE = 'COMPOSE_POLL_SETTINGS_CHANGE'; +export const INIT_MEDIA_EDIT_MODAL = 'INIT_MEDIA_EDIT_MODAL'; + +export const COMPOSE_CHANGE_MEDIA_DESCRIPTION = 'COMPOSE_CHANGE_MEDIA_DESCRIPTION'; +export const COMPOSE_CHANGE_MEDIA_FOCUS = 'COMPOSE_CHANGE_MEDIA_FOCUS'; + const messages = defineMessages({ uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' }, uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' }, @@ -339,6 +345,32 @@ export const uploadThumbnailFail = error => ({ skipLoading: true, }); +export function initMediaEditModal(id) { + return dispatch => { + dispatch({ + type: INIT_MEDIA_EDIT_MODAL, + id, + }); + + dispatch(openModal('FOCAL_POINT', { id })); + }; +}; + +export function onChangeMediaDescription(description) { + return { + type: COMPOSE_CHANGE_MEDIA_DESCRIPTION, + description, + }; +}; + +export function onChangeMediaFocus(focusX, focusY) { + return { + type: COMPOSE_CHANGE_MEDIA_FOCUS, + focusX, + focusY, + }; +}; + export function changeUploadCompose(id, params) { return (dispatch, getState) => { dispatch(changeUploadComposeRequest()); diff --git a/app/javascript/flavours/glitch/features/compose/containers/upload_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_container.js index f687fae99..f3ca4ce7b 100644 --- a/app/javascript/flavours/glitch/features/compose/containers/upload_container.js +++ b/app/javascript/flavours/glitch/features/compose/containers/upload_container.js @@ -1,7 +1,6 @@ import { connect } from 'react-redux'; import Upload from '../components/upload'; -import { undoUploadCompose } from 'flavours/glitch/actions/compose'; -import { openModal } from 'flavours/glitch/actions/modal'; +import { undoUploadCompose, initMediaEditModal } from 'flavours/glitch/actions/compose'; import { submitCompose } from 'flavours/glitch/actions/compose'; const mapStateToProps = (state, { id }) => ({ @@ -15,7 +14,7 @@ const mapDispatchToProps = dispatch => ({ }, onOpenFocalPoint: id => { - dispatch(openModal('FOCAL_POINT', { id })); + dispatch(initMediaEditModal(id)); }, onSubmit (router) { diff --git a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js index b7ec63333..5a4baa5a1 100644 --- a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; import classNames from 'classnames'; -import { changeUploadCompose, uploadThumbnail } from 'flavours/glitch/actions/compose'; +import { changeUploadCompose, uploadThumbnail, onChangeMediaDescription, onChangeMediaFocus } from 'flavours/glitch/actions/compose'; import { getPointerPosition } from 'flavours/glitch/features/video'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import IconButton from 'flavours/glitch/components/icon_button'; @@ -27,14 +27,22 @@ import { assetHost } from 'flavours/glitch/util/config'; const messages = defineMessages({ close: { id: 'lightbox.close', defaultMessage: 'Close' }, apply: { id: 'upload_modal.apply', defaultMessage: 'Apply' }, + applying: { id: 'upload_modal.applying', defaultMessage: 'Applying…' }, placeholder: { id: 'upload_modal.description_placeholder', defaultMessage: 'A quick brown fox jumps over the lazy dog' }, chooseImage: { id: 'upload_modal.choose_image', defaultMessage: 'Choose image' }, + discardMessage: { id: 'confirmations.discard_edit_media.message', defaultMessage: 'You have unsaved changes to the media description or preview, discard them anyway?' }, + discardConfirm: { id: 'confirmations.discard_edit_media.confirm', defaultMessage: 'Discard' }, }); const mapStateToProps = (state, { id }) => ({ media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id), account: state.getIn(['accounts', me]), isUploadingThumbnail: state.getIn(['compose', 'isUploadingThumbnail']), + description: state.getIn(['compose', 'media_modal', 'description']), + focusX: state.getIn(['compose', 'media_modal', 'focusX']), + focusY: state.getIn(['compose', 'media_modal', 'focusY']), + dirty: state.getIn(['compose', 'media_modal', 'dirty']), + is_changing_upload: state.getIn(['compose', 'is_changing_upload']), }); const mapDispatchToProps = (dispatch, { id }) => ({ @@ -43,6 +51,14 @@ const mapDispatchToProps = (dispatch, { id }) => ({ dispatch(changeUploadCompose(id, { description, focus: `${x.toFixed(2)},${y.toFixed(2)}` })); }, + onChangeDescription: (description) => { + dispatch(onChangeMediaDescription(description)); + }, + + onChangeFocus: (focusX, focusY) => { + dispatch(onChangeMediaFocus(focusX, focusY)); + }, + onSelectThumbnail: files => { dispatch(uploadThumbnail(id, files[0])); }, @@ -83,8 +99,8 @@ class ImageLoader extends React.PureComponent { } -export default @connect(mapStateToProps, mapDispatchToProps) -@injectIntl +export default @connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true }) +@(component => injectIntl(component, { withRef: true })) class FocalPointModal extends ImmutablePureComponent { static propTypes = { @@ -92,34 +108,21 @@ class FocalPointModal extends ImmutablePureComponent { account: ImmutablePropTypes.map.isRequired, isUploadingThumbnail: PropTypes.bool, onSave: PropTypes.func.isRequired, + onChangeDescription: PropTypes.func.isRequired, + onChangeFocus: PropTypes.func.isRequired, onSelectThumbnail: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, }; state = { - x: 0, - y: 0, - focusX: 0, - focusY: 0, dragging: false, - description: '', dirty: false, progress: 0, loading: true, ocrStatus: '', }; - componentWillMount () { - this.updatePositionFromMedia(this.props.media); - } - - componentWillReceiveProps (nextProps) { - if (this.props.media.get('id') !== nextProps.media.get('id')) { - this.updatePositionFromMedia(nextProps.media); - } - } - componentWillUnmount () { document.removeEventListener('mousemove', this.handleMouseMove); document.removeEventListener('mouseup', this.handleMouseUp); @@ -164,54 +167,37 @@ class FocalPointModal extends ImmutablePureComponent { const focusX = (x - .5) * 2; const focusY = (y - .5) * -2; - this.setState({ x, y, focusX, focusY, dirty: true }); - } - - updatePositionFromMedia = media => { - const focusX = media.getIn(['meta', 'focus', 'x']); - const focusY = media.getIn(['meta', 'focus', 'y']); - const description = media.get('description') || ''; - - if (focusX && focusY) { - const x = (focusX / 2) + .5; - const y = (focusY / -2) + .5; - - this.setState({ - x, - y, - focusX, - focusY, - description, - dirty: false, - }); - } else { - this.setState({ - x: 0.5, - y: 0.5, - focusX: 0, - focusY: 0, - description, - dirty: false, - }); - } + this.props.onChangeFocus(focusX, focusY); } handleChange = e => { - this.setState({ description: e.target.value, dirty: true }); + this.props.onChangeDescription(e.target.value); } handleKeyDown = (e) => { if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { e.preventDefault(); e.stopPropagation(); - this.setState({ description: e.target.value, dirty: true }); + this.props.onChangeDescription(e.target.value); this.handleSubmit(); } } handleSubmit = () => { - this.props.onSave(this.state.description, this.state.focusX, this.state.focusY); - this.props.onClose(); + this.props.onSave(this.props.description, this.props.focusX, this.props.focusY); + } + + getCloseConfirmationMessage = () => { + const { intl, dirty } = this.props; + + if (dirty) { + return { + message: intl.formatMessage(messages.discardMessage), + confirm: intl.formatMessage(messages.discardConfirm), + }; + } else { + return null; + } } setRef = c => { @@ -257,7 +243,8 @@ class FocalPointModal extends ImmutablePureComponent { await worker.loadLanguage('eng'); await worker.initialize('eng'); const { data: { text } } = await worker.recognize(media_url); - this.setState({ description: removeExtraLineBreaks(text), dirty: true, detecting: false }); + this.setState({ detecting: false }); + this.props.onChangeDescription(removeExtraLineBreaks(text)); await worker.terminate(); })().catch((e) => { if (refreshCache) { @@ -274,7 +261,6 @@ class FocalPointModal extends ImmutablePureComponent { handleThumbnailChange = e => { if (e.target.files.length > 0) { - this.setState({ dirty: true }); this.props.onSelectThumbnail(e.target.files); } } @@ -288,8 +274,10 @@ class FocalPointModal extends ImmutablePureComponent { } render () { - const { media, intl, account, onClose, isUploadingThumbnail } = this.props; - const { x, y, dragging, description, dirty, detecting, progress, ocrStatus } = this.state; + const { media, intl, account, onClose, isUploadingThumbnail, description, focusX, focusY, dirty, is_changing_upload } = this.props; + const { dragging, detecting, progress, ocrStatus } = this.state; + const x = (focusX / 2) + .5; + const y = (focusY / -2) + .5; const width = media.getIn(['meta', 'original', 'width']) || null; const height = media.getIn(['meta', 'original', 'height']) || null; @@ -344,7 +332,7 @@ class FocalPointModal extends ImmutablePureComponent { accept='image/png,image/jpeg' onChange={this.handleThumbnailChange} style={{ display: 'none' }} - disabled={isUploadingThumbnail} + disabled={isUploadingThumbnail || is_changing_upload} /> @@ -363,7 +351,7 @@ class FocalPointModal extends ImmutablePureComponent { value={detecting ? '…' : description} onChange={this.handleChange} onKeyDown={this.handleKeyDown} - disabled={detecting} + disabled={detecting || is_changing_upload} autoFocus /> @@ -373,11 +361,11 @@ class FocalPointModal extends ImmutablePureComponent {
- +
-
diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js index 2636e79f5..62bb167a0 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js @@ -83,16 +83,33 @@ export default class ModalRoot extends React.PureComponent { return ; } + handleClose = () => { + const { onClose } = this.props; + let message = null; + try { + message = this._modal?.getWrappedInstance?.().getCloseConfirmationMessage?.(); + } catch (_) { + // injectIntl defines `getWrappedInstance` but errors out if `withRef` + // isn't set. + // This would be much smoother with react-intl 3+ and `forwardRef`. + } + onClose(message); + } + + setModalRef = (c) => { + this._modal = c; + } + render () { - const { type, props, onClose } = this.props; + const { type, props } = this.props; const { backgroundColor } = this.state; const visible = !!type; return ( - + {visible && ( - {(SpecificComponent) => } + {(SpecificComponent) => } )} diff --git a/app/javascript/flavours/glitch/features/ui/containers/modal_container.js b/app/javascript/flavours/glitch/features/ui/containers/modal_container.js index e13e745e6..039aabd8a 100644 --- a/app/javascript/flavours/glitch/features/ui/containers/modal_container.js +++ b/app/javascript/flavours/glitch/features/ui/containers/modal_container.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { closeModal } from 'flavours/glitch/actions/modal'; +import { openModal, closeModal } from 'flavours/glitch/actions/modal'; import ModalRoot from '../components/modal_root'; const mapStateToProps = state => ({ @@ -8,8 +8,18 @@ const mapStateToProps = state => ({ }); const mapDispatchToProps = dispatch => ({ - onClose () { - dispatch(closeModal()); + onClose (confirmationMessage) { + if (confirmationMessage) { + dispatch( + openModal('CONFIRM', { + message: confirmationMessage.message, + confirm: confirmationMessage.confirm, + onConfirm: () => dispatch(closeModal()), + }), + ); + } else { + dispatch(closeModal()); + } }, }); diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js index e989401d8..1735cfb4d 100644 --- a/app/javascript/flavours/glitch/reducers/compose.js +++ b/app/javascript/flavours/glitch/reducers/compose.js @@ -42,6 +42,9 @@ import { COMPOSE_POLL_OPTION_CHANGE, COMPOSE_POLL_OPTION_REMOVE, COMPOSE_POLL_SETTINGS_CHANGE, + INIT_MEDIA_EDIT_MODAL, + COMPOSE_CHANGE_MEDIA_DESCRIPTION, + COMPOSE_CHANGE_MEDIA_FOCUS, } from 'flavours/glitch/actions/compose'; import { TIMELINE_DELETE } from 'flavours/glitch/actions/timelines'; import { STORE_HYDRATE } from 'flavours/glitch/actions/store'; @@ -97,6 +100,13 @@ const initialState = ImmutableMap({ resetFileKey: Math.floor((Math.random() * 0x10000)), idempotencyKey: null, tagHistory: ImmutableList(), + media_modal: ImmutableMap({ + id: null, + description: '', + focusX: 0, + focusY: 0, + dirty: false, + }), doodle: ImmutableMap({ fg: 'rgb( 0, 0, 0)', bg: 'rgb(255, 255, 255)', @@ -455,6 +465,19 @@ export default function compose(state = initialState, action) { return item; })); + case INIT_MEDIA_EDIT_MODAL: + const media = state.get('media_attachments').find(item => item.get('id') === action.id); + return state.set('media_modal', ImmutableMap({ + id: action.id, + description: media.get('description') || '', + focusX: media.getIn(['meta', 'focus', 'x'], 0), + focusY: media.getIn(['meta', 'focus', 'y'], 0), + dirty: false, + })); + case COMPOSE_CHANGE_MEDIA_DESCRIPTION: + return state.setIn(['media_modal', 'description'], action.description).setIn(['media_modal', 'dirty'], true); + case COMPOSE_CHANGE_MEDIA_FOCUS: + return state.setIn(['media_modal', 'focusX'], action.focusX).setIn(['media_modal', 'focusY'], action.focusY).setIn(['media_modal', 'dirty'], true); case COMPOSE_MENTION: return state.withMutations(map => { map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' ')); @@ -491,6 +514,7 @@ export default function compose(state = initialState, action) { case COMPOSE_UPLOAD_CHANGE_SUCCESS: return state .set('is_changing_upload', false) + .setIn(['media_modal', 'dirty'], false) .update('media_attachments', list => list.map(item => { if (item.get('id') === action.media.id) { return fromJS(action.media); diff --git a/app/javascript/flavours/glitch/reducers/modal.js b/app/javascript/flavours/glitch/reducers/modal.js index f8fdc2995..ae205c6d5 100644 --- a/app/javascript/flavours/glitch/reducers/modal.js +++ b/app/javascript/flavours/glitch/reducers/modal.js @@ -1,5 +1,6 @@ import { MODAL_OPEN, MODAL_CLOSE } from 'flavours/glitch/actions/modal'; import { TIMELINE_DELETE } from 'flavours/glitch/actions/timelines'; +import { COMPOSE_UPLOAD_CHANGE_SUCCESS } from 'flavours/glitch/actions/compose'; import { Stack as ImmutableStack, Map as ImmutableMap } from 'immutable'; export default function modal(state = ImmutableStack(), action) { @@ -8,6 +9,8 @@ export default function modal(state = ImmutableStack(), action) { return state.unshift(ImmutableMap({ modalType: action.modalType, modalProps: action.modalProps })); case MODAL_CLOSE: return (action.modalType === undefined || action.modalType === state.getIn([0, 'modalType'])) ? state.shift() : state; + case COMPOSE_UPLOAD_CHANGE_SUCCESS: + return state.getIn([0, 'modalType']) === 'FOCAL_POINT' ? state.shift() : state; case TIMELINE_DELETE: return state.filterNot((modal) => modal.get('modalProps').statusId === action.id); default: -- cgit From 8681ef85d0728b9d34dc62785fab6fcec30ba95c Mon Sep 17 00:00:00 2001 From: Takeshi Umeda Date: Fri, 6 Aug 2021 19:14:13 +0900 Subject: [Glitch] Fix logout link not working in safari Port b2875b1864d5bd72e6902ffc842d1be6818c210e to glitch-soc Signed-off-by: Claire --- .../glitch/features/compose/containers/header_container.js | 1 + .../flavours/glitch/features/ui/components/confirmation_modal.js | 9 ++++++++- .../flavours/glitch/features/ui/components/link_footer.js | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch/features/ui') diff --git a/app/javascript/flavours/glitch/features/compose/containers/header_container.js b/app/javascript/flavours/glitch/features/compose/containers/header_container.js index b4dcb4d56..2f0da48c8 100644 --- a/app/javascript/flavours/glitch/features/compose/containers/header_container.js +++ b/app/javascript/flavours/glitch/features/compose/containers/header_container.js @@ -27,6 +27,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ dispatch(openModal('CONFIRM', { message: intl.formatMessage(messages.logoutMessage), confirm: intl.formatMessage(messages.logoutConfirm), + closeWhenConfirm: false, onConfirm: () => logOut(), })); }, diff --git a/app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js b/app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js index 47a49c0c7..a665b9fb1 100644 --- a/app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js @@ -13,16 +13,23 @@ class ConfirmationModal extends React.PureComponent { onConfirm: PropTypes.func.isRequired, secondary: PropTypes.string, onSecondary: PropTypes.func, + closeWhenConfirm: PropTypes.bool, onDoNotAsk: PropTypes.func, intl: PropTypes.object.isRequired, }; + static defaultProps = { + closeWhenConfirm: true, + }; + componentDidMount() { this.button.focus(); } handleClick = () => { - this.props.onClose(); + if (this.props.closeWhenConfirm) { + this.props.onClose(); + } this.props.onConfirm(); if (this.props.onDoNotAsk && this.doNotAskCheckbox.checked) { this.props.onDoNotAsk(); diff --git a/app/javascript/flavours/glitch/features/ui/components/link_footer.js b/app/javascript/flavours/glitch/features/ui/components/link_footer.js index 40ef506cc..722b47140 100644 --- a/app/javascript/flavours/glitch/features/ui/components/link_footer.js +++ b/app/javascript/flavours/glitch/features/ui/components/link_footer.js @@ -18,6 +18,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ dispatch(openModal('CONFIRM', { message: intl.formatMessage(messages.logoutMessage), confirm: intl.formatMessage(messages.logoutConfirm), + closeWhenConfirm: false, onConfirm: () => logOut(), })); }, -- cgit From 4a94f4127b57176f73e7de136137aa7efe9a0140 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 8 Sep 2021 13:47:48 +0200 Subject: Fix glitch-soc front-end not linking to the provided SOURCE_URL --- .../flavours/glitch/components/error_boundary.js | 8 +++++++- .../flavours/glitch/features/ui/components/link_footer.js | 4 ++-- .../glitch/features/ui/components/onboarding_modal.js | 15 +++++++++++++-- app/javascript/flavours/glitch/util/initial_state.js | 2 ++ 4 files changed, 24 insertions(+), 5 deletions(-) (limited to 'app/javascript/flavours/glitch/features/ui') diff --git a/app/javascript/flavours/glitch/components/error_boundary.js b/app/javascript/flavours/glitch/components/error_boundary.js index 8e6cd1461..4537bde1d 100644 --- a/app/javascript/flavours/glitch/components/error_boundary.js +++ b/app/javascript/flavours/glitch/components/error_boundary.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; +import { source_url } from 'flavours/glitch/util/initial_state'; import { preferencesLink } from 'flavours/glitch/util/backend_links'; import StackTrace from 'stacktrace-js'; @@ -64,6 +65,11 @@ export default class ErrorBoundary extends React.PureComponent { debugInfo += 'React component stack\n---------------------\n\n```\n' + componentStack.toString() + '\n```'; } + let issueTracker = source_url; + if (source_url.match(/^https:\/\/github\.com\/[^/]+\/[^/]+\/?$/)) { + issueTracker = source_url + '/issues'; + } + return (
@@ -84,7 +90,7 @@ export default class ErrorBoundary extends React.PureComponent { }} + values={{ issuetracker: }} /> { debugInfo !== '' && (
diff --git a/app/javascript/flavours/glitch/features/ui/components/link_footer.js b/app/javascript/flavours/glitch/features/ui/components/link_footer.js index 722b47140..d9579e9c9 100644 --- a/app/javascript/flavours/glitch/features/ui/components/link_footer.js +++ b/app/javascript/flavours/glitch/features/ui/components/link_footer.js @@ -3,7 +3,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import { Link } from 'react-router-dom'; -import { invitesEnabled, version, limitedFederationMode, repository, source_url } from 'flavours/glitch/util/initial_state'; +import { invitesEnabled, limitedFederationMode, version, repository, source_url } from 'flavours/glitch/util/initial_state'; import { signOutLink, securityLink } from 'flavours/glitch/util/backend_links'; import { logOut } from 'flavours/glitch/util/log_out'; import { openModal } from 'flavours/glitch/actions/modal'; @@ -61,7 +61,7 @@ class LinkFooter extends React.PureComponent { id='getting_started.open_source_notice' defaultMessage='Glitchsoc is open source software, a friendly fork of {Mastodon}. You can contribute or report issues on GitHub at {github}.' values={{ - github: glitch-soc/mastodon (v{version}), + github: {repository} (v{version}), Mastodon: Mastodon }} />

diff --git a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js index 935c26be6..e0872927a 100644 --- a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js @@ -10,7 +10,7 @@ import ComposeForm from 'flavours/glitch/features/compose/components/compose_for import DrawerAccount from 'flavours/glitch/features/compose/components/navigation_bar'; import Search from 'flavours/glitch/features/compose/components/search'; import ColumnHeader from './column_header'; -import { me } from 'flavours/glitch/util/initial_state'; +import { me, source_url } from 'flavours/glitch/util/initial_state'; const noop = () => { }; @@ -141,7 +141,18 @@ const PageSix = ({ admin, domain }) => {

{adminSection} -

fork, Mastodon: Mastodon, github: GitHub }} />

+

+ fork, + Mastodon: Mastodon, + github: GitHub, + }} + /> +

}} />

diff --git a/app/javascript/flavours/glitch/util/initial_state.js b/app/javascript/flavours/glitch/util/initial_state.js index 370d982d2..7154e020b 100644 --- a/app/javascript/flavours/glitch/util/initial_state.js +++ b/app/javascript/flavours/glitch/util/initial_state.js @@ -25,6 +25,8 @@ export const maxChars = (initialState && initialState.max_toot_chars) || 500; export const pollLimits = (initialState && initialState.poll_limits); export const invitesEnabled = getMeta('invites_enabled'); export const limitedFederationMode = getMeta('limited_federation_mode'); +export const repository = getMeta('repository'); +export const source_url = getMeta('source_url'); export const version = getMeta('version'); export const mascot = getMeta('mascot'); export const profile_directory = getMeta('profile_directory'); -- cgit From a7f6524c6b052f4d207525c813436ca12c929f00 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 26 Sep 2021 05:46:13 +0200 Subject: [Glitch] Change routing paths to use usernames in web UI Port 52e5c07948c4c91b73062846e1f19ea278ec0e24 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/actions/accounts.js | 32 ++++++++++ app/javascript/flavours/glitch/actions/compose.js | 5 +- .../flavours/glitch/components/account.js | 4 +- .../flavours/glitch/components/avatar_composite.js | 2 +- .../flavours/glitch/components/display_name.js | 4 +- .../flavours/glitch/components/hashtag.js | 2 +- .../flavours/glitch/components/status.js | 18 ++---- .../glitch/components/status_action_bar.js | 4 +- .../flavours/glitch/components/status_content.js | 6 +- .../flavours/glitch/components/status_header.js | 6 +- .../flavours/glitch/components/status_prepend.js | 2 +- .../flavours/glitch/containers/mastodon.js | 26 +++++++- .../features/account/components/action_bar.js | 6 +- .../glitch/features/account_gallery/index.js | 60 +++++++++++++----- .../features/account_timeline/components/header.js | 6 +- .../account_timeline/components/moved_note.js | 2 +- .../glitch/features/account_timeline/index.js | 64 ++++++++++++++----- .../glitch/features/compose/components/header.js | 6 +- .../features/compose/components/navigation_bar.js | 4 +- .../direct_timeline/components/conversation.js | 2 +- .../features/directory/components/account_card.js | 2 +- .../components/account_authorize.js | 2 +- .../flavours/glitch/features/followers/index.js | 72 +++++++++++++++------- .../flavours/glitch/features/following/index.js | 72 +++++++++++++++------- .../getting_started/components/announcements.js | 6 +- .../glitch/features/getting_started/index.js | 12 ++-- .../flavours/glitch/features/lists/index.js | 2 +- .../features/notifications/components/follow.js | 4 +- .../notifications/components/follow_request.js | 6 +- .../picture_in_picture/components/footer.js | 2 +- .../picture_in_picture/components/header.js | 2 +- .../features/status/components/detailed_status.js | 6 +- .../flavours/glitch/features/status/index.js | 2 +- .../glitch/features/ui/components/boost_modal.js | 2 +- .../glitch/features/ui/components/columns_area.js | 2 +- .../features/ui/components/favourite_modal.js | 2 +- .../glitch/features/ui/components/list_panel.js | 2 +- .../glitch/features/ui/components/media_modal.js | 9 --- .../features/ui/components/navigation_panel.js | 8 +-- .../features/ui/components/onboarding_modal.js | 4 +- .../glitch/features/ui/components/tabs_bar.js | 6 +- .../flavours/glitch/features/ui/index.js | 48 ++++++++------- .../flavours/glitch/reducers/accounts_map.js | 15 +++++ app/javascript/flavours/glitch/reducers/index.js | 2 + app/javascript/flavours/glitch/util/api.js | 26 ++++++-- 45 files changed, 382 insertions(+), 195 deletions(-) create mode 100644 app/javascript/flavours/glitch/reducers/accounts_map.js (limited to 'app/javascript/flavours/glitch/features/ui') diff --git a/app/javascript/flavours/glitch/actions/accounts.js b/app/javascript/flavours/glitch/actions/accounts.js index 912a3d179..0cf64e076 100644 --- a/app/javascript/flavours/glitch/actions/accounts.js +++ b/app/javascript/flavours/glitch/actions/accounts.js @@ -5,6 +5,10 @@ export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST'; export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS'; export const ACCOUNT_FETCH_FAIL = 'ACCOUNT_FETCH_FAIL'; +export const ACCOUNT_LOOKUP_REQUEST = 'ACCOUNT_LOOKUP_REQUEST'; +export const ACCOUNT_LOOKUP_SUCCESS = 'ACCOUNT_LOOKUP_SUCCESS'; +export const ACCOUNT_LOOKUP_FAIL = 'ACCOUNT_LOOKUP_FAIL'; + export const ACCOUNT_FOLLOW_REQUEST = 'ACCOUNT_FOLLOW_REQUEST'; export const ACCOUNT_FOLLOW_SUCCESS = 'ACCOUNT_FOLLOW_SUCCESS'; export const ACCOUNT_FOLLOW_FAIL = 'ACCOUNT_FOLLOW_FAIL'; @@ -104,6 +108,34 @@ export function fetchAccount(id) { }; }; +export const lookupAccount = acct => (dispatch, getState) => { + dispatch(lookupAccountRequest(acct)); + + api(getState).get('/api/v1/accounts/lookup', { params: { acct } }).then(response => { + dispatch(fetchRelationships([response.data.id])); + dispatch(importFetchedAccount(response.data)); + dispatch(lookupAccountSuccess()); + }).catch(error => { + dispatch(lookupAccountFail(acct, error)); + }); +}; + +export const lookupAccountRequest = (acct) => ({ + type: ACCOUNT_LOOKUP_REQUEST, + acct, +}); + +export const lookupAccountSuccess = () => ({ + type: ACCOUNT_LOOKUP_SUCCESS, +}); + +export const lookupAccountFail = (acct, error) => ({ + type: ACCOUNT_LOOKUP_FAIL, + acct, + error, + skipAlert: true, +}); + export function fetchAccountRequest(id) { return { type: ACCOUNT_FETCH_REQUEST, diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index eebe98626..ac6e7f0c4 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -83,7 +83,7 @@ const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1); export const ensureComposeIsVisible = (getState, routerHistory) => { if (!getState().getIn(['compose', 'mounted']) && window.innerWidth < COMPOSE_PANEL_BREAKPOINT) { - routerHistory.push('/statuses/new'); + routerHistory.push('/publish'); } }; @@ -176,7 +176,8 @@ export function submitCompose(routerHistory) { 'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']), }, }).then(function (response) { - if (routerHistory && routerHistory.location.pathname === '/statuses/new' + if (routerHistory + && routerHistory.location.pathname === '/publish' && window.history.state && !getState().getIn(['compose', 'advanced_options', 'threaded_mode'])) { routerHistory.goBack(); diff --git a/app/javascript/flavours/glitch/components/account.js b/app/javascript/flavours/glitch/components/account.js index 20313535b..396a36ea0 100644 --- a/app/javascript/flavours/glitch/components/account.js +++ b/app/javascript/flavours/glitch/components/account.js @@ -128,7 +128,7 @@ class Account extends ImmutablePureComponent {
- +
{mute_expires_at} diff --git a/app/javascript/flavours/glitch/components/avatar_composite.js b/app/javascript/flavours/glitch/components/avatar_composite.js index 125b51c44..e30dfe68a 100644 --- a/app/javascript/flavours/glitch/components/avatar_composite.js +++ b/app/javascript/flavours/glitch/components/avatar_composite.js @@ -82,7 +82,7 @@ export default class AvatarComposite extends React.PureComponent { this.props.onAccountClick(account.get('id'), e)} + onClick={(e) => this.props.onAccountClick(account.get('acct'), e)} title={`@${account.get('acct')}`} key={account.get('id')} > diff --git a/app/javascript/flavours/glitch/components/display_name.js b/app/javascript/flavours/glitch/components/display_name.js index ad978a2c6..9c7da744e 100644 --- a/app/javascript/flavours/glitch/components/display_name.js +++ b/app/javascript/flavours/glitch/components/display_name.js @@ -61,7 +61,7 @@ export default class DisplayName extends React.PureComponent { onAccountClick(a.get('id'), e)} + onClick={(e) => onAccountClick(a.get('acct'), e)} title={`@${a.get('acct')}`} rel='noopener noreferrer' > @@ -76,7 +76,7 @@ export default class DisplayName extends React.PureComponent { } suffix = ( - onAccountClick(account.get('id'), e)} rel='noopener noreferrer'> + onAccountClick(account.get('acct'), e)} rel='noopener noreferrer'> @{acct} ); diff --git a/app/javascript/flavours/glitch/components/hashtag.js b/app/javascript/flavours/glitch/components/hashtag.js index 24c595ed7..d00c01e77 100644 --- a/app/javascript/flavours/glitch/components/hashtag.js +++ b/app/javascript/flavours/glitch/components/hashtag.js @@ -52,7 +52,7 @@ const Hashtag = ({ hashtag }) => (
#{hashtag.get('name')} diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js index b72c2417c..72d59f55a 100644 --- a/app/javascript/flavours/glitch/components/status.js +++ b/app/javascript/flavours/glitch/components/status.js @@ -346,7 +346,9 @@ class Status extends ImmutablePureComponent { return; } else { if (destination === undefined) { - destination = `/statuses/${ + destination = `/@${ + status.getIn(['reblog', 'account', 'acct'], status.getIn(['account', 'acct'])) + }/${ status.getIn(['reblog', 'id'], status.get('id')) }`; } @@ -362,16 +364,6 @@ class Status extends ImmutablePureComponent { this.setState({ showMedia: !this.state.showMedia }); } - handleAccountClick = (e) => { - if (this.context.router && e.button === 0) { - const id = e.currentTarget.getAttribute('data-id'); - e.preventDefault(); - let state = {...this.context.router.history.location.state}; - state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1; - this.context.router.history.push(`/accounts/${id}`, state); - } - } - handleExpandedToggle = () => { if (this.props.status.get('spoiler_text')) { this.setExpansion(!this.state.isExpanded); @@ -433,13 +425,13 @@ class Status extends ImmutablePureComponent { handleHotkeyOpen = () => { let state = {...this.context.router.history.location.state}; state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1; - this.context.router.history.push(`/statuses/${this.props.status.get('id')}`, state); + this.context.router.history.push(`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`, state); } handleHotkeyOpenProfile = () => { let state = {...this.context.router.history.location.state}; state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1; - this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`, state); + this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`, state); } handleHotkeyMoveUp = e => { diff --git a/app/javascript/flavours/glitch/components/status_action_bar.js b/app/javascript/flavours/glitch/components/status_action_bar.js index 206ae74c8..d63c6b142 100644 --- a/app/javascript/flavours/glitch/components/status_action_bar.js +++ b/app/javascript/flavours/glitch/components/status_action_bar.js @@ -148,10 +148,10 @@ class StatusActionBar extends ImmutablePureComponent { handleOpen = () => { let state = {...this.context.router.history.location.state}; if (state.mastodonModalKey) { - this.context.router.history.replace(`/statuses/${this.props.status.get('id')}`, { mastodonBackSteps: (state.mastodonBackSteps || 0) + 1 }); + this.context.router.history.replace(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}`, { mastodonBackSteps: (state.mastodonBackSteps || 0) + 1 }); } else { state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1; - this.context.router.history.push(`/statuses/${this.props.status.get('id')}`, state); + this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}`, state); } } diff --git a/app/javascript/flavours/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js index 82d066432..1d32b35e5 100644 --- a/app/javascript/flavours/glitch/components/status_content.js +++ b/app/javascript/flavours/glitch/components/status_content.js @@ -197,7 +197,7 @@ export default class StatusContent extends React.PureComponent { onMentionClick = (mention, e) => { if (this.props.parseClick) { - this.props.parseClick(e, `/accounts/${mention.get('id')}`); + this.props.parseClick(e, `/@${mention.get('acct')}`); } } @@ -205,7 +205,7 @@ export default class StatusContent extends React.PureComponent { hashtag = hashtag.replace(/^#/, ''); if (this.props.parseClick) { - this.props.parseClick(e, `/timelines/tag/${hashtag}`); + this.props.parseClick(e, `/tags/${hashtag}`); } } @@ -277,7 +277,7 @@ export default class StatusContent extends React.PureComponent { const mentionLinks = status.get('mentions').map(item => ( { + handleClick = (acct, e) => { const { parseClick } = this.props; - parseClick(e, `/accounts/${id}`); + parseClick(e, `/@${acct}`); } handleAccountClick = (e) => { const { status } = this.props; - this.handleClick(status.getIn(['account', 'id']), e); + this.handleClick(status.getIn(['account', 'acct']), e); } // Rendering. diff --git a/app/javascript/flavours/glitch/components/status_prepend.js b/app/javascript/flavours/glitch/components/status_prepend.js index af6acdef9..5f8d70c9a 100644 --- a/app/javascript/flavours/glitch/components/status_prepend.js +++ b/app/javascript/flavours/glitch/components/status_prepend.js @@ -17,7 +17,7 @@ export default class StatusPrepend extends React.PureComponent { handleClick = (e) => { const { account, parseClick } = this.props; - parseClick(e, `/accounts/${account.get('id')}`); + parseClick(e, `/${account.get('acct')}`); } Message = () => { diff --git a/app/javascript/flavours/glitch/containers/mastodon.js b/app/javascript/flavours/glitch/containers/mastodon.js index 131303fd3..de8ea8ee2 100644 --- a/app/javascript/flavours/glitch/containers/mastodon.js +++ b/app/javascript/flavours/glitch/containers/mastodon.js @@ -23,14 +23,38 @@ store.dispatch(hydrateAction); // load custom emojis store.dispatch(fetchCustomEmojis()); +const createIdentityContext = state => ({ + signedIn: !!state.meta.me, + accountId: state.meta.me, + accessToken: state.meta.access_token, +}); + export default class Mastodon extends React.PureComponent { static propTypes = { locale: PropTypes.string.isRequired, }; + static childContextTypes = { + identity: PropTypes.shape({ + signedIn: PropTypes.bool.isRequired, + accountId: PropTypes.string, + accessToken: PropTypes.string, + }).isRequired, + }; + + identity = createIdentityContext(initialState); + + getChildContext() { + return { + identity: this.identity, + }; + } + componentDidMount() { - this.disconnect = store.dispatch(connectUserStream()); + if (this.identity.signedIn) { + this.disconnect = store.dispatch(connectUserStream()); + } } componentWillUnmount () { diff --git a/app/javascript/flavours/glitch/features/account/components/action_bar.js b/app/javascript/flavours/glitch/features/account/components/action_bar.js index 2d4cc7f49..23120d57e 100644 --- a/app/javascript/flavours/glitch/features/account/components/action_bar.js +++ b/app/javascript/flavours/glitch/features/account/components/action_bar.js @@ -62,17 +62,17 @@ class ActionBar extends React.PureComponent {
- + - + - + { account.get('followers_count') < 0 ? '-' : } diff --git a/app/javascript/flavours/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js index 434a47dfc..508f49107 100644 --- a/app/javascript/flavours/glitch/features/account_gallery/index.js +++ b/app/javascript/flavours/glitch/features/account_gallery/index.js @@ -16,13 +16,24 @@ import LoadMore from 'flavours/glitch/components/load_more'; import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import { openModal } from 'flavours/glitch/actions/modal'; -const mapStateToProps = (state, props) => ({ - isAccount: !!state.getIn(['accounts', props.params.accountId]), - attachments: getAccountGallery(state, props.params.accountId), - isLoading: state.getIn(['timelines', `account:${props.params.accountId}:media`, 'isLoading']), - hasMore: state.getIn(['timelines', `account:${props.params.accountId}:media`, 'hasMore']), - suspended: state.getIn(['accounts', props.params.accountId, 'suspended'], false), -}); +const mapStateToProps = (state, { params: { acct } }) => { + const accountId = state.getIn(['accounts_map', acct]); + + if (!accountId) { + return { + isLoading: true, + }; + } + + return { + accountId, + isAccount: !!state.getIn(['accounts', accountId]), + attachments: getAccountGallery(state, accountId), + isLoading: state.getIn(['timelines', `account:${accountId}:media`, 'isLoading']), + hasMore: state.getIn(['timelines', `account:${accountId}:media`, 'hasMore']), + suspended: state.getIn(['accounts', accountId, 'suspended'], false), + }; +}; class LoadMoreMedia extends ImmutablePureComponent { @@ -50,7 +61,10 @@ export default @connect(mapStateToProps) class AccountGallery extends ImmutablePureComponent { static propTypes = { - params: PropTypes.object.isRequired, + params: PropTypes.shape({ + acct: PropTypes.string.isRequired, + }).isRequired, + accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, attachments: ImmutablePropTypes.list.isRequired, isLoading: PropTypes.bool, @@ -64,15 +78,29 @@ class AccountGallery extends ImmutablePureComponent { width: 323, }; + _load () { + const { accountId, dispatch } = this.props; + + dispatch(expandAccountMediaTimeline(accountId)); + } + componentDidMount () { - this.props.dispatch(fetchAccount(this.props.params.accountId)); - this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId)); + const { params: { acct }, accountId, dispatch } = this.props; + + if (accountId) { + this._load(); + } else { + dispatch(lookupAccount(acct)); + } } - componentWillReceiveProps (nextProps) { - if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) { - this.props.dispatch(fetchAccount(nextProps.params.accountId)); - this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId)); + componentDidUpdate (prevProps) { + const { params: { acct }, accountId, dispatch } = this.props; + + if (prevProps.accountId !== accountId && accountId) { + this._load(); + } else if (prevProps.params.acct !== acct) { + dispatch(lookupAccount(acct)); } } @@ -96,7 +124,7 @@ class AccountGallery extends ImmutablePureComponent { } handleLoadMore = maxId => { - this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId, { maxId })); + this.props.dispatch(expandAccountMediaTimeline(this.props.accountId, { maxId })); }; handleLoadOlder = e => { @@ -162,7 +190,7 @@ class AccountGallery extends ImmutablePureComponent {
- + {suspended ? (
diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/header.js b/app/javascript/flavours/glitch/features/account_timeline/components/header.js index a6b57d331..e70f011b7 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/components/header.js +++ b/app/javascript/flavours/glitch/features/account_timeline/components/header.js @@ -128,9 +128,9 @@ export default class Header extends ImmutablePureComponent { {!hideTabs && (
- - - + + +
)}
diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js b/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js index fcaa7b494..308407e94 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js +++ b/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js @@ -23,7 +23,7 @@ export default class MovedNote extends ImmutablePureComponent { e.preventDefault(); let state = {...this.context.router.history.location.state}; state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1; - this.context.router.history.push(`/accounts/${this.props.to.get('id')}`, state); + this.context.router.history.push(`/@${this.props.to.get('acct')}`, state); } e.stopPropagation(); diff --git a/app/javascript/flavours/glitch/features/account_timeline/index.js b/app/javascript/flavours/glitch/features/account_timeline/index.js index 0d24980a9..3d2bbb3b7 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/index.js +++ b/app/javascript/flavours/glitch/features/account_timeline/index.js @@ -2,7 +2,7 @@ import React from 'react'; import { connect } from 'react-redux'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; -import { fetchAccount } from 'flavours/glitch/actions/accounts'; +import { lookupAccount, fetchAccount } from 'flavours/glitch/actions/accounts'; import { expandAccountFeaturedTimeline, expandAccountTimeline } from 'flavours/glitch/actions/timelines'; import StatusList from '../../components/status_list'; import LoadingIndicator from '../../components/loading_indicator'; @@ -19,10 +19,19 @@ import TimelineHint from 'flavours/glitch/components/timeline_hint'; const emptyList = ImmutableList(); -const mapStateToProps = (state, { params: { accountId }, withReplies = false }) => { +const mapStateToProps = (state, { params: { acct }, withReplies = false }) => { + const accountId = state.getIn(['accounts_map', acct]); + + if (!accountId) { + return { + isLoading: true, + }; + } + const path = withReplies ? `${accountId}:with_replies` : accountId; return { + accountId, remote: !!(state.getIn(['accounts', accountId, 'acct']) !== state.getIn(['accounts', accountId, 'username'])), remoteUrl: state.getIn(['accounts', accountId, 'url']), isAccount: !!state.getIn(['accounts', accountId]), @@ -46,7 +55,10 @@ export default @connect(mapStateToProps) class AccountTimeline extends ImmutablePureComponent { static propTypes = { - params: PropTypes.object.isRequired, + params: PropTypes.shape({ + acct: PropTypes.string.isRequired, + }).isRequired, + accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, statusIds: ImmutablePropTypes.list, featuredStatusIds: ImmutablePropTypes.list, @@ -60,25 +72,47 @@ class AccountTimeline extends ImmutablePureComponent { multiColumn: PropTypes.bool, }; - componentWillMount () { - const { params: { accountId }, withReplies } = this.props; + _load () { + const { accountId, withReplies, dispatch } = this.props; - this.props.dispatch(fetchAccount(accountId)); - this.props.dispatch(fetchAccountIdentityProofs(accountId)); + dispatch(fetchAccount(accountId)); + dispatch(fetchAccountIdentityProofs(accountId)); if (!withReplies) { - this.props.dispatch(expandAccountFeaturedTimeline(accountId)); + dispatch(expandAccountFeaturedTimeline(accountId)); + } + dispatch(expandAccountTimeline(accountId, { withReplies })); + } + + componentDidMount () { + const { params: { acct }, accountId, dispatch } = this.props; + + if (accountId) { + this._load(); + } else { + dispatch(lookupAccount(acct)); + } + } + + componentDidUpdate (prevProps) { + const { params: { acct }, accountId, dispatch } = this.props; + + if (prevProps.accountId !== accountId && accountId) { + this._load(); + } else if (prevProps.params.acct !== acct) { + dispatch(lookupAccount(acct)); } - this.props.dispatch(expandAccountTimeline(accountId, { withReplies })); } componentWillReceiveProps (nextProps) { + const { dispatch } = this.props; + if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) { - this.props.dispatch(fetchAccount(nextProps.params.accountId)); - this.props.dispatch(fetchAccountIdentityProofs(nextProps.params.accountId)); + dispatch(fetchAccount(nextProps.params.accountId)); + dispatch(fetchAccountIdentityProofs(nextProps.params.accountId)); if (!nextProps.withReplies) { - this.props.dispatch(expandAccountFeaturedTimeline(nextProps.params.accountId)); + dispatch(expandAccountFeaturedTimeline(nextProps.params.accountId)); } - this.props.dispatch(expandAccountTimeline(nextProps.params.accountId, { withReplies: nextProps.params.withReplies })); + dispatch(expandAccountTimeline(nextProps.params.accountId, { withReplies: nextProps.params.withReplies })); } } @@ -87,7 +121,7 @@ class AccountTimeline extends ImmutablePureComponent { } handleLoadMore = maxId => { - this.props.dispatch(expandAccountTimeline(this.props.params.accountId, { maxId, withReplies: this.props.withReplies })); + this.props.dispatch(expandAccountTimeline(this.props.accountId, { maxId, withReplies: this.props.withReplies })); } setRef = c => { @@ -131,7 +165,7 @@ class AccountTimeline extends ImmutablePureComponent { } + prepend={} alwaysPrepend append={remoteMessage} scrollKey='account_timeline' diff --git a/app/javascript/flavours/glitch/features/compose/components/header.js b/app/javascript/flavours/glitch/features/compose/components/header.js index 5b456b717..c6e4cc36b 100644 --- a/app/javascript/flavours/glitch/features/compose/components/header.js +++ b/app/javascript/flavours/glitch/features/compose/components/header.js @@ -87,7 +87,7 @@ class Header extends ImmutablePureComponent { ))} {renderForColumn('NOTIFICATIONS', ( @@ -106,14 +106,14 @@ class Header extends ImmutablePureComponent { ))} {renderForColumn('PUBLIC', ( ))} - + {this.props.account.get('acct')}
- + @{this.props.account.get('acct')} diff --git a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js index 98b48cd90..9796ded65 100644 --- a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js +++ b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js @@ -163,7 +163,7 @@ class Conversation extends ImmutablePureComponent { menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDelete }); - const names = accounts.map(a => ).reduce((prev, cur) => [prev, ', ', cur]); + const names = accounts.map(a => ).reduce((prev, cur) => [prev, ', ', cur]); const handlers = { reply: this.handleReply, diff --git a/app/javascript/flavours/glitch/features/directory/components/account_card.js b/app/javascript/flavours/glitch/features/directory/components/account_card.js index 9fe84c10b..2a3fd1ecf 100644 --- a/app/javascript/flavours/glitch/features/directory/components/account_card.js +++ b/app/javascript/flavours/glitch/features/directory/components/account_card.js @@ -213,7 +213,7 @@ class AccountCard extends ImmutablePureComponent { diff --git a/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js b/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js index eb9f3db7e..cbe7a1032 100644 --- a/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js +++ b/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js @@ -30,7 +30,7 @@ class AccountAuthorize extends ImmutablePureComponent { return (
- +
diff --git a/app/javascript/flavours/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js index 25f7f05b4..21e25b869 100644 --- a/app/javascript/flavours/glitch/features/followers/index.js +++ b/app/javascript/flavours/glitch/features/followers/index.js @@ -5,7 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import { debounce } from 'lodash'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { - fetchAccount, + lookupAccount, fetchFollowers, expandFollowers, } from 'flavours/glitch/actions/accounts'; @@ -19,14 +19,25 @@ import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; import TimelineHint from 'flavours/glitch/components/timeline_hint'; -const mapStateToProps = (state, props) => ({ - remote: !!(state.getIn(['accounts', props.params.accountId, 'acct']) !== state.getIn(['accounts', props.params.accountId, 'username'])), - remoteUrl: state.getIn(['accounts', props.params.accountId, 'url']), - isAccount: !!state.getIn(['accounts', props.params.accountId]), - accountIds: state.getIn(['user_lists', 'followers', props.params.accountId, 'items']), - hasMore: !!state.getIn(['user_lists', 'followers', props.params.accountId, 'next']), - isLoading: state.getIn(['user_lists', 'followers', props.params.accountId, 'isLoading'], true), -}); +const mapStateToProps = (state, { params: { acct } }) => { + const accountId = state.getIn(['accounts_map', acct]); + + if (!accountId) { + return { + isLoading: true, + }; + } + + return { + accountId, + remote: !!(state.getIn(['accounts', accountId, 'acct']) !== state.getIn(['accounts', accountId, 'username'])), + remoteUrl: state.getIn(['accounts', accountId, 'url']), + isAccount: !!state.getIn(['accounts', accountId]), + accountIds: state.getIn(['user_lists', 'followers', accountId, 'items']), + hasMore: !!state.getIn(['user_lists', 'followers', accountId, 'next']), + isLoading: state.getIn(['user_lists', 'followers', accountId, 'isLoading'], true), + }; +}; const RemoteHint = ({ url }) => ( } /> @@ -40,7 +51,10 @@ export default @connect(mapStateToProps) class Followers extends ImmutablePureComponent { static propTypes = { - params: PropTypes.object.isRequired, + params: PropTypes.shape({ + acct: PropTypes.string.isRequired, + }).isRequired, + accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, @@ -51,32 +65,44 @@ class Followers extends ImmutablePureComponent { multiColumn: PropTypes.bool, }; - componentWillMount () { - if (!this.props.accountIds) { - this.props.dispatch(fetchAccount(this.props.params.accountId)); - this.props.dispatch(fetchFollowers(this.props.params.accountId)); - } + _load () { + const { accountId, dispatch } = this.props; + + dispatch(fetchFollowers(accountId)); } - componentWillReceiveProps (nextProps) { - if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) { - this.props.dispatch(fetchAccount(nextProps.params.accountId)); - this.props.dispatch(fetchFollowers(nextProps.params.accountId)); + componentDidMount () { + const { params: { acct }, accountId, dispatch } = this.props; + + if (accountId) { + this._load(); + } else { + dispatch(lookupAccount(acct)); } } - handleHeaderClick = () => { - this.column.scrollTop(); + componentDidUpdate (prevProps) { + const { params: { acct }, accountId, dispatch } = this.props; + + if (prevProps.accountId !== accountId && accountId) { + this._load(); + } else if (prevProps.params.acct !== acct) { + dispatch(lookupAccount(acct)); + } } handleLoadMore = debounce(() => { - this.props.dispatch(expandFollowers(this.props.params.accountId)); + this.props.dispatch(expandFollowers(this.props.accountId)); }, 300, { leading: true }); setRef = c => { this.column = c; } + handleHeaderClick = () => { + this.column.scrollTop(); + } + render () { const { accountIds, hasMore, isAccount, multiColumn, isLoading, remote, remoteUrl } = this.props; @@ -115,7 +141,7 @@ class Followers extends ImmutablePureComponent { hasMore={hasMore} isLoading={isLoading} onLoadMore={this.handleLoadMore} - prepend={} + prepend={} alwaysPrepend append={remoteMessage} emptyMessage={emptyMessage} diff --git a/app/javascript/flavours/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js index 968829fd5..c1d026d98 100644 --- a/app/javascript/flavours/glitch/features/following/index.js +++ b/app/javascript/flavours/glitch/features/following/index.js @@ -5,7 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import { debounce } from 'lodash'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { - fetchAccount, + lookupAccount, fetchFollowing, expandFollowing, } from 'flavours/glitch/actions/accounts'; @@ -19,14 +19,25 @@ import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; import TimelineHint from 'flavours/glitch/components/timeline_hint'; -const mapStateToProps = (state, props) => ({ - remote: !!(state.getIn(['accounts', props.params.accountId, 'acct']) !== state.getIn(['accounts', props.params.accountId, 'username'])), - remoteUrl: state.getIn(['accounts', props.params.accountId, 'url']), - isAccount: !!state.getIn(['accounts', props.params.accountId]), - accountIds: state.getIn(['user_lists', 'following', props.params.accountId, 'items']), - hasMore: !!state.getIn(['user_lists', 'following', props.params.accountId, 'next']), - isLoading: state.getIn(['user_lists', 'following', props.params.accountId, 'isLoading'], true), -}); +const mapStateToProps = (state, { params: { acct } }) => { + const accountId = state.getIn(['accounts_map', acct]); + + if (!accountId) { + return { + isLoading: true, + }; + } + + return { + accountId, + remote: !!(state.getIn(['accounts', accountId, 'acct']) !== state.getIn(['accounts', accountId, 'username'])), + remoteUrl: state.getIn(['accounts', accountId, 'url']), + isAccount: !!state.getIn(['accounts', accountId]), + accountIds: state.getIn(['user_lists', 'following', accountId, 'items']), + hasMore: !!state.getIn(['user_lists', 'following', accountId, 'next']), + isLoading: state.getIn(['user_lists', 'following', accountId, 'isLoading'], true), + }; +}; const RemoteHint = ({ url }) => ( } /> @@ -40,7 +51,10 @@ export default @connect(mapStateToProps) class Following extends ImmutablePureComponent { static propTypes = { - params: PropTypes.object.isRequired, + params: PropTypes.shape({ + acct: PropTypes.string.isRequired, + }).isRequired, + accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, @@ -51,32 +65,44 @@ class Following extends ImmutablePureComponent { multiColumn: PropTypes.bool, }; - componentWillMount () { - if (!this.props.accountIds) { - this.props.dispatch(fetchAccount(this.props.params.accountId)); - this.props.dispatch(fetchFollowing(this.props.params.accountId)); - } + _load () { + const { accountId, dispatch } = this.props; + + dispatch(fetchFollowing(accountId)); } - componentWillReceiveProps (nextProps) { - if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) { - this.props.dispatch(fetchAccount(nextProps.params.accountId)); - this.props.dispatch(fetchFollowing(nextProps.params.accountId)); + componentDidMount () { + const { params: { acct }, accountId, dispatch } = this.props; + + if (accountId) { + this._load(); + } else { + dispatch(lookupAccount(acct)); } } - handleHeaderClick = () => { - this.column.scrollTop(); + componentDidUpdate (prevProps) { + const { params: { acct }, accountId, dispatch } = this.props; + + if (prevProps.accountId !== accountId && accountId) { + this._load(); + } else if (prevProps.params.acct !== acct) { + dispatch(lookupAccount(acct)); + } } handleLoadMore = debounce(() => { - this.props.dispatch(expandFollowing(this.props.params.accountId)); + this.props.dispatch(expandFollowing(this.props.accountId)); }, 300, { leading: true }); setRef = c => { this.column = c; } + handleHeaderClick = () => { + this.column.scrollTop(); + } + render () { const { accountIds, hasMore, isAccount, multiColumn, isLoading, remote, remoteUrl } = this.props; @@ -115,7 +141,7 @@ class Following extends ImmutablePureComponent { hasMore={hasMore} isLoading={isLoading} onLoadMore={this.handleLoadMore} - prepend={} + prepend={} alwaysPrepend append={remoteMessage} emptyMessage={emptyMessage} diff --git a/app/javascript/flavours/glitch/features/getting_started/components/announcements.js b/app/javascript/flavours/glitch/features/getting_started/components/announcements.js index 4eebe83ef..2f6d2de5c 100644 --- a/app/javascript/flavours/glitch/features/getting_started/components/announcements.js +++ b/app/javascript/flavours/glitch/features/getting_started/components/announcements.js @@ -87,7 +87,7 @@ class Content extends ImmutablePureComponent { onMentionClick = (mention, e) => { if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) { e.preventDefault(); - this.context.router.history.push(`/accounts/${mention.get('id')}`); + this.context.router.history.push(`/@${mention.get('acct')}`); } } @@ -96,14 +96,14 @@ class Content extends ImmutablePureComponent { if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) { e.preventDefault(); - this.context.router.history.push(`/timelines/tag/${hashtag}`); + this.context.router.history.push(`/tags/${hashtag}`); } } onStatusClick = (status, e) => { if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) { e.preventDefault(); - this.context.router.history.push(`/statuses/${status.get('id')}`); + this.context.router.history.push(`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`); } } diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js index b4549fdf8..56750fd88 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.js +++ b/app/javascript/flavours/glitch/features/getting_started/index.js @@ -107,7 +107,7 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2); const { fetchFollowRequests, multiColumn } = this.props; if (!multiColumn && window.innerWidth >= NAVIGATION_PANEL_BREAKPOINT) { - this.context.router.history.replace('/timelines/home'); + this.context.router.history.replace('/home'); return; } @@ -122,7 +122,7 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2); if (multiColumn) { if (!columns.find(item => item.get('id') === 'HOME')) { - navItems.push(); + navItems.push(); } if (!columns.find(item => item.get('id') === 'NOTIFICATIONS')) { @@ -130,16 +130,16 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2); } if (!columns.find(item => item.get('id') === 'COMMUNITY')) { - navItems.push(); + navItems.push(); } if (!columns.find(item => item.get('id') === 'PUBLIC')) { - navItems.push(); + navItems.push(); } } if (!multiColumn || !columns.find(item => item.get('id') === 'DIRECT')) { - navItems.push(); + navItems.push(); } if (!multiColumn || !columns.find(item => item.get('id') === 'BOOKMARKS')) { @@ -160,7 +160,7 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2);
{lists.filter(list => !columns.find(item => item.get('id') === 'LIST' && item.getIn(['params', 'id']) === list.get('id'))).map(list => - + )}
, ]); diff --git a/app/javascript/flavours/glitch/features/lists/index.js b/app/javascript/flavours/glitch/features/lists/index.js index e384f301b..b92389d82 100644 --- a/app/javascript/flavours/glitch/features/lists/index.js +++ b/app/javascript/flavours/glitch/features/lists/index.js @@ -73,7 +73,7 @@ class Lists extends ImmutablePureComponent { bindToDocument={!multiColumn} > {lists.map(list => - , + , )} diff --git a/app/javascript/flavours/glitch/features/notifications/components/follow.js b/app/javascript/flavours/glitch/features/notifications/components/follow.js index 0d3162fc9..b8fad19d0 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/follow.js +++ b/app/javascript/flavours/glitch/features/notifications/components/follow.js @@ -39,7 +39,7 @@ export default class NotificationFollow extends ImmutablePureComponent { handleOpenProfile = () => { const { notification } = this.props; - this.context.router.history.push(`/accounts/${notification.getIn(['account', 'id'])}`); + this.context.router.history.push(`/@${notification.getIn(['account', 'acct'])}`); } handleMention = e => { @@ -70,7 +70,7 @@ export default class NotificationFollow extends ImmutablePureComponent { className='notification__display-name' href={account.get('url')} title={account.get('acct')} - to={`/accounts/${account.get('id')}`} + to={`/@${account.get('acct')}`} dangerouslySetInnerHTML={{ __html: displayName }} /> ); diff --git a/app/javascript/flavours/glitch/features/notifications/components/follow_request.js b/app/javascript/flavours/glitch/features/notifications/components/follow_request.js index f351c1035..69b92a06f 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/follow_request.js +++ b/app/javascript/flavours/glitch/features/notifications/components/follow_request.js @@ -45,7 +45,7 @@ class FollowRequest extends ImmutablePureComponent { handleOpenProfile = () => { const { notification } = this.props; - this.context.router.history.push(`/accounts/${notification.getIn(['account', 'id'])}`); + this.context.router.history.push(`/@${notification.getIn(['account', 'acct'])}`); } handleMention = e => { @@ -89,7 +89,7 @@ class FollowRequest extends ImmutablePureComponent { className='notification__display-name' href={account.get('url')} title={account.get('acct')} - to={`/accounts/${account.get('id')}`} + to={`/@${account.get('acct')}`} dangerouslySetInnerHTML={{ __html: displayName }} /> ); @@ -111,7 +111,7 @@ class FollowRequest extends ImmutablePureComponent {
- +
diff --git a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.js b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.js index 98d1f40b2..e01d277a1 100644 --- a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.js +++ b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.js @@ -122,7 +122,7 @@ class Footer extends ImmutablePureComponent { onClose(); } - router.history.push(`/statuses/${status.get('id')}`); + router.history.push(`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`); } render () { diff --git a/app/javascript/flavours/glitch/features/picture_in_picture/components/header.js b/app/javascript/flavours/glitch/features/picture_in_picture/components/header.js index 28526ca88..26f2da374 100644 --- a/app/javascript/flavours/glitch/features/picture_in_picture/components/header.js +++ b/app/javascript/flavours/glitch/features/picture_in_picture/components/header.js @@ -34,7 +34,7 @@ class Header extends ImmutablePureComponent { return (
- + diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js index 416a4ca13..a1f981484 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js @@ -51,7 +51,7 @@ export default class DetailedStatus extends ImmutablePureComponent { e.preventDefault(); let state = {...this.context.router.history.location.state}; state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1; - this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`, state); + this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`, state); } e.stopPropagation(); @@ -216,7 +216,7 @@ export default class DetailedStatus extends ImmutablePureComponent { reblogLink = ( · - + @@ -240,7 +240,7 @@ export default class DetailedStatus extends ImmutablePureComponent { if (this.context.router) { favouriteLink = ( - + diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index 9dbba4772..bddf1a2ef 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -405,7 +405,7 @@ class Status extends ImmutablePureComponent { handleHotkeyOpenProfile = () => { let state = {...this.context.router.history.location.state}; state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1; - this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`, state); + this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`, state); } handleMoveUp = id => { diff --git a/app/javascript/flavours/glitch/features/ui/components/boost_modal.js b/app/javascript/flavours/glitch/features/ui/components/boost_modal.js index c4af25599..c23aec5ee 100644 --- a/app/javascript/flavours/glitch/features/ui/components/boost_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/boost_modal.js @@ -69,7 +69,7 @@ class BoostModal extends ImmutablePureComponent { this.props.onClose(); let state = {...this.context.router.history.location.state}; state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1; - this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`, state); + this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`, state); } } diff --git a/app/javascript/flavours/glitch/features/ui/components/columns_area.js b/app/javascript/flavours/glitch/features/ui/components/columns_area.js index d4e0bedac..5ab8f249d 100644 --- a/app/javascript/flavours/glitch/features/ui/components/columns_area.js +++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.js @@ -216,7 +216,7 @@ class ColumnsArea extends ImmutablePureComponent { const columnIndex = getIndex(this.context.router.history.location.pathname); if (singleColumn) { - const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : ; + const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : ; const content = columnIndex !== -1 ? ( diff --git a/app/javascript/flavours/glitch/features/ui/components/favourite_modal.js b/app/javascript/flavours/glitch/features/ui/components/favourite_modal.js index ea1d7876e..9b7f9d1fb 100644 --- a/app/javascript/flavours/glitch/features/ui/components/favourite_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/favourite_modal.js @@ -49,7 +49,7 @@ class FavouriteModal extends ImmutablePureComponent { this.props.onClose(); let state = {...this.context.router.history.location.state}; state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1; - this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`, state); + this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`, state); } } diff --git a/app/javascript/flavours/glitch/features/ui/components/list_panel.js b/app/javascript/flavours/glitch/features/ui/components/list_panel.js index 354e35027..e61234283 100644 --- a/app/javascript/flavours/glitch/features/ui/components/list_panel.js +++ b/app/javascript/flavours/glitch/features/ui/components/list_panel.js @@ -46,7 +46,7 @@ class ListPanel extends ImmutablePureComponent {
{lists.map(list => ( - {list.get('title')} + {list.get('title')} ))}
); diff --git a/app/javascript/flavours/glitch/features/ui/components/media_modal.js b/app/javascript/flavours/glitch/features/ui/components/media_modal.js index a8cbb837e..6974aab26 100644 --- a/app/javascript/flavours/glitch/features/ui/components/media_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/media_modal.js @@ -112,15 +112,6 @@ class MediaModal extends ImmutablePureComponent { })); }; - handleStatusClick = e => { - if (e.button === 0 && !(e.ctrlKey || e.metaKey)) { - e.preventDefault(); - this.context.router.history.push(`/statuses/${this.props.statusId}`); - } - - this._sendBackgroundColor(); - } - componentDidUpdate (prevProps, prevState) { if (prevState.index !== this.state.index) { this._sendBackgroundColor(); diff --git a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js index 50e7d5c48..2dcd535ca 100644 --- a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js +++ b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js @@ -11,12 +11,12 @@ import TrendsContainer from 'flavours/glitch/features/getting_started/containers const NavigationPanel = ({ onOpenSettings }) => (
- + - - - + + + {profile_directory && } diff --git a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js index e0872927a..e7be62ad8 100644 --- a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js @@ -79,7 +79,7 @@ const PageThree = ({ intl, myAccount }) => (
-

#illustration, introductions: #introductions }} />

+

#illustration, introductions: #introductions }} />

); @@ -130,7 +130,7 @@ const PageSix = ({ admin, domain }) => { if (admin) { adminSection = (

- @{admin.get('acct')} }} /> + @{admin.get('acct')} }} />
}} />

diff --git a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js index a67405215..55cc84f5e 100644 --- a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js +++ b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js @@ -8,10 +8,10 @@ import Icon from 'flavours/glitch/components/icon'; import NotificationsCounterIcon from './notifications_counter_icon'; export const links = [ - , + , , - , - , + , + , , , ]; diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index ad063f01b..4683f11cd 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -78,6 +78,7 @@ const mapStateToProps = state => ({ hicolorPrivacyIcons: state.getIn(['local_settings', 'hicolor_privacy_icons']), moved: state.getIn(['accounts', me, 'moved']) && state.getIn(['accounts', state.getIn(['accounts', me, 'moved'])]), firstLaunch: state.getIn(['settings', 'introductionVersion'], 0) < INTRODUCTION_VERSION, + username: state.getIn(['accounts', me, 'username']), }); const keyMap = { @@ -190,7 +191,7 @@ class SwitchingColumnsArea extends React.PureComponent { render () { const { children, navbarUnder } = this.props; const singleColumn = this.state.mobile; - const redirect = singleColumn ? : ; + const redirect = singleColumn ? : ; return ( @@ -198,32 +199,32 @@ class SwitchingColumnsArea extends React.PureComponent { {redirect} - - - - - - + + + + + + + + - - - - - - - - - - + + + + + + + + @@ -265,6 +266,7 @@ class UI extends React.Component { showFaviconBadge: PropTypes.bool, moved: PropTypes.map, firstLaunch: PropTypes.bool, + username: PropTypes.string, }; state = { @@ -517,7 +519,7 @@ class UI extends React.Component { } handleHotkeyGoToHome = () => { - this.props.history.push('/timelines/home'); + this.props.history.push('/home'); } handleHotkeyGoToNotifications = () => { @@ -525,15 +527,15 @@ class UI extends React.Component { } handleHotkeyGoToLocal = () => { - this.props.history.push('/timelines/public/local'); + this.props.history.push('/public/local'); } handleHotkeyGoToFederated = () => { - this.props.history.push('/timelines/public'); + this.props.history.push('/public'); } handleHotkeyGoToDirect = () => { - this.props.history.push('/timelines/direct'); + this.props.history.push('/conversations'); } handleHotkeyGoToStart = () => { @@ -549,7 +551,7 @@ class UI extends React.Component { } handleHotkeyGoToProfile = () => { - this.props.history.push(`/accounts/${me}`); + this.props.history.push(`/@${this.props.username}`); } handleHotkeyGoToBlocked = () => { @@ -616,7 +618,7 @@ class UI extends React.Component { id='moved_to_warning' defaultMessage='This account is marked as moved to {moved_to_link}, and may thus not accept new follows.' values={{ moved_to_link: ( - + @{moved.get('acct')} )}} diff --git a/app/javascript/flavours/glitch/reducers/accounts_map.js b/app/javascript/flavours/glitch/reducers/accounts_map.js new file mode 100644 index 000000000..e0d42e9cd --- /dev/null +++ b/app/javascript/flavours/glitch/reducers/accounts_map.js @@ -0,0 +1,15 @@ +import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer'; +import { Map as ImmutableMap } from 'immutable'; + +const initialState = ImmutableMap(); + +export default function accountsMap(state = initialState, action) { + switch(action.type) { + case ACCOUNT_IMPORT: + return state.set(action.account.acct, action.account.id); + case ACCOUNTS_IMPORT: + return state.withMutations(map => action.accounts.forEach(account => map.set(account.acct, account.id))); + default: + return state; + } +}; diff --git a/app/javascript/flavours/glitch/reducers/index.js b/app/javascript/flavours/glitch/reducers/index.js index c452e834c..7d7fe6fd3 100644 --- a/app/javascript/flavours/glitch/reducers/index.js +++ b/app/javascript/flavours/glitch/reducers/index.js @@ -40,6 +40,7 @@ import announcements from './announcements'; import markers from './markers'; import account_notes from './account_notes'; import picture_in_picture from './picture_in_picture'; +import accounts_map from './accounts_map'; const reducers = { announcements, @@ -54,6 +55,7 @@ const reducers = { status_lists, accounts, accounts_counters, + accounts_map, statuses, relationships, settings, diff --git a/app/javascript/flavours/glitch/util/api.js b/app/javascript/flavours/glitch/util/api.js index c59a24518..90d8465ef 100644 --- a/app/javascript/flavours/glitch/util/api.js +++ b/app/javascript/flavours/glitch/util/api.js @@ -12,21 +12,35 @@ export const getLinks = response => { return LinkHeader.parse(value); }; -let csrfHeader = {}; +const csrfHeader = {}; -function setCSRFHeader() { +const setCSRFHeader = () => { const csrfToken = document.querySelector('meta[name=csrf-token]'); + if (csrfToken) { csrfHeader['X-CSRF-Token'] = csrfToken.content; } -} +}; ready(setCSRFHeader); +const authorizationHeaderFromState = getState => { + const accessToken = getState && getState().getIn(['meta', 'access_token'], ''); + + if (!accessToken) { + return {}; + } + + return { + 'Authorization': `Bearer ${accessToken}`, + }; +}; + export default getState => axios.create({ - headers: Object.assign(csrfHeader, getState ? { - 'Authorization': `Bearer ${getState().getIn(['meta', 'access_token'], '')}`, - } : {}), + headers: { + ...csrfHeader, + ...authorizationHeaderFromState(getState), + }, transformResponse: [function (data) { try { -- cgit From 188d66c9a81b508fd6c036aaff05048c47d1ea72 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 27 Sep 2021 07:23:48 +0200 Subject: [Glitch] Add aliases for WebUI routes that were renamed in #16171 Port 11502ae46e4813bc23aeb5d03093a01d53991ab8 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/actions/compose.js | 2 +- .../glitch/features/account_gallery/index.js | 12 ++++++---- .../glitch/features/account_timeline/index.js | 7 +++--- .../flavours/glitch/features/followers/index.js | 11 +++++---- .../flavours/glitch/features/following/index.js | 11 +++++---- .../flavours/glitch/features/ui/index.js | 27 ++++++++++++++-------- 6 files changed, 43 insertions(+), 27 deletions(-) (limited to 'app/javascript/flavours/glitch/features/ui') diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index ac6e7f0c4..96931546c 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -177,7 +177,7 @@ export function submitCompose(routerHistory) { }, }).then(function (response) { if (routerHistory - && routerHistory.location.pathname === '/publish' + && (routerHistory.location.pathname === '/publish' || routerHistory.location.pathname === '/statuses/new') && window.history.state && !getState().getIn(['compose', 'advanced_options', 'threaded_mode'])) { routerHistory.goBack(); diff --git a/app/javascript/flavours/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js index 508f49107..8df1bf4ca 100644 --- a/app/javascript/flavours/glitch/features/account_gallery/index.js +++ b/app/javascript/flavours/glitch/features/account_gallery/index.js @@ -2,7 +2,7 @@ import React from 'react'; import { connect } from 'react-redux'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; -import { fetchAccount } from 'flavours/glitch/actions/accounts'; +import { lookupAccount, fetchAccount } from 'flavours/glitch/actions/accounts'; import { expandAccountMediaTimeline } from 'flavours/glitch/actions/timelines'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import Column from 'flavours/glitch/features/ui/components/column'; @@ -16,8 +16,8 @@ import LoadMore from 'flavours/glitch/components/load_more'; import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import { openModal } from 'flavours/glitch/actions/modal'; -const mapStateToProps = (state, { params: { acct } }) => { - const accountId = state.getIn(['accounts_map', acct]); +const mapStateToProps = (state, { params: { acct, id } }) => { + const accountId = id || state.getIn(['accounts_map', acct]); if (!accountId) { return { @@ -62,7 +62,8 @@ class AccountGallery extends ImmutablePureComponent { static propTypes = { params: PropTypes.shape({ - acct: PropTypes.string.isRequired, + acct: PropTypes.string, + id: PropTypes.string, }).isRequired, accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, @@ -79,8 +80,9 @@ class AccountGallery extends ImmutablePureComponent { }; _load () { - const { accountId, dispatch } = this.props; + const { accountId, isAccount, dispatch } = this.props; + if (!isAccount) dispatch(fetchAccount(accountId)); dispatch(expandAccountMediaTimeline(accountId)); } diff --git a/app/javascript/flavours/glitch/features/account_timeline/index.js b/app/javascript/flavours/glitch/features/account_timeline/index.js index 3d2bbb3b7..0d091579d 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/index.js +++ b/app/javascript/flavours/glitch/features/account_timeline/index.js @@ -19,8 +19,8 @@ import TimelineHint from 'flavours/glitch/components/timeline_hint'; const emptyList = ImmutableList(); -const mapStateToProps = (state, { params: { acct }, withReplies = false }) => { - const accountId = state.getIn(['accounts_map', acct]); +const mapStateToProps = (state, { params: { acct, id }, withReplies = false }) => { + const accountId = id || state.getIn(['accounts_map', acct]); if (!accountId) { return { @@ -56,7 +56,8 @@ class AccountTimeline extends ImmutablePureComponent { static propTypes = { params: PropTypes.shape({ - acct: PropTypes.string.isRequired, + acct: PropTypes.string, + id: PropTypes.string, }).isRequired, accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, diff --git a/app/javascript/flavours/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js index 21e25b869..978436dcc 100644 --- a/app/javascript/flavours/glitch/features/followers/index.js +++ b/app/javascript/flavours/glitch/features/followers/index.js @@ -6,6 +6,7 @@ import { debounce } from 'lodash'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { lookupAccount, + fetchAccount, fetchFollowers, expandFollowers, } from 'flavours/glitch/actions/accounts'; @@ -19,8 +20,8 @@ import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; import TimelineHint from 'flavours/glitch/components/timeline_hint'; -const mapStateToProps = (state, { params: { acct } }) => { - const accountId = state.getIn(['accounts_map', acct]); +const mapStateToProps = (state, { params: { acct, id } }) => { + const accountId = id || state.getIn(['accounts_map', acct]); if (!accountId) { return { @@ -52,7 +53,8 @@ class Followers extends ImmutablePureComponent { static propTypes = { params: PropTypes.shape({ - acct: PropTypes.string.isRequired, + acct: PropTypes.string, + id: PropTypes.string, }).isRequired, accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, @@ -66,8 +68,9 @@ class Followers extends ImmutablePureComponent { }; _load () { - const { accountId, dispatch } = this.props; + const { accountId, isAccount, dispatch } = this.props; + if (!isAccount) dispatch(fetchAccount(accountId)); dispatch(fetchFollowers(accountId)); } diff --git a/app/javascript/flavours/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js index c1d026d98..446a19894 100644 --- a/app/javascript/flavours/glitch/features/following/index.js +++ b/app/javascript/flavours/glitch/features/following/index.js @@ -6,6 +6,7 @@ import { debounce } from 'lodash'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { lookupAccount, + fetchAccount, fetchFollowing, expandFollowing, } from 'flavours/glitch/actions/accounts'; @@ -19,8 +20,8 @@ import MissingIndicator from 'flavours/glitch/components/missing_indicator'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; import TimelineHint from 'flavours/glitch/components/timeline_hint'; -const mapStateToProps = (state, { params: { acct } }) => { - const accountId = state.getIn(['accounts_map', acct]); +const mapStateToProps = (state, { params: { acct, id } }) => { + const accountId = id || state.getIn(['accounts_map', acct]); if (!accountId) { return { @@ -52,7 +53,8 @@ class Following extends ImmutablePureComponent { static propTypes = { params: PropTypes.shape({ - acct: PropTypes.string.isRequired, + acct: PropTypes.string, + id: PropTypes.string, }).isRequired, accountId: PropTypes.string, dispatch: PropTypes.func.isRequired, @@ -66,8 +68,9 @@ class Following extends ImmutablePureComponent { }; _load () { - const { accountId, dispatch } = this.props; + const { accountId, isAccount, dispatch } = this.props; + if (!isAccount) dispatch(fetchAccount(accountId)); dispatch(fetchFollowing(accountId)); } diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 4683f11cd..7ca1adf7c 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -200,10 +200,10 @@ class SwitchingColumnsArea extends React.PureComponent { - - - - + + + + @@ -215,17 +215,24 @@ class SwitchingColumnsArea extends React.PureComponent { - + - - - - - + + + + + + {/* Legacy routes, cannot be easily factored with other routes because they share a param name */} + + + + + + -- cgit From 345b64340bd3dfae4e127eeba1cb7fbdd0a2763d Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 27 Sep 2021 07:24:04 +0200 Subject: [Glitch] Fix incorrect use of old WebUI paths Port 6b19e1e632491117bb1d3458fff31cd353b761b7 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/features/direct_timeline/components/conversation.js | 2 +- .../glitch/features/follow_recommendations/components/account.js | 2 +- app/javascript/flavours/glitch/features/follow_recommendations/index.js | 2 +- app/javascript/flavours/glitch/features/ui/components/columns_area.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'app/javascript/flavours/glitch/features/ui') diff --git a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js index 9796ded65..202d96676 100644 --- a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js +++ b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js @@ -104,7 +104,7 @@ class Conversation extends ImmutablePureComponent { markRead(); } - this.context.router.history.push(`/statuses/${lastStatus.get('id')}`); + this.context.router.history.push(`/@${lastStatus.getIn(['account', 'acct'])}/${lastStatus.get('id')}`); } handleMarkAsRead = () => { diff --git a/app/javascript/flavours/glitch/features/follow_recommendations/components/account.js b/app/javascript/flavours/glitch/features/follow_recommendations/components/account.js index 046d03a9b..2c668da3e 100644 --- a/app/javascript/flavours/glitch/features/follow_recommendations/components/account.js +++ b/app/javascript/flavours/glitch/features/follow_recommendations/components/account.js @@ -66,7 +66,7 @@ class Account extends ImmutablePureComponent { return (
- +
diff --git a/app/javascript/flavours/glitch/features/follow_recommendations/index.js b/app/javascript/flavours/glitch/features/follow_recommendations/index.js index fee4d8757..d050e3cc7 100644 --- a/app/javascript/flavours/glitch/features/follow_recommendations/index.js +++ b/app/javascript/flavours/glitch/features/follow_recommendations/index.js @@ -68,7 +68,7 @@ class FollowRecommendations extends ImmutablePureComponent { } })); - router.history.push('/timelines/home'); + router.history.push('/home'); } render () { diff --git a/app/javascript/flavours/glitch/features/ui/components/columns_area.js b/app/javascript/flavours/glitch/features/ui/components/columns_area.js index 5ab8f249d..e39a31e5d 100644 --- a/app/javascript/flavours/glitch/features/ui/components/columns_area.js +++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.js @@ -47,7 +47,7 @@ const componentMap = { 'DIRECTORY': Directory, }; -const shouldHideFAB = path => path.match(/^\/statuses\/|^\/search|^\/getting-started|^\/start/); +const shouldHideFAB = path => path.match(/^\/statuses\/|^\/@[^/]+\/\d+|^\/publish|^\/search|^\/getting-started|^\/start/); const messages = defineMessages({ publish: { id: 'compose_form.publish', defaultMessage: 'Toot' }, -- cgit