#22: decpouple ApplicationsIndex from HOCs. Create ContactLink component

This commit is contained in:
SleepWalker 2018-05-05 10:42:29 +03:00
parent e66840a391
commit f6b925122f
6 changed files with 57 additions and 51 deletions

View File

@ -0,0 +1,22 @@
// @flow
import React from 'react';
import { connect } from 'react-redux';
import { create as createPopup } from 'components/ui/popup/actions';
import ContactForm from './ContactForm';
function ContactLink({createContactPopup, ...props}: {
createContactPopup: () => void,
props: Object
}) {
return (
<a href="#" onClick={(event) => {
event.preventDefault();
createContactPopup();
}} {...props} />
);
}
export default connect(null, {
createContactPopup: () => createPopup(ContactForm),
})(ContactLink);

View File

@ -0,0 +1,3 @@
// @flow
export { default as ContactLink } from './ContactLink';

View File

@ -1,17 +1,13 @@
// @flow
import type { Node } from 'react';
import type { Location } from 'react-router';
import type { OauthAppResponse } from 'services/api/oauth';
import React, { Component } from 'react';
import { FormattedMessage as Message } from 'react-intl';
import { Helmet } from 'react-helmet';
import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import { create as createPopup } from 'components/ui/popup/actions';
import ContactForm from 'components/contact/ContactForm';
import { LinkButton } from 'components/ui/form';
import { COLOR_GREEN, COLOR_BLUE } from 'components/ui';
import { restoreScroll } from 'components/ui/scroll/scroll';
import { ContactLink } from 'components/contact';
import styles from './applicationsIndex.scss';
import messages from './ApplicationsIndex.intl.json';
@ -21,11 +17,10 @@ import toolsIcon from './icons/tools.svg';
import ApplicationItem from './ApplicationItem';
type Props = {
location: Location,
clientId?: ?string,
displayForGuest: bool,
applications: Array<OauthAppResponse>,
isLoading: bool,
createContactPopup: () => void,
deleteApp: (string) => Promise<any>,
resetApp: (string, bool) => Promise<any>,
};
@ -34,7 +29,7 @@ type State = {
expandedApp: ?string,
};
class ApplicationsIndex extends Component<Props, State> {
export default class ApplicationsIndex extends Component<Props, State> {
state = {
expandedApp: null,
};
@ -42,13 +37,11 @@ class ApplicationsIndex extends Component<Props, State> {
appsRefs: {[key: string]: ?HTMLDivElement} = {};
componentDidUpdate(prevProps: Props) {
const { applications, isLoading, location } = this.props;
const { applications, isLoading, clientId } = this.props;
if (isLoading !== prevProps.isLoading && applications.length) {
const hash = location.hash.substr(1);
if (hash !== '' && applications.some((app) => app.clientId === hash)) {
requestAnimationFrame(() => this.onTileClick(hash));
if (clientId && applications.some((app) => app.clientId === clientId)) {
requestAnimationFrame(() => this.onTileClick(clientId));
}
}
}
@ -162,9 +155,9 @@ class ApplicationsIndex extends Component<Props, State> {
<div className={styles.welcomeParagraph}>
<Message {...messages.ifYouHaveAnyTroubles} values={{
feedback: (
<a href="#" onClick={this.onContact}>
<ContactLink>
<Message {...messages.feedback} />
</a>
</ContactLink>
),
}} />
</div>
@ -185,14 +178,4 @@ class ApplicationsIndex extends Component<Props, State> {
}
});
};
onContact = (event) => {
event.preventDefault();
this.props.createContactPopup();
};
}
export default withRouter(connect(null, {
createContactPopup: () => createPopup(ContactForm),
})(ApplicationsIndex));

View File

@ -3,9 +3,9 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { FormattedMessage as Message } from 'react-intl';
import ContactForm from 'components/contact/ContactForm';
import LanguageSwitcher from 'components/languageSwitcher';
import { create as createPopup } from 'components/ui/popup/actions';
import { ContactLink } from 'components/contact';
import styles from './footerMenu.scss';
import messages from './footerMenu.intl.json';
@ -23,9 +23,9 @@ class FooterMenu extends Component<{
<Message {...messages.rules} />
</Link>
{' | '}
<a href="#" onClick={this.onContact}>
<ContactLink>
<Message {...messages.contactUs} />
</a>
</ContactLink>
{' | '}
<Link to="/dev">
<Message {...messages.forDevelopers} />
@ -41,13 +41,9 @@ class FooterMenu extends Component<{
);
}
onContact = (event) => {
onLanguageSwitcher = (event: SyntheticMouseEvent<HTMLElement>) => {
event.preventDefault();
this.props.createContactPopup();
};
onLanguageSwitcher = (event) => {
event.preventDefault();
this.props.createLanguageSwitcherPopup();
};
}
@ -55,6 +51,5 @@ class FooterMenu extends Component<{
// mark this component, as not pure, because it is stateless,
// but should be re-rendered, if current lang was changed
export default connect(null, {
createContactPopup: () => createPopup(ContactForm),
createLanguageSwitcherPopup: () => createPopup(LanguageSwitcher),
}, null, {pure: false})(FooterMenu);

View File

@ -1,3 +1,5 @@
// @flow
import type { ElementType } from 'react';
export const POPUP_CREATE = 'POPUP_CREATE';
/**
@ -7,7 +9,10 @@ export const POPUP_CREATE = 'POPUP_CREATE';
*
* @return {object}
*/
export function create(payload) {
export function create(payload: ElementType | {
Popup: ElementType,
disableOverlayClose?: bool,
}) {
if (typeof payload === 'function') {
payload = {
Popup: payload
@ -21,7 +26,7 @@ export function create(payload) {
}
export const POPUP_DESTROY = 'POPUP_DESTROY';
export function destroy(popup) {
export function destroy(popup: ElementType) {
return {
type: POPUP_DESTROY,
payload: popup

View File

@ -1,34 +1,34 @@
// @flow
import React, { Component } from 'react';
import ApplicationsIndex from 'components/dev/apps/ApplicationsIndex';
import type { User } from 'components/user';
import type { OauthAppResponse } from 'services/api/oauth';
import type { Location } from 'react-router';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchAvailableApps, resetApp, deleteApp } from 'components/dev/apps/actions';
import ApplicationsIndex from 'components/dev/apps/ApplicationsIndex';
class ApplicationsListPage extends Component<{
location: Location,
user: User,
apps: Array<OauthAppResponse>,
fetchAvailableApps: () => Promise<*>,
deleteApp: (string) => Promise<*>,
resetApp: (string, bool) => Promise<*>,
fetchAvailableApps: () => Promise<void>,
deleteApp: (string) => Promise<void>,
resetApp: (string, bool) => Promise<void>,
}, {
isLoading: bool,
}> {
static displayName = 'ApplicationsListPage';
state = {
appsList: [],
isLoading: false,
};
componentWillMount() {
componentDidMount() {
!this.props.user.isGuest && this.loadApplicationsList();
}
render() {
const { user, apps, resetApp, deleteApp } = this.props;
const { user, apps, resetApp, deleteApp, location } = this.props;
const { isLoading } = this.state;
const clientId = location.hash.substr(1) || null;
return (
<ApplicationsIndex
@ -37,6 +37,7 @@ class ApplicationsListPage extends Component<{
isLoading={isLoading}
deleteApp={deleteApp}
resetApp={resetApp}
clientId={clientId}
/>
);
}
@ -48,9 +49,6 @@ class ApplicationsListPage extends Component<{
};
}
import { connect } from 'react-redux';
import { fetchAvailableApps, resetApp, deleteApp } from 'components/dev/apps/actions';
export default connect((state) => ({
user: state.user,
apps: state.apps.available,