...
 
Commits (2)
import React from 'react';
import PropTypes from 'prop-types';
import illustration from '../../images/elephant_ui_disappointed.svg';
export default class ErrorBoundary extends React.PureComponent {
static propTypes = {
children: PropTypes.node,
};
state = {
hasError: false,
stackTrace: undefined,
componentStack: undefined,
}
componentDidCatch(error, info) {
this.setState({
hasError: true,
stackTrace: error.stack,
componentStack: info && info.componentStack,
});
}
render() {
const { hasError } = this.state;
if (!hasError) {
return this.props.children;
}
return (
<div>
<img src={illustration} alt='' />
</div>
);
}
}
......@@ -13,6 +13,7 @@ import { connectUserStream } from '../actions/streaming';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from '../locales';
import initialState from '../initial_state';
import ErrorBoundary from '../components/error_boundary';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
......@@ -75,7 +76,9 @@ export default class Mastodon extends React.PureComponent {
return (
<IntlProvider locale={locale} messages={messages}>
<Provider store={store}>
<MastodonMount />
<ErrorBoundary>
<MastodonMount />
</ErrorBoundary>
</Provider>
</IntlProvider>
);
......
......@@ -53,6 +53,11 @@ class Bundle extends React.PureComponent {
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();
}
onFetch();
if (cachedMod) {
......
......@@ -10,10 +10,7 @@
= image_tag invite.user.account.avatar.url(:original), alt: '', width: 16, height: 16, class: 'avatar'
%span.username= invite.user.account.username
- if invite.expired?
%td{ colspan: 2 }
= t('invites.expired')
- else
- if invite.valid_for_use?
%td
= fa_icon 'user fw'
= invite.uses
......@@ -24,6 +21,10 @@
- else
%time.formatted{ datetime: invite.expires_at.iso8601, title: l(invite.expires_at) }
= l invite.expires_at
- else
%td{ colspan: 2 }
= t('invites.expired')
%td
- if !invite.expired? && policy(invite).destroy?
- if invite.valid_for_use? && policy(invite).destroy?
= table_link_to 'times', t('invites.delete'), admin_invite_path(invite), method: :delete
......@@ -5,10 +5,7 @@
%input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: public_invite_url(invite_code: invite.code) }
%button{ type: :button }= t('generic.copy')
- if invite.expired?
%td{ colspan: 2 }
= t('invites.expired')
- else
- if invite.valid_for_use?
%td
= fa_icon 'user fw'
= invite.uses
......@@ -19,7 +16,10 @@
- else
%time.formatted{ datetime: invite.expires_at.iso8601, title: l(invite.expires_at) }
= l invite.expires_at
- else
%td{ colspan: 2 }
= t('invites.expired')
%td
- if !invite.expired? && policy(invite).destroy?
- if invite.valid_for_use? && policy(invite).destroy?
= table_link_to 'times', t('invites.delete'), invite_path(invite), method: :delete