From 6f650ba0c5d9e7fa56d948034c24545c45a93bdb Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Sat, 5 May 2018 09:43:43 +0300 Subject: [PATCH] #22: minor code style and type anotations improvements --- flow-typed/npm/react-intl_v2.x.x.js | 265 +++++++++++++++++++ src/components/dev/apps/ApplicationsIndex.js | 34 +-- src/components/ui/form/Checkbox.js | 9 +- src/components/ui/form/Input.js | 12 +- src/components/ui/form/LinkButton.js | 4 +- src/components/ui/form/Radio.js | 9 +- src/components/ui/form/TextArea.js | 15 +- src/index.scss | 3 +- src/pages/dev/DevPage.js | 34 ++- src/storeFactory.js | 1 + 10 files changed, 315 insertions(+), 71 deletions(-) create mode 100644 flow-typed/npm/react-intl_v2.x.x.js diff --git a/flow-typed/npm/react-intl_v2.x.x.js b/flow-typed/npm/react-intl_v2.x.x.js new file mode 100644 index 0000000..f7785f0 --- /dev/null +++ b/flow-typed/npm/react-intl_v2.x.x.js @@ -0,0 +1,265 @@ +// flow-typed signature: e68caa23426dedefced5662fb92b4638 +// flow-typed version: d13a175635/react-intl_v2.x.x/flow_>=v0.57.x + +/** + * Original implementation of this file by @marudor at https://github.com/marudor/flowInterfaces + * Copied here based on intention to merge with flow-typed expressed here: + * https://github.com/marudor/flowInterfaces/issues/6 + */ +// Mostly from https://github.com/yahoo/react-intl/wiki/API#react-intl-api + +import type { Element, ChildrenArray } from "react"; + +type $npm$ReactIntl$LocaleData = { + locale: string, + [key: string]: any +}; + +type $npm$ReactIntl$MessageDescriptor = { + id: string, + description?: string, + defaultMessage?: string +}; + +type $npm$ReactIntl$IntlConfig = { + locale: string, + formats: Object, + messages: { [id: string]: string }, + + defaultLocale?: string, + defaultFormats?: Object +}; + +type $npm$ReactIntl$IntlProviderConfig = { + locale?: string, + formats?: Object, + messages?: { [id: string]: string }, + + defaultLocale?: string, + defaultFormats?: Object +}; + +type $npm$ReactIntl$IntlFormat = { + formatDate: (value: any, options?: Object) => string, + formatTime: (value: any, options?: Object) => string, + formatRelative: (value: any, options?: Object) => string, + formatNumber: (value: any, options?: Object) => string, + formatPlural: (value: any, options?: Object) => string, + formatMessage: ( + messageDescriptor: $npm$ReactIntl$MessageDescriptor, + values?: Object + ) => string, + formatHTMLMessage: ( + messageDescriptor: $npm$ReactIntl$MessageDescriptor, + values?: Object + ) => string +}; + +type $npm$ReactIntl$IntlShape = $npm$ReactIntl$IntlConfig & + $npm$ReactIntl$IntlFormat & { now: () => number }; + +type $npm$ReactIntl$DateTimeFormatOptions = { + localeMatcher?: "best fit" | "lookup", + formatMatcher?: "basic" | "best fit", + + timeZone?: string, + hour12?: boolean, + + weekday?: "narrow" | "short" | "long", + era?: "narrow" | "short" | "long", + year?: "numeric" | "2-digit", + month?: "numeric" | "2-digit" | "narrow" | "short" | "long", + day?: "numeric" | "2-digit", + hour?: "numeric" | "2-digit", + minute?: "numeric" | "2-digit", + second?: "numeric" | "2-digit", + timeZoneName?: "short" | "long" +}; + +type $npm$ReactIntl$RelativeFormatOptions = { + style?: "best fit" | "numeric", + units?: "second" | "minute" | "hour" | "day" | "month" | "year" +}; + +type $npm$ReactIntl$NumberFormatOptions = { + localeMatcher?: "best fit" | "lookup", + + style?: "decimal" | "currency" | "percent", + + currency?: string, + currencyDisplay?: "symbol" | "code" | "name", + + useGrouping?: boolean, + + minimumIntegerDigits?: number, + minimumFractionDigits?: number, + maximumFractionDigits?: number, + minimumSignificantDigits?: number, + maximumSignificantDigits?: number +}; + +type $npm$ReactIntl$PluralFormatOptions = { + style?: "cardinal" | "ordinal" +}; + +type $npm$ReactIntl$PluralCategoryString = + | "zero" + | "one" + | "two" + | "few" + | "many" + | "other"; + +type $npm$ReactIntl$DateParseable = number | string | Date; + +declare module "react-intl" { + // PropType checker + declare function intlShape( + props: Object, + propName: string, + componentName: string + ): void; + declare function addLocaleData( + data: $npm$ReactIntl$LocaleData | Array<$npm$ReactIntl$LocaleData> + ): void; + declare function defineMessages< + T: { [key: string]: $npm$ReactIntl$MessageDescriptor } + >( + messageDescriptors: T + ): T; + + declare type InjectIntlProvidedProps = { + intl: $npm$ReactIntl$IntlShape + } + + declare type ComponentWithDefaultProps = + | React$ComponentType + | React$StatelessFunctionalComponent + | ChildrenArray>; + + declare type InjectIntlOptions = { + intlPropName?: string, + withRef?: boolean + } + + declare class IntlInjectedComponent extends React$Component { + static WrappedComponent: Class>, + static defaultProps: TDefaultProps, + props: TOwnProps + } + + declare type IntlInjectedComponentClass = Class< + IntlInjectedComponent + >; + + declare function injectIntl + ( + component: ComponentWithDefaultProps, + options?: InjectIntlOptions, + ): + IntlInjectedComponentClass<$Diff, DefaultProps> + + declare function injectIntl + ( + component: React$ComponentType, + options?: InjectIntlOptions, + ): + IntlInjectedComponentClass<$Diff>; + + declare function formatMessage( + messageDescriptor: $npm$ReactIntl$MessageDescriptor, + values?: Object + ): string; + declare function formatHTMLMessage( + messageDescriptor: $npm$ReactIntl$MessageDescriptor, + values?: Object + ): string; + declare function formatDate( + value: any, + options?: $npm$ReactIntl$DateTimeFormatOptions & { format: string } + ): string; + declare function formatTime( + value: any, + options?: $npm$ReactIntl$DateTimeFormatOptions & { format: string } + ): string; + declare function formatRelative( + value: any, + options?: $npm$ReactIntl$RelativeFormatOptions & { + format: string, + now: any + } + ): string; + declare function formatNumber( + value: any, + options?: $npm$ReactIntl$NumberFormatOptions & { format: string } + ): string; + declare function formatPlural( + value: any, + options?: $npm$ReactIntl$PluralFormatOptions + ): $npm$ReactIntl$PluralCategoryString; + + declare class FormattedMessage extends React$Component< + $npm$ReactIntl$MessageDescriptor & { + values?: Object, + tagName?: string, + children?: (...formattedMessage: Array) => React$Node + } + > {} + declare class FormattedHTMLMessage extends React$Component< + $npm$ReactIntl$DateTimeFormatOptions & { + values?: Object, + tagName?: string, + children?: (...formattedMessage: Array) => React$Node + } + > {} + declare class FormattedDate extends React$Component< + $npm$ReactIntl$DateTimeFormatOptions & { + value: $npm$ReactIntl$DateParseable, + format?: string, + children?: (formattedDate: string) => React$Node + } + > {} + declare class FormattedTime extends React$Component< + $npm$ReactIntl$DateTimeFormatOptions & { + value: $npm$ReactIntl$DateParseable, + format?: string, + children?: (formattedDate: string) => React$Node + } + > {} + declare class FormattedRelative extends React$Component< + $npm$ReactIntl$RelativeFormatOptions & { + value: $npm$ReactIntl$DateParseable, + format?: string, + updateInterval?: number, + initialNow?: $npm$ReactIntl$DateParseable, + children?: (formattedDate: string) => React$Node + } + > {} + declare class FormattedNumber extends React$Component< + $npm$ReactIntl$NumberFormatOptions & { + value: number | string, + format?: string, + children?: (formattedNumber: string) => React$Node + } + > {} + declare class FormattedPlural extends React$Component< + $npm$ReactIntl$PluralFormatOptions & { + value: number | string, + other: React$Node, + zero?: React$Node, + one?: React$Node, + two?: React$Node, + few?: React$Node, + many?: React$Node, + children?: (formattedPlural: React$Node) => React$Node + } + > {} + declare class IntlProvider extends React$Component< + $npm$ReactIntl$IntlProviderConfig & { + children?: React$Node, + initialNow?: $npm$ReactIntl$DateParseable + } + > {} + declare type IntlShape = $npm$ReactIntl$IntlShape; + declare type MessageDescriptor = $npm$ReactIntl$MessageDescriptor; +} diff --git a/src/components/dev/apps/ApplicationsIndex.js b/src/components/dev/apps/ApplicationsIndex.js index 5adde2b..5e13cdb 100644 --- a/src/components/dev/apps/ApplicationsIndex.js +++ b/src/components/dev/apps/ApplicationsIndex.js @@ -1,27 +1,27 @@ // @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 styles from './applicationsIndex.scss'; import messages from './ApplicationsIndex.intl.json'; import cubeIcon from './icons/cube.svg'; import loadingCubeIcon from './icons/loading-cube.svg'; import toolsIcon from './icons/tools.svg'; - import ApplicationItem from './ApplicationItem'; -import { LinkButton } from 'components/ui/form'; -import { COLOR_GREEN, COLOR_BLUE } from 'components/ui'; -import { restoreScroll } from 'components/ui/scroll/scroll'; - -import type { Node } from 'react'; -import type { OauthAppResponse } from 'services/api/oauth'; - type Props = { - location: { - hash: string, - }, + location: Location, displayForGuest: bool, applications: Array, isLoading: bool, @@ -39,12 +39,14 @@ class ApplicationsIndex extends Component { expandedApp: null, }; - appsRefs = {}; + appsRefs: {[key: string]: ?HTMLDivElement} = {}; componentDidUpdate(prevProps: Props) { const { applications, isLoading, location } = 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)); } @@ -56,6 +58,7 @@ class ApplicationsIndex extends Component { const { expandedApp } = this.state; let content: Node; + if (displayForGuest) { content = (
@@ -174,6 +177,7 @@ class ApplicationsIndex extends Component { onTileClick = (clientId: string) => { const expandedApp = this.state.expandedApp === clientId ? null : clientId; + this.setState({expandedApp}, () => { if (expandedApp !== null) { // TODO: @SleepWalker: мб у тебя есть идея, как это сделать более правильно и менее дёргано? @@ -184,15 +188,11 @@ class ApplicationsIndex extends Component { onContact = (event) => { event.preventDefault(); + this.props.createContactPopup(); }; } -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'; - export default withRouter(connect(null, { createContactPopup: () => createPopup(ContactForm), })(ApplicationsIndex)); diff --git a/src/components/ui/form/Checkbox.js b/src/components/ui/form/Checkbox.js index 5426950..a547149 100644 --- a/src/components/ui/form/Checkbox.js +++ b/src/components/ui/form/Checkbox.js @@ -1,24 +1,19 @@ // @flow +import type { Color, Skin } from 'components/ui'; +import type { MessageDescriptor } from 'react-intl'; import React from 'react'; - import classNames from 'classnames'; - import { SKIN_DARK, COLOR_GREEN } from 'components/ui'; import { omit } from 'functions'; import styles from './form.scss'; import FormInputComponent from './FormInputComponent'; -import type { Color, Skin } from 'components/ui'; -import type { MessageDescriptor } from 'react-intl'; - export default class Checkbox extends FormInputComponent<{ color: Color, skin: Skin, label: string | MessageDescriptor, }> { - static displayName = 'Checkbox'; - static defaultProps = { color: COLOR_GREEN, skin: SKIN_DARK, diff --git a/src/components/ui/form/Input.js b/src/components/ui/form/Input.js index b6cf588..59ce3de 100644 --- a/src/components/ui/form/Input.js +++ b/src/components/ui/form/Input.js @@ -1,8 +1,8 @@ // @flow +import type { Skin, Color } from 'components/ui'; +import type { MessageDescriptor } from 'react-intl'; import React from 'react'; - import classNames from 'classnames'; - import { uniqueId, omit } from 'functions'; import copy from 'services/copy'; import icons from 'components/ui/icons.scss'; @@ -11,10 +11,7 @@ import { SKIN_DARK, COLOR_GREEN } from 'components/ui'; import styles from './form.scss'; import FormInputComponent from './FormInputComponent'; -import type { Skin, Color } from 'components/ui'; -import type { MessageDescriptor } from 'react-intl'; - -let copiedStateTimeout; +let copiedStateTimeout: ?TimeoutID; export default class Input extends FormInputComponent<{ skin: Skin, @@ -29,8 +26,6 @@ export default class Input extends FormInputComponent<{ }, { wasCopied: bool, }> { - static displayName = 'Input'; - static defaultProps = { color: COLOR_GREEN, skin: SKIN_DARK, @@ -69,6 +64,7 @@ export default class Input extends FormInputComponent<{ props.placeholder = this.formatMessage(props.placeholder); let baseClass = styles.formRow; + if (icon) { baseClass = styles.formIconRow; icon = ( diff --git a/src/components/ui/form/LinkButton.js b/src/components/ui/form/LinkButton.js index 452494c..b9d3844 100644 --- a/src/components/ui/form/LinkButton.js +++ b/src/components/ui/form/LinkButton.js @@ -1,11 +1,11 @@ // @flow +import type { ElementProps } from 'react'; import React from 'react'; -import type {ElementProps} from 'react'; import { Link } from 'react-router-dom'; import Button from './Button'; -export default function LinkButton(props: ElementProps | ElementProps) { +export default function LinkButton(props: ElementProps & ElementProps) { const {to, ...restProps} = props; return ( diff --git a/src/components/ui/form/Radio.js b/src/components/ui/form/Radio.js index 0d6fbb7..883cdcd 100644 --- a/src/components/ui/form/Radio.js +++ b/src/components/ui/form/Radio.js @@ -1,24 +1,19 @@ // @flow +import type { Color, Skin } from 'components/ui'; +import type { MessageDescriptor } from 'react-intl'; import React from 'react'; - import classNames from 'classnames'; - import { SKIN_DARK, COLOR_GREEN } from 'components/ui'; import { omit } from 'functions'; import styles from './form.scss'; import FormInputComponent from './FormInputComponent'; -import type { Color, Skin } from 'components/ui'; -import type { MessageDescriptor } from 'react-intl'; - export default class Radio extends FormInputComponent<{ color: Color, skin: Skin, label: string | MessageDescriptor, }> { - static displayName = 'Radio'; - static defaultProps = { color: COLOR_GREEN, skin: SKIN_DARK, diff --git a/src/components/ui/form/TextArea.js b/src/components/ui/form/TextArea.js index c2d7e06..64da447 100644 --- a/src/components/ui/form/TextArea.js +++ b/src/components/ui/form/TextArea.js @@ -1,25 +1,22 @@ // @flow +import type { Skin, Color } from 'components/ui'; +import type { MessageDescriptor } from 'react-intl'; import React from 'react'; import TextareaAutosize from 'react-textarea-autosize'; - import classNames from 'classnames'; - import { uniqueId, omit } from 'functions'; import { SKIN_DARK, COLOR_GREEN } from 'components/ui'; import styles from './form.scss'; import FormInputComponent from './FormInputComponent'; -import type { Skin, Color } from 'components/ui'; -import type { MessageDescriptor } from 'react-intl'; - type TextareaAutosizeProps = { onHeightChange?: (number, TextareaAutosizeProps) => void, useCacheForDOMMeasurements?: bool, minRows?: number, maxRows?: number, - inputRef?: (HTMLTextAreaElement) => void, -} | HTMLTextAreaElement; + inputRef?: (?HTMLTextAreaElement) => void, +}; export default class TextArea extends FormInputComponent<{ placeholder?: string | MessageDescriptor, @@ -27,9 +24,7 @@ export default class TextArea extends FormInputComponent<{ error?: string, skin: Skin, color: Color, -} | TextareaAutosizeProps> { - static displayName = 'TextArea'; - +} & TextareaAutosizeProps> { static defaultProps = { color: COLOR_GREEN, skin: SKIN_DARK, diff --git a/src/index.scss b/src/index.scss index dcb3b59..ae74198 100644 --- a/src/index.scss +++ b/src/index.scss @@ -25,7 +25,8 @@ b { font-weight: $font-weight-bold; } -a, .textLink { +a, +.textLink { color: #444; border-bottom: 1px dotted #444; text-decoration: none; diff --git a/src/pages/dev/DevPage.js b/src/pages/dev/DevPage.js index f35e838..87b03b5 100644 --- a/src/pages/dev/DevPage.js +++ b/src/pages/dev/DevPage.js @@ -1,30 +1,26 @@ // @flow -import React, { Component } from 'react'; +import React from 'react'; import { Redirect, Route, Switch } from 'react-router-dom'; +import { FooterMenu } from 'components/footerMenu'; import styles from './dev.scss'; - import ApplicationsListPage from './ApplicationsListPage'; import CreateNewApplicationPage from './CreateNewApplicationPage'; import UpdateApplicationPage from './UpdateApplicationPage'; -import { FooterMenu } from 'components/footerMenu'; +export default function DevPage() { + return ( +
+ + + + + + -export default class DevPage extends Component<{}> { - render() { - return ( -
- - - - - - - -
- -
+
+
- ); - } +
+ ); } diff --git a/src/storeFactory.js b/src/storeFactory.js index 0905445..d967228 100644 --- a/src/storeFactory.js +++ b/src/storeFactory.js @@ -33,6 +33,7 @@ export default function storeFactory() { const store = createStore(reducers, {}, enhancer); // Hot reload reducers + // $FlowFixMe if (module.hot && typeof module.hot.accept === 'function') { module.hot.accept('reducers', () => store.replaceReducer(require('reducers').default)