diff --git a/packages/cra-template-typescript/template.json b/packages/cra-template-typescript/template.json index bdff039e051..9fbaa1796b8 100644 --- a/packages/cra-template-typescript/template.json +++ b/packages/cra-template-typescript/template.json @@ -39,6 +39,7 @@ "react-redux": "7.x", "react-router-dom": "5.x", "redux": "4.x", + "redux-promise-listener": "1.x", "redux-saga": "1.x", "redux-sentry-middleware": "0.x", "reselect": "4.x" diff --git a/packages/cra-template-typescript/template/src/modules/auth/components/Login.tsx b/packages/cra-template-typescript/template/src/modules/auth/components/Login.tsx index aef49c844b5..ca0a100ef6f 100644 --- a/packages/cra-template-typescript/template/src/modules/auth/components/Login.tsx +++ b/packages/cra-template-typescript/template/src/modules/auth/components/Login.tsx @@ -1,5 +1,5 @@ import firewall from '../HOC/firewall'; -import LoginForm from '../containers/LoginForm'; +import LoginForm from './LoginForm'; import AuthContent from './AuthContent'; export default firewall(AuthContent, LoginForm); diff --git a/packages/cra-template-typescript/template/src/modules/auth/components/LoginForm.tsx b/packages/cra-template-typescript/template/src/modules/auth/components/LoginForm.tsx index 42200cb6919..76739d33bbf 100644 --- a/packages/cra-template-typescript/template/src/modules/auth/components/LoginForm.tsx +++ b/packages/cra-template-typescript/template/src/modules/auth/components/LoginForm.tsx @@ -1,43 +1,61 @@ -import React from "react"; -import { Form } from "redux-form"; -import { Button } from "antd"; -import { TextField } from "@ackee/mateus"; -import { FormattedMessage } from "react-intl"; - -interface LoginFormProps { - handleSubmit: () => void; - submitting: boolean; - error?: string; -} - -function LoginForm({ handleSubmit, submitting, error = '' }: LoginFormProps) { +import React from 'react'; +import { FormattedMessage, useIntl } from 'react-intl'; +import { Form, Field } from 'react-final-form'; + +import { useSubmitForm, validatorsWithMessage, composeValidators, translate } from 'modules/form'; + +import { types } from '../services/actions'; +import { LoginFormField } from '../types'; + +const { required, email } = validatorsWithMessage; + +const validators = { + [LoginFormField.EMAIL]: composeValidators(required, email), + [LoginFormField.PASSWORD]: required, +}; + +const LoginForm = () => { + const { formatMessage } = useIntl(); + const onSubmit = useSubmitForm(types.login); + return ( -
- } - autoComplete="email" - autoFocus - /> - - } - autoComplete="current-password" - /> - - - - {error &&

{error}

} - +
( + +
+ + +
+ +
+ + +
+ + + + {submitError &&

{submitError}

} +
+ )} + /> ); -} +}; export default LoginForm; diff --git a/packages/cra-template-typescript/template/src/modules/auth/containers/LoginForm/LoginForm.ts b/packages/cra-template-typescript/template/src/modules/auth/containers/LoginForm/LoginForm.ts deleted file mode 100644 index 74873a36f08..00000000000 --- a/packages/cra-template-typescript/template/src/modules/auth/containers/LoginForm/LoginForm.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { compose } from "redux"; -import { reduxForm } from "redux-form"; -import { connect } from "react-redux"; -import { injectIntl } from "react-intl"; -import { submitForm } from "@ackee/mateus"; - -import config from "config"; - -import LoginForm from '../../components/LoginForm'; -import { loginForm } from '../../services/actions'; - -import validate from './LoginForm.validate'; - -export default compose>( - connect(null, { - // TODO: bug in @ackee/mateus types - loginForm is action crater not an actual action - // @ts-ignore - onSubmit: submitForm(config.forms.login, loginForm), - }), - injectIntl, - reduxForm({ - form: config.forms.login, - validate, - }), -)(LoginForm); diff --git a/packages/cra-template-typescript/template/src/modules/auth/containers/LoginForm/LoginForm.validate.ts b/packages/cra-template-typescript/template/src/modules/auth/containers/LoginForm/LoginForm.validate.ts deleted file mode 100644 index 89a038de639..00000000000 --- a/packages/cra-template-typescript/template/src/modules/auth/containers/LoginForm/LoginForm.validate.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { LoginFormField } from "../../config"; -import type { LoginFormValues } from "../../config"; - -export default function validate(values: LoginFormValues, { intl }) { - const errors: Partial> = {}; - - if (!values.email) { - errors.email = 'Required'; - } - if (!values.password) { - errors.password = 'Required'; - } - - return errors; -} diff --git a/packages/cra-template-typescript/template/src/modules/auth/containers/LoginForm/index.ts b/packages/cra-template-typescript/template/src/modules/auth/containers/LoginForm/index.ts deleted file mode 100644 index 1195444e543..00000000000 --- a/packages/cra-template-typescript/template/src/modules/auth/containers/LoginForm/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './LoginForm'; diff --git a/packages/cra-template-typescript/template/src/modules/auth/services/actions/index.ts b/packages/cra-template-typescript/template/src/modules/auth/services/actions/index.ts index 6c4b578eff3..d94388ea77b 100644 --- a/packages/cra-template-typescript/template/src/modules/auth/services/actions/index.ts +++ b/packages/cra-template-typescript/template/src/modules/auth/services/actions/index.ts @@ -1,2 +1,5 @@ -export { default as types } from './types'; -export * from './login'; +import * as types from './types'; + +export { default as login } from './login'; + +export { types }; diff --git a/packages/cra-template-typescript/template/src/modules/auth/services/actions/login.ts b/packages/cra-template-typescript/template/src/modules/auth/services/actions/login.ts index 0fea3ecfe46..1a1300e51c3 100644 --- a/packages/cra-template-typescript/template/src/modules/auth/services/actions/login.ts +++ b/packages/cra-template-typescript/template/src/modules/auth/services/actions/login.ts @@ -1,5 +1,5 @@ -import types from './types'; +import { createFormActions } from 'react-final-form-redux-submit'; -export const loginForm = () => ({ - type: types.LOGIN_FORM, -}); +import { login as loginTypes } from './types'; + +export default createFormActions(loginTypes); diff --git a/packages/cra-template-typescript/template/src/modules/auth/services/actions/types.ts b/packages/cra-template-typescript/template/src/modules/auth/services/actions/types.ts index 9333a2f2ed9..61df17d7450 100644 --- a/packages/cra-template-typescript/template/src/modules/auth/services/actions/types.ts +++ b/packages/cra-template-typescript/template/src/modules/auth/services/actions/types.ts @@ -1,11 +1,3 @@ -import { createAsyncType } from "@ackee/redux-utils"; +import { createFormActionTypes } from 'react-final-form-redux-submit'; -const asyncType = createAsyncType({ - modulePrefix: 'auth', -}); - -export default { - ...asyncType({ - types: ['LOGIN_FORM'], - }), -}; +export const login = createFormActionTypes('LOGIN_FORM'); diff --git a/packages/cra-template-typescript/template/src/modules/auth/services/sagas/loginForm.ts b/packages/cra-template-typescript/template/src/modules/auth/services/sagas/loginForm.ts index 9a9dbd6dfa9..ca1a263af79 100644 --- a/packages/cra-template-typescript/template/src/modules/auth/services/sagas/loginForm.ts +++ b/packages/cra-template-typescript/template/src/modules/auth/services/sagas/loginForm.ts @@ -1,28 +1,21 @@ -import * as Petrus from "@ackee/petrus"; -import * as sagaEffects from "redux-saga/effects"; +import { LOGIN_SUCCESS, LOGIN_FAILURE, loginRequest } from '@ackee/petrus'; +import { put, take, takeLeading } from 'redux-saga/effects'; -import { types } from '../actions'; +import { types, login } from '../actions'; -const { put, take, takeEvery } = sagaEffects; +function* handleLoginForm(action: ReturnType) { + yield put(loginRequest(action.payload)); -function* handleLoginForm(action) { - yield action.startSubmit(); + const result = yield take([LOGIN_SUCCESS, LOGIN_FAILURE]); - yield put(Petrus.loginRequest(action.data)); - - const result = yield take([Petrus.LOGIN_SUCCESS, Petrus.LOGIN_FAILURE]); - - let payload; - - if (result.type === Petrus.LOGIN_FAILURE) { - payload = { - _error: 'Login failed', - }; + if (result.type === LOGIN_SUCCESS) { + yield put(login.submitSuccess()); + } else { + console.error(result.error); + yield put(login.submitFailure('login.failed')); } - - yield action.stopSubmit(payload); } -export default function*() { - yield takeEvery(types.LOGIN_FORM, handleLoginForm); +export default function* () { + yield takeLeading(types.login.SUBMIT, handleLoginForm); } diff --git a/packages/cra-template-typescript/template/src/modules/auth/types.ts b/packages/cra-template-typescript/template/src/modules/auth/types.ts index d69153282db..a301a04f4cd 100644 --- a/packages/cra-template-typescript/template/src/modules/auth/types.ts +++ b/packages/cra-template-typescript/template/src/modules/auth/types.ts @@ -1,5 +1,10 @@ -export type User = {email: string}; +export type User = { email: string }; export interface PetrusEntitiesState { user: null | User; -} \ No newline at end of file +} + +export enum LoginFormField { + EMAIL = 'email', + PASSWORD = 'password', +} diff --git a/packages/cra-template-typescript/template/src/modules/core/modules/redux/config/enhancer.ts b/packages/cra-template-typescript/template/src/modules/core/modules/redux/config/enhancer.ts index 1f12e06e47d..67bce094633 100644 --- a/packages/cra-template-typescript/template/src/modules/core/modules/redux/config/enhancer.ts +++ b/packages/cra-template-typescript/template/src/modules/core/modules/redux/config/enhancer.ts @@ -1,9 +1,5 @@ import { applyMiddleware, compose } from 'redux'; import createSagaMiddleware from 'redux-saga'; -// TODO: replace with use-form-module -// @use-auth-module-begin -import createReduxPromiseListener from 'redux-promise-listener'; -// @use-auth-module-end import { routerMiddlewareWithHistory } from 'modules/core/modules/router'; import { sentryMiddleware } from 'modules/core/modules/sentry'; @@ -13,16 +9,16 @@ import * as Log from 'config/loglevel'; import * as Consts from 'constants/index'; import type { StoreEnhancer } from 'redux'; +// @use-form-module-begin +import promiseListener from './promiseListener'; +// @use-form-module-end + declare global { interface Window { __REDUX_DEVTOOLS_EXTENSION__: any; } } -// @use-auth-module-begin -export const promiseListener = createReduxPromiseListener(); -// @use-auth-module-end - export default function configureEnhancer() { const sagaMiddleware = createSagaMiddleware({ onError: Log.error, @@ -31,9 +27,9 @@ export default function configureEnhancer() { const middlewares = [ routerMiddlewareWithHistory, sagaMiddleware, - // @use-auth-module-begin + // @use-form-module-begin promiseListener.middleware, - // @use-auth-module-end + // @use-form-module-end sentryMiddleware, ]; const enhancerArgs = [applyMiddleware(...middlewares)]; diff --git a/packages/cra-template-typescript/template/src/modules/core/modules/redux/config/promiseListener.ts b/packages/cra-template-typescript/template/src/modules/core/modules/redux/config/promiseListener.ts new file mode 100644 index 00000000000..86ae354011f --- /dev/null +++ b/packages/cra-template-typescript/template/src/modules/core/modules/redux/config/promiseListener.ts @@ -0,0 +1,5 @@ +// @use-form-module-begin +import createReduxPromiseListener from 'redux-promise-listener'; + +export default createReduxPromiseListener(); +// @use-form-module-end diff --git a/packages/cra-template-typescript/template/src/modules/form/hooks/useSubmitForm.ts b/packages/cra-template-typescript/template/src/modules/form/hooks/useSubmitForm.ts index 6755169c5b5..c1fdb9fc537 100644 --- a/packages/cra-template-typescript/template/src/modules/form/hooks/useSubmitForm.ts +++ b/packages/cra-template-typescript/template/src/modules/form/hooks/useSubmitForm.ts @@ -1,5 +1,5 @@ import { createSubmitFormHook } from 'react-final-form-redux-submit'; -import { promiseListener } from 'modules/core/modules/redux'; +import promiseListener from 'modules/core/modules/redux/config/promiseListener'; const useSubmitForm = createSubmitFormHook(promiseListener); diff --git a/packages/cra-template-typescript/template/src/services/reducers/index.ts b/packages/cra-template-typescript/template/src/services/reducers/index.ts index b4796a44298..7ade5ba41c6 100644 --- a/packages/cra-template-typescript/template/src/services/reducers/index.ts +++ b/packages/cra-template-typescript/template/src/services/reducers/index.ts @@ -1,4 +1,3 @@ -import { reducer as formReducer } from 'redux-form'; // @use-auth-module-begin import { reducer as auth } from 'modules/auth'; // @use-auth-module-end @@ -10,7 +9,6 @@ const reducers = { // @use-auth-module-begin auth, // @use-auth-module-end - form: formReducer, }; export default reducers; diff --git a/packages/cra-template-typescript/template/src/services/sagas/index.ts b/packages/cra-template-typescript/template/src/services/sagas/index.ts index d5e55f265c5..0e46e5e9bb7 100644 --- a/packages/cra-template-typescript/template/src/services/sagas/index.ts +++ b/packages/cra-template-typescript/template/src/services/sagas/index.ts @@ -1,6 +1,5 @@ import { all } from 'redux-saga/effects'; -import { submitFormSaga } from '@ackee/mateus'; // @use-auth-module-begin import { saga as auth } from 'modules/auth'; // @use-auth-module-end @@ -10,6 +9,5 @@ export default function* appSaga() { // @use-auth-module-begin auth(), // @use-auth-module-end - submitFormSaga(), ]); } diff --git a/packages/react-scripts/custom/scripts/init/useAuthModule/applyAnswer.js b/packages/react-scripts/custom/scripts/init/useAuthModule/applyAnswer.js index cdb4dd50f54..93101e43bb3 100644 --- a/packages/react-scripts/custom/scripts/init/useAuthModule/applyAnswer.js +++ b/packages/react-scripts/custom/scripts/init/useAuthModule/applyAnswer.js @@ -21,7 +21,7 @@ const createPrettierFormatter = async templatePath => { } const mergedOptions = { - parser: 'babel', + parser: 'typescript', ...options, }; @@ -29,9 +29,9 @@ const createPrettierFormatter = async templatePath => { }; // {/* ... */} or // ... -const BEGIN = /(\/\/|\{\/\*) @use-auth-module-begin(\s\*\/}$)?/gm; -const END = /(\/\/|\{\/\*) @use-auth-module-end(\s\*\/}$)?/gm; -const BEGIN_OR_END = /(\/\/|\{\/\*) @use-auth-module-(begin|end)(\s\*\/}$)?/gm; +const BEGIN = /(\/\/|\{\/\*) @use-(auth|form)-module-begin(\s\*\/}$)?/gm; +const END = /(\/\/|\{\/\*) @use-(auth|form)-module-end(\s\*\/}$)?/gm; +const BEGIN_OR_END = /(\/\/|\{\/\*) @use-(auth|form)-module-(begin|end)(\s\*\/}$)?/gm; /** * get content that is outside of @use-auth-module-begin and @use-auth-module-end comments diff --git a/packages/react-scripts/custom/scripts/init/useAuthModule/getDependencies.js b/packages/react-scripts/custom/scripts/init/useAuthModule/getDependencies.js index 9704e73c48f..5cf0c2f6969 100644 --- a/packages/react-scripts/custom/scripts/init/useAuthModule/getDependencies.js +++ b/packages/react-scripts/custom/scripts/init/useAuthModule/getDependencies.js @@ -8,19 +8,26 @@ module.exports = templatePath => { return { files: [ - resolveTemplateSrc('config/antonio/index.js'), - resolveTemplateSrc('services/sagas/modules/index.js'), - resolveTemplateSrc('services/sagas/index.js'), - resolveTemplateSrc('services/reducers/index.js'), - resolveTemplateSrc('modules/application/dependencies.js'), - resolveTemplateSrc('modules/application/components/App.jsx'), - resolveTemplateSrc('modules/core/modules/sentry/config/index.js'), - resolveTemplateSrc('modules/core/modules/sentry/dependencies.js'), - resolveTemplateSrc('modules/sharedDependencies.js'), + resolveTemplateSrc('config/antonio/index.ts'), + resolveTemplateSrc('services/sagas/modules/index.ts'), + resolveTemplateSrc('services/sagas/index.ts'), + resolveTemplateSrc('services/reducers/index.ts'), + resolveTemplateSrc('modules/application/components/App.tsx'), + resolveTemplateSrc('modules/core/modules/sentry/config/index.ts'), + resolveTemplateSrc('modules/core/modules/redux/config/enhancers.ts'), + resolveTemplateSrc( + 'modules/core/modules/redux/config/promiseListener.ts' + ), ], directories: [resolveTemplateSrc('modules/auth')], packageJson: { - dependencies: ['@ackee/petrus'], + dependencies: [ + '@ackee/petrus', + 'final-form', + 'react-final-form', + 'react-final-form-redux-submit', + 'redux-promise-listener', + ], }, }; }; diff --git a/packages/react-scripts/custom/scripts/init/useAuthModule/index.js b/packages/react-scripts/custom/scripts/init/useAuthModule/index.js index 820c037c0da..6e1fc924850 100644 --- a/packages/react-scripts/custom/scripts/init/useAuthModule/index.js +++ b/packages/react-scripts/custom/scripts/init/useAuthModule/index.js @@ -14,4 +14,6 @@ module.exports = async props => { }); await applyAnswer(result.useAuthModule, props); + + return result.useAuthModule; };