From d95573393206bc3931202d363bfb6c54974e0203 Mon Sep 17 00:00:00 2001
From: muhamedsalih-tw <104364298+muhamedsalih-tw@users.noreply.github.com>
Date: Fri, 28 Oct 2022 07:37:55 +0530
Subject: Transform welcome component tree to TS (#715)
---
src/components/auth/Welcome.jsx | 109 -------------------------------
src/components/auth/Welcome.tsx | 118 ++++++++++++++++++++++++++++++++++
src/components/ui/Link.js | 86 -------------------------
src/components/ui/Link.tsx | 73 +++++++++++++++++++++
src/components/ui/button/index.tsx | 76 +++++++++-------------
src/components/ui/input/index.tsx | 2 +
src/containers/auth/WelcomeScreen.tsx | 15 +++--
src/helpers/array-helpers.ts | 4 +-
8 files changed, 236 insertions(+), 247 deletions(-)
delete mode 100644 src/components/auth/Welcome.jsx
create mode 100644 src/components/auth/Welcome.tsx
delete mode 100644 src/components/ui/Link.js
create mode 100644 src/components/ui/Link.tsx
(limited to 'src')
diff --git a/src/components/auth/Welcome.jsx b/src/components/auth/Welcome.jsx
deleted file mode 100644
index 9e5d10126..000000000
--- a/src/components/auth/Welcome.jsx
+++ /dev/null
@@ -1,109 +0,0 @@
-/* eslint jsx-a11y/anchor-is-valid: 0 */
-import { Component } from 'react';
-import PropTypes from 'prop-types';
-import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react';
-import { defineMessages, injectIntl } from 'react-intl';
-import serverlessLogin from '../../helpers/serverless-helpers';
-import shuffleArray from '../../helpers/array-helpers';
-import { serverName } from '../../api/apiBase';
-
-import Link from '../ui/Link';
-import { H1 } from '../ui/headline';
-
-const messages = defineMessages({
- signupButton: {
- id: 'welcome.signupButton',
- defaultMessage: 'Create a free account',
- },
- loginButton: {
- id: 'welcome.loginButton',
- defaultMessage: 'Login to your account',
- },
- changeServerMessage: {
- id: 'login.changeServerMessage',
- defaultMessage:
- 'You are using {serverNameParse} Server, do you want to switch?',
- },
- changeServer: {
- id: 'login.changeServer',
- defaultMessage: 'Change here!',
- },
- serverless: {
- id: 'services.serverless',
- defaultMessage: 'Use Ferdium without an Account',
- },
-});
-
-class Welcome extends Component {
- static propTypes = {
- loginRoute: PropTypes.string.isRequired,
- signupRoute: PropTypes.string.isRequired,
- changeServerRoute: PropTypes.string.isRequired,
- recipes: MobxPropTypes.arrayOrObservableArray.isRequired,
- actions: PropTypes.object.isRequired,
- };
-
- useLocalServer() {
- serverlessLogin(this.props.actions);
- }
-
- render() {
- const { intl } = this.props;
- const { loginRoute, signupRoute, changeServerRoute } = this.props;
- let { recipes } = this.props;
- recipes = shuffleArray(recipes);
- recipes.length = 8 * 2;
-
- let serverNameParse = serverName();
- serverNameParse =
- serverNameParse === 'Custom' ? 'a Custom' : serverNameParse;
-
- return (
-
-
-
-
-
-
Ferdium
-
-
-
- {intl.formatMessage(messages.signupButton)}
-
-
- {intl.formatMessage(messages.loginButton)}
-
-
-
- {intl.formatMessage(messages.changeServerMessage, {
- serverNameParse,
- })}
-
-
- {intl.formatMessage(messages.changeServer)}
-
-
-
-
-
-
- {intl.formatMessage(messages.serverless)}
-
-
-
- {recipes.map(recipe => (
-
-
-
- ))}
-
-
- );
- }
-}
-
-export default injectIntl(inject('actions')(observer(Welcome)));
diff --git a/src/components/auth/Welcome.tsx b/src/components/auth/Welcome.tsx
new file mode 100644
index 000000000..1aa8da4d6
--- /dev/null
+++ b/src/components/auth/Welcome.tsx
@@ -0,0 +1,118 @@
+import { Component, ReactElement } from 'react';
+import { observer, inject } from 'mobx-react';
+import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
+import { noop } from 'lodash';
+import serverlessLogin from '../../helpers/serverless-helpers';
+import shuffleArray from '../../helpers/array-helpers';
+import { serverName } from '../../api/apiBase';
+import Link from '../ui/Link';
+import { H1 } from '../ui/headline';
+import { StoresProps } from '../../@types/ferdium-components.types';
+import RecipePreview from '../../models/RecipePreview';
+
+const messages = defineMessages({
+ signupButton: {
+ id: 'welcome.signupButton',
+ defaultMessage: 'Create a free account',
+ },
+ loginButton: {
+ id: 'welcome.loginButton',
+ defaultMessage: 'Login to your account',
+ },
+ changeServerMessage: {
+ id: 'login.changeServerMessage',
+ defaultMessage:
+ 'You are using {serverNameParse} Server, do you want to switch?',
+ },
+ changeServer: {
+ id: 'login.changeServer',
+ defaultMessage: 'Change here!',
+ },
+ serverless: {
+ id: 'services.serverless',
+ defaultMessage: 'Use Ferdium without an Account',
+ },
+});
+
+interface IProps extends Partial, WrappedComponentProps {
+ loginRoute: string;
+ signupRoute: string;
+ changeServerRoute: string;
+ recipes: RecipePreview[];
+}
+
+@inject('actions')
+@observer
+class Welcome extends Component {
+ constructor(props: IProps) {
+ super(props);
+ }
+
+ useLocalServer(): void {
+ serverlessLogin(this.props.actions);
+ }
+
+ render(): ReactElement {
+ const { loginRoute, signupRoute, changeServerRoute, intl } = this.props;
+ let { recipes } = this.props;
+ recipes = shuffleArray(recipes);
+ recipes.length = 8 * 2;
+
+ let serverNameParse = serverName();
+ serverNameParse =
+ serverNameParse === 'Custom' ? 'a Custom' : serverNameParse;
+
+ return (
+
+
+
+
+
+
Ferdium
+
+
+
+ {intl.formatMessage(messages.signupButton)}
+
+
+ {intl.formatMessage(messages.loginButton)}
+
+
+
+ {intl.formatMessage(messages.changeServerMessage, {
+ serverNameParse,
+ })}
+
+
+ {intl.formatMessage(messages.changeServer)}
+
+
+
+
+
+
+ {recipes.map(recipe => (
+
+
+
+ ))}
+
+
+ );
+ }
+}
+
+export default injectIntl(Welcome);
diff --git a/src/components/ui/Link.js b/src/components/ui/Link.js
deleted file mode 100644
index 714fc5a68..000000000
--- a/src/components/ui/Link.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import { Component } from 'react';
-import PropTypes from 'prop-types';
-import { inject, observer } from 'mobx-react';
-import { RouterStore } from '@superwf/mobx-react-router';
-import classnames from 'classnames';
-
-import { oneOrManyChildElements } from '../../prop-types';
-import matchRoute from '../../helpers/routing-helpers';
-import { openExternalUrl } from '../../helpers/url-helpers';
-
-// Should this file be converted into the coding style similar to './toggle/index.tsx'?
-// TODO: create container component for this component
-class Link extends Component {
- onClick(e) {
- if (this.props.disabled) {
- e.preventDefault();
- } else if (this.props.target === '_blank') {
- e.preventDefault();
- openExternalUrl(this.props.to, true);
- }
- // Note: if neither of the above, then let the other onClick handlers process it
- }
-
- render() {
- const {
- children,
- stores,
- to,
- className,
- activeClassName,
- strictFilter,
- style,
- } = this.props;
- const { router } = stores;
-
- let filter = `${to}(*action)`;
- if (strictFilter) {
- filter = `${to}`;
- }
-
- const match = matchRoute(filter, router.location.pathname);
-
- const linkClasses = classnames({
- [`${className}`]: true,
- [`${activeClassName}`]: match,
- 'is-disabled': this.props.disabled,
- });
-
- return (
- this.onClick(e)}
- >
- {children}
-
- );
- }
-}
-
-Link.propTypes = {
- stores: PropTypes.shape({
- router: PropTypes.instanceOf(RouterStore).isRequired,
- }).isRequired,
- children: PropTypes.oneOfType([oneOrManyChildElements, PropTypes.string])
- .isRequired,
- to: PropTypes.string.isRequired,
- className: PropTypes.string,
- activeClassName: PropTypes.string,
- strictFilter: PropTypes.bool,
- target: PropTypes.string,
- style: PropTypes.object,
- disabled: PropTypes.bool,
-};
-
-Link.defaultProps = {
- className: '',
- activeClassName: '',
- strictFilter: false,
- disabled: false,
- target: '',
- style: {},
-};
-
-export default inject('stores')(observer(Link));
diff --git a/src/components/ui/Link.tsx b/src/components/ui/Link.tsx
new file mode 100644
index 000000000..b5890ebd1
--- /dev/null
+++ b/src/components/ui/Link.tsx
@@ -0,0 +1,73 @@
+import { Component, CSSProperties, ReactNode, MouseEvent } from 'react';
+import { inject, observer } from 'mobx-react';
+import classnames from 'classnames';
+import matchRoute from '../../helpers/routing-helpers';
+import { openExternalUrl } from '../../helpers/url-helpers';
+import { StoresProps } from '../../@types/ferdium-components.types';
+
+interface IProps extends Partial {
+ children: ReactNode;
+ to: string;
+ className?: string;
+ activeClassName?: string;
+ strictFilter?: boolean;
+ target?: string;
+ style?: CSSProperties;
+ disabled?: boolean;
+}
+
+// TODO: create container component for this component
+@inject('stores')
+@observer
+class Link extends Component {
+ constructor(props: IProps) {
+ super(props);
+ }
+
+ onClick(e: MouseEvent): void {
+ const { disabled = false, target = '', to } = this.props;
+ if (disabled) {
+ e.preventDefault();
+ } else if (target === '_blank') {
+ e.preventDefault();
+ openExternalUrl(to, true);
+ }
+ // Note: if neither of the above, then let the other onClick handlers process it
+ }
+
+ render() {
+ const {
+ children,
+ stores,
+ to,
+ className = '',
+ activeClassName = '',
+ strictFilter = false,
+ disabled = false,
+ style = {},
+ } = this.props;
+ const { router } = stores!;
+
+ const filter = strictFilter ? `${to}` : `${to}(*action)`;
+ const match = matchRoute(filter, router.location.pathname);
+
+ const linkClasses = classnames({
+ [`${className}`]: true,
+ [`${activeClassName}`]: match,
+ 'is-disabled': disabled,
+ });
+
+ return (
+ this.onClick(e)}
+ >
+ {children}
+
+ );
+ }
+}
+
+export default Link;
diff --git a/src/components/ui/button/index.tsx b/src/components/ui/button/index.tsx
index a8bbfe730..c1e647bc0 100644
--- a/src/components/ui/button/index.tsx
+++ b/src/components/ui/button/index.tsx
@@ -1,10 +1,10 @@
import Icon from '@mdi/react';
import classnames from 'classnames';
import { Property } from 'csstype';
+import { noop } from 'lodash';
import { Component, MouseEvent } from 'react';
import withStyles, { WithStylesProps } from 'react-jss';
import Loader from 'react-loader';
-
import { Theme } from '../../../themes';
import { IFormField } from '../typings/generic';
@@ -16,24 +16,6 @@ type ButtonType =
| 'warning'
| 'inverted';
-interface IProps extends IFormField, WithStylesProps {
- className?: string;
- label?: string;
- disabled?: boolean;
- id?: string;
- type?: 'button' | 'reset' | 'submit' | undefined;
- onClick: (
- event: MouseEvent | MouseEvent,
- ) => void;
- buttonType?: ButtonType;
- loaded?: boolean;
- busy?: boolean;
- icon?: string;
- href?: string;
- target?: string;
- htmlForm?: string;
-}
-
let buttonTransition: string = 'none';
let loaderContainerTransition: string = 'none';
@@ -148,38 +130,38 @@ const styles = (theme: Theme) => ({
},
});
-class ButtonComponent extends Component {
- customDefaultProps: {
- disabled: boolean;
- type: 'button' | 'reset' | 'submit' | undefined;
- onClick: (
- event: MouseEvent | MouseEvent,
- ) => void;
- buttonType: ButtonType;
- busy: boolean;
- } = {
- type: 'button',
- disabled: false,
- onClick: () => null,
- buttonType: 'primary' as ButtonType,
- busy: false,
- };
+interface IProps extends IFormField, WithStylesProps {
+ className?: string;
+ label?: string;
+ disabled?: boolean;
+ id?: string;
+ type?: 'button' | 'reset' | 'submit' | undefined;
+ onClick: (event: MouseEvent) => void;
+ buttonType?: ButtonType;
+ loaded?: boolean;
+ busy?: boolean;
+ icon?: string;
+ href?: string;
+ target?: string;
+ htmlForm?: string;
+}
- state = {
- busy: false,
- };
+interface IState {
+ busy: boolean;
+}
+class ButtonComponent extends Component {
constructor(props: IProps) {
super(props);
this.state = {
- busy: props.busy || false,
+ busy: this.props.busy || false,
};
}
- static getDerivedStateFromProps(nextProps: IProps) {
+ static getDerivedStateFromProps(nextProps: IProps): IState {
return {
- busy: nextProps.busy,
+ busy: nextProps.busy || false,
};
}
@@ -188,27 +170,29 @@ class ButtonComponent extends Component {
classes,
className,
// theme,
- disabled,
id,
label,
- type,
- onClick,
- buttonType,
loaded,
icon,
href,
target,
htmlForm,
- } = { ...this.customDefaultProps, ...this.props };
+ type = 'button',
+ disabled = false,
+ onClick = noop,
+ buttonType = 'primary' as ButtonType,
+ } = this.props;
const { busy } = this.state;
let showLoader = false;
+
if (loaded) {
showLoader = !loaded;
console.warn(
'Ferdium Button prop `loaded` will be deprecated in the future. Please use `busy` instead',
);
}
+
if (busy) {
showLoader = busy;
}
diff --git a/src/components/ui/input/index.tsx b/src/components/ui/input/index.tsx
index b19bb4bc9..3bafc93e7 100644
--- a/src/components/ui/input/index.tsx
+++ b/src/components/ui/input/index.tsx
@@ -106,6 +106,7 @@ class InputComponent extends Component {
showPasswordToggle = false,
type = 'text',
disabled = false,
+ readOnly,
} = this.props;
const { showPassword, passwordScore } = this.state;
@@ -152,6 +153,7 @@ class InputComponent extends Component {
min={min}
max={max}
step={step}
+ readOnly={readOnly}
/>
{suffix && {suffix}}
{showPasswordToggle && (
diff --git a/src/containers/auth/WelcomeScreen.tsx b/src/containers/auth/WelcomeScreen.tsx
index c03319179..561eef236 100644
--- a/src/containers/auth/WelcomeScreen.tsx
+++ b/src/containers/auth/WelcomeScreen.tsx
@@ -1,12 +1,19 @@
import { Component, ReactElement } from 'react';
import { inject, observer } from 'mobx-react';
-
import { StoresProps } from '../../@types/ferdium-components.types';
import Welcome from '../../components/auth/Welcome';
-class WelcomeScreen extends Component {
+interface IProps extends Partial {}
+
+@inject('stores', 'actions')
+@observer
+class WelcomeScreen extends Component {
+ constructor(props: IProps) {
+ super(props);
+ }
+
render(): ReactElement {
- const { user, recipePreviews } = this.props.stores;
+ const { user, recipePreviews } = this.props.stores!;
return (
{
}
}
-export default inject('stores', 'actions')(observer(WelcomeScreen));
+export default WelcomeScreen;
diff --git a/src/helpers/array-helpers.ts b/src/helpers/array-helpers.ts
index 33be12fa7..ffb584eab 100644
--- a/src/helpers/array-helpers.ts
+++ b/src/helpers/array-helpers.ts
@@ -1,6 +1,6 @@
-export default function shuffleArray(arr: any[]): any[] {
+export default function shuffleArray(arr: T[]): T[] {
return arr
- .map(a => [Math.random(), a])
+ .map(a => [Math.random(), a] as [number, T])
.sort((a, b) => a[0] - b[0])
.map(a => a[1]);
}
--
cgit v1.2.3-54-g00ecf