This commit is contained in:
mgabdev
2020-02-22 18:26:23 -05:00
parent bebc39f150
commit d255982ec5
39 changed files with 1054 additions and 885 deletions

View File

@@ -10,7 +10,6 @@ import {
import StatusListContainer from '../../containers/status_list_container';;
// import ColumnSettingsContainer from '.containers/column_settings_container';
import Column from '../../components/column';
// import { HomeColumnHeader } from '../../components/column_header';
const messages = defineMessages({
title: { id: 'column.community', defaultMessage: 'Community timeline' },
@@ -100,9 +99,6 @@ class CommunityTimeline extends PureComponent {
return (
<Column label={intl.formatMessage(messages.title)}>
{ /* <HomeColumnHeader activeItem='all' active={hasUnread} >
<ColumnSettingsContainer />
</HomeColumnHeader> */ }
<StatusListContainer
scrollKey={`${timelineId}_timeline`}
timelineId={`${timelineId}${onlyMedia ? ':media' : ''}`}

View File

@@ -0,0 +1,44 @@
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { fetchGroups } from '../../actions/groups'
import Block from '../../components/block'
import GroupCollectionItem from '../../components/group_collection_item'
const mapStateToProps = (state, { activeTab }) => ({
groupIds: state.getIn(['group_lists', activeTab]),
})
export default @connect(mapStateToProps)
class GroupsCollection extends ImmutablePureComponent {
static propTypes = {
activeTab: PropTypes.string.isRequired,
dispatch: PropTypes.func.isRequired,
groupIds: ImmutablePropTypes.list,
}
componentWillMount() {
this.props.dispatch(fetchGroups(this.props.activeTab))
}
componentDidUpdate(oldProps) {
if (this.props.activeTab && this.props.activeTab !== oldProps.activeTab) {
this.props.dispatch(fetchGroups(this.props.activeTab))
}
}
render() {
const { groupIds } = this.props
console.log("groupIds: ", groupIds)
return (
<div className={[_s.default, _s.flexRow, _s.flexWrap].join(' ')}>
{
groupIds.map((groupId, i) => (
<GroupCollectionItem key={`group-collection-item-${i}`} id={groupId} />
))
}
</div>
)
}
}

View File

@@ -0,0 +1 @@
export { default } from './groups_collection';

View File

@@ -1,104 +0,0 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { Link } from 'react-router-dom';
import classNames from 'classnames';
import { fetchGroups } from '../../../actions/groups';
import { openModal } from '../../../actions/modal';
import { me } from '../../../initial_state';
import GroupCard from './card';
import GroupCreate from '../create';
const messages = defineMessages({
heading: { id: 'column.groups', defaultMessage: 'Groups' },
create: { id: 'groups.create', defaultMessage: 'Create group' },
tab_featured: { id: 'groups.tab_featured', defaultMessage: 'Featured' },
tab_member: { id: 'groups.tab_member', defaultMessage: 'Member' },
tab_admin: { id: 'groups.tab_admin', defaultMessage: 'Manage' },
});
const mapStateToProps = (state, { activeTab }) => ({
groupIds: state.getIn(['group_lists', activeTab]),
account: state.getIn(['accounts', me]),
});
export default @connect(mapStateToProps)
@injectIntl
class Groups extends ImmutablePureComponent {
static propTypes = {
params: PropTypes.object.isRequired,
activeTab: PropTypes.string.isRequired,
showCreateForm: PropTypes.bool,
dispatch: PropTypes.func.isRequired,
groups: ImmutablePropTypes.map,
groupIds: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired,
};
componentWillMount () {
this.props.dispatch(fetchGroups(this.props.activeTab));
}
componentDidUpdate(oldProps) {
if (this.props.activeTab && this.props.activeTab !== oldProps.activeTab) {
this.props.dispatch(fetchGroups(this.props.activeTab));
}
}
handleOpenProUpgradeModal = () => {
this.props.dispatch(openModal('PRO_UPGRADE'));
}
renderHeader() {
const { intl, activeTab, account, onOpenProUpgradeModal } = this.props;
const isPro = account.get('is_pro');
return (
<div className="group-column-header">
<div className="group-column-header__cta">
{
account && isPro &&
<Link to="/groups/create" className="button standard-small">{intl.formatMessage(messages.create)}</Link>
}
{
account && !isPro &&
<button onClick={this.handleOpenProUpgradeModal} className="button standard-small">{intl.formatMessage(messages.create)}</button>
}
</div>
<div className="group-column-header__title">{intl.formatMessage(messages.heading)}</div>
<div className="column-header__wrapper">
<h1 className="column-header">
<Link to='/groups' className={classNames('btn grouped', {'active': 'featured' === activeTab})}>
{intl.formatMessage(messages.tab_featured)}
</Link>
<Link to='/groups/browse/member' className={classNames('btn grouped', {'active': 'member' === activeTab})}>
{intl.formatMessage(messages.tab_member)}
</Link>
<Link to='/groups/browse/admin' className={classNames('btn grouped', {'active': 'admin' === activeTab})}>
{intl.formatMessage(messages.tab_admin)}
</Link>
</h1>
</div>
</div>
);
}
render () {
const { groupIds, showCreateForm } = this.props;
return (
<div>
{!showCreateForm && this.renderHeader()}
{showCreateForm && <GroupCreate /> }
<div className="group-card-list">
{groupIds.map(id => <GroupCard key={id} id={id} />)}
</div>
</div>
);
}
}

View File

@@ -1 +0,0 @@
export { default } from './groups_directory';

View File

@@ -4,7 +4,6 @@ import { expandHashtagTimeline, clearTimeline } from '../../actions/timelines';
import { connectHashtagStream } from '../../actions/streaming';
import StatusListContainer from '../../containers/status_list_container';
import Column from '../../components/column';
import { ColumnHeader } from '../../components/column_header';
const mapStateToProps = (state, props) => ({
hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0,
@@ -104,7 +103,6 @@ class HashtagTimeline extends PureComponent {
return (
<Column heading={`#${id}`}>
<ColumnHeader icon='hashtag' active={hasUnread} title={this.title()} />
<StatusListContainer
scrollKey='hashtag_timeline'
timelineId={`hashtag:${id}`}

View File

@@ -131,6 +131,8 @@ class Notifications extends ImmutablePureComponent {
// ? (<FilterBarContainer />)
// : null;
// : todo : include follow requests
console.log("notifications:", notifications)
if (isLoading && this.scrollableContent) {

View File

@@ -444,7 +444,7 @@ class Status extends ImmutablePureComponent {
return (
<Column heading={intl.formatMessage(messages.detailedStatus)}>
{ me &&
{ /* me &&
<ColumnHeader
extraButton={(
<button
@@ -461,7 +461,7 @@ class Status extends ImmutablePureComponent {
</button>
)}
/>
}
*/ }
<div ref={this.setRef}>
{ancestors}

View File

@@ -15,19 +15,17 @@ import { fetchFilters } from '../../actions/filters';
import { clearHeight } from '../../actions/height_cache';
import { openModal } from '../../actions/modal';
import WrappedRoute from './util/wrapped_route';
import { isMobile } from '../../utils/is_mobile';
// import NotificationsContainer from '../../containers/notifications_container';
// import LoadingBarContainer from '../../containers/loading_bar_container';
// import ModalContainer from '../../containers/modal_container';
// import UploadArea from '../../components/upload_area';
// import FooterBar from '../../components/footer_bar';
// import TrendsPanel from './components/trends_panel';
// import { WhoToFollowPanel } from '../../components/panel';
// import LinkFooter from '../../components/link_footer';
import ProfilePage from '../../pages/profile_page'
// import GroupsPage from 'gabsocial/pages/groups_page';
// import GroupPage from '../../pages/group_page';
// import SearchPage from '../../pages/search_page';
import GroupsPage from '../../pages/groups_page'
import SearchPage from '../../pages/search_page'
import ErrorPage from '../../pages/error_page'
import HomePage from '../../pages/home_page'
import NotificationsPage from '../../pages/notifications_page'
import ListPage from '../../pages/list_page'
@@ -49,15 +47,15 @@ import {
// HashtagTimeline,
Notifications,
// FollowRequests,
// GenericNotFound,
GenericNotFound,
// FavouritedStatuses,
// Blocks,
// DomainBlocks,
// Mutes,
// PinnedStatuses,
// Search,
Search,
// Explore,
// Groups,
GroupsCollection,
// GroupTimeline,
ListTimeline,
ListsDirectory,
@@ -113,36 +111,7 @@ const keyMap = {
toggleSensitive: 'h',
};
const LAYOUT = {
// EMPTY: {
// LEFT: null,
// RIGHT: null,
// },
// DEFAULT: {
// LEFT: [
// <WhoToFollowPanel key='0' />,
// <LinkFooter key='1' />,
// ],
// RIGHT: [
// // <TrendsPanel />,
// <GroupSidebarPanel key='0' />
// ],
// },
// STATUS: {
// TOP: null,
// LEFT: null,
// RIGHT: [
// <GroupSidebarPanel key='0' />,
// <WhoToFollowPanel key='1' />,
// // <TrendsPanel />,
// <LinkFooter key='2' />,
// ],
// },
};
const shouldHideFAB = path => path.match(/^\/posts\/|^\/search|^\/getting-started/);
class SwitchingColumnsArea extends PureComponent {
class SwitchingArea extends PureComponent {
static propTypes = {
children: PropTypes.node,
@@ -150,69 +119,76 @@ class SwitchingColumnsArea extends PureComponent {
onLayoutChange: PropTypes.func.isRequired,
};
state = {
mobile: isMobile(window.innerWidth),
};
componentWillMount() {
window.addEventListener('resize', this.handleResize, { passive: true });
window.addEventListener('resize', this.handleResize, {
passive: true
})
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize);
window.removeEventListener('resize', this.handleResize)
}
handleResize = debounce(() => {
// The cached heights are no longer accurate, invalidate
this.props.onLayoutChange();
this.setState({ mobile: isMobile(window.innerWidth) });
this.props.onLayoutChange()
}, 500, {
trailing: true,
});
})
setRef = c => {
this.node = c.getWrappedInstance();
this.node = c.getWrappedInstance()
}
render() {
const { children } = this.props;
const { children } = this.props
return (
<Switch>
<Redirect from='/' to='/home' exact />
<WrappedRoute path='/home' exact page={HomePage} component={HomeTimeline} content={children} />
{/*<WrappedRoute path='/timeline/all' exact page={HomePage} component={CommunityTimeline} content={children} />
<WrappedRoute path='/groups' exact page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'featured' }} />
{/*<WrappedRoute path='/timeline/all' exact page={HomePage} component={CommunityTimeline} content={children} />*/}
<WrappedRoute path='/groups' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'featured' }} />
<WrappedRoute path='/groups/browse/member' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'member' }} />
<WrappedRoute path='/groups/browse/admin' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'admin' }} />
{ /*
<WrappedRoute path='/groups/create' page={GroupsPage} component={Groups} content={children} componentParams={{ showCreateForm: true, activeTab: 'featured' }} />
<WrappedRoute path='/groups/browse/member' page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'member' }} />
<WrappedRoute path='/groups/browse/admin' page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'admin' }} />
<WrappedRoute path='/groups/:id/members' page={GroupPage} component={GroupMembers} content={children} />
<WrappedRoute path='/groups/:id/removed_accounts' page={GroupPage} component={GroupRemovedAccounts} content={children} />
<WrappedRoute path='/groups/:id/edit' page={GroupPage} component={GroupEdit} content={children} />
<WrappedRoute path='/groups/:id' page={GroupPage} component={GroupTimeline} content={children} />
<WrappedRoute path='/tags/:id' publicRoute component={HashtagTimeline} content={children} />
*/}
<WrappedRoute path='/lists' page={ListsPage} component={ListsDirectory} content={children} />
*/ }
<WrappedRoute path='/lists' exact page={ListsPage} component={ListsDirectory} content={children} />
<WrappedRoute path='/list/:id' page={ListPage} component={ListTimeline} content={children} />
<WrappedRoute path='/notifications' page={NotificationsPage} component={Notifications} content={children} />
{/*
<WrappedRoute path='/notifications' exact page={NotificationsPage} component={Notifications} content={children} />
<WrappedRoute path='/search' exact publicRoute page={SearchPage} component={Search} content={children} />
<WrappedRoute path='/search/people' exact page={SearchPage} component={Search} content={children} />
<WrappedRoute path='/search/hashtags' exact page={SearchPage} component={Search} content={children} />
<WrappedRoute path='/search/groups' exact page={SearchPage} component={Search} content={children} />
<WrappedRoute path='/follow_requests' layout={LAYOUT.DEFAULT} component={FollowRequests} content={children} />
<WrappedRoute path='/blocks' layout={LAYOUT.DEFAULT} component={Blocks} content={children} />
<WrappedRoute path='/domain_blocks' layout={LAYOUT.DEFAULT} component={DomainBlocks} content={children} />
<WrappedRoute path='/mutes' layout={LAYOUT.DEFAULT} component={Mutes} content={children} />
{/*
<WrappedRoute path='/settings/account' exact page={SettingsPage} component={Mutes} content={children} />
<WrappedRoute path='/settings/profile' exact page={SettingsPage} component={Mutes} content={children} />
<WrappedRoute path='/settings/domain_blocks' exact page={SettingsPage} component={DomainBlocks} content={children} />
<WrappedRoute path='/settings/relationships' exact page={SettingsPage} component={DomainBlocks} content={children} />
<WrappedRoute path='/settings/filters' exact page={SettingsPage} component={DomainBlocks} content={children} />
<WrappedRoute path='/settings/blocks' exact page={SettingsPage} component={Blocks} content={children} />
<WrappedRoute path='/settings/mutes' exact page={SettingsPage} component={Mutes} content={children} />
<WrappedRoute path='/settings/development' exact page={SettingsPage} component={Mutes} content={children} />
<WrappedRoute path='/settings/billing' exact page={SettingsPage} component={Mutes} content={children} />
*/ }
<Redirect from='/@:username' to='/:username' exact />
<WrappedRoute path='/:username' publicRoute exact component={AccountTimeline} page={ProfilePage} content={children} />
{ /*
<WrappedRoute path='/:username' publicRoute exact page={ProfilePage} component={AccountTimeline} content={children} />
{ /*
<Redirect from='/@:username/with_replies' to='/:username/with_replies' />
<WrappedRoute path='/:username/with_replies' component={AccountTimeline} page={ProfilePage} content={children} componentParams={{ withReplies: true }} />
@@ -233,27 +209,30 @@ class SwitchingColumnsArea extends PureComponent {
<Redirect from='/@:username/pins' to='/:username/pins' />
<WrappedRoute path='/:username/pins' component={PinnedStatuses} page={ProfilePage} content={children} />
*/ }
<Redirect from='/@:username/posts/:statusId' to='/:username/posts/:statusId' exact />
<WrappedRoute path='/:username/posts/:statusId' publicRoute exact layout={LAYOUT.STATUS} component={Status} content={children} />
<WrappedRoute path='/:username/posts/:statusId' publicRoute exact component={Status} content={children} />
*/ }
{ /*
<Redirect from='/@:username/posts/:statusId/reblogs' to='/:username/posts/:statusId/reblogs' />
<WrappedRoute path='/:username/posts/:statusId/reblogs' layout={LAYOUT.STATUS} component={Reblogs} content={children} />
<WrappedRoute layout={LAYOUT.EMPTY} component={GenericNotFound} content={children} />*/}
<WrappedRoute path='/:username/posts/:statusId/reblogs' component={Reblogs} content={children} />
*/}
<WrappedRoute page={ErrorPage} component={GenericNotFound} content={children} />
</Switch>
);
}
}
export default @connect(mapStateToProps)
export default
@connect(mapStateToProps)
@injectIntl
@withRouter
class UI extends PureComponent {
static contextTypes = {
router: PropTypes.object.isRequired,
};
}
static propTypes = {
dispatch: PropTypes.func.isRequired,
@@ -264,69 +243,79 @@ class UI extends PureComponent {
location: PropTypes.object,
intl: PropTypes.object.isRequired,
dropdownMenuIsOpen: PropTypes.bool,
};
}
state = {
draggingOver: false,
};
}
handleBeforeUnload = (e) => {
const { intl, isComposing, hasComposingText, hasMediaAttachments } = this.props;
const {
intl,
isComposing,
hasComposingText,
hasMediaAttachments
} = this.props
if (isComposing && (hasComposingText || hasMediaAttachments)) {
// Setting returnValue to any string causes confirmation dialog.
// Many browsers no longer display this text to users,
// but we set user-friendly message for other browsers, e.g. Edge.
e.returnValue = intl.formatMessage(messages.beforeUnload);
e.returnValue = intl.formatMessage(messages.beforeUnload)
}
}
handleLayoutChange = () => {
// The cached heights are no longer accurate, invalidate
this.props.dispatch(clearHeight());
this.props.dispatch(clearHeight())
}
handleDragEnter = (e) => {
e.preventDefault();
e.preventDefault()
if (!this.dragTargets) {
this.dragTargets = [];
this.dragTargets = []
}
if (this.dragTargets.indexOf(e.target) === -1) {
this.dragTargets.push(e.target);
this.dragTargets.push(e.target)
}
if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files')) {
this.setState({ draggingOver: true });
this.setState({
draggingOver: true
})
}
}
handleDragOver = (e) => {
if (this.dataTransferIsText(e.dataTransfer)) return false;
e.preventDefault();
e.stopPropagation();
if (this.dataTransferIsText(e.dataTransfer)) return false
e.preventDefault()
e.stopPropagation()
try {
e.dataTransfer.dropEffect = 'copy';
} catch (err) {
//
}
return false;
return false
}
handleDrop = (e) => {
if (!me) return;
if (!me) return
if (this.dataTransferIsText(e.dataTransfer)) return;
e.preventDefault();
if (this.dataTransferIsText(e.dataTransfer)) return
e.preventDefault()
this.setState({ draggingOver: false });
this.dragTargets = [];
this.setState({
draggingOver: false
})
this.dragTargets = []
if (e.dataTransfer && e.dataTransfer.files.length >= 1) {
this.props.dispatch(uploadCompose(e.dataTransfer.files));
this.props.dispatch(uploadCompose(e.dataTransfer.files))
}
}
@@ -336,19 +325,25 @@ class UI extends PureComponent {
this.dragTargets = this.dragTargets.filter(el => el !== e.target && this.node.contains(el));
if (this.dragTargets.length > 0) {
return;
}
if (this.dragTargets.length > 0) return
this.setState({ draggingOver: false });
this.setState({
draggingOver: false
})
}
dataTransferIsText = (dataTransfer) => {
return (dataTransfer && Array.from(dataTransfer.types).includes('text/plain') && dataTransfer.items.length === 1);
return (
dataTransfer
&& Array.from(dataTransfer.types).includes('text/plain')
&& dataTransfer.items.length === 1
)
}
closeUploadModal = () => {
this.setState({ draggingOver: false });
this.setState({
draggingOver: false
})
}
handleServiceWorkerPostMessage = ({ data }) => {
@@ -388,6 +383,7 @@ class UI extends PureComponent {
componentDidMount() {
if (!me) return;
this.hotkeys.__mousetrap__.stopCallback = (e, element) => {
return ['TEXTAREA', 'SELECT', 'INPUT'].includes(element.tagName);
};
@@ -451,9 +447,9 @@ class UI extends PureComponent {
handleHotkeyBack = () => {
if (window.history && window.history.length === 1) {
this.context.router.history.push('/home'); // homehack
this.context.router.history.push('/home') // homehack
} else {
this.context.router.history.goBack();
this.context.router.history.goBack()
}
}
@@ -462,52 +458,52 @@ class UI extends PureComponent {
}
handleHotkeyToggleHelp = () => {
this.props.dispatch(openModal("HOTKEYS"));
this.props.dispatch(openModal("HOTKEYS"))
}
handleHotkeyGoToHome = () => {
this.context.router.history.push('/home');
this.context.router.history.push('/home')
}
handleHotkeyGoToNotifications = () => {
this.context.router.history.push('/notifications');
this.context.router.history.push('/notifications')
}
handleHotkeyGoToStart = () => {
this.context.router.history.push('/getting-started');
this.context.router.history.push('/getting-started')
}
handleHotkeyGoToFavourites = () => {
this.context.router.history.push(`/${meUsername}/favorites`);
this.context.router.history.push(`/${meUsername}/favorites`)
}
handleHotkeyGoToPinned = () => {
this.context.router.history.push(`/${meUsername}/pins`);
this.context.router.history.push(`/${meUsername}/pins`)
}
handleHotkeyGoToProfile = () => {
this.context.router.history.push(`/${meUsername}`);
this.context.router.history.push(`/${meUsername}`)
}
handleHotkeyGoToBlocked = () => {
this.context.router.history.push('/blocks');
this.context.router.history.push('/blocks')
}
handleHotkeyGoToMuted = () => {
this.context.router.history.push('/mutes');
this.context.router.history.push('/mutes')
}
handleHotkeyGoToRequests = () => {
this.context.router.history.push('/follow_requests');
this.context.router.history.push('/follow_requests')
}
handleOpenComposeModal = () => {
this.props.dispatch(openModal("COMPOSE"));
this.props.dispatch(openModal("COMPOSE"))
}
render() {
const { draggingOver } = this.state;
const { intl, children, isComposing, location, dropdownMenuIsOpen } = this.props;
const { children, location, dropdownMenuIsOpen } = this.props;
const handlers = me ? {
help: this.handleHotkeyToggleHelp,
@@ -527,21 +523,29 @@ class UI extends PureComponent {
goToRequests: this.handleHotkeyGoToRequests,
} : {};
const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <button key='floating-action-button' onClick={this.handleOpenComposeModal} className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}></button>;
return (
<HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef} attach={window} focused>
<div ref={this.setRef} style={{ pointerEvents: dropdownMenuIsOpen ? 'none' : null }}>
<SwitchingColumnsArea location={location} onLayoutChange={this.handleLayoutChange}>
<HotKeys
keyMap={keyMap}
handlers={handlers}
ref={this.setHotkeysRef}
attach={window}
focused
>
<div
ref={this.setRef}
style={{
pointerEvents: dropdownMenuIsOpen ? 'none' : null
}}
>
<SwitchingArea
location={location}
onLayoutChange={this.handleLayoutChange}
>
{children}
</SwitchingColumnsArea>
{ /* <FooterBar /> */ }
{ /* me && floatingActionButton */ }
</SwitchingArea>
{ /*
<NotificationsContainer />
<LoadingBarContainer className='loading-bar' />
<ModalContainer />
<UploadArea active={draggingOver} onClose={this.closeUploadModal} />
*/ }

View File

@@ -1,143 +1,143 @@
export function EmojiPicker () {
return import(/* webpackChunkName: "emoji_picker" */'../../../components/emoji/emoji_picker');
export function EmojiPicker() {
return import(/* webpackChunkName: "emoji_picker" */'../../../components/emoji/emoji_picker')
}
export function Compose () {
return import(/* webpackChunkName: "features/compose" */'../../compose');
export function Compose() {
return import(/* webpackChunkName: "features/compose" */'../../compose')
}
export function Notifications () {
return import(/* webpackChunkName: "features/notifications" */'../../notifications');
export function Notifications() {
return import(/* webpackChunkName: "features/notifications" */'../../notifications')
}
export function HomeTimeline () {
return import(/* webpackChunkName: "features/home_timeline" */'../../home_timeline');
export function HomeTimeline() {
return import(/* webpackChunkName: "features/home_timeline" */'../../home_timeline')
}
export function CommunityTimeline () {
return import(/* webpackChunkName: "features/community_timeline" */'../../community_timeline');
export function CommunityTimeline() {
return import(/* webpackChunkName: "features/community_timeline" */'../../community_timeline')
}
export function HashtagTimeline () {
return import(/* webpackChunkName: "features/hashtag_timeline" */'../../hashtag_timeline');
export function HashtagTimeline() {
return import(/* webpackChunkName: "features/hashtag_timeline" */'../../hashtag_timeline')
}
export function ListTimeline () {
return import(/* webpackChunkName: "features/list_timeline" */'../../list_timeline');
export function ListTimeline() {
return import(/* webpackChunkName: "features/list_timeline" */'../../list_timeline')
}
export function GroupTimeline () {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/timeline');
export function GroupTimeline() {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/timeline')
}
export function GroupMembers () {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/members');
export function GroupMembers() {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/members')
}
export function GroupRemovedAccounts () {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/removed_accounts');
export function GroupRemovedAccounts() {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/removed_accounts')
}
export function GroupCreate () {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/create');
export function GroupCreate() {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/create')
}
export function GroupEdit () {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/edit');
export function GroupEdit() {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/edit')
}
export function Groups () {
return import(/* webpackChunkName: "features/groups/index" */'../../groups/index');
export function GroupsCollection() {
return import(/* webpackChunkName: "features/groups_collection" */'../../g../../groups_collection')
}
export function ListsDirectory () {
return import(/* webpackChunkName: "features/lists_directory" */'../../lists_directory');
export function ListsDirectory() {
return import(/* webpackChunkName: "features/lists_directory" */'../../lists_directory')
}
export function Status () {
return import(/* webpackChunkName: "features/status" */'../../status');
export function Status() {
return import(/* webpackChunkName: "features/status" */'../../status')
}
export function PinnedStatuses () {
return import(/* webpackChunkName: "features/pinned_statuses" */'../../pinned_statuses');
export function PinnedStatuses() {
return import(/* webpackChunkName: "features/pinned_statuses" */'../../pinned_statuses')
}
export function AccountTimeline () {
return import(/* webpackChunkName: "features/account_timeline" */'../../account_timeline');
export function AccountTimeline() {
return import(/* webpackChunkName: "features/account_timeline" */'../../account_timeline')
}
export function AccountGallery () {
return import(/* webpackChunkName: "features/account_gallery" */'../../account_gallery');
export function AccountGallery() {
return import(/* webpackChunkName: "features/account_gallery" */'../../account_gallery')
}
export function Followers () {
return import(/* webpackChunkName: "features/followers" */'../../followers');
export function Followers() {
return import(/* webpackChunkName: "features/followers" */'../../followers')
}
export function Following () {
return import(/* webpackChunkName: "features/following" */'../../following');
export function Following() {
return import(/* webpackChunkName: "features/following" */'../../following')
}
export function Reblogs () {
return import(/* webpackChunkName: "features/reblogs" */'../../reblogs');
export function Reblogs() {
return import(/* webpackChunkName: "features/reblogs" */'../../reblogs')
}
export function FollowRequests () {
return import(/* webpackChunkName: "features/follow_requests" */'../../follow_requests');
export function FollowRequests() {
return import(/* webpackChunkName: "features/follow_requests" */'../../follow_requests')
}
export function GenericNotFound () {
return import(/* webpackChunkName: "features/generic_not_found" */'../../generic_not_found');
export function GenericNotFound() {
return import(/* webpackChunkName: "features/generic_not_found" */'../../generic_not_found')
}
export function FavouritedStatuses () {
return import(/* webpackChunkName: "features/favourited_statuses" */'../../favourited_statuses');
export function FavouritedStatuses() {
return import(/* webpackChunkName: "features/favourited_statuses" */'../../favourited_statuses')
}
export function Blocks () {
return import(/* webpackChunkName: "features/blocks" */'../../blocks');
export function Blocks() {
return import(/* webpackChunkName: "features/blocks" */'../../blocks')
}
export function DomainBlocks () {
return import(/* webpackChunkName: "features/domain_blocks" */'../../domain_blocks');
export function DomainBlocks() {
return import(/* webpackChunkName: "features/domain_blocks" */'../../domain_blocks')
}
export function Mutes () {
return import(/* webpackChunkName: "features/mutes" */'../../mutes');
export function Mutes() {
return import(/* webpackChunkName: "features/mutes" */'../../mutes')
}
export function MuteModal () {
return import(/* webpackChunkName: "modals/mute_modal" */'../../../components/modal');
export function MuteModal() {
return import(/* webpackChunkName: "modals/mute_modal" */'../../../components/modal')
}
export function StatusRevisionModal () {
return import(/* webpackChunkName: "modals/mute_modal" */'../../../components/modal');
export function StatusRevisionModal() {
return import(/* webpackChunkName: "modals/mute_modal" */'../../../components/modal')
}
export function ReportModal () {
return import(/* webpackChunkName: "modals/report_modal" */'../../../components/modal');
export function ReportModal() {
return import(/* webpackChunkName: "modals/report_modal" */'../../../components/modal')
}
export function MediaGallery () {
return import(/* webpackChunkName: "status/media_gallery" */'../../../components/media_gallery');
export function MediaGallery() {
return import(/* webpackChunkName: "status/media_gallery" */'../../../components/media_gallery')
}
export function Video () {
return import(/* webpackChunkName: "features/video" */'../../video');
export function Video() {
return import(/* webpackChunkName: "features/video" */'../../video')
}
export function EmbedModal () {
return import(/* webpackChunkName: "modals/embed_modal" */'../../../components/modal');
export function EmbedModal() {
return import(/* webpackChunkName: "modals/embed_modal" */'../../../components/modal')
}
export function ListEditor () {
return import(/* webpackChunkName: "features/list_editor" */'../../list_editor');
export function ListEditor() {
return import(/* webpackChunkName: "features/list_editor" */'../../list_editor')
}
export function ListAdder () {
return import(/*webpackChunkName: "features/list_adder" */'../../list_adder');
export function ListAdder() {
return import(/*webpackChunkName: "features/list_adder" */'../../list_adder')
}
export function Search () {
return import(/*webpackChunkName: "features/search" */'../../search');
export function Search() {
return import(/*webpackChunkName: "features/search" */'../../search')
}

View File

@@ -1,21 +1,26 @@
import { fetchBundleRequest, fetchBundleSuccess, fetchBundleFail } from '../../../actions/bundles';
import {
fetchBundleRequest,
fetchBundleSuccess,
fetchBundleFail
} from '../../../actions/bundles'
const mapDispatchToProps = dispatch => ({
onFetch() {
dispatch(fetchBundleRequest());
dispatch(fetchBundleRequest())
},
onFetchSuccess() {
dispatch(fetchBundleSuccess());
dispatch(fetchBundleSuccess())
},
onFetchFail(error) {
dispatch(fetchBundleFail(error));
dispatch(fetchBundleFail(error))
},
});
})
const emptyComponent = () => null;
const noop = () => { };
const emptyComponent = () => null
const noop = () => { }
export default @connect(null, mapDispatchToProps)
export default
@connect(null, mapDispatchToProps)
class Bundle extends PureComponent {
static propTypes = {
@@ -46,69 +51,94 @@ class Bundle extends PureComponent {
}
componentWillMount() {
this.load(this.props);
this.load(this.props)
}
componentWillReceiveProps(nextProps) {
if (nextProps.fetchComponent !== this.props.fetchComponent) {
this.load(nextProps);
this.load(nextProps)
}
}
componentWillUnmount () {
componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
clearTimeout(this.timeout)
}
}
load = (props) => {
const { fetchComponent, onFetch, onFetchSuccess, onFetchFail, renderDelay } = props || this.props;
const cachedMod = Bundle.cache.get(fetchComponent);
const {
fetchComponent,
onFetch,
onFetchSuccess,
onFetchFail,
renderDelay
} = props || this.props
const cachedMod = Bundle.cache.get(fetchComponent)
if (fetchComponent === undefined) {
this.setState({ mod: null });
return Promise.resolve();
this.setState({
mod: null
})
return Promise.resolve()
}
onFetch();
onFetch()
if (cachedMod) {
this.setState({ mod: cachedMod.default });
onFetchSuccess();
return Promise.resolve();
this.setState({
mod: cachedMod.default
})
onFetchSuccess()
return Promise.resolve()
}
this.setState({ mod: undefined });
this.setState({
mod: undefined
})
if (renderDelay !== 0) {
this.timestamp = new Date();
this.timeout = setTimeout(() => this.setState({ forceRender: true }), renderDelay);
this.timestamp = new Date()
this.timeout = setTimeout(() => this.setState({
forceRender: true
}), renderDelay)
}
return fetchComponent()
.then((mod) => {
Bundle.cache.set(fetchComponent, mod);
this.setState({ mod: mod.default });
onFetchSuccess();
Bundle.cache.set(fetchComponent, mod)
this.setState({
mod: mod.default
})
onFetchSuccess()
})
.catch((error) => {
this.setState({ mod: null });
onFetchFail(error);
});
this.setState({
mod: null
})
onFetchFail(error)
})
}
render() {
const { loading: Loading, error: Error, children, renderDelay } = this.props;
const { mod, forceRender } = this.state;
const elapsed = this.timestamp ? (new Date() - this.timestamp) : renderDelay;
const {
loading: LoadingComponent,
error: ErrorComponent,
children,
renderDelay
} = this.props
const { mod, forceRender } = this.state
const elapsed = this.timestamp ? (new Date() - this.timestamp) : renderDelay
if (mod === undefined) {
return (elapsed >= renderDelay || forceRender) ? <Loading /> : null;
return (elapsed >= renderDelay || forceRender) ? <LoadingComponent /> : null
} else if (mod === null) {
return <Error onRetry={this.load} />;
return <ErrorComponent onRetry={this.load} />
}
return children(mod);
return children(mod)
}
}

View File

@@ -1,77 +1,64 @@
import { Route } from 'react-router-dom';
import DefaultLayout from '../../../components/layouts/default_layout';
import BundleColumnError from '../../../components/bundle_column_error';
import Bundle from './bundle';
import { me } from '../../../initial_state';
import ColumnIndicator from '../../../components/column_indicator';
import { Route } from 'react-router-dom'
import BundleColumnError from '../../../components/bundle_column_error'
import Bundle from './bundle'
import { me } from '../../../initial_state'
export default class WrappedRoute extends Component {
static propTypes = {
component: PropTypes.func.isRequired,
page: PropTypes.func,
page: PropTypes.func.isRequired,
content: PropTypes.node,
componentParams: PropTypes.object,
layout: PropTypes.object,
publicRoute: PropTypes.bool,
};
}
static defaultProps = {
componentParams: {},
};
}
renderComponent = ({ match }) => {
const { component, content, componentParams, layout, page: Page } = this.props;
if (Page) {
return (
<Bundle fetchComponent={component} loading={this.renderLoading} error={this.renderError}>
{Component =>
(
<Page params={match.params} {...componentParams}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</Page>
)
}
</Bundle>
);
}
const {
component,
content,
componentParams,
page: Page
} = this.props
return (
<Bundle fetchComponent={component} loading={this.renderLoading} error={this.renderError}>
<Bundle fetchComponent={component} error={this.renderError}>
{Component =>
(
<DefaultLayout layout={layout}>
<Page params={match.params} {...componentParams}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</DefaultLayout>
</Page>
)
}
</Bundle>
);
}
renderLoading = () => {
return <div />
)
}
renderError = (props) => {
return <BundleColumnError {...props} />;
return <BundleColumnError {...props} />
}
render() {
const { component: Component, content, publicRoute, ...rest } = this.props;
const {
component: Component,
content,
publicRoute,
...rest
} = this.props
if (!publicRoute && !me) {
const actualUrl = encodeURIComponent(this.props.computedMatch.url);
const actualUrl = encodeURIComponent(this.props.computedMatch.url)
return <Route path={this.props.path} component={() => {
window.location.href = `/auth/sign_in?redirect_uri=${actualUrl}`;
return null;
window.location.href = `/auth/sign_in?redirect_uri=${actualUrl}`
return null
}} />
}
return <Route {...rest} render={this.renderComponent} />;
return <Route {...rest} render={this.renderComponent} />
}
}